summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.mailmap2
-rw-r--r--CREDITS12
-rw-r--r--Documentation/ABI/testing/sysfs-bus-rbd29
-rw-r--r--Documentation/ABI/testing/sysfs-class-power8
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff15
-rw-r--r--Documentation/ABI/testing/sysfs-driver-wacom5
-rw-r--r--Documentation/DMA-API.txt22
-rw-r--r--Documentation/DocBook/crypto-API.tmpl38
-rw-r--r--Documentation/PCI/pcieaer-howto.txt26
-rw-r--r--Documentation/arm/sunxi/README2
-rw-r--r--Documentation/block/biodoc.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/davinci.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt39
-rw-r--r--Documentation/devicetree/bindings/arm/marvell/armada-39x.txt15
-rw-r--r--Documentation/devicetree/bindings/arm/marvell/marvell,orion5x.txt25
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip.txt12
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/pmu.txt1
-rw-r--r--Documentation/devicetree/bindings/arm/shmobile.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/sunxi.txt1
-rw-r--r--Documentation/devicetree/bindings/arm/technologic.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/zte.txt24
-rw-r--r--Documentation/devicetree/bindings/bus/qcom,ebi2.txt138
-rw-r--r--Documentation/devicetree/bindings/clock/mvebu-core-clock.txt1
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gcc.txt16
-rw-r--r--Documentation/devicetree/bindings/clock/st,stm32-rcc.txt42
-rw-r--r--Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt4
-rw-r--r--Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt47
-rw-r--r--Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt1
-rw-r--r--Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt4
-rw-r--r--Documentation/devicetree/bindings/dma/sun6i-dma.txt1
-rw-r--r--Documentation/devicetree/bindings/firmware/meson/meson_sm.txt15
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt8
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-arb.txt35
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-gate.txt41
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-meson.txt2
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mux.txt23
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-rcar.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/nxp,pca9541.txt29
-rw-r--r--Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt107
-rw-r--r--Documentation/devicetree/bindings/input/adc-keys.txt49
-rw-r--r--Documentation/devicetree/bindings/input/gpio-decoder.txt23
-rw-r--r--Documentation/devicetree/bindings/input/gpio-keys-polled.txt5
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt8
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt27
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt35
-rw-r--r--Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt17
-rw-r--r--Documentation/devicetree/bindings/mailbox/meson-mhu.txt34
-rw-r--r--Documentation/devicetree/bindings/media/meson-ir.txt5
-rw-r--r--Documentation/devicetree/bindings/mfd/ac100.txt54
-rw-r--r--Documentation/devicetree/bindings/mfd/act8945a.txt22
-rw-r--r--Documentation/devicetree/bindings/mfd/arizona.txt18
-rw-r--r--Documentation/devicetree/bindings/mfd/aspeed-scu.txt18
-rw-r--r--Documentation/devicetree/bindings/mfd/axp20x.txt28
-rw-r--r--Documentation/devicetree/bindings/mfd/lp873x.txt59
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt1
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom-rpm.txt15
-rw-r--r--Documentation/devicetree/bindings/mfd/rk808.txt37
-rw-r--r--Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt70
-rw-r--r--Documentation/devicetree/bindings/mfd/twl6040.txt1
-rw-r--r--Documentation/devicetree/bindings/mtd/nand.txt9
-rw-r--r--Documentation/devicetree/bindings/net/brcm,amac.txt24
-rw-r--r--Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt24
-rw-r--r--Documentation/devicetree/bindings/net/meson-dwmac.txt45
-rw-r--r--Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt39
-rw-r--r--Documentation/devicetree/bindings/pci/designware-pcie.txt3
-rw-r--r--Documentation/devicetree/bindings/pci/rockchip-pcie.txt106
-rw-r--r--Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt112
-rw-r--r--Documentation/devicetree/bindings/phy/meson-usb2-phy.txt27
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt4
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt44
-rw-r--r--Documentation/devicetree/bindings/power/act8945a-charger.txt35
-rw-r--r--Documentation/devicetree/bindings/power/reset/axxia-reset.txt (renamed from Documentation/devicetree/bindings/power_supply/axxia-reset.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/reset/imx-snvs-poweroff.txt (renamed from Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/reset/msm-poweroff.txt (renamed from Documentation/devicetree/bindings/power_supply/msm-poweroff.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/reset/qnap-poweroff.txt (renamed from Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/reset/restart-poweroff.txt (renamed from Documentation/devicetree/bindings/power_supply/restart-poweroff.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/reset/st-reset.txt7
-rw-r--r--Documentation/devicetree/bindings/power/supply/ab8500/btemp.txt (renamed from Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/ab8500/chargalg.txt (renamed from Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/ab8500/charger.txt (renamed from Documentation/devicetree/bindings/power_supply/ab8500/charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/ab8500/fg.txt (renamed from Documentation/devicetree/bindings/power_supply/ab8500/fg.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/act8945a-charger.txt48
-rw-r--r--Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt (renamed from Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/bq2415x.txt (renamed from Documentation/devicetree/bindings/power/bq2415x.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/bq24257.txt (renamed from Documentation/devicetree/bindings/power/bq24257.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/bq25890.txt (renamed from Documentation/devicetree/bindings/power/bq25890.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/charger-manager.txt (renamed from Documentation/devicetree/bindings/power_supply/charger-manager.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/da9150-charger.txt (renamed from Documentation/devicetree/bindings/power/da9150-charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/da9150-fg.txt (renamed from Documentation/devicetree/bindings/power/da9150-fg.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/gpio-charger.txt (renamed from Documentation/devicetree/bindings/power_supply/gpio-charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/isp1704.txt (renamed from Documentation/devicetree/bindings/power/isp1704.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/lp8727_charger.txt (renamed from Documentation/devicetree/bindings/power_supply/lp8727_charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/ltc2941.txt (renamed from Documentation/devicetree/bindings/power/ltc2941.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/max17042_battery.txt (renamed from Documentation/devicetree/bindings/power_supply/max17042_battery.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/max8925_batter.txt (renamed from Documentation/devicetree/bindings/power_supply/max8925_batter.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/olpc_battery.txt (renamed from Documentation/devicetree/bindings/power_supply/olpc_battery.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/power_supply.txt (renamed from Documentation/devicetree/bindings/power_supply/power_supply.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom,coincell-charger.txt (renamed from Documentation/devicetree/bindings/power/qcom,coincell-charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom_smbb.txt (renamed from Documentation/devicetree/bindings/power_supply/qcom_smbb.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/rt9455_charger.txt (renamed from Documentation/devicetree/bindings/power/rt9455_charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/rx51-battery.txt (renamed from Documentation/devicetree/bindings/power/rx51-battery.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt (renamed from Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/ti,bq24735.txt (renamed from Documentation/devicetree/bindings/power_supply/ti,bq24735.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/tps65090.txt (renamed from Documentation/devicetree/bindings/power_supply/tps65090.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/tps65217_charger.txt (renamed from Documentation/devicetree/bindings/power_supply/tps65217_charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/supply/twl-charger.txt (renamed from Documentation/devicetree/bindings/power/twl-charger.txt)0
-rw-r--r--Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt132
-rw-r--r--Documentation/devicetree/bindings/reset/st,stm32-rcc.txt6
-rw-r--r--Documentation/devicetree/bindings/reset/uniphier-reset.txt93
-rw-r--r--Documentation/devicetree/bindings/usb/dwc2.txt2
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt3
-rw-r--r--Documentation/dmaengine/provider.txt11
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--Documentation/filesystems/Locking32
-rw-r--r--Documentation/filesystems/ceph.txt4
-rw-r--r--Documentation/filesystems/directory-locking2
-rw-r--r--Documentation/filesystems/porting8
-rw-r--r--Documentation/filesystems/proc.txt12
-rw-r--r--Documentation/filesystems/vfs.txt56
-rw-r--r--Documentation/hid/intel-ish-hid.txt454
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--Documentation/livepatch/module-elf-format.txt20
-rw-r--r--Documentation/perf/xgene-pmu.txt48
-rw-r--r--Documentation/power/power_supply_class.txt4
-rw-r--r--Documentation/powerpc/cxlflash.txt44
-rw-r--r--Documentation/powerpc/syscall64-abi.txt105
-rw-r--r--Documentation/remoteproc.txt6
-rw-r--r--Documentation/scsi/00-INDEX2
-rw-r--r--Documentation/scsi/dtc3x80.txt43
-rw-r--r--Documentation/scsi/in2000.txt202
-rw-r--r--Documentation/scsi/scsi-parameters.txt18
-rw-r--r--Documentation/scsi/smartpqi.txt80
-rw-r--r--Documentation/x86/protection-keys.txt70
-rw-r--r--MAINTAINERS155
-rw-r--r--arch/alpha/Kconfig1
-rw-r--r--arch/alpha/include/uapi/asm/mman.h5
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S1
-rw-r--r--arch/arc/include/asm/Kbuild1
-rw-r--r--arch/arc/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm/Kconfig5
-rw-r--r--arch/arm/Kconfig.debug22
-rw-r--r--arch/arm/boot/dts/Makefile59
-rw-r--r--arch/arm/boot/dts/am335x-baltos.dtsi6
-rw-r--r--arch/arm/boot/dts/am335x-base0033.dts4
-rw-r--r--arch/arm/boot/dts/am335x-bone-common.dtsi12
-rw-r--r--arch/arm/boot/dts/am335x-boneblack.dts11
-rw-r--r--arch/arm/boot/dts/am335x-chilisom.dtsi2
-rw-r--r--arch/arm/boot/dts/am335x-cm-t335.dts8
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts18
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts70
-rw-r--r--arch/arm/boot/dts/am335x-icev2.dts47
-rw-r--r--arch/arm/boot/dts/am335x-igep0033.dtsi8
-rw-r--r--arch/arm/boot/dts/am335x-lxm.dts6
-rw-r--r--arch/arm/boot/dts/am335x-nano.dts4
-rw-r--r--arch/arm/boot/dts/am335x-pepper.dts18
-rw-r--r--arch/arm/boot/dts/am335x-phycore-som.dtsi4
-rw-r--r--arch/arm/boot/dts/am335x-shc.dts16
-rw-r--r--arch/arm/boot/dts/am335x-sl50.dts15
-rw-r--r--arch/arm/boot/dts/am335x-wega.dtsi64
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi92
-rw-r--r--arch/arm/boot/dts/am3517-craneboard.dts2
-rw-r--r--arch/arm/boot/dts/am3517-evm.dts2
-rw-r--r--arch/arm/boot/dts/am3517.dtsi2
-rw-r--r--arch/arm/boot/dts/am3517_mt_ventoux.dts2
-rw-r--r--arch/arm/boot/dts/am4372.dtsi10
-rw-r--r--arch/arm/boot/dts/am437x-cm-t43.dts6
-rw-r--r--arch/arm/boot/dts/am437x-gp-evm.dts21
-rw-r--r--arch/arm/boot/dts/am437x-idk-evm.dts2
-rw-r--r--arch/arm/boot/dts/am437x-sk-evm.dts45
-rw-r--r--arch/arm/boot/dts/am43x-epos-evm.dts11
-rw-r--r--arch/arm/boot/dts/am572x-idk.dts2
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi596
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15-revb1.dts24
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15.dts812
-rw-r--r--arch/arm/boot/dts/am57xx-cl-som-am57x.dts4
-rw-r--r--arch/arm/boot/dts/am57xx-idk-common.dtsi49
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd-ctrevb.dts32
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd.dts28
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-11mp-ctrevb.dts (renamed from arch/arm/boot/dts/arm-realview-eb-11mp-revb.dts)0
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-11mp.dts2
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-a9mp-bbrevd.dts28
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-bbrevd.dts29
-rw-r--r--arch/arm/boot/dts/arm-realview-eb-bbrevd.dtsi45
-rw-r--r--arch/arm/boot/dts/arm-realview-eb.dtsi23
-rw-r--r--arch/arm/boot/dts/armada-370-db.dts29
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi40
-rw-r--r--arch/arm/boot/dts/armada-370-synology-ds213j.dts112
-rw-r--r--arch/arm/boot/dts/armada-370-xp.dtsi56
-rw-r--r--arch/arm/boot/dts/armada-370.dtsi34
-rw-r--r--arch/arm/boot/dts/armada-385-db-ap.dts58
-rw-r--r--arch/arm/boot/dts/armada-385-linksys.dtsi9
-rw-r--r--arch/arm/boot/dts/armada-388-clearfog.dts48
-rw-r--r--arch/arm/boot/dts/armada-388-db.dts25
-rw-r--r--arch/arm/boot/dts/armada-388-gp.dts30
-rw-r--r--arch/arm/boot/dts/armada-388-rd.dts25
-rw-r--r--arch/arm/boot/dts/armada-38x.dtsi57
-rw-r--r--arch/arm/boot/dts/armada-390-db.dts175
-rw-r--r--arch/arm/boot/dts/armada-390.dtsi3
-rw-r--r--arch/arm/boot/dts/armada-395-gp.dts163
-rw-r--r--arch/arm/boot/dts/armada-395.dtsi76
-rw-r--r--arch/arm/boot/dts/armada-398-db.dts56
-rw-r--r--arch/arm/boot/dts/armada-398.dtsi10
-rw-r--r--arch/arm/boot/dts/armada-39x.dtsi126
-rw-r--r--arch/arm/boot/dts/armada-xp-axpwifiap.dts24
-rw-r--r--arch/arm/boot/dts/armada-xp-db.dts24
-rw-r--r--arch/arm/boot/dts/armada-xp-gp.dts24
-rw-r--r--arch/arm/boot/dts/armada-xp-linksys-mamba.dts24
-rw-r--r--arch/arm/boot/dts/armada-xp-synology-ds414.dts112
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi31
-rw-r--r--arch/arm/boot/dts/armv7-m.dtsi2
-rw-r--r--arch/arm/boot/dts/artpec6.dtsi31
-rw-r--r--arch/arm/boot/dts/axp209.dtsi6
-rw-r--r--arch/arm/boot/dts/bcm-nsp.dtsi37
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-a-plus.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-a.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-plus.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts1
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-zero.dts40
-rw-r--r--arch/arm/boot/dts/bcm2836-rpi-2-b.dts1
-rw-r--r--arch/arm/boot/dts/bcm283x-rpi-usb-host.dtsi3
-rw-r--r--arch/arm/boot/dts/bcm283x.dtsi9
-rw-r--r--arch/arm/boot/dts/bcm5301x.dtsi11
-rw-r--r--arch/arm/boot/dts/bcm958522er.dts130
-rw-r--r--arch/arm/boot/dts/bcm958525er.dts142
-rw-r--r--arch/arm/boot/dts/bcm958525xmc.dts44
-rw-r--r--arch/arm/boot/dts/bcm958622hr.dts170
-rw-r--r--arch/arm/boot/dts/bcm958623hr.dts178
-rw-r--r--arch/arm/boot/dts/bcm958625hr.dts71
-rw-r--r--arch/arm/boot/dts/bcm958625k.dts13
-rw-r--r--arch/arm/boot/dts/bcm988312hr.dts182
-rw-r--r--arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts2
-rw-r--r--arch/arm/boot/dts/berlin2.dtsi7
-rw-r--r--arch/arm/boot/dts/berlin2cd-google-chromecast.dts2
-rw-r--r--arch/arm/boot/dts/berlin2cd.dtsi5
-rw-r--r--arch/arm/boot/dts/berlin2q-marvell-dmp.dts2
-rw-r--r--arch/arm/boot/dts/berlin2q.dtsi8
-rw-r--r--arch/arm/boot/dts/da850-evm.dts51
-rw-r--r--arch/arm/boot/dts/da850-lcdk.dts221
-rw-r--r--arch/arm/boot/dts/da850.dtsi80
-rw-r--r--arch/arm/boot/dts/dm8148-evm.dts4
-rw-r--r--arch/arm/boot/dts/dm8148-t410.dts4
-rw-r--r--arch/arm/boot/dts/dm814x.dtsi4
-rw-r--r--arch/arm/boot/dts/dm8168-evm.dts4
-rw-r--r--arch/arm/boot/dts/dm816x.dtsi4
-rw-r--r--arch/arm/boot/dts/dra62x-j5eco-evm.dts4
-rw-r--r--arch/arm/boot/dts/dra7-evm.dts14
-rw-r--r--arch/arm/boot/dts/dra7.dtsi36
-rw-r--r--arch/arm/boot/dts/dra72-evm-common.dtsi4
-rw-r--r--arch/arm/boot/dts/dra72-evm-revc.dts2
-rw-r--r--arch/arm/boot/dts/dra72-evm.dts2
-rw-r--r--arch/arm/boot/dts/dra74x.dtsi1
-rw-r--r--arch/arm/boot/dts/dra7xx-clocks.dtsi15
-rw-r--r--arch/arm/boot/dts/efm32gg-dk3750.dts5
-rw-r--r--arch/arm/boot/dts/efm32gg.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos3250-artik5.dtsi3
-rw-r--r--arch/arm/boot/dts/exynos3250-monk.dts3
-rw-r--r--arch/arm/boot/dts/exynos3250-pinctrl.dtsi346
-rw-r--r--arch/arm/boot/dts/exynos3250-rinato.dts3
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi3
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi3
-rw-r--r--arch/arm/boot/dts/exynos4210-origen.dts3
-rw-r--r--arch/arm/boot/dts/exynos4210-pinctrl.dtsi458
-rw-r--r--arch/arm/boot/dts/exynos4210-smdkv310.dts15
-rw-r--r--arch/arm/boot/dts/exynos4210-trats.dts3
-rw-r--r--arch/arm/boot/dts/exynos4210-universal_c210.dts13
-rw-r--r--arch/arm/boot/dts/exynos4412-odroid-common.dtsi16
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidu3.dts3
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidx.dts5
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidx2.dts3
-rw-r--r--arch/arm/boot/dts/exynos4412-origen.dts15
-rw-r--r--arch/arm/boot/dts/exynos4412-smdk4412.dts15
-rw-r--r--arch/arm/boot/dts/exynos4412-tiny4412.dts3
-rw-r--r--arch/arm/boot/dts/exynos4412-trats2.dts3
-rw-r--r--arch/arm/boot/dts/exynos4415-pinctrl.dtsi296
-rw-r--r--arch/arm/boot/dts/exynos4415.dtsi3
-rw-r--r--arch/arm/boot/dts/exynos4x12-pinctrl.dtsi525
-rw-r--r--arch/arm/boot/dts/exynos4x12.dtsi5
-rw-r--r--arch/arm/boot/dts/exynos5.dtsi3
-rw-r--r--arch/arm/boot/dts/exynos5250-arndale.dts5
-rw-r--r--arch/arm/boot/dts/exynos5250-pinctrl.dtsi404
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts11
-rw-r--r--arch/arm/boot/dts/exynos5250-snow-common.dtsi81
-rw-r--r--arch/arm/boot/dts/exynos5250-snow-rev5.dts6
-rw-r--r--arch/arm/boot/dts/exynos5250-snow.dts6
-rw-r--r--arch/arm/boot/dts/exynos5250-spring.dts77
-rw-r--r--arch/arm/boot/dts/exynos5260-pinctrl.dtsi280
-rw-r--r--arch/arm/boot/dts/exynos5260-xyref5260.dts9
-rw-r--r--arch/arm/boot/dts/exynos5260.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos5410-odroidxu.dts35
-rw-r--r--arch/arm/boot/dts/exynos5410-pinctrl.dtsi182
-rw-r--r--arch/arm/boot/dts/exynos5410-smdk5410.dts13
-rw-r--r--arch/arm/boot/dts/exynos5420-arndale-octa.dts22
-rw-r--r--arch/arm/boot/dts/exynos5420-peach-pit.dts131
-rw-r--r--arch/arm/boot/dts/exynos5420-pinctrl.dtsi356
-rw-r--r--arch/arm/boot/dts/exynos5420-smdk5420.dts23
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi25
-rw-r--r--arch/arm/boot/dts/exynos5440-sd5v1.dts6
-rw-r--r--arch/arm/boot/dts/exynos5440-ssdk5440.dts6
-rw-r--r--arch/arm/boot/dts/exynos5440.dtsi3
-rw-r--r--arch/arm/boot/dts/exynos54xx.dtsi1
-rw-r--r--arch/arm/boot/dts/exynos5800-peach-pi.dts131
-rw-r--r--arch/arm/boot/dts/imx35.dtsi7
-rw-r--r--arch/arm/boot/dts/imx50.dtsi10
-rw-r--r--arch/arm/boot/dts/imx53-usbarmory.dts224
-rw-r--r--arch/arm/boot/dts/imx53.dtsi18
-rw-r--r--arch/arm/boot/dts/imx6dl-gw553x.dts55
-rw-r--r--arch/arm/boot/dts/imx6dl-riotboard.dts22
-rw-r--r--arch/arm/boot/dts/imx6dl-ts4900.dts49
-rw-r--r--arch/arm/boot/dts/imx6dl.dtsi53
-rw-r--r--arch/arm/boot/dts/imx6q-arm2.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-b450v3.dts16
-rw-r--r--arch/arm/boot/dts/imx6q-b650v3.dts9
-rw-r--r--arch/arm/boot/dts/imx6q-ba16.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6q-bx50v3.dtsi70
-rw-r--r--arch/arm/boot/dts/imx6q-cm-fx6.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-evi.dts28
-rw-r--r--arch/arm/boot/dts/imx6q-gw5400-a.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-gw553x.dts55
-rw-r--r--arch/arm/boot/dts/imx6q-marsboard.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-novena.dts12
-rw-r--r--arch/arm/boot/dts/imx6q-sbc6x.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-tbs2910.dts24
-rw-r--r--arch/arm/boot/dts/imx6q-ts4900.dts53
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi37
-rw-r--r--arch/arm/boot/dts/imx6qdl-apalis.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw51xx.dtsi36
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw52xx.dtsi39
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw53xx.dtsi39
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw54xx.dtsi44
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw551x.dtsi12
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw552x.dtsi12
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw553x.dtsi433
-rw-r--r--arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi12
-rw-r--r--arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi36
-rw-r--r--arch/arm/boot/dts/imx6qdl-rex.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabreauto.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabrelite.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabresd.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-ts4900.dtsi481
-rw-r--r--arch/arm/boot/dts/imx6qdl-udoo.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6qdl-wandboard.dtsi24
-rw-r--r--arch/arm/boot/dts/imx6sl.dtsi47
-rw-r--r--arch/arm/boot/dts/imx6sx-pinfunc.h14
-rw-r--r--arch/arm/boot/dts/imx6sx.dtsi22
-rw-r--r--arch/arm/boot/dts/imx6ul-geam-kit.dts101
-rw-r--r--arch/arm/boot/dts/imx6ul-geam.dtsi361
-rw-r--r--arch/arm/boot/dts/imx6ul-pico-hobbit.dts33
-rw-r--r--arch/arm/boot/dts/imx6ul.dtsi9
-rw-r--r--arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi4
-rw-r--r--arch/arm/boot/dts/imx7-colibri.dtsi61
-rw-r--r--arch/arm/boot/dts/imx7d.dtsi42
-rw-r--r--arch/arm/boot/dts/imx7s-warp.dts446
-rw-r--r--arch/arm/boot/dts/imx7s.dtsi371
-rw-r--r--arch/arm/boot/dts/integratorap.dts51
-rw-r--r--arch/arm/boot/dts/integratorcp.dts74
-rw-r--r--arch/arm/boot/dts/keystone-k2e-evm.dts12
-rw-r--r--arch/arm/boot/dts/keystone-k2e.dtsi4
-rw-r--r--arch/arm/boot/dts/keystone-k2g.dtsi32
-rw-r--r--arch/arm/boot/dts/keystone-k2hk-evm.dts6
-rw-r--r--arch/arm/boot/dts/keystone-k2l-evm.dts6
-rw-r--r--arch/arm/boot/dts/keystone.dtsi4
-rw-r--r--arch/arm/boot/dts/kirkwood-openblocks_a6.dts9
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-som.dtsi5
-rw-r--r--arch/arm/boot/dts/lpc18xx.dtsi7
-rw-r--r--arch/arm/boot/dts/lpc32xx.dtsi12
-rw-r--r--arch/arm/boot/dts/lpc4337-ciaa.dts2
-rw-r--r--arch/arm/boot/dts/lpc4350-hitex-eval.dts4
-rw-r--r--arch/arm/boot/dts/lpc4357-ea4357-devkit.dts2
-rw-r--r--arch/arm/boot/dts/ls1021a-twr.dts13
-rw-r--r--arch/arm/boot/dts/meson8b.dtsi21
-rw-r--r--arch/arm/boot/dts/mps2.dtsi1
-rw-r--r--arch/arm/boot/dts/ntc-gr8-evb.dts342
-rw-r--r--arch/arm/boot/dts/ntc-gr8.dtsi1087
-rw-r--r--arch/arm/boot/dts/omap2.dtsi4
-rw-r--r--arch/arm/boot/dts/omap2420-h4.dts2
-rw-r--r--arch/arm/boot/dts/omap2420-n8x0-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap2430-sdp.dts2
-rw-r--r--arch/arm/boot/dts/omap3-beagle-xm.dts2
-rw-r--r--arch/arm/boot/dts/omap3-beagle.dts2
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3x.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-evm-37xx.dts2
-rw-r--r--arch/arm/boot/dts/omap3-evm.dts2
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-igep.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-ldp.dts2
-rw-r--r--arch/arm/boot/dts/omap3-lilly-a83x.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-n900.dts2
-rw-r--r--arch/arm/boot/dts/omap3-n950-n9.dtsi6
-rw-r--r--arch/arm/boot/dts/omap3-overo-alto35-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-base.dtsi6
-rw-r--r--arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-palo35-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-overo-palo43-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-pandora-common.dtsi10
-rw-r--r--arch/arm/boot/dts/omap3-sniper.dts2
-rw-r--r--arch/arm/boot/dts/omap3-tao3530.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-zoom3.dts2
-rw-r--r--arch/arm/boot/dts/omap3.dtsi6
-rw-r--r--arch/arm/boot/dts/omap3430-sdp.dts2
-rw-r--r--arch/arm/boot/dts/omap34xx.dtsi2
-rw-r--r--arch/arm/boot/dts/omap36xx.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4-duovero-parlor.dts2
-rw-r--r--arch/arm/boot/dts/omap4-duovero.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4-kc1.dts2
-rw-r--r--arch/arm/boot/dts/omap4-panda-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap4-sdp.dts2
-rw-r--r--arch/arm/boot/dts/omap4-var-som-om44.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4.dtsi4
-rw-r--r--arch/arm/boot/dts/omap5-board-common.dtsi29
-rw-r--r--arch/arm/boot/dts/omap5-cm-t54.dts6
-rw-r--r--arch/arm/boot/dts/omap5-igep0050.dts42
-rw-r--r--arch/arm/boot/dts/omap5-uevm.dts18
-rw-r--r--arch/arm/boot/dts/omap5.dtsi26
-rw-r--r--arch/arm/boot/dts/orion5x-mv88f5181.dtsi49
-rw-r--r--arch/arm/boot/dts/orion5x-netgear-wnr854t.dts251
-rw-r--r--arch/arm/boot/dts/orion5x.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom-apq8060-dragonboard.dts39
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts15
-rw-r--r--arch/arm/boot/dts/qcom-apq8064.dtsi180
-rw-r--r--arch/arm/boot/dts/qcom-apq8084.dtsi103
-rw-r--r--arch/arm/boot/dts/qcom-ipq8064-ap148.dts1
-rw-r--r--arch/arm/boot/dts/qcom-msm8660.dtsi75
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts262
-rw-r--r--arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts81
-rw-r--r--arch/arm/boot/dts/qcom-msm8974.dtsi139
-rw-r--r--arch/arm/boot/dts/qcom-pm8941.dtsi5
-rw-r--r--arch/arm/boot/dts/r7s72100-rskrza1.dts61
-rw-r--r--arch/arm/boot/dts/r7s72100.dtsi22
-rw-r--r--arch/arm/boot/dts/r8a7790.dtsi23
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi18
-rw-r--r--arch/arm/boot/dts/r8a7792-blanche.dts264
-rw-r--r--arch/arm/boot/dts/r8a7792-wheat.dts199
-rw-r--r--arch/arm/boot/dts/r8a7792.dtsi554
-rw-r--r--arch/arm/boot/dts/r8a7794-alt.dts106
-rw-r--r--arch/arm/boot/dts/r8a7794-silk.dts70
-rw-r--r--arch/arm/boot/dts/r8a7794.dtsi309
-rw-r--r--arch/arm/boot/dts/rk3036.dtsi12
-rw-r--r--arch/arm/boot/dts/rk3288-evb-act8846.dts4
-rw-r--r--arch/arm/boot/dts/rk3288-evb-rk808.dts4
-rw-r--r--arch/arm/boot/dts/rk3288-evb.dtsi45
-rw-r--r--arch/arm/boot/dts/rk3288-fennec.dts382
-rw-r--r--arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi310
-rw-r--r--arch/arm/boot/dts/rk3288-firefly-reload.dts403
-rw-r--r--arch/arm/boot/dts/rk3288-popmetal.dts12
-rw-r--r--arch/arm/boot/dts/rk3288.dtsi73
-rw-r--r--arch/arm/boot/dts/rk3xxx.dtsi12
-rw-r--r--arch/arm/boot/dts/s3c2416-pinctrl.dtsi38
-rw-r--r--arch/arm/boot/dts/s3c6410-mini6410.dts4
-rw-r--r--arch/arm/boot/dts/s3c64xx-pinctrl.dtsi356
-rw-r--r--arch/arm/boot/dts/s5pv210-aquila.dts6
-rw-r--r--arch/arm/boot/dts/s5pv210-goni.dts2
-rw-r--r--arch/arm/boot/dts/s5pv210-pinctrl.dtsi476
-rw-r--r--arch/arm/boot/dts/s5pv210-smdkc110.dts2
-rw-r--r--arch/arm/boot/dts/s5pv210-smdkv210.dts2
-rw-r--r--arch/arm/boot/dts/s5pv210-torbreck.dts2
-rw-r--r--arch/arm/boot/dts/s5pv210.dtsi4
-rw-r--r--arch/arm/boot/dts/sama5d2.dtsi29
-rw-r--r--arch/arm/boot/dts/skeleton.dtsi4
-rw-r--r--arch/arm/boot/dts/ste-nomadik-nhk15.dts68
-rw-r--r--arch/arm/boot/dts/ste-nomadik-stn8815.dtsi28
-rw-r--r--arch/arm/boot/dts/stih407-clock.dtsi22
-rw-r--r--arch/arm/boot/dts/stih407-family.dtsi173
-rw-r--r--arch/arm/boot/dts/stih407-pinctrl.dtsi140
-rw-r--r--arch/arm/boot/dts/stih407.dtsi16
-rw-r--r--arch/arm/boot/dts/stih410-b2260.dts194
-rw-r--r--arch/arm/boot/dts/stih410-clock.dtsi20
-rw-r--r--arch/arm/boot/dts/stih410.dtsi34
-rw-r--r--arch/arm/boot/dts/stih415-pinctrl.dtsi54
-rw-r--r--arch/arm/boot/dts/stih416-b2020e.dts6
-rw-r--r--arch/arm/boot/dts/stih416-pinctrl.dtsi65
-rw-r--r--arch/arm/boot/dts/stih416.dtsi8
-rw-r--r--arch/arm/boot/dts/stih418-b2199.dts8
-rw-r--r--arch/arm/boot/dts/stih418-clock.dtsi20
-rw-r--r--arch/arm/boot/dts/stih41x-b2000.dtsi5
-rw-r--r--arch/arm/boot/dts/stih41x-b2020.dtsi6
-rw-r--r--arch/arm/boot/dts/stihxxx-b2120.dtsi52
-rw-r--r--arch/arm/boot/dts/stm32f429.dtsi2
-rw-r--r--arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts4
-rw-r--r--arch/arm/boot/dts/sun5i-a13-empire-electronix-m712.dts51
-rw-r--r--arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts164
-rw-r--r--arch/arm/boot/dts/sun5i-r8-chip.dts10
-rw-r--r--arch/arm/boot/dts/sun6i-a31.dtsi424
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-colorfly-e708-q1.dts138
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-inet-q972.dts100
-rw-r--r--arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi193
-rw-r--r--arch/arm/boot/dts/sun8i-a23-a33.dtsi306
-rw-r--r--arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts195
-rw-r--r--arch/arm/boot/dts/sun8i-a23-inet86dz.dts9
-rw-r--r--arch/arm/boot/dts/sun8i-a23-polaroid-mid2407pxe03.dts68
-rw-r--r--arch/arm/boot/dts/sun8i-a23-polaroid-mid2809pxe04.dts51
-rw-r--r--arch/arm/boot/dts/sun8i-a23.dtsi80
-rw-r--r--arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts28
-rw-r--r--arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts108
-rw-r--r--arch/arm/boot/dts/sun8i-a33-olinuxino.dts226
-rw-r--r--arch/arm/boot/dts/sun8i-a33.dtsi236
-rw-r--r--arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts2
-rw-r--r--arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts125
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-2.dts28
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts178
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-one.dts18
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts88
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts18
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts2
-rw-r--r--arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts53
-rw-r--r--arch/arm/boot/dts/sun8i-h3.dtsi93
-rw-r--r--arch/arm/boot/dts/sun8i-q8-common.dtsi49
-rw-r--r--arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi26
-rw-r--r--arch/arm/boot/dts/sun9i-a80-cubieboard4.dts145
-rw-r--r--arch/arm/boot/dts/sun9i-a80-optimus.dts152
-rw-r--r--arch/arm/boot/dts/sun9i-a80.dtsi14
-rw-r--r--arch/arm/boot/dts/tegra114.dtsi8
-rw-r--r--arch/arm/boot/dts/uniphier-common32.dtsi63
-rw-r--r--arch/arm/boot/dts/uniphier-ld4-ref.dts (renamed from arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-ld4.dtsi (renamed from arch/arm/boot/dts/uniphier-ph1-ld4.dtsi)59
-rw-r--r--arch/arm/boot/dts/uniphier-ld6b-ref.dts (renamed from arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-ld6b.dtsi (renamed from arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi)17
-rw-r--r--arch/arm/boot/dts/uniphier-pro4-ace.dts (renamed from arch/arm/boot/dts/uniphier-ph1-pro4-ace.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-pro4-ref.dts (renamed from arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-pro4-sanji.dts (renamed from arch/arm/boot/dts/uniphier-ph1-pro4-sanji.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-pro4.dtsi (renamed from arch/arm/boot/dts/uniphier-ph1-pro4.dtsi)63
-rw-r--r--arch/arm/boot/dts/uniphier-pro5.dtsi (renamed from arch/arm/boot/dts/uniphier-ph1-pro5.dtsi)58
-rw-r--r--arch/arm/boot/dts/uniphier-pxs2-gentil.dts (renamed from arch/arm/boot/dts/uniphier-proxstream2-gentil.dts)12
-rw-r--r--arch/arm/boot/dts/uniphier-pxs2-vodka.dts (renamed from arch/arm/boot/dts/uniphier-proxstream2-vodka.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-pxs2.dtsi (renamed from arch/arm/boot/dts/uniphier-proxstream2.dtsi)62
-rw-r--r--arch/arm/boot/dts/uniphier-sld3-ref.dts (renamed from arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-sld3.dtsi (renamed from arch/arm/boot/dts/uniphier-ph1-sld3.dtsi)75
-rw-r--r--arch/arm/boot/dts/uniphier-sld8-ref.dts (renamed from arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts)11
-rw-r--r--arch/arm/boot/dts/uniphier-sld8.dtsi (renamed from arch/arm/boot/dts/uniphier-ph1-sld8.dtsi)59
-rw-r--r--arch/arm/boot/dts/vf-colibri-eval-v3.dtsi13
-rw-r--r--arch/arm/boot/dts/vf610m4.dtsi1
-rw-r--r--arch/arm/configs/colibri_pxa270_defconfig1
-rw-r--r--arch/arm/configs/davinci_all_defconfig66
-rw-r--r--arch/arm/configs/exynos_defconfig9
-rw-r--r--arch/arm/configs/imx_v4_v5_defconfig3
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig17
-rw-r--r--arch/arm/configs/integrator_defconfig13
-rw-r--r--arch/arm/configs/lpd270_defconfig1
-rw-r--r--arch/arm/configs/multi_v4t_defconfig4
-rw-r--r--arch/arm/configs/multi_v7_defconfig11
-rw-r--r--arch/arm/configs/mvebu_v5_defconfig5
-rw-r--r--arch/arm/configs/mvebu_v7_defconfig3
-rw-r--r--arch/arm/configs/omap2plus_defconfig2
-rw-r--r--arch/arm/configs/pxa255-idp_defconfig1
-rw-r--r--arch/arm/configs/pxa_defconfig2
-rw-r--r--arch/arm/configs/s3c2410_defconfig1
-rw-r--r--arch/arm/configs/trizeps4_defconfig2
-rw-r--r--arch/arm/crypto/ghash-ce-glue.c26
-rw-r--r--arch/arm/crypto/sha1-armv7-neon.S1
-rw-r--r--arch/arm/include/asm/hardware/cache-uniphier.h20
-rw-r--r--arch/arm/include/asm/irq.h5
-rw-r--r--arch/arm/include/debug/brcmstb.S145
-rw-r--r--arch/arm/kernel/smp.c13
-rw-r--r--arch/arm/kernel/vmlinux-xip.lds.S1
-rw-r--r--arch/arm/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm/mach-at91/Kconfig1
-rw-r--r--arch/arm/mach-axxia/Kconfig2
-rw-r--r--arch/arm/mach-bcm/Kconfig14
-rw-r--r--arch/arm/mach-bcm/brcmstb.c16
-rw-r--r--arch/arm/mach-clps711x/Makefile.boot0
-rw-r--r--arch/arm/mach-clps711x/board-autcpu12.c275
-rw-r--r--arch/arm/mach-clps711x/board-cdb89712.c147
-rw-r--r--arch/arm/mach-clps711x/board-clep7312.c45
-rw-r--r--arch/arm/mach-clps711x/board-edb7211.c188
-rw-r--r--arch/arm/mach-clps711x/board-p720t.c373
-rw-r--r--arch/arm/mach-clps711x/common.c65
-rw-r--r--arch/arm/mach-clps711x/common.h23
-rw-r--r--arch/arm/mach-clps711x/devices.c149
-rw-r--r--arch/arm/mach-clps711x/devices.h12
-rw-r--r--arch/arm/mach-cns3xxx/Kconfig1
-rw-r--r--arch/arm/mach-davinci/da850.c1
-rw-r--r--arch/arm/mach-davinci/da8xx-dt.c2
-rw-r--r--arch/arm/mach-exynos/Kconfig3
-rw-r--r--arch/arm/mach-exynos/exynos.c15
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h5
-rw-r--r--arch/arm/mach-imx/Kconfig52
-rw-r--r--arch/arm/mach-imx/Makefile8
-rw-r--r--arch/arm/mach-imx/common.h7
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c2
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sx.c11
-rw-r--r--arch/arm/mach-imx/devices-imx1.h30
-rw-r--r--arch/arm/mach-imx/devices/Makefile1
-rw-r--r--arch/arm/mach-imx/devices/devices-common.h12
-rw-r--r--arch/arm/mach-imx/devices/platform-imx-fb.c5
-rw-r--r--arch/arm/mach-imx/devices/platform-imx-i2c.c5
-rw-r--r--arch/arm/mach-imx/devices/platform-imx-uart.c37
-rw-r--r--arch/arm/mach-imx/devices/platform-spi_imx.c9
-rw-r--r--arch/arm/mach-imx/hardware.h3
-rw-r--r--arch/arm/mach-imx/iomux-mx1.h155
-rw-r--r--arch/arm/mach-imx/iomux-mx3.h34
-rw-r--r--arch/arm/mach-imx/mach-apf9328.c148
-rw-r--r--arch/arm/mach-imx/mach-armadillo5x0.c39
-rw-r--r--arch/arm/mach-imx/mach-imx1.c (renamed from arch/arm/mach-imx/imx1-dt.c)23
-rw-r--r--arch/arm/mach-imx/mach-imx27_visstrim_m10.c24
-rw-r--r--arch/arm/mach-imx/mach-imx6ul.c3
-rw-r--r--arch/arm/mach-imx/mach-kzm_arm11_01.c15
-rw-r--r--arch/arm/mach-imx/mach-mx21ads.c13
-rw-r--r--arch/arm/mach-imx/mach-mx27_3ds.c30
-rw-r--r--arch/arm/mach-imx/mach-mx27ads.c13
-rw-r--r--arch/arm/mach-imx/mach-mx31_3ds.c39
-rw-r--r--arch/arm/mach-imx/mach-mx31ads.c18
-rw-r--r--arch/arm/mach-imx/mach-mx31lilly.c50
-rw-r--r--arch/arm/mach-imx/mach-mx31lite.c68
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c23
-rw-r--r--arch/arm/mach-imx/mach-mx35_3ds.c15
-rw-r--r--arch/arm/mach-imx/mach-pca100.c26
-rw-r--r--arch/arm/mach-imx/mach-pcm037.c69
-rw-r--r--arch/arm/mach-imx/mach-pcm043.c10
-rw-r--r--arch/arm/mach-imx/mach-qong.c2
-rw-r--r--arch/arm/mach-imx/mach-scb9328.c143
-rw-r--r--arch/arm/mach-imx/mach-vpr200.c29
-rw-r--r--arch/arm/mach-imx/mm-imx1.c67
-rw-r--r--arch/arm/mach-imx/mx1.h172
-rw-r--r--arch/arm/mach-imx/mx31lilly-db.c20
-rw-r--r--arch/arm/mach-imx/mx31lite-db.c33
-rw-r--r--arch/arm/mach-imx/pm-imx6.c8
-rw-r--r--arch/arm/mach-integrator/Kconfig1
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c36
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c123
-rw-r--r--arch/arm/mach-keystone/Kconfig2
-rw-r--r--arch/arm/mach-mv78xx0/common.c9
-rw-r--r--arch/arm/mach-mxs/mach-mxs.c77
-rw-r--r--arch/arm/mach-nomadik/Kconfig1
-rw-r--r--arch/arm/mach-omap1/board-h2-mmc.c2
-rw-r--r--arch/arm/mach-omap1/board-h2.c2
-rw-r--r--arch/arm/mach-omap1/board-h3-mmc.c2
-rw-r--r--arch/arm/mach-omap1/board-h3.c2
-rw-r--r--arch/arm/mach-omap1/board-htcherald.c4
-rw-r--r--arch/arm/mach-omap1/board-innovator.c4
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c4
-rw-r--r--arch/arm/mach-omap1/board-sx1-mmc.c2
-rw-r--r--arch/arm/mach-omap1/devices.c10
-rw-r--r--arch/arm/mach-omap1/fb.c2
-rw-r--r--arch/arm/mach-omap1/include/mach/usb.h2
-rw-r--r--arch/arm/mach-omap1/mmc.h2
-rw-r--r--arch/arm/mach-omap1/usb.c6
-rw-r--r--arch/arm/mach-omap2/Kconfig12
-rw-r--r--arch/arm/mach-omap2/Makefile4
-rw-r--r--arch/arm/mach-omap2/board-flash.c10
-rw-r--r--arch/arm/mach-omap2/board-flash.h11
-rw-r--r--arch/arm/mach-omap2/board-ldp.c430
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c5
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c1313
-rw-r--r--arch/arm/mach-omap2/board-rx51-video.c67
-rw-r--r--arch/arm/mach-omap2/board-rx51.c141
-rw-r--r--arch/arm/mach-omap2/board-rx51.h11
-rw-r--r--arch/arm/mach-omap2/common-board-devices.c3
-rw-r--r--arch/arm/mach-omap2/devices.c7
-rw-r--r--arch/arm/mach-omap2/drm.c2
-rw-r--r--arch/arm/mach-omap2/fb.c2
-rw-r--r--arch/arm/mach-omap2/gpmc-smsc911x.h2
-rw-r--r--arch/arm/mach-omap2/hsmmc.c2
-rw-r--r--arch/arm/mach-omap2/hsmmc.h2
-rw-r--r--arch/arm/mach-omap2/twl-common.c3
-rw-r--r--arch/arm/mach-orion5x/common.c4
-rw-r--r--arch/arm/mach-orion5x/common.h2
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c4
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c5
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c6
-rw-r--r--arch/arm/mach-orion5x/wnr854t-setup.c4
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c4
-rw-r--r--arch/arm/mach-pxa/Kconfig11
-rw-r--r--arch/arm/mach-pxa/Makefile3
-rw-r--r--arch/arm/mach-pxa/corgi_pm.c13
-rw-r--r--arch/arm/mach-pxa/devices.h1
-rw-r--r--arch/arm/mach-pxa/generic.h2
-rw-r--r--arch/arm/mach-pxa/include/mach/dma.h1
-rw-r--r--arch/arm/mach-pxa/magician.c4
-rw-r--r--arch/arm/mach-pxa/pm.c5
-rw-r--r--arch/arm/mach-pxa/pxa-dt.c35
-rw-r--r--arch/arm/mach-pxa/pxa25x.c26
-rw-r--r--arch/arm/mach-pxa/pxa27x.c14
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c11
-rw-r--r--arch/arm/mach-pxa/pxa_cplds_irqs.c24
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.c2
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.h2
-rw-r--r--arch/arm/mach-pxa/spitz_pm.c9
-rw-r--r--arch/arm/mach-qcom/Makefile1
-rw-r--r--arch/arm/mach-realview/Kconfig72
-rw-r--r--arch/arm/mach-realview/Makefile12
-rw-r--r--arch/arm/mach-realview/board-eb.h94
-rw-r--r--arch/arm/mach-realview/board-pb1176.h81
-rw-r--r--arch/arm/mach-realview/board-pb11mp.h96
-rw-r--r--arch/arm/mach-realview/board-pba8.h71
-rw-r--r--arch/arm/mach-realview/board-pbx.h106
-rw-r--r--arch/arm/mach-realview/core.c405
-rw-r--r--arch/arm/mach-realview/core.h58
-rw-r--r--arch/arm/mach-realview/hardware.h40
-rw-r--r--arch/arm/mach-realview/hotplug.h1
-rw-r--r--arch/arm/mach-realview/irqs-eb.h114
-rw-r--r--arch/arm/mach-realview/irqs-pb1176.h77
-rw-r--r--arch/arm/mach-realview/irqs-pb11mp.h97
-rw-r--r--arch/arm/mach-realview/irqs-pba8.h71
-rw-r--r--arch/arm/mach-realview/irqs-pbx.h87
-rw-r--r--arch/arm/mach-realview/platform.h247
-rw-r--r--arch/arm/mach-realview/platsmp-dt.c3
-rw-r--r--arch/arm/mach-realview/platsmp.c86
-rw-r--r--arch/arm/mach-realview/realview_eb.c492
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c395
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c385
-rw-r--r--arch/arm/mach-realview/realview_pba8.c307
-rw-r--r--arch/arm/mach-realview/realview_pbx.c402
-rw-r--r--arch/arm/mach-s3c24xx/common.c55
-rw-r--r--arch/arm/mach-s3c24xx/mach-mini2440.c1
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410-module.c3
-rw-r--r--arch/arm/mach-sa1100/jornada720.c16
-rw-r--r--arch/arm/mach-shmobile/Kconfig1
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7790.c2
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7791.c2
-rw-r--r--arch/arm/mach-spear/Kconfig1
-rw-r--r--arch/arm/mach-sunxi/Kconfig1
-rw-r--r--arch/arm/mach-sunxi/sunxi.c1
-rw-r--r--arch/arm/mach-uniphier/Makefile2
-rw-r--r--arch/arm/mach-uniphier/headsmp.S43
-rw-r--r--arch/arm/mach-uniphier/platsmp.c209
-rw-r--r--arch/arm/mach-versatile/Kconfig1
-rw-r--r--arch/arm/mm/cache-uniphier.c63
-rw-r--r--arch/arm/mm/dma-mapping.c63
-rw-r--r--arch/arm/plat-orion/common.c85
-rw-r--r--arch/arm/plat-orion/include/plat/common.h10
-rw-r--r--arch/arm/plat-pxa/Makefile2
-rw-r--r--arch/arm/plat-pxa/dma.c386
-rw-r--r--arch/arm/plat-pxa/include/plat/dma.h100
-rw-r--r--arch/arm/plat-samsung/include/plat/map-s5p.h4
-rw-r--r--arch/arm64/Kconfig2
-rw-r--r--arch/arm64/Kconfig.platforms17
-rw-r--r--arch/arm64/boot/dts/Makefile1
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts11
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts6
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi35
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi42
-rw-r--r--arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi329
-rw-r--r--arch/arm64/boot/dts/apm/apm-shadowcat.dtsi135
-rw-r--r--arch/arm64/boot/dts/apm/apm-storm.dtsi103
-rw-r--r--arch/arm64/boot/dts/broadcom/ns2.dtsi8
-rw-r--r--arch/arm64/boot/dts/exynos/exynos7.dtsi13
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts14
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts8
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi7
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts3
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts4
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi18
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts86
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220.dtsi61
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05.dtsi5
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi180
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip06-d03.dts28
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip06.dtsi365
-rw-r--r--arch/arm64/boot/dts/marvell/Makefile1
-rw-r--r--arch/arm64/boot/dts/marvell/armada-8020.dtsi1
-rw-r--r--arch/arm64/boot/dts/marvell/armada-8040-db.dts150
-rw-r--r--arch/arm64/boot/dts/marvell/armada-8040.dtsi1
-rw-r--r--arch/arm64/boot/dts/marvell/armada-ap806.dtsi14
-rw-r--r--arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi3
-rw-r--r--arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi249
-rw-r--r--arch/arm64/boot/dts/marvell/berlin4ct.dtsi12
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173-evb.dts38
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173.dtsi77
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra210-smaug.dts120
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra210.dtsi79
-rw-r--r--arch/arm64/boot/dts/qcom/Makefile1
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi48
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi82
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi39
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c.dts (renamed from arch/arm/mach-qcom/board.c)24
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi88
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi286
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi94
-rw-r--r--arch/arm64/boot/dts/renesas/Makefile2
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts328
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts87
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7795.dtsi276
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts16
-rw-r--r--arch/arm64/boot/dts/renesas/r8a7796.dtsi117
-rw-r--r--arch/arm64/boot/dts/rockchip/Makefile1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts382
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-r88.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368.dtsi10
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-evb.dts87
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399.dtsi607
-rw-r--r--arch/arm64/boot/dts/socionext/Makefile4
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts100
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi338
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts (renamed from arch/arm64/boot/dts/socionext/uniphier-ph1-ld20-ref.dts)11
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi (renamed from arch/arm64/boot/dts/socionext/uniphier-ph1-ld20.dtsi)94
-rw-r--r--arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts2
-rw-r--r--arch/arm64/boot/dts/xilinx/zynqmp.dtsi100
-rw-r--r--arch/arm64/boot/dts/zte/Makefile5
-rw-r--r--arch/arm64/boot/dts/zte/zx296718-evb.dts64
-rw-r--r--arch/arm64/boot/dts/zte/zx296718.dtsi292
-rw-r--r--arch/arm64/configs/defconfig35
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S1
-rw-r--r--arch/avr32/kernel/traps.c3
-rw-r--r--arch/avr32/kernel/vmlinux.lds.S1
-rw-r--r--arch/avr32/mm/fault.c2
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S1
-rw-r--r--arch/c6x/kernel/vmlinux.lds.S1
-rw-r--r--arch/cris/Kconfig2
-rw-r--r--arch/cris/arch-v10/drivers/axisflashmap.c19
-rw-r--r--arch/cris/arch-v10/drivers/eeprom.c2
-rw-r--r--arch/cris/arch-v10/lib/dram_init.S2
-rw-r--r--arch/cris/arch-v32/drivers/cryptocop.c2
-rw-r--r--arch/cris/arch-v32/drivers/pci/bios.c2
-rw-r--r--arch/cris/arch-v32/drivers/sync_serial.c6
-rw-r--r--arch/cris/arch-v32/kernel/fasttimer.c15
-rw-r--r--arch/cris/arch-v32/kernel/irq.c3
-rw-r--r--arch/cris/arch-v32/mach-a3/dma.c1
-rw-r--r--arch/cris/arch-v32/mach-a3/dram_init.S2
-rw-r--r--arch/cris/arch-v32/mach-fs/dma.c1
-rw-r--r--arch/cris/arch-v32/mach-fs/dram_init.S2
-rw-r--r--arch/cris/arch-v32/mm/intmem.c13
-rw-r--r--arch/cris/configs/artpec_3_defconfig1
-rw-r--r--arch/cris/configs/dev88_defconfig48
-rw-r--r--arch/cris/configs/etrax-100lx_v2_defconfig1
-rw-r--r--arch/cris/configs/etraxfs_defconfig1
-rw-r--r--arch/cris/include/arch-v32/arch/cryptocop.h2
-rw-r--r--arch/cris/include/asm/io.h171
-rw-r--r--arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h2
-rw-r--r--arch/cris/kernel/vmlinux.lds.S1
-rw-r--r--arch/cris/mm/fault.c2
-rw-r--r--arch/frv/kernel/vmlinux.lds.S1
-rw-r--r--arch/h8300/kernel/vmlinux.lds.S1
-rw-r--r--arch/hexagon/kernel/vmlinux.lds.S1
-rw-r--r--arch/ia64/include/asm/atomic.h16
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S1
-rw-r--r--arch/m32r/kernel/vmlinux.lds.S1
-rw-r--r--arch/m68k/kernel/vmlinux-nommu.lds1
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds1
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds1
-rw-r--r--arch/metag/kernel/vmlinux.lds.S1
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S1
-rw-r--r--arch/microblaze/pci/pci-common.c4
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/include/asm/irq.h5
-rw-r--r--arch/mips/include/asm/pgtable.h2
-rw-r--r--arch/mips/include/asm/uprobes.h12
-rw-r--r--arch/mips/include/uapi/asm/mman.h5
-rw-r--r--arch/mips/kernel/process.c11
-rw-r--r--arch/mips/kernel/vmlinux.lds.S1
-rw-r--r--arch/mn10300/kernel/vmlinux.lds.S1
-rw-r--r--arch/nios2/include/asm/cpuinfo.h8
-rw-r--r--arch/nios2/kernel/cpuinfo.c15
-rw-r--r--arch/nios2/kernel/vmlinux.lds.S1
-rw-r--r--arch/openrisc/kernel/vmlinux.lds.S1
-rw-r--r--arch/parisc/Kconfig5
-rw-r--r--arch/parisc/include/asm/dwarf.h23
-rw-r--r--arch/parisc/include/asm/linkage.h12
-rw-r--r--arch/parisc/include/asm/pgtable.h2
-rw-r--r--arch/parisc/include/asm/uaccess.h48
-rw-r--r--arch/parisc/include/uapi/asm/mman.h5
-rw-r--r--arch/parisc/kernel/cache.c2
-rw-r--r--arch/parisc/kernel/entry.S46
-rw-r--r--arch/parisc/kernel/hpmc.S16
-rw-r--r--arch/parisc/kernel/inventory.c2
-rw-r--r--arch/parisc/kernel/pacache.S84
-rw-r--r--arch/parisc/kernel/real2.S24
-rw-r--r--arch/parisc/kernel/setup.c8
-rw-r--r--arch/parisc/kernel/smp.c4
-rw-r--r--arch/parisc/kernel/time.c6
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S3
-rw-r--r--arch/parisc/lib/fixup.S16
-rw-r--r--arch/parisc/lib/lusercopy.S8
-rw-r--r--arch/parisc/lib/memcpy.c11
-rw-r--r--arch/parisc/mm/fault.c48
-rw-r--r--arch/parisc/mm/init.c126
-rw-r--r--arch/powerpc/Kconfig11
-rw-r--r--arch/powerpc/Makefile43
-rw-r--r--arch/powerpc/boot/Makefile86
-rw-r--r--arch/powerpc/boot/cuboot-c2k.c1
-rw-r--r--arch/powerpc/boot/decompress.c148
-rw-r--r--arch/powerpc/boot/fixup-headers.sed12
-rw-r--r--arch/powerpc/boot/gunzip_util.c204
-rw-r--r--arch/powerpc/boot/gunzip_util.h45
-rw-r--r--arch/powerpc/boot/main.c35
-rw-r--r--arch/powerpc/boot/ops.h3
-rw-r--r--arch/powerpc/boot/stdbool.h14
-rw-r--r--arch/powerpc/boot/stdint.h13
-rw-r--r--arch/powerpc/boot/types.h14
-rwxr-xr-xarch/powerpc/boot/wrapper61
-rw-r--r--arch/powerpc/boot/xz_config.h39
-rw-r--r--arch/powerpc/configs/powernv_defconfig19
-rw-r--r--arch/powerpc/configs/ppc64_defconfig19
-rw-r--r--arch/powerpc/configs/pseries_defconfig19
-rw-r--r--arch/powerpc/crypto/sha1-powerpc-asm.S13
-rw-r--r--arch/powerpc/include/asm/asm-prototypes.h43
-rw-r--r--arch/powerpc/include/asm/atomic.h4
-rw-r--r--arch/powerpc/include/asm/book3s/32/pgtable.h3
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h7
-rw-r--r--arch/powerpc/include/asm/book3s/64/radix.h88
-rw-r--r--arch/powerpc/include/asm/book3s/64/tlbflush-radix.h1
-rw-r--r--arch/powerpc/include/asm/cputable.h4
-rw-r--r--arch/powerpc/include/asm/exception-64s.h148
-rw-r--r--arch/powerpc/include/asm/fadump.h4
-rw-r--r--arch/powerpc/include/asm/head-64.h393
-rw-r--r--arch/powerpc/include/asm/machdep.h2
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h3
-rw-r--r--arch/powerpc/include/asm/mmu.h4
-rw-r--r--arch/powerpc/include/asm/mmu_context.h4
-rw-r--r--arch/powerpc/include/asm/mmzone.h3
-rw-r--r--arch/powerpc/include/asm/mpic_msgr.h6
-rw-r--r--arch/powerpc/include/asm/nohash/32/pgtable.h3
-rw-r--r--arch/powerpc/include/asm/nohash/64/pgtable.h3
-rw-r--r--arch/powerpc/include/asm/parport.h2
-rw-r--r--arch/powerpc/include/asm/pnv-pci.h4
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h2
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h49
-rw-r--r--arch/powerpc/include/asm/processor.h16
-rw-r--r--arch/powerpc/include/asm/reg.h5
-rw-r--r--arch/powerpc/include/asm/signal.h2
-rw-r--r--arch/powerpc/include/asm/tm.h5
-rw-r--r--arch/powerpc/kernel/Makefile15
-rw-r--r--arch/powerpc/kernel/asm-offsets.c12
-rw-r--r--arch/powerpc/kernel/cputable.c19
-rw-r--r--arch/powerpc/kernel/eeh.c4
-rw-r--r--arch/powerpc/kernel/eeh_driver.c10
-rw-r--r--arch/powerpc/kernel/eeh_pe.c1
-rw-r--r--arch/powerpc/kernel/entry_32.S1
-rw-r--r--arch/powerpc/kernel/entry_64.S21
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S2024
-rw-r--r--arch/powerpc/kernel/fadump.c13
-rw-r--r--arch/powerpc/kernel/fpu.S26
-rw-r--r--arch/powerpc/kernel/head_32.S3
-rw-r--r--arch/powerpc/kernel/head_64.S53
-rw-r--r--arch/powerpc/kernel/head_8xx.S1
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c9
-rw-r--r--arch/powerpc/kernel/ibmebus.c2
-rw-r--r--arch/powerpc/kernel/irq.c17
-rw-r--r--arch/powerpc/kernel/legacy_serial.c14
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c75
-rw-r--r--arch/powerpc/kernel/misc_32.S4
-rw-r--r--arch/powerpc/kernel/misc_64.S30
-rw-r--r--arch/powerpc/kernel/module.c2
-rw-r--r--arch/powerpc/kernel/nvram_64.c10
-rw-r--r--arch/powerpc/kernel/pci-common.c5
-rw-r--r--arch/powerpc/kernel/pci_of_scan.c2
-rw-r--r--arch/powerpc/kernel/process.c181
-rw-r--r--arch/powerpc/kernel/prom_init.c82
-rw-r--r--arch/powerpc/kernel/ptrace.c353
-rw-r--r--arch/powerpc/kernel/signal.c41
-rw-r--r--arch/powerpc/kernel/signal.h18
-rw-r--r--arch/powerpc/kernel/signal_32.c122
-rw-r--r--arch/powerpc/kernel/signal_64.c207
-rw-r--r--arch/powerpc/kernel/syscalls.c1
-rw-r--r--arch/powerpc/kernel/time.c1
-rw-r--r--arch/powerpc/kernel/tm.S94
-rw-r--r--arch/powerpc/kernel/traps.c83
-rw-r--r--arch/powerpc/kernel/vdso64/Makefile6
-rw-r--r--arch/powerpc/kernel/vdso64/datapage.S2
-rw-r--r--arch/powerpc/kernel/vdso64/gettimeofday.S2
-rw-r--r--arch/powerpc/kernel/vector.S25
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S56
-rw-r--r--arch/powerpc/lib/Makefile2
-rw-r--r--arch/powerpc/lib/mem_64.S2
-rw-r--r--arch/powerpc/mm/Makefile7
-rw-r--r--arch/powerpc/mm/fault.c4
-rw-r--r--arch/powerpc/mm/hash_utils_64.c81
-rw-r--r--arch/powerpc/mm/hugetlbpage.c7
-rw-r--r--arch/powerpc/mm/init_32.c2
-rw-r--r--arch/powerpc/mm/mmu_context_iommu.c81
-rw-r--r--arch/powerpc/mm/pgtable-book3s64.c11
-rw-r--r--arch/powerpc/mm/pgtable-radix.c40
-rw-r--r--arch/powerpc/mm/pgtable.c2
-rw-r--r--arch/powerpc/mm/slb_low.S8
-rw-r--r--arch/powerpc/mm/tlb-radix.c24
-rw-r--r--arch/powerpc/net/bpf_jit.h2
-rw-r--r--arch/powerpc/net/bpf_jit64.h26
-rw-r--r--arch/powerpc/net/bpf_jit_comp64.c264
-rw-r--r--arch/powerpc/oprofile/cell/spu_profiler.c2
-rw-r--r--arch/powerpc/oprofile/cell/spu_task_sync.c4
-rw-r--r--arch/powerpc/perf/core-book3s.c2
-rw-r--r--arch/powerpc/perf/hv-gpci.c2
-rw-r--r--arch/powerpc/perf/power7-pmu.c2
-rw-r--r--arch/powerpc/perf/power8-pmu.c2
-rw-r--r--arch/powerpc/perf/power9-pmu.c2
-rw-r--r--arch/powerpc/platforms/44x/warp.c2
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads_cpld.c8
-rw-r--r--arch/powerpc/platforms/512x/mpc512x_lpbfifo.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c2
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads-pci-pic.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c2
-rw-r--r--arch/powerpc/platforms/83xx/suspend.c4
-rw-r--r--arch/powerpc/platforms/85xx/common.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c4
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c4
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.c6
-rw-r--r--arch/powerpc/platforms/86xx/pic.c4
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c2
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype2
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c6
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c2
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c18
-rw-r--r--arch/powerpc/platforms/cell/iommu.c4
-rw-r--r--arch/powerpc/platforms/cell/pmu.c4
-rw-r--r--arch/powerpc/platforms/cell/ras.c2
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c18
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c16
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c9
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c2
-rw-r--r--arch/powerpc/platforms/chrp/setup.c4
-rw-r--r--arch/powerpc/platforms/embedded6xx/flipper-pic.c2
-rw-r--r--arch/powerpc/platforms/embedded6xx/hlwd-pic.c4
-rw-r--r--arch/powerpc/platforms/embedded6xx/mvme5100.c4
-rw-r--r--arch/powerpc/platforms/maple/pci.c6
-rw-r--r--arch/powerpc/platforms/maple/setup.c4
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig10
-rw-r--r--arch/powerpc/platforms/pasemi/gpio_mdio.c4
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c2
-rw-r--r--arch/powerpc/platforms/pasemi/misc.c2
-rw-r--r--arch/powerpc/platforms/pasemi/msi.c4
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c8
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c6
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c4
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_core.c2
-rw-r--r--arch/powerpc/platforms/powermac/pic.c6
-rw-r--r--arch/powerpc/platforms/powermac/smp.c2
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c18
-rw-r--r--arch/powerpc/platforms/powernv/npu-dma.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal-irqchip.c4
-rw-r--r--arch/powerpc/platforms/powernv/pci-cxl.c4
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c59
-rw-r--r--arch/powerpc/platforms/powernv/pci.c8
-rw-r--r--arch/powerpc/platforms/ps3/device-init.c2
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c10
-rw-r--r--arch/powerpc/platforms/ps3/smp.c4
-rw-r--r--arch/powerpc/platforms/ps3/spu.c4
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c5
-rw-r--r--arch/powerpc/platforms/pseries/event_sources.c2
-rw-r--r--arch/powerpc/platforms/pseries/msi.c6
-rw-r--r--arch/powerpc/platforms/pseries/scanlog.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c4
-rw-r--r--arch/powerpc/sysdev/axonram.c6
-rw-r--r--arch/powerpc/sysdev/cpm1.c8
-rw-r--r--arch/powerpc/sysdev/ehv_pic.c4
-rw-r--r--arch/powerpc/sysdev/fsl_gtm.c2
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_err.c6
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c12
-rw-r--r--arch/powerpc/sysdev/ge/ge_pic.c8
-rw-r--r--arch/powerpc/sysdev/i8259.c4
-rw-r--r--arch/powerpc/sysdev/ipic.c4
-rw-r--r--arch/powerpc/sysdev/mmio_nvram.c2
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c2
-rw-r--r--arch/powerpc/sysdev/mpic.c14
-rw-r--r--arch/powerpc/sysdev/mpic_msgr.c4
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c4
-rw-r--r--arch/powerpc/sysdev/mv64x60_pic.c2
-rw-r--r--arch/powerpc/sysdev/pmi.c2
-rw-r--r--arch/powerpc/sysdev/ppc4xx_hsta_msi.c6
-rw-r--r--arch/powerpc/sysdev/ppc4xx_msi.c6
-rw-r--r--arch/powerpc/sysdev/ppc4xx_soc.c2
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c2
-rw-r--r--arch/powerpc/sysdev/uic.c2
-rw-r--r--arch/powerpc/sysdev/xics/icp-hv.c6
-rw-r--r--arch/powerpc/sysdev/xics/icp-native.c6
-rw-r--r--arch/powerpc/sysdev/xics/icp-opal.c8
-rw-r--r--arch/powerpc/sysdev/xics/xics-common.c2
-rw-r--r--arch/powerpc/xmon/spr_access.S4
-rw-r--r--arch/s390/Kconfig2
-rw-r--r--arch/s390/hypfs/inode.c4
-rw-r--r--arch/s390/include/asm/uprobes.h10
-rw-r--r--arch/s390/kernel/compat_linux.c4
-rw-r--r--arch/s390/kernel/vmlinux.lds.S1
-rw-r--r--arch/score/kernel/vmlinux.lds.S1
-rw-r--r--arch/sh/kernel/vmlinux.lds.S1
-rw-r--r--arch/sparc/Kconfig1
-rw-r--r--arch/sparc/include/asm/irq_64.h5
-rw-r--r--arch/sparc/kernel/process_64.c10
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S1
-rw-r--r--arch/tile/Kconfig1
-rw-r--r--arch/tile/include/asm/irq.h5
-rw-r--r--arch/tile/kernel/entry.S2
-rw-r--r--arch/tile/kernel/pmc.c3
-rw-r--r--arch/tile/kernel/process.c73
-rw-r--r--arch/tile/kernel/traps.c9
-rw-r--r--arch/tile/kernel/vmlinux.lds.S1
-rw-r--r--arch/um/kernel/dyn.lds.S1
-rw-r--r--arch/um/kernel/uml.lds.S1
-rw-r--r--arch/unicore32/kernel/vmlinux.lds.S1
-rw-r--r--arch/x86/Kconfig15
-rw-r--r--arch/x86/Makefile5
-rw-r--r--arch/x86/entry/entry_64.S2
-rw-r--r--arch/x86/entry/syscalls/syscall_32.tbl5
-rw-r--r--arch/x86/entry/syscalls/syscall_64.tbl5
-rw-r--r--arch/x86/entry/syscalls/syscalltbl.sh15
-rw-r--r--arch/x86/include/asm/fpu/xstate.h7
-rw-r--r--arch/x86/include/asm/irq.h5
-rw-r--r--arch/x86/include/asm/irqflags.h12
-rw-r--r--arch/x86/include/asm/mmu.h8
-rw-r--r--arch/x86/include/asm/mmu_context.h25
-rw-r--r--arch/x86/include/asm/pci.h14
-rw-r--r--arch/x86/include/asm/pgtable_types.h2
-rw-r--r--arch/x86/include/asm/pkeys.h73
-rw-r--r--arch/x86/include/asm/unwind.h14
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/acpi/boot.c4
-rw-r--r--arch/x86/kernel/acpi/cstate.c2
-rw-r--r--arch/x86/kernel/apic/apic.c8
-rw-r--r--arch/x86/kernel/apic/hw_nmi.c18
-rw-r--r--arch/x86/kernel/apic/vector.c23
-rw-r--r--arch/x86/kernel/cpu/vmware.c12
-rw-r--r--arch/x86/kernel/fpu/core.c4
-rw-r--r--arch/x86/kernel/fpu/xstate.c5
-rw-r--r--arch/x86/kernel/livepatch.c65
-rw-r--r--arch/x86/kernel/process.c4
-rw-r--r--arch/x86/kernel/process_64.c13
-rw-r--r--arch/x86/kernel/smpboot.c18
-rw-r--r--arch/x86/kernel/unwind_guess.c10
-rw-r--r--arch/x86/kernel/vmlinux.lds.S1
-rw-r--r--arch/x86/mm/fault.c9
-rw-r--r--arch/x86/mm/pkeys.c142
-rw-r--r--arch/x86/pci/Makefile2
-rw-r--r--arch/x86/pci/common.c7
-rw-r--r--arch/xtensa/include/uapi/asm/mman.h5
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S3
-rw-r--r--block/Kconfig6
-rw-r--r--block/Makefile4
-rw-r--r--block/bio.c5
-rw-r--r--block/blk-core.c16
-rw-r--r--block/blk-flush.c6
-rw-r--r--block/blk-mq-cpu.c67
-rw-r--r--block/blk-mq-cpumap.c25
-rw-r--r--block/blk-mq-pci.c47
-rw-r--r--block/blk-mq-sysfs.c40
-rw-r--r--block/blk-mq-tag.c514
-rw-r--r--block/blk-mq-tag.h44
-rw-r--r--block/blk-mq.c389
-rw-r--r--block/blk-mq.h28
-rw-r--r--block/blk-sysfs.c4
-rw-r--r--block/blk.h11
-rw-r--r--block/cfq-iosched.c13
-rw-r--r--crypto/algif_hash.c73
-rw-r--r--crypto/async_tx/async_pq.c8
-rw-r--r--crypto/crct10dif_generic.c5
-rw-r--r--crypto/crypto_engine.c187
-rw-r--r--crypto/drbg.c31
-rw-r--r--crypto/gcm.c2
-rw-r--r--crypto/ghash-generic.c13
-rw-r--r--crypto/mcryptd.c7
-rw-r--r--crypto/rsa_helper.c4
-rw-r--r--crypto/testmgr.c24
-rw-r--r--crypto/testmgr.h4
-rw-r--r--crypto/xor.c41
-rw-r--r--crypto/xts.c2
-rw-r--r--drivers/acpi/apei/ghes.c2
-rw-r--r--drivers/acpi/processor_idle.c5
-rw-r--r--drivers/base/memory.c5
-rw-r--r--drivers/block/loop.c1
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c3
-rw-r--r--drivers/block/nbd.c410
-rw-r--r--drivers/block/null_blk.c129
-rw-r--r--drivers/block/rbd.c1433
-rw-r--r--drivers/block/rbd_types.h11
-rw-r--r--drivers/block/virtio_blk.c1
-rw-r--r--drivers/block/xen-blkfront.c1
-rw-r--r--drivers/bus/Kconfig14
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/qcom-ebi2.c408
-rw-r--r--drivers/bus/tegra-aconnect.c22
-rw-r--r--drivers/char/hw_random/Kconfig13
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/amd-rng.c140
-rw-r--r--drivers/char/hw_random/bcm2835-rng.c5
-rw-r--r--drivers/char/hw_random/cavium-rng-vf.c99
-rw-r--r--drivers/char/hw_random/cavium-rng.c94
-rw-r--r--drivers/char/hw_random/core.c37
-rw-r--r--drivers/char/hw_random/geode-rng.c58
-rw-r--r--drivers/char/hw_random/meson-rng.c3
-rw-r--r--drivers/char/hw_random/omap-rng.c4
-rw-r--r--drivers/char/hw_random/omap3-rom-rng.c10
-rw-r--r--drivers/char/hw_random/pasemi-rng.c39
-rw-r--r--drivers/char/hw_random/pic32-rng.c1
-rw-r--r--drivers/char/hw_random/st-rng.c4
-rw-r--r--drivers/char/hw_random/tx4939-rng.c11
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/virtio_console.c2
-rw-r--r--drivers/clk/imx/clk-imx1.c46
-rw-r--r--drivers/clk/meson/gxbb.h18
-rw-r--r--drivers/clk/mvebu/orion.c70
-rw-r--r--drivers/clocksource/Kconfig2
-rw-r--r--drivers/clocksource/exynos_mct.c4
-rw-r--r--drivers/cpuidle/driver.c5
-rw-r--r--drivers/crypto/Kconfig3
-rw-r--r--drivers/crypto/caam/caamalg.c161
-rw-r--r--drivers/crypto/caam/caamhash.c581
-rw-r--r--drivers/crypto/caam/ctrl.c3
-rw-r--r--drivers/crypto/caam/desc.h6
-rw-r--r--drivers/crypto/caam/desc_constr.h17
-rw-r--r--drivers/crypto/caam/intern.h1
-rw-r--r--drivers/crypto/caam/jr.c26
-rw-r--r--drivers/crypto/caam/regs.h8
-rw-r--r--drivers/crypto/caam/sg_sw_sec4.h2
-rw-r--r--drivers/crypto/ccp/Makefile1
-rw-r--r--drivers/crypto/ccp/ccp-crypto-sha.c18
-rw-r--r--drivers/crypto/ccp/ccp-dev-v3.c182
-rw-r--r--drivers/crypto/ccp/ccp-dev-v5.c1017
-rw-r--r--drivers/crypto/ccp/ccp-dev.c113
-rw-r--r--drivers/crypto/ccp/ccp-dev.h312
-rw-r--r--drivers/crypto/ccp/ccp-dmaengine.c11
-rw-r--r--drivers/crypto/ccp/ccp-ops.c576
-rw-r--r--drivers/crypto/ccp/ccp-pci.c23
-rw-r--r--drivers/crypto/hifn_795x.c12
-rw-r--r--drivers/crypto/img-hash.c108
-rw-r--r--drivers/crypto/ixp4xx_crypto.c9
-rw-r--r--drivers/crypto/marvell/cesa.c1
-rw-r--r--drivers/crypto/marvell/hash.c44
-rw-r--r--drivers/crypto/marvell/tdma.c1
-rw-r--r--drivers/crypto/mv_cesa.c7
-rw-r--r--drivers/crypto/mxc-scc.c4
-rw-r--r--drivers/crypto/omap-aes.c141
-rw-r--r--drivers/crypto/omap-des.c35
-rw-r--r--drivers/crypto/omap-sham.c568
-rw-r--r--drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h2
-rw-r--r--drivers/crypto/qat/qat_common/adf_admin.c20
-rw-r--r--drivers/crypto/qat/qat_common/qat_uclo.c8
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto.c6
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-cipher.c6
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-core.c68
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-hash.c165
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss.h2
-rw-r--r--drivers/crypto/vmx/Kconfig1
-rw-r--r--drivers/crypto/vmx/ghash.c31
-rw-r--r--drivers/dma/Kconfig40
-rw-r--r--drivers/dma/at_hdmac.c11
-rw-r--r--drivers/dma/at_xdmac.c8
-rw-r--r--drivers/dma/bestcomm/bestcomm.c4
-rw-r--r--drivers/dma/coh901318.c56
-rw-r--r--drivers/dma/coh901318_lli.c4
-rw-r--r--drivers/dma/cppi41.c142
-rw-r--r--drivers/dma/dma-jz4740.c2
-rw-r--r--drivers/dma/dma-jz4780.c10
-rw-r--r--drivers/dma/dmaengine.c7
-rw-r--r--drivers/dma/dmaengine.h84
-rw-r--r--drivers/dma/dmatest.c23
-rw-r--r--drivers/dma/dw/core.c14
-rw-r--r--drivers/dma/edma.c38
-rw-r--r--drivers/dma/ep93xx_dma.c28
-rw-r--r--drivers/dma/fsl_raid.c12
-rw-r--r--drivers/dma/fsldma.c24
-rw-r--r--drivers/dma/imx-dma.c4
-rw-r--r--drivers/dma/imx-sdma.c35
-rw-r--r--drivers/dma/ioat/dma.c213
-rw-r--r--drivers/dma/ioat/init.c2
-rw-r--r--drivers/dma/ioat/registers.h2
-rw-r--r--drivers/dma/iop-adma.c3
-rw-r--r--drivers/dma/ipu/ipu_idmac.c18
-rw-r--r--drivers/dma/ipu/ipu_irq.c9
-rw-r--r--drivers/dma/k3dma.c215
-rw-r--r--drivers/dma/mic_x100_dma.c6
-rw-r--r--drivers/dma/mmp_pdma.c14
-rw-r--r--drivers/dma/mmp_tdma.c6
-rw-r--r--drivers/dma/moxart-dma.c2
-rw-r--r--drivers/dma/mpc512x_dma.c7
-rw-r--r--drivers/dma/mv_xor.c102
-rw-r--r--drivers/dma/mv_xor.h7
-rw-r--r--drivers/dma/mxs-dma.c13
-rw-r--r--drivers/dma/nbpfaxi.c9
-rw-r--r--drivers/dma/omap-dma.c243
-rw-r--r--drivers/dma/pch_dma.c7
-rw-r--r--drivers/dma/pl330.c25
-rw-r--r--drivers/dma/ppc4xx/adma.c11
-rw-r--r--drivers/dma/qcom/hidma.c57
-rw-r--r--drivers/dma/qcom/hidma.h2
-rw-r--r--drivers/dma/qcom/hidma_ll.c32
-rw-r--r--drivers/dma/s3c24xx-dma.c9
-rw-r--r--drivers/dma/sa11x0-dma.c14
-rw-r--r--drivers/dma/sh/rcar-dmac.c132
-rw-r--r--drivers/dma/sh/shdma-base.c12
-rw-r--r--drivers/dma/sirf-dma.c9
-rw-r--r--drivers/dma/ste_dma40.c299
-rw-r--r--drivers/dma/stm32-dma.c2
-rw-r--r--drivers/dma/sun6i-dma.c7
-rw-r--r--drivers/dma/tegra20-apb-dma.c10
-rw-r--r--drivers/dma/tegra210-adma.c14
-rw-r--r--drivers/dma/ti-dma-crossbar.c30
-rw-r--r--drivers/dma/timb_dma.c9
-rw-r--r--drivers/dma/txx9dmac.c9
-rw-r--r--drivers/dma/virt-dma.c17
-rw-r--r--drivers/dma/virt-dma.h10
-rw-r--r--drivers/dma/xgene-dma.c6
-rw-r--r--drivers/dma/xilinx/xilinx_dma.c10
-rw-r--r--drivers/firmware/Kconfig1
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/meson/Kconfig9
-rw-r--r--drivers/firmware/meson/Makefile1
-rw-r--r--drivers/firmware/meson/meson_sm.c248
-rw-r--r--drivers/firmware/qcom_scm.c19
-rw-r--r--drivers/gpio/gpio-pca953x.c16
-rw-r--r--drivers/gpu/drm/armada/armada_gem.c2
-rw-r--r--drivers/gpu/drm/drm_debugfs.c4
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c10
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c6
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c2
-rw-r--r--drivers/gpu/drm/msm/msm_perf.c4
-rw-r--r--drivers/gpu/drm/msm/msm_rd.c4
-rw-r--r--drivers/hid/Kconfig26
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-alps.c26
-rw-r--r--drivers/hid/hid-core.c12
-rw-r--r--drivers/hid/hid-ids.h12
-rw-r--r--drivers/hid/hid-input.c10
-rw-r--r--drivers/hid/hid-kye.c123
-rw-r--r--drivers/hid/hid-lg.c86
-rw-r--r--drivers/hid/hid-lg4ff.c109
-rw-r--r--drivers/hid/hid-lg4ff.h4
-rw-r--r--drivers/hid/hid-microsoft.c12
-rw-r--r--drivers/hid/hid-saitek.c2
-rw-r--r--drivers/hid/hid-sensor-hub.c4
-rw-r--r--drivers/hid/hid-sony.c88
-rw-r--r--drivers/hid/hid-uclogic.c187
-rw-r--r--drivers/hid/hid-waltop.c36
-rw-r--r--drivers/hid/intel-ish-hid/Kconfig17
-rw-r--r--drivers/hid/intel-ish-hid/Makefile22
-rw-r--r--drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h220
-rw-r--r--drivers/hid/intel-ish-hid/ipc/hw-ish.h71
-rw-r--r--drivers/hid/intel-ish-hid/ipc/ipc.c881
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c322
-rw-r--r--drivers/hid/intel-ish-hid/ipc/utils.h64
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid-client.c978
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid.c246
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid.h182
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c788
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.h114
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client-buffers.c257
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client.c1054
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client.h182
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/dma-if.c175
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/hbm.c1032
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/hbm.h321
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/init.c115
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h277
-rw-r--r--drivers/hid/usbhid/hid-quirks.c4
-rw-r--r--drivers/hid/wacom.h96
-rw-r--r--drivers/hid/wacom_sys.c1187
-rw-r--r--drivers/hid/wacom_wac.c435
-rw-r--r--drivers/hid/wacom_wac.h22
-rw-r--r--drivers/i2c/busses/Kconfig13
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-amd756.c5
-rw-r--r--drivers/i2c/busses/i2c-at91.c2
-rw-r--r--drivers/i2c/busses/i2c-axxia.c8
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c8
-rw-r--r--drivers/i2c/busses/i2c-bcm-kona.c4
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c4
-rw-r--r--drivers/i2c/busses/i2c-brcmstb.c4
-rw-r--r--drivers/i2c/busses/i2c-cadence.c4
-rw-r--r--drivers/i2c/busses/i2c-cpm.c4
-rw-r--r--drivers/i2c/busses/i2c-cros-ec-tunnel.c4
-rw-r--r--drivers/i2c/busses/i2c-davinci.c4
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c196
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h12
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c43
-rw-r--r--drivers/i2c/busses/i2c-diolan-u2c.c4
-rw-r--r--drivers/i2c/busses/i2c-dln2.c4
-rw-r--r--drivers/i2c/busses/i2c-efm32.c1
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c4
-rw-r--r--drivers/i2c/busses/i2c-hix5hd2.c4
-rw-r--r--drivers/i2c/busses/i2c-i801.c5
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c4
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c4
-rw-r--r--drivers/i2c/busses/i2c-imx.c35
-rw-r--r--drivers/i2c/busses/i2c-isch.c4
-rw-r--r--drivers/i2c/busses/i2c-ismt.c4
-rw-r--r--drivers/i2c/busses/i2c-jz4780.c4
-rw-r--r--drivers/i2c/busses/i2c-lpc2k.c4
-rw-r--r--drivers/i2c/busses/i2c-meson.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c4
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c4
-rw-r--r--drivers/i2c/busses/i2c-mxs.c1
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c1
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c4
-rw-r--r--drivers/i2c/busses/i2c-ocores.c4
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.c (renamed from drivers/i2c/busses/i2c-octeon.c)1080
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.h216
-rw-r--r--drivers/i2c/busses/i2c-octeon-platdrv.c286
-rw-r--r--drivers/i2c/busses/i2c-omap.c4
-rw-r--r--drivers/i2c/busses/i2c-piix4.c1
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c4
-rw-r--r--drivers/i2c/busses/i2c-pnx.c4
-rw-r--r--drivers/i2c/busses/i2c-puv3.c5
-rw-r--r--drivers/i2c/busses/i2c-pxa.c4
-rw-r--r--drivers/i2c/busses/i2c-rcar.c5
-rw-r--r--drivers/i2c/busses/i2c-riic.c4
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c9
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c4
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c1
-rw-r--r--drivers/i2c/busses/i2c-sirf.c4
-rw-r--r--drivers/i2c/busses/i2c-st.c4
-rw-r--r--drivers/i2c/busses/i2c-stu300.c5
-rw-r--r--drivers/i2c/busses/i2c-tegra.c279
-rw-r--r--drivers/i2c/busses/i2c-thunderx-pcidrv.c259
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c106
-rw-r--r--drivers/i2c/busses/i2c-uniphier.c78
-rw-r--r--drivers/i2c/busses/i2c-wmt.c4
-rw-r--r--drivers/i2c/busses/i2c-xgene-slimpro.c1
-rw-r--r--drivers/i2c/busses/i2c-xiic.c1
-rw-r--r--drivers/i2c/busses/i2c-xlp9xx.c4
-rw-r--r--drivers/i2c/busses/i2c-xlr.c4
-rw-r--r--drivers/i2c/i2c-core.c272
-rw-r--r--drivers/i2c/i2c-mux.c73
-rw-r--r--drivers/i2c/muxes/i2c-arb-gpio-challenge.c2
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca9541.c11
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c46
-rw-r--r--drivers/idle/intel_idle.c4
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/core/cma.c2
-rw-r--r--drivers/infiniband/core/iwcm.c2
-rw-r--r--drivers/infiniband/core/mad.c4
-rw-r--r--drivers/infiniband/core/multicast.c2
-rw-r--r--drivers/infiniband/core/sa_query.c2
-rw-r--r--drivers/infiniband/core/sysfs.c2
-rw-r--r--drivers/infiniband/core/ucma.c3
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c121
-rw-r--r--drivers/infiniband/core/verbs.c77
-rw-r--r--drivers/infiniband/hw/Makefile1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c3
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c17
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h2
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c1
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c67
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h4
-rw-r--r--drivers/infiniband/hw/cxgb4/t4fw_ri_api.h12
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.c3
-rw-r--r--drivers/infiniband/hw/hns/Kconfig10
-rw-r--r--drivers/infiniband/hw/hns/Makefile8
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_ah.c128
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_alloc.c257
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cmd.c368
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cmd.h80
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_common.h325
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cq.c446
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h734
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_eq.c762
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_eq.h130
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hem.c476
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hem.h131
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v1.c2800
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v1.h981
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c1142
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_mr.c614
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_pd.c144
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_qp.c855
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_user.h53
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_cm.c7
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_main.c2
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c2
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c73
-rw-r--r--drivers/infiniband/hw/mlx4/main.c147
-rw-r--r--drivers/infiniband/hw/mlx4/mcg.c4
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h7
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c25
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c2
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c1
-rw-r--r--drivers/infiniband/hw/mlx5/mad.c2
-rw-r--r--drivers/infiniband/hw/mlx5/main.c391
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h50
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c3
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c4
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c158
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_catas.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c3
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c7
-rw-r--r--drivers/infiniband/hw/nes/nes.h2
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c4
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c3
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c3
-rw-r--r--drivers/infiniband/sw/rdmavt/dma.c17
-rw-r--r--drivers/infiniband/sw/rxe/rxe.c36
-rw-r--r--drivers/infiniband/sw/rxe/rxe.h5
-rw-r--r--drivers/infiniband/sw/rxe/rxe_av.c4
-rw-r--r--drivers/infiniband/sw/rxe/rxe_comp.c6
-rw-r--r--drivers/infiniband/sw/rxe/rxe_dma.c17
-rw-r--r--drivers/infiniband/sw/rxe/rxe_loc.h2
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mmap.c2
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mr.c2
-rw-r--r--drivers/infiniband/sw/rxe/rxe_net.c51
-rw-r--r--drivers/infiniband/sw/rxe/rxe_net.h3
-rw-r--r--drivers/infiniband/sw/rxe/rxe_qp.c55
-rw-r--r--drivers/infiniband/sw/rxe/rxe_recv.c3
-rw-r--r--drivers/infiniband/sw/rxe/rxe_req.c19
-rw-r--r--drivers/infiniband/sw/rxe/rxe_resp.c27
-rw-r--r--drivers/infiniband/sw/rxe/rxe_sysfs.c12
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c50
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h1
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c6
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c22
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c56
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h3
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c2
-rw-r--r--drivers/input/keyboard/Kconfig15
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/adc-keys.c210
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c135
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c59
-rw-r--r--drivers/input/keyboard/snvs_pwrkey.c1
-rw-r--r--drivers/input/misc/Kconfig16
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/gpio_decoder.c137
-rw-r--r--drivers/input/misc/max77693-haptic.c4
-rw-r--r--drivers/input/misc/tps65218-pwrbutton.c92
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c20
-rw-r--r--drivers/input/mouse/focaltech.c3
-rw-r--r--drivers/input/mouse/psmouse-base.c2
-rw-r--r--drivers/input/serio/serport.c17
-rw-r--r--drivers/input/tablet/pegasus_notetaker.c1
-rw-r--r--drivers/input/touchscreen/Kconfig25
-rw-r--r--drivers/input/touchscreen/Makefile2
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c8
-rw-r--r--drivers/input/touchscreen/ektf2127.c336
-rw-r--r--drivers/input/touchscreen/elants_i2c.c31
-rw-r--r--drivers/input/touchscreen/ft6236.c326
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c21
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c24
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c13
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c5
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c2
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-metag-ext.c1
-rw-r--r--drivers/irqchip/irq-vic.c1
-rw-r--r--drivers/lightnvm/Kconfig2
-rw-r--r--drivers/lightnvm/Makefile2
-rw-r--r--drivers/lightnvm/core.c55
-rw-r--r--drivers/lightnvm/lightnvm.h35
-rw-r--r--drivers/lightnvm/sysfs.c198
-rw-r--r--drivers/macintosh/macio_asic.c4
-rw-r--r--drivers/macintosh/rack-meter.c2
-rw-r--r--drivers/macintosh/smu.c18
-rw-r--r--drivers/macintosh/via-cuda.c2
-rw-r--r--drivers/macintosh/via-pmu.c6
-rw-r--r--drivers/mailbox/Kconfig10
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/platform_mhu.c205
-rw-r--r--drivers/md/bcache/btree.c6
-rw-r--r--drivers/md/bcache/debug.c6
-rw-r--r--drivers/md/bcache/movinggc.c5
-rw-r--r--drivers/md/bcache/request.c9
-rw-r--r--drivers/md/bcache/writeback.c5
-rw-r--r--drivers/md/bitmap.c4
-rw-r--r--drivers/md/dm-bufio.c31
-rw-r--r--drivers/md/dm-cache-metadata.c183
-rw-r--r--drivers/md/dm-cache-policy-cleaner.c2
-rw-r--r--drivers/md/dm-cache-policy-internal.h6
-rw-r--r--drivers/md/dm-cache-policy-smq.c45
-rw-r--r--drivers/md/dm-cache-policy.h10
-rw-r--r--drivers/md/dm-crypt.c26
-rw-r--r--drivers/md/dm-log-writes.c6
-rw-r--r--drivers/md/dm-mpath.c59
-rw-r--r--drivers/md/dm-rq.c107
-rw-r--r--drivers/md/dm-rq.h2
-rw-r--r--drivers/md/dm.c37
-rw-r--r--drivers/md/md-cluster.c99
-rw-r--r--drivers/md/md.c44
-rw-r--r--drivers/md/md.h5
-rw-r--r--drivers/md/persistent-data/dm-array.c228
-rw-r--r--drivers/md/persistent-data/dm-array.h52
-rw-r--r--drivers/md/persistent-data/dm-btree.c162
-rw-r--r--drivers/md/persistent-data/dm-btree.h35
-rw-r--r--drivers/md/raid1.c8
-rw-r--r--drivers/md/raid5.c11
-rw-r--r--drivers/media/rc/meson-ir.c29
-rw-r--r--drivers/memory/atmel-ebi.c10
-rw-r--r--drivers/memory/atmel-sdramc.c4
-rw-r--r--drivers/memory/omap-gpmc.c20
-rw-r--r--drivers/message/fusion/mptbase.c7
-rw-r--r--drivers/message/fusion/mptfc.c7
-rw-r--r--drivers/mfd/Kconfig26
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/ab8500-debugfs.c114
-rw-r--r--drivers/mfd/ac100.c137
-rw-r--r--drivers/mfd/act8945a.c1
-rw-r--r--drivers/mfd/altera-a10sr.c16
-rw-r--r--drivers/mfd/arizona-core.c113
-rw-r--r--drivers/mfd/atmel-hlcdc.c5
-rw-r--r--drivers/mfd/axp20x-rsb.c1
-rw-r--r--drivers/mfd/axp20x.c75
-rw-r--r--drivers/mfd/cros_ec.c58
-rw-r--r--drivers/mfd/cros_ec_spi.c2
-rw-r--r--drivers/mfd/da9052-core.c51
-rw-r--r--drivers/mfd/da9063-core.c7
-rw-r--r--drivers/mfd/da9063-i2c.c2
-rw-r--r--drivers/mfd/da9063-irq.c2
-rw-r--r--drivers/mfd/db8500-prcmu.c19
-rw-r--r--drivers/mfd/dm355evm_msp.c17
-rw-r--r--drivers/mfd/exynos-lpass.c185
-rw-r--r--drivers/mfd/intel-lpss-acpi.c14
-rw-r--r--drivers/mfd/intel-lpss-pci.c51
-rw-r--r--drivers/mfd/intel_msic.c9
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c23
-rw-r--r--drivers/mfd/lp873x.c2
-rw-r--r--drivers/mfd/max14577.c4
-rw-r--r--drivers/mfd/max8997-irq.c2
-rw-r--r--drivers/mfd/omap-usb-host.c2
-rw-r--r--drivers/mfd/pm8921-core.c1
-rw-r--r--drivers/mfd/qcom_rpm.c72
-rw-r--r--drivers/mfd/rk808.c226
-rw-r--r--drivers/mfd/rtsx_usb.c10
-rw-r--r--drivers/mfd/sm501.c2
-rw-r--r--drivers/mfd/smsc-ece1099.c11
-rw-r--r--drivers/mfd/sun6i-prcm.c8
-rw-r--r--drivers/mfd/tps65217.c205
-rw-r--r--drivers/mfd/twl-core.c9
-rw-r--r--drivers/mfd/twl6040.c6
-rw-r--r--drivers/mfd/ucb1x00-core.c6
-rw-r--r--drivers/misc/cxl/cxl.h6
-rw-r--r--drivers/misc/cxl/native.c31
-rw-r--r--drivers/misc/cxl/of.c8
-rw-r--r--drivers/misc/cxl/pci.c7
-rw-r--r--drivers/misc/eeprom/at24.c15
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c2
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/mtdcore.c104
-rw-r--r--drivers/mtd/mtdpart.c19
-rw-r--r--drivers/mtd/nand/Kconfig12
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c3
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.c15
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.h13
-rw-r--r--drivers/mtd/nand/brcmnand/iproc_nand.c18
-rw-r--r--drivers/mtd/nand/docg4.c3
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c3
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c3
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c3
-rw-r--r--drivers/mtd/nand/jz4780_nand.c3
-rw-r--r--drivers/mtd/nand/mxc_nand.c137
-rw-r--r--drivers/mtd/nand/nand_base.c260
-rw-r--r--drivers/mtd/nand/nand_bbt.c161
-rw-r--r--drivers/mtd/nand/nand_timings.c470
-rw-r--r--drivers/mtd/nand/ndfc.c3
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c3
-rw-r--r--drivers/mtd/nand/qcom_nandc.c3
-rw-r--r--drivers/mtd/nand/s3c2410.c7
-rw-r--r--drivers/mtd/nand/sh_flctl.c8
-rw-r--r--drivers/mtd/nand/sunxi_nand.c108
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c3
-rw-r--r--drivers/mtd/ubi/block.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c17
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c47
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h9
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c53
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h3
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c324
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c4
-rw-r--r--drivers/ntb/ntb_transport.c193
-rw-r--r--drivers/nvme/host/core.c158
-rw-r--r--drivers/nvme/host/fabrics.c25
-rw-r--r--drivers/nvme/host/fabrics.h11
-rw-r--r--drivers/nvme/host/lightnvm.c33
-rw-r--r--drivers/nvme/host/nvme.h31
-rw-r--r--drivers/nvme/host/pci.c109
-rw-r--r--drivers/nvme/host/rdma.c27
-rw-r--r--drivers/nvme/host/scsi.c80
-rw-r--r--drivers/nvme/target/admin-cmd.c88
-rw-r--r--drivers/nvme/target/io-cmd.c3
-rw-r--r--drivers/nvme/target/loop.c2
-rw-r--r--drivers/nvme/target/rdma.c2
-rw-r--r--drivers/nvmem/Kconfig10
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/meson-efuse.c93
-rw-r--r--drivers/of/Kconfig4
-rw-r--r--drivers/of/base.c2
-rw-r--r--drivers/oprofile/oprofilefs.c2
-rw-r--r--drivers/pci/Kconfig2
-rw-r--r--drivers/pci/host/Kconfig27
-rw-r--r--drivers/pci/host/Makefile2
-rw-r--r--drivers/pci/host/pci-aardvark.c12
-rw-r--r--drivers/pci/host/pci-dra7xx.c31
-rw-r--r--drivers/pci/host/pci-exynos.c16
-rw-r--r--drivers/pci/host/pci-host-common.c15
-rw-r--r--drivers/pci/host/pci-hyperv.c65
-rw-r--r--drivers/pci/host/pci-imx6.c9
-rw-r--r--drivers/pci/host/pci-keystone.c5
-rw-r--r--drivers/pci/host/pci-tegra.c54
-rw-r--r--drivers/pci/host/pci-versatile.c8
-rw-r--r--drivers/pci/host/pcie-altera-msi.c20
-rw-r--r--drivers/pci/host/pcie-altera.c209
-rw-r--r--drivers/pci/host/pcie-artpec6.c4
-rw-r--r--drivers/pci/host/pcie-designware-plat.c3
-rw-r--r--drivers/pci/host/pcie-designware.c209
-rw-r--r--drivers/pci/host/pcie-designware.h10
-rw-r--r--drivers/pci/host/pcie-qcom.c28
-rw-r--r--drivers/pci/host/pcie-rcar.c190
-rw-r--r--drivers/pci/host/pcie-rockchip.c1229
-rw-r--r--drivers/pci/host/pcie-spear13xx.c11
-rw-r--r--drivers/pci/host/pcie-xilinx-nwl.c105
-rw-r--r--drivers/pci/host/pcie-xilinx.c90
-rw-r--r--drivers/pci/host/vmd.c (renamed from arch/x86/pci/vmd.c)49
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h2
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c10
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c18
-rw-r--r--drivers/pci/hotplug/pciehp.h3
-rw-r--r--drivers/pci/hotplug/pciehp_core.c23
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c84
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c121
-rw-r--r--drivers/pci/hotplug/pnv_php.c283
-rw-r--r--drivers/pci/iov.c5
-rw-r--r--drivers/pci/pci-acpi.c22
-rw-r--r--drivers/pci/pci-driver.c17
-rw-r--r--drivers/pci/pci.c75
-rw-r--r--drivers/pci/pci.h9
-rw-r--r--drivers/pci/pcie/Kconfig11
-rw-r--r--drivers/pci/pcie/Makefile1
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c36
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h9
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c61
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c6
-rw-r--r--drivers/pci/pcie/pcie-dpc.c18
-rw-r--r--drivers/pci/pcie/pme.c16
-rw-r--r--drivers/pci/pcie/portdrv_pci.c17
-rw-r--r--drivers/pci/pcie/ptm.c142
-rw-r--r--drivers/pci/probe.c6
-rw-r--r--drivers/pci/quirks.c29
-rw-r--r--drivers/pcmcia/sa1100_assabet.c9
-rw-r--r--drivers/pcmcia/sa1100_cerf.c9
-rw-r--r--drivers/pcmcia/soc_common.c238
-rw-r--r--drivers/pcmcia/soc_common.h29
-rw-r--r--drivers/perf/Kconfig7
-rw-r--r--drivers/perf/Makefile1
-rw-r--r--drivers/perf/xgene_pmu.c1398
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-orion.c23
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c92
-rw-r--r--drivers/platform/x86/sony-laptop.c2
-rw-r--r--drivers/power/Kconfig518
-rw-r--r--drivers/power/Makefile75
-rw-r--r--drivers/power/act8945a_charger.c359
-rw-r--r--drivers/power/reset/keystone-reset.c2
-rw-r--r--drivers/power/reset/reboot-mode.c59
-rw-r--r--drivers/power/reset/reboot-mode.h4
-rw-r--r--drivers/power/reset/st-poweroff.c41
-rw-r--r--drivers/power/reset/syscon-reboot-mode.c12
-rw-r--r--drivers/power/reset/xgene-reboot.c4
-rw-r--r--drivers/power/reset/zx-reboot.c5
-rw-r--r--drivers/power/supply/88pm860x_battery.c (renamed from drivers/power/88pm860x_battery.c)0
-rw-r--r--drivers/power/supply/88pm860x_charger.c (renamed from drivers/power/88pm860x_charger.c)0
-rw-r--r--drivers/power/supply/Kconfig514
-rw-r--r--drivers/power/supply/Makefile74
-rw-r--r--drivers/power/supply/ab8500_bmdata.c (renamed from drivers/power/ab8500_bmdata.c)0
-rw-r--r--drivers/power/supply/ab8500_btemp.c (renamed from drivers/power/ab8500_btemp.c)2
-rw-r--r--drivers/power/supply/ab8500_charger.c (renamed from drivers/power/ab8500_charger.c)4
-rw-r--r--drivers/power/supply/ab8500_fg.c (renamed from drivers/power/ab8500_fg.c)11
-rw-r--r--drivers/power/supply/abx500_chargalg.c (renamed from drivers/power/abx500_chargalg.c)4
-rw-r--r--drivers/power/supply/act8945a_charger.c666
-rw-r--r--drivers/power/supply/apm_power.c (renamed from drivers/power/apm_power.c)0
-rw-r--r--drivers/power/supply/axp20x_usb_power.c (renamed from drivers/power/axp20x_usb_power.c)0
-rw-r--r--drivers/power/supply/axp288_charger.c (renamed from drivers/power/axp288_charger.c)1
-rw-r--r--drivers/power/supply/axp288_fuel_gauge.c (renamed from drivers/power/axp288_fuel_gauge.c)1
-rw-r--r--drivers/power/supply/bq2415x_charger.c (renamed from drivers/power/bq2415x_charger.c)0
-rw-r--r--drivers/power/supply/bq24190_charger.c (renamed from drivers/power/bq24190_charger.c)0
-rw-r--r--drivers/power/supply/bq24257_charger.c (renamed from drivers/power/bq24257_charger.c)12
-rw-r--r--drivers/power/supply/bq24735-charger.c (renamed from drivers/power/bq24735-charger.c)45
-rw-r--r--drivers/power/supply/bq25890_charger.c (renamed from drivers/power/bq25890_charger.c)0
-rw-r--r--drivers/power/supply/bq27xxx_battery.c (renamed from drivers/power/bq27xxx_battery.c)43
-rw-r--r--drivers/power/supply/bq27xxx_battery_i2c.c (renamed from drivers/power/bq27xxx_battery_i2c.c)0
-rw-r--r--drivers/power/supply/charger-manager.c (renamed from drivers/power/charger-manager.c)0
-rw-r--r--drivers/power/supply/collie_battery.c (renamed from drivers/power/collie_battery.c)0
-rw-r--r--drivers/power/supply/da9030_battery.c (renamed from drivers/power/da9030_battery.c)0
-rw-r--r--drivers/power/supply/da9052-battery.c (renamed from drivers/power/da9052-battery.c)0
-rw-r--r--drivers/power/supply/da9150-charger.c (renamed from drivers/power/da9150-charger.c)0
-rw-r--r--drivers/power/supply/da9150-fg.c (renamed from drivers/power/da9150-fg.c)0
-rw-r--r--drivers/power/supply/ds2760_battery.c (renamed from drivers/power/ds2760_battery.c)7
-rw-r--r--drivers/power/supply/ds2780_battery.c (renamed from drivers/power/ds2780_battery.c)4
-rw-r--r--drivers/power/supply/ds2781_battery.c (renamed from drivers/power/ds2781_battery.c)4
-rw-r--r--drivers/power/supply/ds2782_battery.c (renamed from drivers/power/ds2782_battery.c)0
-rw-r--r--drivers/power/supply/generic-adc-battery.c (renamed from drivers/power/generic-adc-battery.c)0
-rw-r--r--drivers/power/supply/goldfish_battery.c (renamed from drivers/power/goldfish_battery.c)0
-rw-r--r--drivers/power/supply/gpio-charger.c (renamed from drivers/power/gpio-charger.c)0
-rw-r--r--drivers/power/supply/intel_mid_battery.c (renamed from drivers/power/intel_mid_battery.c)3
-rw-r--r--drivers/power/supply/ipaq_micro_battery.c (renamed from drivers/power/ipaq_micro_battery.c)2
-rw-r--r--drivers/power/supply/isp1704_charger.c (renamed from drivers/power/isp1704_charger.c)0
-rw-r--r--drivers/power/supply/jz4740-battery.c (renamed from drivers/power/jz4740-battery.c)0
-rw-r--r--drivers/power/supply/lp8727_charger.c (renamed from drivers/power/lp8727_charger.c)0
-rw-r--r--drivers/power/supply/lp8788-charger.c (renamed from drivers/power/lp8788-charger.c)0
-rw-r--r--drivers/power/supply/ltc2941-battery-gauge.c (renamed from drivers/power/ltc2941-battery-gauge.c)0
-rw-r--r--drivers/power/supply/max14577_charger.c (renamed from drivers/power/max14577_charger.c)4
-rw-r--r--drivers/power/supply/max17040_battery.c (renamed from drivers/power/max17040_battery.c)0
-rw-r--r--drivers/power/supply/max17042_battery.c (renamed from drivers/power/max17042_battery.c)0
-rw-r--r--drivers/power/supply/max77693_charger.c (renamed from drivers/power/max77693_charger.c)4
-rw-r--r--drivers/power/supply/max8903_charger.c (renamed from drivers/power/max8903_charger.c)0
-rw-r--r--drivers/power/supply/max8925_power.c (renamed from drivers/power/max8925_power.c)0
-rw-r--r--drivers/power/supply/max8997_charger.c (renamed from drivers/power/max8997_charger.c)0
-rw-r--r--drivers/power/supply/max8998_charger.c (renamed from drivers/power/max8998_charger.c)0
-rw-r--r--drivers/power/supply/olpc_battery.c (renamed from drivers/power/olpc_battery.c)0
-rw-r--r--drivers/power/supply/pcf50633-charger.c (renamed from drivers/power/pcf50633-charger.c)0
-rw-r--r--drivers/power/supply/pda_power.c (renamed from drivers/power/pda_power.c)0
-rw-r--r--drivers/power/supply/pm2301_charger.c (renamed from drivers/power/pm2301_charger.c)3
-rw-r--r--drivers/power/supply/pm2301_charger.h (renamed from drivers/power/pm2301_charger.h)0
-rw-r--r--drivers/power/supply/pmu_battery.c (renamed from drivers/power/pmu_battery.c)0
-rw-r--r--drivers/power/supply/power_supply.h (renamed from drivers/power/power_supply.h)0
-rw-r--r--drivers/power/supply/power_supply_core.c (renamed from drivers/power/power_supply_core.c)0
-rw-r--r--drivers/power/supply/power_supply_leds.c (renamed from drivers/power/power_supply_leds.c)0
-rw-r--r--drivers/power/supply/power_supply_sysfs.c (renamed from drivers/power/power_supply_sysfs.c)0
-rw-r--r--drivers/power/supply/qcom_smbb.c (renamed from drivers/power/qcom_smbb.c)0
-rw-r--r--drivers/power/supply/rt5033_battery.c (renamed from drivers/power/rt5033_battery.c)0
-rw-r--r--drivers/power/supply/rt9455_charger.c (renamed from drivers/power/rt9455_charger.c)0
-rw-r--r--drivers/power/supply/rx51_battery.c (renamed from drivers/power/rx51_battery.c)0
-rw-r--r--drivers/power/supply/s3c_adc_battery.c (renamed from drivers/power/s3c_adc_battery.c)0
-rw-r--r--drivers/power/supply/sbs-battery.c (renamed from drivers/power/sbs-battery.c)254
-rw-r--r--drivers/power/supply/smb347-charger.c (renamed from drivers/power/smb347-charger.c)0
-rw-r--r--drivers/power/supply/test_power.c (renamed from drivers/power/test_power.c)0
-rw-r--r--drivers/power/supply/tosa_battery.c (renamed from drivers/power/tosa_battery.c)0
-rw-r--r--drivers/power/supply/tps65090-charger.c (renamed from drivers/power/tps65090-charger.c)0
-rw-r--r--drivers/power/supply/tps65217_charger.c (renamed from drivers/power/tps65217_charger.c)40
-rw-r--r--drivers/power/supply/twl4030_charger.c (renamed from drivers/power/twl4030_charger.c)0
-rw-r--r--drivers/power/supply/twl4030_madc_battery.c (renamed from drivers/power/twl4030_madc_battery.c)0
-rw-r--r--drivers/power/supply/wm831x_backup.c (renamed from drivers/power/wm831x_backup.c)0
-rw-r--r--drivers/power/supply/wm831x_power.c (renamed from drivers/power/wm831x_power.c)0
-rw-r--r--drivers/power/supply/wm8350_power.c (renamed from drivers/power/wm8350_power.c)0
-rw-r--r--drivers/power/supply/wm97xx_battery.c (renamed from drivers/power/wm97xx_battery.c)2
-rw-r--r--drivers/power/supply/z2_battery.c (renamed from drivers/power/z2_battery.c)1
-rw-r--r--drivers/ps3/ps3-vuart.c4
-rw-r--r--drivers/regulator/Kconfig4
-rw-r--r--drivers/regulator/axp20x-regulator.c118
-rw-r--r--drivers/regulator/qcom_rpm-regulator.c66
-rw-r--r--drivers/regulator/rk808-regulator.c143
-rw-r--r--drivers/remoteproc/Kconfig20
-rw-r--r--drivers/remoteproc/Makefile2
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c6
-rw-r--r--drivers/remoteproc/omap_remoteproc.c9
-rw-r--r--drivers/remoteproc/qcom_q6v5_pil.c8
-rw-r--r--drivers/remoteproc/qcom_wcnss.c624
-rw-r--r--drivers/remoteproc/qcom_wcnss.h22
-rw-r--r--drivers/remoteproc/qcom_wcnss_iris.c188
-rw-r--r--drivers/remoteproc/remoteproc_core.c248
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c20
-rw-r--r--drivers/remoteproc/remoteproc_elf_loader.c6
-rw-r--r--drivers/remoteproc/remoteproc_internal.h15
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c35
-rw-r--r--drivers/remoteproc/st_remoteproc.c4
-rw-r--r--drivers/remoteproc/ste_modem_rproc.c4
-rw-r--r--drivers/remoteproc/wkup_m3_rproc.c6
-rw-r--r--drivers/reset/Kconfig65
-rw-r--r--drivers/reset/Makefile20
-rw-r--r--drivers/reset/core.c12
-rw-r--r--drivers/reset/hisilicon/Kconfig3
-rw-r--r--drivers/reset/reset-ath79.c1
-rw-r--r--drivers/reset/reset-socfpga.c19
-rw-r--r--drivers/reset/reset-stm32.c108
-rw-r--r--drivers/reset/reset-uniphier.c440
-rw-r--r--drivers/rpmsg/Kconfig14
-rw-r--r--drivers/rpmsg/Makefile4
-rw-r--r--drivers/rpmsg/qcom_smd.c1434
-rw-r--r--drivers/rpmsg/rpmsg_core.c498
-rw-r--r--drivers/rpmsg/rpmsg_internal.h82
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c541
-rw-r--r--drivers/rtc/Kconfig14
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-ac100.c627
-rw-r--r--drivers/rtc/rtc-pm8xxx.c1
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c162
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h14
-rw-r--r--drivers/s390/scsi/zfcp_erp.c12
-rw-r--r--drivers/s390/scsi/zfcp_ext.h8
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c22
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h4
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c8
-rw-r--r--drivers/scsi/Kconfig136
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/NCR5380.c15
-rw-r--r--drivers/scsi/NCR5380.h10
-rw-r--r--drivers/scsi/aacraid/src.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c12
-rw-r--r--drivers/scsi/be2iscsi/be.h15
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c1096
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h142
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c408
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h25
-rw-r--r--drivers/scsi/be2iscsi/be_main.c2478
-rw-r--r--drivers/scsi/be2iscsi/be_main.h220
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c1497
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h51
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c4
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_els.c4
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c12
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c2
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c2
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c5
-rw-r--r--drivers/scsi/cxlflash/main.c81
-rw-r--r--drivers/scsi/cxlflash/superpipe.c180
-rw-r--r--drivers/scsi/cxlflash/superpipe.h3
-rw-r--r--drivers/scsi/cxlflash/vlun.c13
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c1
-rw-r--r--drivers/scsi/dtc.c447
-rw-r--r--drivers/scsi/dtc.h42
-rw-r--r--drivers/scsi/esas2r/esas2r_init.c4
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c2
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c53
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h18
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c238
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c36
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c130
-rw-r--r--drivers/scsi/hosts.c12
-rw-r--r--drivers/scsi/hpsa.c139
-rw-r--r--drivers/scsi/hpsa.h1
-rw-r--r--drivers/scsi/hpsa_cmd.h1
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c12
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h1
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c37
-rw-r--r--drivers/scsi/in2000.c2302
-rw-r--r--drivers/scsi/in2000.h412
-rw-r--r--drivers/scsi/ipr.c134
-rw-r--r--drivers/scsi/ipr.h8
-rw-r--r--drivers/scsi/libfc/fc_exch.c1
-rw-r--r--drivers/scsi/libfc/fc_rport.c26
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c82
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c34
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c4
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c28
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h9
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c259
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h24
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c7
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c49
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c169
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c28
-rw-r--r--drivers/scsi/mvsas/mv_64xx.c19
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c41
-rw-r--r--drivers/scsi/mvsas/mv_sas.c16
-rw-r--r--drivers/scsi/pas16.c565
-rw-r--r--drivers/scsi/pas16.h121
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c2
-rw-r--r--drivers/scsi/pmcraid.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h10
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c18
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c2
-rw-r--r--drivers/scsi/scsi_debug.c54
-rw-r--r--drivers/scsi/scsi_lib.c1
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_scan.c2
-rw-r--r--drivers/scsi/sd.c11
-rw-r--r--drivers/scsi/sd.h30
-rw-r--r--drivers/scsi/sd_dif.c10
-rw-r--r--drivers/scsi/sg.c20
-rw-r--r--drivers/scsi/smartpqi/Kconfig54
-rw-r--r--drivers/scsi/smartpqi/Makefile3
-rw-r--r--drivers/scsi/smartpqi/smartpqi.h1136
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c6303
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sas_transport.c350
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.c404
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.h34
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c2
-rw-r--r--drivers/scsi/t128.c407
-rw-r--r--drivers/scsi/t128.h97
-rw-r--r--drivers/scsi/u14-34f.c1971
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.c1
-rw-r--r--drivers/scsi/ufs/ufs.h1
-rw-r--r--drivers/scsi/ufs/ufshcd.c6
-rw-r--r--drivers/scsi/ultrastor.c1210
-rw-r--r--drivers/scsi/ultrastor.h80
-rw-r--r--drivers/scsi/virtio_scsi.c2
-rw-r--r--drivers/scsi/wd7000.c1657
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c2
-rw-r--r--drivers/soc/qcom/smd.c265
-rw-r--r--drivers/soc/qcom/smem.c3
-rw-r--r--drivers/soc/rockchip/pm_domains.c100
-rw-r--r--drivers/soc/tegra/pmc.c28
-rw-r--r--drivers/staging/lustre/lnet/Kconfig1
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_acl.h6
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c96
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h15
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c14
-rw-r--r--drivers/staging/lustre/lustre/llite/symlink.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_internal.h14
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c45
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/wiretest.c44
-rw-r--r--drivers/tty/vt/vt.c6
-rw-r--r--drivers/usb/core/devio.c18
-rw-r--r--drivers/usb/dwc2/platform.c34
-rw-r--r--drivers/usb/gadget/function/f_fs.c8
-rw-r--r--drivers/usb/gadget/legacy/inode.c2
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c90
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c52
-rw-r--r--drivers/vfio/pci/vfio_pci_private.h1
-rw-r--r--drivers/vfio/platform/reset/vfio_platform_amdxgbe.c2
-rw-r--r--drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c2
-rw-r--r--drivers/vfio/platform/vfio_platform_common.c6
-rw-r--r--drivers/video/backlight/pwm_bl.c4
-rw-r--r--drivers/video/backlight/tosa_bl.c1
-rw-r--r--fs/9p/acl.c40
-rw-r--r--fs/9p/v9fs.h3
-rw-r--r--fs/9p/vfs_inode.c10
-rw-r--r--fs/9p/vfs_inode_dotl.c11
-rw-r--r--fs/Kconfig3
-rw-r--r--fs/adfs/inode.c4
-rw-r--r--fs/affs/affs.h3
-rw-r--r--fs/affs/amigaffs.c6
-rw-r--r--fs/affs/inode.c4
-rw-r--r--fs/affs/namei.c6
-rw-r--r--fs/afs/dir.c9
-rw-r--r--fs/aio.c9
-rw-r--r--fs/attr.c52
-rw-r--r--fs/autofs4/inode.c2
-rw-r--r--fs/autofs4/root.c6
-rw-r--r--fs/bad_inode.c25
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/bfs/dir.c20
-rw-r--r--fs/binfmt_misc.c2
-rw-r--r--fs/block_dev.c18
-rw-r--r--fs/btrfs/acl.c6
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/file.c8
-rw-r--r--fs/btrfs/inode.c60
-rw-r--r--fs/btrfs/ioctl.c8
-rw-r--r--fs/btrfs/send.c2
-rw-r--r--fs/btrfs/transaction.c4
-rw-r--r--fs/btrfs/tree-log.c4
-rw-r--r--fs/btrfs/xattr.c2
-rw-r--r--fs/buffer.c3
-rw-r--r--fs/cachefiles/bind.c4
-rw-r--r--fs/cachefiles/interface.c8
-rw-r--r--fs/cachefiles/internal.h3
-rw-r--r--fs/cachefiles/namei.c15
-rw-r--r--fs/ceph/acl.c11
-rw-r--r--fs/ceph/addr.c24
-rw-r--r--fs/ceph/dir.c9
-rw-r--r--fs/ceph/file.c8
-rw-r--r--fs/ceph/inode.c27
-rw-r--r--fs/ceph/locks.c4
-rw-r--r--fs/ceph/mds_client.c30
-rw-r--r--fs/ceph/mds_client.h1
-rw-r--r--fs/ceph/strings.c2
-rw-r--r--fs/ceph/super.c49
-rw-r--r--fs/ceph/xattr.c2
-rw-r--r--fs/cifs/cifsfs.c11
-rw-r--r--fs/cifs/cifsfs.h10
-rw-r--r--fs/cifs/cifsproto.h3
-rw-r--r--fs/cifs/cifssmb.c27
-rw-r--r--fs/cifs/dir.c6
-rw-r--r--fs/cifs/file.c18
-rw-r--r--fs/cifs/inode.c6
-rw-r--r--fs/cifs/link.c2
-rw-r--r--fs/coda/dir.c8
-rw-r--r--fs/coda/file.c25
-rw-r--r--fs/coda/inode.c2
-rw-r--r--fs/compat.c16
-rw-r--r--fs/configfs/inode.c6
-rw-r--r--fs/crypto/crypto.c11
-rw-r--r--fs/crypto/fname.c85
-rw-r--r--fs/crypto/keyinfo.c71
-rw-r--r--fs/dax.c2
-rw-r--r--fs/debugfs/inode.c4
-rw-r--r--fs/devpts/inode.c6
-rw-r--r--fs/direct-io.c3
-rw-r--r--fs/dlm/lowcomms.c8
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h2
-rw-r--r--fs/ecryptfs/inode.c75
-rw-r--r--fs/ecryptfs/main.c1
-rw-r--r--fs/ecryptfs/mmap.c13
-rw-r--r--fs/efivarfs/inode.c2
-rw-r--r--fs/exofs/dir.c6
-rw-r--r--fs/exofs/inode.c6
-rw-r--r--fs/exofs/namei.c14
-rw-r--r--fs/ext2/acl.c12
-rw-r--r--fs/ext2/dir.c6
-rw-r--r--fs/ext2/file.c4
-rw-r--r--fs/ext2/ialloc.c2
-rw-r--r--fs/ext2/inode.c6
-rw-r--r--fs/ext2/ioctl.c4
-rw-r--r--fs/ext2/namei.c18
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext2/symlink.c6
-rw-r--r--fs/ext2/xattr.c2
-rw-r--r--fs/ext4/acl.c12
-rw-r--r--fs/ext4/dir.c8
-rw-r--r--fs/ext4/ext4.h35
-rw-r--r--fs/ext4/extents.c27
-rw-r--r--fs/ext4/file.c14
-rw-r--r--fs/ext4/fsync.c9
-rw-r--r--fs/ext4/ialloc.c2
-rw-r--r--fs/ext4/inode.c73
-rw-r--r--fs/ext4/ioctl.c11
-rw-r--r--fs/ext4/move_extent.c7
-rw-r--r--fs/ext4/namei.c30
-rw-r--r--fs/ext4/page-io.c4
-rw-r--r--fs/ext4/super.c126
-rw-r--r--fs/ext4/symlink.c19
-rw-r--r--fs/ext4/xattr.c340
-rw-r--r--fs/f2fs/acl.c6
-rw-r--r--fs/f2fs/dir.c14
-rw-r--r--fs/f2fs/file.c13
-rw-r--r--fs/f2fs/inline.c2
-rw-r--r--fs/f2fs/namei.c32
-rw-r--r--fs/f2fs/node.c7
-rw-r--r--fs/f2fs/xattr.c2
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/fat/file.c8
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fat/namei_msdos.c18
-rw-r--r--fs/fat/namei_vfat.c35
-rw-r--r--fs/file.c34
-rw-r--r--fs/fuse/control.c2
-rw-r--r--fs/fuse/dev.c63
-rw-r--r--fs/fuse/dir.c20
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/fuse/fuse_i.h2
-rw-r--r--fs/gfs2/acl.c12
-rw-r--r--fs/gfs2/bmap.c8
-rw-r--r--fs/gfs2/dir.c12
-rw-r--r--fs/gfs2/file.c28
-rw-r--r--fs/gfs2/inode.c21
-rw-r--r--fs/gfs2/quota.c2
-rw-r--r--fs/gfs2/xattr.c8
-rw-r--r--fs/hfs/attr.c83
-rw-r--r--fs/hfs/catalog.c8
-rw-r--r--fs/hfs/dir.c8
-rw-r--r--fs/hfs/hfs_fs.h6
-rw-r--r--fs/hfs/inode.c9
-rw-r--r--fs/hfs/super.c1
-rw-r--r--fs/hfsplus/catalog.c8
-rw-r--r--fs/hfsplus/dir.c15
-rw-r--r--fs/hfsplus/inode.c7
-rw-r--r--fs/hfsplus/ioctl.c2
-rw-r--r--fs/hfsplus/posix_acl.c4
-rw-r--r--fs/hostfs/hostfs_kern.c4
-rw-r--r--fs/hpfs/file.c6
-rw-r--r--fs/hpfs/inode.c2
-rw-r--r--fs/hpfs/namei.c6
-rw-r--r--fs/hugetlbfs/inode.c24
-rw-r--r--fs/inode.c105
-rw-r--r--fs/internal.h11
-rw-r--r--fs/jbd2/journal.c131
-rw-r--r--fs/jbd2/transaction.c6
-rw-r--r--fs/jffs2/acl.c11
-rw-r--r--fs/jffs2/dir.c12
-rw-r--r--fs/jffs2/file.c3
-rw-r--r--fs/jffs2/fs.c4
-rw-r--r--fs/jffs2/symlink.c3
-rw-r--r--fs/jffs2/xattr.h6
-rw-r--r--fs/jfs/acl.c8
-rw-r--r--fs/jfs/file.c5
-rw-r--r--fs/jfs/inode.c2
-rw-r--r--fs/jfs/jfs_inode.c2
-rw-r--r--fs/jfs/namei.c32
-rw-r--r--fs/jfs/super.c2
-rw-r--r--fs/jfs/symlink.c6
-rw-r--r--fs/jfs/xattr.c2
-rw-r--r--fs/kernfs/dir.c9
-rw-r--r--fs/kernfs/inode.c159
-rw-r--r--fs/kernfs/kernfs-internal.h7
-rw-r--r--fs/kernfs/mount.c1
-rw-r--r--fs/kernfs/symlink.c3
-rw-r--r--fs/libfs.c51
-rw-r--r--fs/locks.c55
-rw-r--r--fs/logfs/dir.c12
-rw-r--r--fs/logfs/file.c4
-rw-r--r--fs/logfs/inode.c4
-rw-r--r--fs/logfs/readwrite.c4
-rw-r--r--fs/mbcache.c6
-rw-r--r--fs/minix/bitmap.c2
-rw-r--r--fs/minix/dir.c6
-rw-r--r--fs/minix/file.c2
-rw-r--r--fs/minix/itree_common.c4
-rw-r--r--fs/minix/namei.c10
-rw-r--r--fs/namei.c17
-rw-r--r--fs/namespace.c2
-rw-r--r--fs/ncpfs/dir.c11
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/nfs/dir.c6
-rw-r--r--fs/nfs/file.c25
-rw-r--r--fs/nfs/internal.h11
-rw-r--r--fs/nfs/nfs3proc.c6
-rw-r--r--fs/nfs/nfs4file.c2
-rw-r--r--fs/nfs/nfs4proc.c6
-rw-r--r--fs/nfs/pagelist.c2
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/write.c4
-rw-r--r--fs/nfsd/auth.c6
-rw-r--r--fs/nfsd/blocklayout.c2
-rw-r--r--fs/nfsd/nfs4state.c2
-rw-r--r--fs/nfsd/nfsproc.c8
-rw-r--r--fs/nilfs2/dir.c6
-rw-r--r--fs/nilfs2/inode.c6
-rw-r--r--fs/nilfs2/ioctl.c2
-rw-r--r--fs/nilfs2/namei.c12
-rw-r--r--fs/notify/fanotify/fanotify_user.c39
-rw-r--r--fs/notify/group.c6
-rw-r--r--fs/notify/inotify/inotify_user.c16
-rw-r--r--fs/notify/notification.c35
-rw-r--r--fs/nsfs.c2
-rw-r--r--fs/ntfs/file.c2
-rw-r--r--fs/ntfs/inode.c4
-rw-r--r--fs/ntfs/mft.c2
-rw-r--r--fs/ocfs2/acl.c12
-rw-r--r--fs/ocfs2/alloc.c2
-rw-r--r--fs/ocfs2/aops.c2
-rw-r--r--fs/ocfs2/cluster/tcp.c2
-rw-r--r--fs/ocfs2/dir.c4
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c2
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c8
-rw-r--r--fs/ocfs2/file.c51
-rw-r--r--fs/ocfs2/inode.h2
-rw-r--r--fs/ocfs2/move_extents.c2
-rw-r--r--fs/ocfs2/namei.c19
-rw-r--r--fs/ocfs2/ocfs2_trace.h2
-rw-r--r--fs/ocfs2/refcounttree.c4
-rw-r--r--fs/ocfs2/super.c2
-rw-r--r--fs/ocfs2/symlink.c3
-rw-r--r--fs/ocfs2/xattr.c2
-rw-r--r--fs/omfs/dir.c10
-rw-r--r--fs/omfs/file.c2
-rw-r--r--fs/omfs/inode.c2
-rw-r--r--fs/open.c17
-rw-r--r--fs/openpromfs/inode.c2
-rw-r--r--fs/orangefs/acl.c15
-rw-r--r--fs/orangefs/dir.c4
-rw-r--r--fs/orangefs/file.c6
-rw-r--r--fs/orangefs/inode.c19
-rw-r--r--fs/orangefs/namei.c63
-rw-r--r--fs/orangefs/orangefs-debugfs.c4
-rw-r--r--fs/orangefs/symlink.c1
-rw-r--r--fs/orangefs/xattr.c3
-rw-r--r--fs/overlayfs/copy_up.c4
-rw-r--r--fs/overlayfs/dir.c5
-rw-r--r--fs/overlayfs/inode.c8
-rw-r--r--fs/overlayfs/overlayfs.h4
-rw-r--r--fs/overlayfs/super.c6
-rw-r--r--fs/pipe.c15
-rw-r--r--fs/posix_acl.c62
-rw-r--r--fs/proc/array.c189
-rw-r--r--fs/proc/base.c101
-rw-r--r--fs/proc/fd.c8
-rw-r--r--fs/proc/fd.h2
-rw-r--r--fs/proc/generic.c2
-rw-r--r--fs/proc/inode.c3
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/meminfo.c211
-rw-r--r--fs/proc/proc_sysctl.c4
-rw-r--r--fs/proc/self.c2
-rw-r--r--fs/proc/stat.c49
-rw-r--r--fs/proc/task_mmu.c10
-rw-r--r--fs/proc/thread_self.c2
-rw-r--r--fs/pstore/inode.c2
-rw-r--r--fs/ramfs/file-nommu.c2
-rw-r--r--fs/ramfs/inode.c6
-rw-r--r--fs/reiserfs/file.c3
-rw-r--r--fs/reiserfs/inode.c4
-rw-r--r--fs/reiserfs/ioctl.c4
-rw-r--r--fs/reiserfs/namei.c27
-rw-r--r--fs/reiserfs/stree.c8
-rw-r--r--fs/reiserfs/super.c2
-rw-r--r--fs/reiserfs/xattr.c6
-rw-r--r--fs/reiserfs/xattr_acl.c10
-rw-r--r--fs/seq_file.c57
-rw-r--r--fs/splice.c677
-rw-r--r--fs/squashfs/inode.c1
-rw-r--r--fs/squashfs/namei.c1
-rw-r--r--fs/squashfs/symlink.c1
-rw-r--r--fs/squashfs/xattr.h1
-rw-r--r--fs/sysv/dir.c6
-rw-r--r--fs/sysv/file.c2
-rw-r--r--fs/sysv/ialloc.c2
-rw-r--r--fs/sysv/itree.c4
-rw-r--r--fs/sysv/namei.c10
-rw-r--r--fs/tracefs/inode.c2
-rw-r--r--fs/ubifs/dir.c11
-rw-r--r--fs/ubifs/file.c8
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/udf/ialloc.c2
-rw-r--r--fs/udf/inode.c4
-rw-r--r--fs/udf/namei.c26
-rw-r--r--fs/ufs/dir.c6
-rw-r--r--fs/ufs/ialloc.c2
-rw-r--r--fs/ufs/inode.c8
-rw-r--r--fs/ufs/namei.c12
-rw-r--r--fs/utimes.c19
-rw-r--r--fs/xattr.c250
-rw-r--r--fs/xfs/xfs_acl.c15
-rw-r--r--fs/xfs/xfs_file.c46
-rw-r--r--fs/xfs/xfs_inode.c4
-rw-r--r--fs/xfs/xfs_ioctl.c2
-rw-r--r--fs/xfs/xfs_iops.c113
-rw-r--r--fs/xfs/xfs_iops.h3
-rw-r--r--fs/xfs/xfs_trace.h1
-rw-r--r--fs/xfs/xfs_trans_inode.c2
-rw-r--r--include/asm-generic/pgtable.h3
-rw-r--r--include/asm-generic/vmlinux.lds.h6
-rw-r--r--include/crypto/algapi.h70
-rw-r--r--include/crypto/engine.h107
-rw-r--r--include/crypto/ghash.h23
-rw-r--r--include/dt-bindings/clock/gxbb-clkc.h9
-rw-r--r--include/dt-bindings/clock/r7s72100-clock.h3
-rw-r--r--include/dt-bindings/clock/r8a7794-clock.h25
-rw-r--r--include/dt-bindings/mfd/qcom-rpm.h22
-rw-r--r--include/dt-bindings/mfd/stm32f4-rcc.h98
-rw-r--r--include/dt-bindings/pinctrl/samsung.h57
-rw-r--r--include/dt-bindings/soc/rockchip,boot-mode.h15
-rw-r--r--include/linux/aer.h2
-rw-r--r--include/linux/bio.h3
-rw-r--r--include/linux/bitops.h36
-rw-r--r--include/linux/blk-cgroup.h2
-rw-r--r--include/linux/blk-mq-pci.h9
-rw-r--r--include/linux/blk-mq.h48
-rw-r--r--include/linux/blk_types.h21
-rw-r--r--include/linux/blkdev.h4
-rw-r--r--include/linux/blockgroup_lock.h28
-rw-r--r--include/linux/bootmem.h9
-rw-r--r--include/linux/ccp.h3
-rw-r--r--include/linux/ceph/auth.h2
-rw-r--r--include/linux/ceph/ceph_fs.h12
-rw-r--r--include/linux/ceph/cls_lock_client.h49
-rw-r--r--include/linux/ceph/libceph.h3
-rw-r--r--include/linux/ceph/mon_client.h3
-rw-r--r--include/linux/ceph/osd_client.h23
-rw-r--r--include/linux/compaction.h40
-rw-r--r--include/linux/compat.h1
-rw-r--r--include/linux/console.h6
-rw-r--r--include/linux/cpu.h5
-rw-r--r--include/linux/cred.h11
-rw-r--r--include/linux/dcache.h5
-rw-r--r--include/linux/device-mapper.h1
-rw-r--r--include/linux/dma-debug.h19
-rw-r--r--include/linux/dma-mapping.h41
-rw-r--r--include/linux/dmaengine.h16
-rw-r--r--include/linux/fdtable.h6
-rw-r--r--include/linux/firmware/meson/meson_sm.h31
-rw-r--r--include/linux/fs.h53
-rw-r--r--include/linux/fscrypto.h24
-rw-r--r--include/linux/fsnotify.h14
-rw-r--r--include/linux/fsnotify_backend.h3
-rw-r--r--include/linux/hid.h4
-rw-r--r--include/linux/huge_mm.h15
-rw-r--r--include/linux/hugetlb.h8
-rw-r--r--include/linux/hw_random.h4
-rw-r--r--include/linux/i2c-mux.h8
-rw-r--r--include/linux/i2c.h47
-rw-r--r--include/linux/init.h19
-rw-r--r--include/linux/ioprio.h1
-rw-r--r--include/linux/jiffies.h4
-rw-r--r--include/linux/kern_levels.h2
-rw-r--r--include/linux/kernel.h48
-rw-r--r--include/linux/lightnvm.h18
-rw-r--r--include/linux/livepatch.h3
-rw-r--r--include/linux/lockdep.h4
-rw-r--r--include/linux/mbus.h18
-rw-r--r--include/linux/memblock.h1
-rw-r--r--include/linux/memcontrol.h21
-rw-r--r--include/linux/mfd/88pm80x.h4
-rw-r--r--include/linux/mfd/abx500/ab8500.h2
-rw-r--r--include/linux/mfd/ac100.h178
-rw-r--r--include/linux/mfd/arizona/core.h12
-rw-r--r--include/linux/mfd/axp20x.h60
-rw-r--r--include/linux/mfd/cros_ec.h18
-rw-r--r--include/linux/mfd/cros_ec_commands.h34
-rw-r--r--include/linux/mfd/da9063/core.h4
-rw-r--r--include/linux/mfd/da9063/pdata.h4
-rw-r--r--include/linux/mfd/da9063/registers.h4
-rw-r--r--include/linux/mfd/db8500-prcmu.h6
-rw-r--r--include/linux/mfd/dbx500-prcmu.h9
-rw-r--r--include/linux/mfd/lp873x.h1
-rw-r--r--include/linux/mfd/max14577-private.h2
-rw-r--r--include/linux/mfd/max14577.h2
-rw-r--r--include/linux/mfd/rk808.h154
-rw-r--r--include/linux/mfd/syscon/exynos5-pmu.h4
-rw-r--r--include/linux/mfd/tps65217.h12
-rw-r--r--include/linux/mfd/twl6040.h2
-rw-r--r--include/linux/mlx4/device.h13
-rw-r--r--include/linux/mm.h44
-rw-r--r--include/linux/mm_types.h2
-rw-r--r--include/linux/mtd/mtd.h107
-rw-r--r--include/linux/mtd/nand.h234
-rw-r--r--include/linux/nmi.h31
-rw-r--r--include/linux/omap-dma.h19
-rw-r--r--include/linux/omap-gpmc.h4
-rw-r--r--include/linux/oom.h46
-rw-r--r--include/linux/page_ext.h8
-rw-r--r--include/linux/page_owner.h2
-rw-r--r--include/linux/pagemap.h68
-rw-r--r--include/linux/pci.h26
-rw-r--r--include/linux/pipe_fs_i.h59
-rw-r--r--include/linux/pkeys.h41
-rw-r--r--include/linux/platform_data/dma-mmp_tdma.h2
-rw-r--r--include/linux/platform_data/dma-s3c24xx.h6
-rw-r--r--include/linux/platform_data/remoteproc-omap.h6
-rw-r--r--include/linux/posix_acl.h23
-rw-r--r--include/linux/posix_acl_xattr.h31
-rw-r--r--include/linux/power/bq24735-charger.h4
-rw-r--r--include/linux/power/bq27xxx_battery.h1
-rw-r--r--include/linux/power/sbs-battery.h8
-rw-r--r--include/linux/printk.h1
-rw-r--r--include/linux/raid/pq.h4
-rw-r--r--include/linux/remoteproc.h16
-rw-r--r--include/linux/rpmsg.h248
-rw-r--r--include/linux/sbitmap.h373
-rw-r--r--include/linux/sched.h22
-rw-r--r--include/linux/seq_file.h4
-rw-r--r--include/linux/skbuff.h8
-rw-r--r--include/linux/soc/qcom/smd.h29
-rw-r--r--include/linux/splice.h3
-rw-r--r--include/linux/swap.h11
-rw-r--r--include/linux/syscalls.h8
-rw-r--r--include/linux/t10-pi.h20
-rw-r--r--include/linux/uio.h19
-rw-r--r--include/linux/workqueue.h1
-rw-r--r--include/linux/writeback.h1
-rw-r--r--include/linux/xattr.h7
-rw-r--r--include/rdma/ib_verbs.h104
-rw-r--r--include/trace/events/compaction.h2
-rw-r--r--include/trace/events/intel_ish.h30
-rw-r--r--include/trace/events/irq.h2
-rw-r--r--include/uapi/asm-generic/mman-common.h5
-rw-r--r--include/uapi/asm-generic/unistd.h12
-rw-r--r--include/uapi/linux/Kbuild2
-rw-r--r--include/uapi/linux/fs.h1
-rw-r--r--include/uapi/linux/hsi/hsi_char.h17
-rw-r--r--include/uapi/linux/input.h1
-rw-r--r--include/uapi/linux/pci_regs.h12
-rw-r--r--include/uapi/linux/posix_acl.h39
-rw-r--r--include/uapi/linux/posix_acl_xattr.h38
-rw-r--r--include/uapi/rdma/Kbuild7
-rw-r--r--include/uapi/rdma/cxgb3-abi.h (renamed from drivers/infiniband/hw/cxgb3/iwch_user.h)8
-rw-r--r--include/uapi/rdma/cxgb4-abi.h (renamed from drivers/infiniband/hw/cxgb4/user.h)11
-rw-r--r--include/uapi/rdma/ib_user_verbs.h27
-rw-r--r--include/uapi/rdma/mlx4-abi.h (renamed from drivers/infiniband/hw/mlx4/user.h)6
-rw-r--r--include/uapi/rdma/mlx5-abi.h (renamed from drivers/infiniband/hw/mlx5/user.h)52
-rw-r--r--include/uapi/rdma/mthca-abi.h111
-rw-r--r--include/uapi/rdma/nes-abi.h (renamed from drivers/infiniband/hw/nes/nes_user.h)6
-rw-r--r--include/uapi/rdma/ocrdma-abi.h (renamed from drivers/infiniband/hw/ocrdma/ocrdma_abi.h)138
-rw-r--r--include/uapi/scsi/cxlflash_ioctl.h19
-rw-r--r--init/Kconfig6
-rw-r--r--ipc/mqueue.c18
-rw-r--r--kernel/bpf/inode.c2
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c8
-rw-r--r--kernel/groups.c67
-rw-r--r--kernel/livepatch/core.c19
-rw-r--r--kernel/module.c13
-rw-r--r--kernel/power/process.c17
-rw-r--r--kernel/printk/printk.c137
-rw-r--r--kernel/relay.c78
-rw-r--r--kernel/sched/idle.c13
-rw-r--r--kernel/smpboot.c2
-rw-r--r--kernel/sys_ni.c5
-rw-r--r--kernel/sysctl.c14
-rw-r--r--kernel/time/timekeeping.c7
-rw-r--r--kernel/trace/trace_syscalls.c6
-rw-r--r--kernel/uid16.c4
-rw-r--r--kernel/workqueue.c40
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--lib/Makefile2
-rw-r--r--lib/atomic64_test.c4
-rw-r--r--lib/dma-debug.c52
-rw-r--r--lib/iov_iter.c398
-rw-r--r--lib/nmi_backtrace.c42
-rw-r--r--lib/raid6/Makefile2
-rw-r--r--lib/raid6/algos.c12
-rw-r--r--lib/raid6/avx512.c569
-rw-r--r--lib/raid6/recov_avx512.c388
-rw-r--r--lib/raid6/test/Makefile5
-rw-r--r--lib/raid6/test/test.c7
-rw-r--r--lib/raid6/x86.h10
-rw-r--r--lib/sbitmap.c347
-rw-r--r--mm/bootmem.c14
-rw-r--r--mm/compaction.c205
-rw-r--r--mm/debug.c5
-rw-r--r--mm/filemap.c10
-rw-r--r--mm/huge_memory.c81
-rw-r--r--mm/hugetlb.c53
-rw-r--r--mm/internal.h3
-rw-r--r--mm/ksm.c7
-rw-r--r--mm/memblock.c5
-rw-r--r--mm/memcontrol.c154
-rw-r--r--mm/memory.c21
-rw-r--r--mm/memory_hotplug.c4
-rw-r--r--mm/mempolicy.c2
-rw-r--r--mm/migrate.c2
-rw-r--r--mm/mincore.c5
-rw-r--r--mm/mlock.c52
-rw-r--r--mm/mmap.c238
-rw-r--r--mm/mprotect.c93
-rw-r--r--mm/nobootmem.c20
-rw-r--r--mm/oom_kill.c381
-rw-r--r--mm/page-writeback.c34
-rw-r--r--mm/page_alloc.c281
-rw-r--r--mm/page_ext.c45
-rw-r--r--mm/page_io.c7
-rw-r--r--mm/page_isolation.c2
-rw-r--r--mm/page_owner.c156
-rw-r--r--mm/shmem.c156
-rw-r--r--mm/swap.c4
-rw-r--r--mm/swap_state.c14
-rw-r--r--mm/swapfile.c137
-rw-r--r--mm/vmacache.c8
-rw-r--r--mm/vmalloc.c22
-rw-r--r--mm/vmscan.c53
-rw-r--r--mm/vmstat.c95
-rw-r--r--net/9p/trans_rdma.c2
-rw-r--r--net/ceph/Makefile1
-rw-r--r--net/ceph/auth.c13
-rw-r--r--net/ceph/auth_none.c2
-rw-r--r--net/ceph/ceph_common.c13
-rw-r--r--net/ceph/ceph_strings.c1
-rw-r--r--net/ceph/cls_lock_client.c325
-rw-r--r--net/ceph/crush/mapper.c17
-rw-r--r--net/ceph/mon_client.c82
-rw-r--r--net/ceph/osd_client.c169
-rw-r--r--net/core/skbuff.c28
-rw-r--r--net/core/sock.c6
-rw-r--r--net/ipv4/ping.c15
-rw-r--r--net/ipv4/tcp.c5
-rw-r--r--net/ipv4/tcp_ipv4.c3
-rw-r--r--net/kcm/kcmsock.c16
-rw-r--r--net/rds/ib.c2
-rw-r--r--net/socket.c61
-rw-r--r--net/sunrpc/auth_generic.c4
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.c2
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c2
-rw-r--r--net/sunrpc/auth_unix.c4
-rw-r--r--net/sunrpc/rpc_pipe.c2
-rw-r--r--net/sunrpc/svcauth_unix.c6
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c2
-rw-r--r--net/sunrpc/xprtrdma/verbs.c2
-rw-r--r--net/unix/af_unix.c17
-rw-r--r--samples/rpmsg/rpmsg_client_sample.c32
-rw-r--r--scripts/mod/modpost.c2
-rw-r--r--scripts/recordmcount.c1
-rwxr-xr-xscripts/recordmcount.pl1
-rw-r--r--scripts/spelling.txt1
-rw-r--r--security/apparmor/apparmorfs.c2
-rw-r--r--security/commoncap.c25
-rw-r--r--security/inode.c9
-rw-r--r--security/integrity/evm/evm_crypto.c7
-rw-r--r--security/integrity/evm/evm_main.c4
-rw-r--r--security/integrity/ima/ima_appraise.c25
-rw-r--r--security/integrity/ima/ima_main.c2
-rw-r--r--security/selinux/hooks.c19
-rw-r--r--security/selinux/selinuxfs.c2
-rw-r--r--security/selinux/ss/policydb.c4
-rw-r--r--security/smack/smack_lsm.c12
-rw-r--r--security/tomoyo/realpath.c4
-rw-r--r--sound/aoa/core/gpio-feature.c4
-rw-r--r--sound/ppc/tumbler.c8
-rw-r--r--tools/arch/x86/include/asm/cpufeatures.h1
-rw-r--r--tools/arch/x86/lib/memcpy_64.S6
-rw-r--r--tools/build/Build2
-rw-r--r--tools/build/Build.include6
-rw-r--r--tools/build/Makefile8
-rw-r--r--tools/build/Makefile.build26
-rw-r--r--tools/build/Makefile.feature2
-rw-r--r--tools/build/Makefile.include4
-rw-r--r--tools/build/feature/Makefile10
-rw-r--r--tools/build/feature/test-cxx.cpp15
-rw-r--r--tools/include/uapi/linux/bpf.h4
-rw-r--r--tools/lib/subcmd/pager.c16
-rw-r--r--tools/lib/subcmd/pager.h1
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c1
-rw-r--r--tools/perf/Documentation/perf-list.txt12
-rw-r--r--tools/perf/Documentation/tips.txt4
-rw-r--r--tools/perf/Makefile.perf34
-rw-r--r--tools/perf/arch/powerpc/util/header.c11
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c3
-rw-r--r--tools/perf/arch/x86/util/header.c24
-rw-r--r--tools/perf/builtin-list.c20
-rw-r--r--tools/perf/pmu-events/Build13
-rw-r--r--tools/perf/pmu-events/README147
-rw-r--r--tools/perf/pmu-events/jevents.c814
-rw-r--r--tools/perf/pmu-events/jevents.h18
-rw-r--r--tools/perf/pmu-events/jsmn.c313
-rw-r--r--tools/perf/pmu-events/jsmn.h67
-rw-r--r--tools/perf/pmu-events/json.c162
-rw-r--r--tools/perf/pmu-events/json.h38
-rw-r--r--tools/perf/pmu-events/pmu-events.h37
-rw-r--r--tools/perf/util/evlist.c12
-rw-r--r--tools/perf/util/evsel.c3
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c38
-rw-r--r--tools/perf/util/machine.c6
-rw-r--r--tools/perf/util/parse-events.c8
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/pmu.c176
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/strbuf.h3
-rw-r--r--tools/perf/util/thread.c9
-rw-r--r--tools/testing/selftests/powerpc/Makefile1
-rw-r--r--tools/testing/selftests/powerpc/fpu_asm.h80
-rw-r--r--tools/testing/selftests/powerpc/gpr_asm.h96
-rw-r--r--tools/testing/selftests/powerpc/harness.c9
-rw-r--r--tools/testing/selftests/powerpc/math/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/math/fpu_asm.S73
-rw-r--r--tools/testing/selftests/powerpc/math/vmx_asm.S85
-rw-r--r--tools/testing/selftests/powerpc/math/vsx_asm.S61
-rw-r--r--tools/testing/selftests/powerpc/math/vsx_preempt.c147
-rw-r--r--tools/testing/selftests/powerpc/signal/Makefile13
-rw-r--r--tools/testing/selftests/powerpc/signal/signal.S50
-rw-r--r--tools/testing/selftests/powerpc/signal/signal.c111
-rw-r--r--tools/testing/selftests/powerpc/signal/signal_tm.c110
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile8
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c92
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c90
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c110
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c125
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal.S114
-rw-r--r--tools/testing/selftests/powerpc/tm/tm.h27
-rw-r--r--tools/testing/selftests/powerpc/utils.h9
-rw-r--r--tools/testing/selftests/powerpc/vmx_asm.h96
-rw-r--r--tools/testing/selftests/powerpc/vsx_asm.h71
-rw-r--r--tools/testing/selftests/vm/.gitignore1
-rw-r--r--tools/testing/selftests/vm/Makefile4
-rw-r--r--tools/testing/selftests/vm/mlock-random-test.c293
-rw-r--r--tools/testing/selftests/vm/mlock2-tests.c63
-rw-r--r--tools/testing/selftests/vm/mlock2.h62
-rw-r--r--tools/testing/selftests/x86/Makefile3
-rw-r--r--tools/testing/selftests/x86/pkey-helpers.h219
-rw-r--r--tools/testing/selftests/x86/protection_keys.c1410
2647 files changed, 107378 insertions, 50330 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000000..89c411b5ce6b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+*.c diff=cpp
+*.h diff=cpp
diff --git a/.mailmap b/.mailmap
index 967f88210b12..2408e56e241b 100644
--- a/.mailmap
+++ b/.mailmap
@@ -75,6 +75,8 @@ Jean Tourrilhes <jt@hpl.hp.com>
Jeff Garzik <jgarzik@pretzel.yyz.us>
Jens Axboe <axboe@suse.de>
Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+Johan Hovold <johan@kernel.org> <jhovold@gmail.com>
+Johan Hovold <johan@kernel.org> <johan@hovoldconsulting.com>
John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
John Stultz <johnstul@us.ibm.com>
<josh@joshtriplett.org> <josh@freedesktop.org>
diff --git a/CREDITS b/CREDITS
index 936f05a7500c..513aaa3546bf 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1090,6 +1090,10 @@ S: 6350 Stoneridge Mall Road
S: Pleasanton, CA 94588
S: USA
+N: Dmitry Eremin-Solenikov
+E: dbaryshkov@gmail.com
+D: Power Supply Maintainer from v3.14 - v3.15
+
N: Doug Evans
E: dje@cygnus.com
D: Wrote Xenix FS (part of standard kernel since 0.99.15)
@@ -2292,11 +2296,11 @@ D: Initial implementation of VC's, pty's and select()
N: Pavel Machek
E: pavel@ucw.cz
-D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
+P: 4096R/92DFCE96 4FA7 9EEF FCD4 C44F C585 B8C7 C060 2241 92DF CE96
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd,
D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB,
-D: work on suspend-to-ram/disk, killing duplicates from ioctl32
-S: Volkova 1131
-S: 198 00 Praha 9
+D: work on suspend-to-ram/disk, killing duplicates from ioctl32,
+D: Altera SoCFPGA and Nokia N900 support.
S: Czech Republic
N: Paul Mackerras
diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd
index 2ddd680929d8..f208ac58d613 100644
--- a/Documentation/ABI/testing/sysfs-bus-rbd
+++ b/Documentation/ABI/testing/sysfs-bus-rbd
@@ -6,7 +6,7 @@ Description:
Being used for adding and removing rbd block devices.
-Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
+Usage: <mon ip addr> <options> <pool name> <rbd image name> [<snap name>]
$ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add
@@ -14,9 +14,13 @@ The snapshot name can be "-" or omitted to map the image read/write. A <dev-id>
will be assigned for any registered block device. If snapshot is used, it will
be mapped read-only.
-Removal of a device:
+Usage: <dev-id> [force]
- $ echo <dev-id> > /sys/bus/rbd/remove
+ $ echo 2 > /sys/bus/rbd/remove
+
+Optional "force" argument which when passed will wait for running requests and
+then unmap the image. Requests sent to the driver after initiating the removal
+will be failed. (August 2016, since 4.9.)
What: /sys/bus/rbd/add_single_major
Date: December 2013
@@ -43,10 +47,25 @@ Description: Available only if rbd module is inserted with single_major
Entries under /sys/bus/rbd/devices/<dev-id>/
--------------------------------------------
+client_addr
+
+ The ceph unique client entity_addr_t (address + nonce).
+ The format is <address>:<port>/<nonce>: '1.2.3.4:1234/5678' or
+ '[1:2:3:4:5:6:7:8]:1234/5678'. (August 2016, since 4.9.)
+
client_id
The ceph unique client id that was assigned for this specific session.
+cluster_fsid
+
+ The ceph cluster UUID. (August 2016, since 4.9.)
+
+config_info
+
+ The string written into /sys/bus/rbd/add{,_single_major}. (August
+ 2016, since 4.9.)
+
features
A hexadecimal encoding of the feature bits for this image.
@@ -92,6 +111,10 @@ current_snap
The current snapshot for which the device is mapped.
+snap_id
+
+ The current snapshot's id. (August 2016, since 4.9.)
+
parent
Information identifying the chain of parent images in a layered rbd
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
index fa05719f9981..f85ce9e327b9 100644
--- a/Documentation/ABI/testing/sysfs-class-power
+++ b/Documentation/ABI/testing/sysfs-class-power
@@ -22,7 +22,7 @@ Description:
What: /sys/class/power_supply/max14577-charger/device/fast_charge_timer
Date: October 2014
KernelVersion: 3.18.0
-Contact: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Contact: Krzysztof Kozlowski <krzk@kernel.org>
Description:
This entry shows and sets the maximum time the max14577
charger operates in fast-charge mode. When the timer expires
@@ -36,7 +36,7 @@ Description:
What: /sys/class/power_supply/max77693-charger/device/fast_charge_timer
Date: January 2015
KernelVersion: 3.19.0
-Contact: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Contact: Krzysztof Kozlowski <krzk@kernel.org>
Description:
This entry shows and sets the maximum time the max77693
charger operates in fast-charge mode. When the timer expires
@@ -50,7 +50,7 @@ Description:
What: /sys/class/power_supply/max77693-charger/device/top_off_threshold_current
Date: January 2015
KernelVersion: 3.19.0
-Contact: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Contact: Krzysztof Kozlowski <krzk@kernel.org>
Description:
This entry shows and sets the charging current threshold for
entering top-off charging mode. When charging current in fast
@@ -65,7 +65,7 @@ Description:
What: /sys/class/power_supply/max77693-charger/device/top_off_timer
Date: January 2015
KernelVersion: 3.19.0
-Contact: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Contact: Krzysztof Kozlowski <krzk@kernel.org>
Description:
This entry shows and sets the maximum time the max77693
charger operates in top-off charge mode. When the timer expires
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index db197a879580..305dffd229a8 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -35,6 +35,12 @@ Description: Displays a set of alternate modes supported by a wheel. Each
DF-EX <*--------> G25 <-> G27
DF-EX <*----------------> G27
+ G29:
+ DF-EX <*> DFP <-> G25 <-> G27 <-> G29
+ DF-EX <*--------> G25 <-> G27 <-> G29
+ DF-EX <*----------------> G27 <-> G29
+ DF-EX <*------------------------> G29
+
DFGT:
DF-EX <*> DFP <-> DFGT
DF-EX <*--------> DFGT
@@ -50,3 +56,12 @@ Description: Displays the real model of the wheel regardless of any
alternate mode the wheel might be switched to.
It is a read-only value.
This entry is not created for devices that have only one mode.
+
+What: /sys/bus/hid/drivers/logitech/<dev>/combine_pedals
+Date: Sep 2016
+KernelVersion: 4.9
+Contact: Simon Wood <simon@mungewell.org>
+Description: Controls whether a combined value of accelerator and brake is
+ reported on the Y axis of the controller. Useful for older games
+ which can do not work with separate accelerator/brake axis.
+ Off ('0') by default, enabled by setting '1'.
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom
index dca429340772..2aa5503ee200 100644
--- a/Documentation/ABI/testing/sysfs-driver-wacom
+++ b/Documentation/ABI/testing/sysfs-driver-wacom
@@ -24,6 +24,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status0_luminance
Date: August 2014
Contact: linux-input@vger.kernel.org
Description:
+ <obsoleted by the LED class API now exported by the driver>
Writing to this file sets the status LED luminance (1..127)
when the stylus does not touch the tablet surface, and no
button is pressed on the stylus. This luminance level is
@@ -33,6 +34,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status1_luminance
Date: August 2014
Contact: linux-input@vger.kernel.org
Description:
+ <obsoleted by the LED class API now exported by the driver>
Writing to this file sets the status LED luminance (1..127)
when the stylus touches the tablet surface, or any button is
pressed on the stylus.
@@ -41,6 +43,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status_led0_select
Date: August 2014
Contact: linux-input@vger.kernel.org
Description:
+ <obsoleted by the LED class API now exported by the driver>
Writing to this file sets which one of the four (for Intuos 4
and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq
24HD) status LEDs is active (0..3). The other three LEDs on the
@@ -50,6 +53,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status_led1_select
Date: August 2014
Contact: linux-input@vger.kernel.org
Description:
+ <obsoleted by the LED class API now exported by the driver>
Writing to this file sets which one of the left four (for Cintiq 21UX2
and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on
the left are always inactive.
@@ -91,6 +95,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/<serial_number>/r
Date: July 2015
Contact: linux-input@vger.kernel.org
Description:
+ <obsoleted by the LED class API now exported by the driver>
Reading from this file reports the mode status of the
remote as indicated by the LED lights on the device. If no
reports have been received from the paired device, reading
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index 1d26eeb6b5f6..6b20128fab8a 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -277,14 +277,26 @@ and <size> parameters are provided to do partial page mapping, it is
recommended that you never use these unless you really know what the
cache width is.
+dma_addr_t
+dma_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+
+void
+dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+
+API for mapping and unmapping for MMIO resources. All the notes and
+warnings for the other mapping APIs apply here. The API should only be
+used to map device MMIO resources, mapping of RAM is not permitted.
+
int
dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-In some circumstances dma_map_single() and dma_map_page() will fail to create
-a mapping. A driver can check for these errors by testing the returned
-DMA address with dma_mapping_error(). A non-zero return value means the mapping
-could not be created and the driver should take appropriate action (e.g.
-reduce current DMA mapping usage or delay and try again later).
+In some circumstances dma_map_single(), dma_map_page() and dma_map_resource()
+will fail to create a mapping. A driver can check for these errors by testing
+the returned DMA address with dma_mapping_error(). A non-zero return value
+means the mapping could not be created and the driver should take appropriate
+action (e.g. reduce current DMA mapping usage or delay and try again later).
int
dma_map_sg(struct device *dev, struct scatterlist *sg,
diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl
index fb2a1526f6ec..088b79c341ff 100644
--- a/Documentation/DocBook/crypto-API.tmpl
+++ b/Documentation/DocBook/crypto-API.tmpl
@@ -797,7 +797,8 @@ kernel crypto API | Caller
include/linux/crypto.h and their definition can be seen below.
The former function registers a single transformation, while
the latter works on an array of transformation descriptions.
- The latter is useful when registering transformations in bulk.
+ The latter is useful when registering transformations in bulk,
+ for example when a driver implements multiple transformations.
</para>
<programlisting>
@@ -822,18 +823,31 @@ kernel crypto API | Caller
</para>
<para>
- The bulk registration / unregistration functions require
- that struct crypto_alg is an array of count size. These
- functions simply loop over that array and register /
- unregister each individual algorithm. If an error occurs,
- the loop is terminated at the offending algorithm definition.
- That means, the algorithms prior to the offending algorithm
- are successfully registered. Note, the caller has no way of
- knowing which cipher implementations have successfully
- registered. If this is important to know, the caller should
- loop through the different implementations using the single
- instance *_alg functions for each individual implementation.
+ The bulk registration/unregistration functions
+ register/unregister each transformation in the given array of
+ length count. They handle errors as follows:
</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ crypto_register_algs() succeeds if and only if it
+ successfully registers all the given transformations. If an
+ error occurs partway through, then it rolls back successful
+ registrations before returning the error code. Note that if
+ a driver needs to handle registration errors for individual
+ transformations, then it will need to use the non-bulk
+ function crypto_register_alg() instead.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ crypto_unregister_algs() tries to unregister all the given
+ transformations, continuing on error. It logs errors and
+ always returns zero.
+ </para>
+ </listitem>
+ </itemizedlist>
+
</sect1>
<sect1><title>Single-Block Symmetric Ciphers [CIPHER]</title>
diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt
index b4987c0bcb20..ea8cafba255c 100644
--- a/Documentation/PCI/pcieaer-howto.txt
+++ b/Documentation/PCI/pcieaer-howto.txt
@@ -49,25 +49,17 @@ depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and
CONFIG_PCIEAER = y.
2.2 Load PCI Express AER Root Driver
-There is a case where a system has AER support in BIOS. Enabling the AER
-Root driver and having AER support in BIOS may result unpredictable
-behavior. To avoid this conflict, a successful load of the AER Root driver
-requires ACPI _OSC support in the BIOS to allow the AER Root driver to
-request for native control of AER. See the PCI FW 3.0 Specification for
-details regarding OSC usage. Currently, lots of firmwares don't provide
-_OSC support while they use PCI Express. To support such firmwares,
-forceload, a parameter of type bool, could enable AER to continue to
-be initiated although firmwares have no _OSC support. To enable the
-walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line
-when booting kernel. Note that forceload=n by default.
-
-nosourceid, another parameter of type bool, can be used when broken
-hardware (mostly chipsets) has root ports that cannot obtain the reporting
-source ID. nosourceid=n by default.
+
+Some systems have AER support in firmware. Enabling Linux AER support at
+the same time the firmware handles AER may result in unpredictable
+behavior. Therefore, Linux does not handle AER events unless the firmware
+grants AER control to the OS via the ACPI _OSC method. See the PCI FW 3.0
+Specification for details regarding _OSC usage.
2.3 AER error output
-When a PCI-E AER error is captured, an error message will be outputted to
-console. If it's a correctable error, it is outputted as a warning.
+
+When a PCIe AER error is captured, an error message will be output to
+console. If it's a correctable error, it is output as a warning.
Otherwise, it is printed as an error. So users could choose different
log level to filter out correctable error messages.
diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README
index c7a0554523da..cd0243302bc1 100644
--- a/Documentation/arm/sunxi/README
+++ b/Documentation/arm/sunxi/README
@@ -31,6 +31,8 @@ SunXi family
+ User Manual
http://dl.linux-sunxi.org/A13/A13%20User%20Manual%20-%20v1.2%20%282013-01-08%29.pdf
+ - Next Thing Co GR8 (sun5i)
+
* Dual ARM Cortex-A7 based SoCs
- Allwinner A20 (sun7i)
+ User Manual
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index bcdb2b4c1f12..918e1e0d0e78 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -115,7 +115,7 @@ i. Per-queue limits/values exported to the generic layer by the driver
Various parameters that the generic i/o scheduler logic uses are set at
a per-queue level (e.g maximum request size, maximum number of segments in
-a scatter-gather list, hardsect size)
+a scatter-gather list, logical block size)
Some parameters that were earlier available as global arrays indexed by
major/minor are now directly associated with the queue. Some of these may
@@ -156,7 +156,7 @@ Some new queue property settings:
blk_queue_max_segment_size(q, max_seg_size)
Maximum size of a clustered segment, 64kB default.
- blk_queue_hardsect_size(q, hardsect_size)
+ blk_queue_logical_block_size(q, logical_block_size)
Lowest possible sector size that the hardware can operate
on, 512 bytes default.
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
index 6ffe08778465..9c97de23919a 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
@@ -38,6 +38,10 @@ Raspberry Pi Compute Module
Required root node properties:
compatible = "raspberrypi,compute-module", "brcm,bcm2835";
+Raspberry Pi Zero
+Required root node properties:
+compatible = "raspberrypi,model-zero", "brcm,bcm2835";
+
Generic BCM2835 board
Required root node properties:
compatible = "brcm,bcm2835";
diff --git a/Documentation/devicetree/bindings/arm/davinci.txt b/Documentation/devicetree/bindings/arm/davinci.txt
index cfaeda4274e6..f0841ce725b5 100644
--- a/Documentation/devicetree/bindings/arm/davinci.txt
+++ b/Documentation/devicetree/bindings/arm/davinci.txt
@@ -5,6 +5,10 @@ DA850/OMAP-L138/AM18x Evaluation Module (EVM) board
Required root node properties:
- compatible = "ti,da850-evm", "ti,da850";
+DA850/OMAP-L138/AM18x L138/C6748 Development Kit (LCDK) board
+Required root node properties:
+ - compatible = "ti,da850-lcdk", "ti,da850";
+
EnBW AM1808 based CMC board
Required root node properties:
- compatible = "enbw,cmc", "ti,da850;
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 83fe816ae050..3f81575aa6be 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -175,38 +175,55 @@ Example:
};
-----------------------------------------------------------------------
-Hisilicon HiP05 PCIe-SAS system controller
+Hisilicon HiP05/HiP06 PCIe-SAS sub system controller
Required properties:
- compatible : "hisilicon,pcie-sas-subctrl", "syscon";
- reg : Register address and size
-The HiP05 PCIe-SAS system controller is shared by PCIe and SAS controllers in
-HiP05 Soc to implement some basic configurations.
+The PCIe-SAS sub system controller is shared by PCIe and SAS controllers in
+HiP05 or HiP06 Soc to implement some basic configurations.
Example:
- /* for HiP05 PCIe-SAS system */
- pcie_sas: system_controller@0xb0000000 {
+ /* for HiP05 PCIe-SAS sub system */
+ pcie_sas: system_controller@b0000000 {
compatible = "hisilicon,pcie-sas-subctrl", "syscon";
reg = <0xb0000000 0x10000>;
};
-Hisilicon HiP05 PERISUB system controller
+Hisilicon HiP05/HiP06 PERI sub system controller
Required properties:
-- compatible : "hisilicon,hip05-perisubc", "syscon";
+- compatible : "hisilicon,peri-subctrl", "syscon";
- reg : Register address and size
-The HiP05 PERISUB system controller is shared by peripheral controllers in
-HiP05 Soc to implement some basic configurations. The peripheral
+The PERI sub system controller is shared by peripheral controllers in
+HiP05 or HiP06 Soc to implement some basic configurations. The peripheral
controllers include mdio, ddr, iic, uart, timer and so on.
Example:
- /* for HiP05 perisub-ctrl-c system */
+ /* for HiP05 sub peri system */
peri_c_subctrl: syscon@80000000 {
- compatible = "hisilicon,hip05-perisubc", "syscon";
+ compatible = "hisilicon,peri-subctrl", "syscon";
reg = <0x0 0x80000000 0x0 0x10000>;
};
+
+Hisilicon HiP05/HiP06 DSA sub system controller
+
+Required properties:
+- compatible : "hisilicon,dsa-subctrl", "syscon";
+- reg : Register address and size
+
+The DSA sub system controller is shared by peripheral controllers in
+HiP05 or HiP06 Soc to implement some basic configurations.
+
+Example:
+ /* for HiP05 dsa sub system */
+ pcie_sas: system_controller@a0000000 {
+ compatible = "hisilicon,dsa-subctrl", "syscon";
+ reg = <0xa0000000 0x10000>;
+ };
+
-----------------------------------------------------------------------
Hisilicon CPU controller
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-39x.txt b/Documentation/devicetree/bindings/arm/marvell/armada-39x.txt
index 53d4ff9ea8ad..89468664f6ea 100644
--- a/Documentation/devicetree/bindings/arm/marvell/armada-39x.txt
+++ b/Documentation/devicetree/bindings/arm/marvell/armada-39x.txt
@@ -8,8 +8,19 @@ Required root node property:
- compatible: must contain "marvell,armada390"
-In addition, boards using the Marvell Armada 398 SoC shall have the
-following property before the previous one:
+In addition, boards using the Marvell Armada 395 SoC shall have the
+following property before the common "marvell,armada390" one:
+
+Required root node property:
+
+compatible: must contain "marvell,armada395"
+
+Example:
+
+compatible = "marvell,a395-gp", "marvell,armada395", "marvell,armada390";
+
+Boards using the Marvell Armada 398 SoC shall have the following
+property before the common "marvell,armada390" one:
Required root node property:
diff --git a/Documentation/devicetree/bindings/arm/marvell/marvell,orion5x.txt b/Documentation/devicetree/bindings/arm/marvell/marvell,orion5x.txt
new file mode 100644
index 000000000000..748a8f287462
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell/marvell,orion5x.txt
@@ -0,0 +1,25 @@
+Marvell Orion SoC Family Device Tree Bindings
+---------------------------------------------
+
+Boards with a SoC of the Marvell Orion family, eg 88f5181
+
+* Required root node properties:
+compatible: must contain "marvell,orion5x"
+
+In addition, the above compatible shall be extended with the specific
+SoC. Currently known SoC compatibles are:
+
+"marvell,orion5x-88f5181"
+"marvell,orion5x-88f5182"
+
+And in addition, the compatible shall be extended with the specific
+board. Currently known boards are:
+
+"buffalo,lsgl"
+"buffalo,lswsgl"
+"buffalo,lswtgl"
+"lacie,ethernet-disk-mini-v2"
+"lacie,d2-network"
+"marvell,rd-88f5182-nas"
+"maxtor,shared-storage-2"
+"netgear,wnr854t"
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index 94b57f247615..f53e2ee65e35 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -180,3 +180,9 @@ Boards:
- DRA722 EVM: Software Development Board for DRA722
compatible = "ti,dra72-evm", "ti,dra722", "ti,dra72", "ti,dra7"
+
+- DM3730 Logic PD Torpedo + Wireless: Commercial System on Module with WiFi and Bluetooth
+ compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap3630", "ti,omap3"
+
+- DM3730 Logic PD SOM-LV: Commercial System on Module with WiFi and Bluetooth
+ compatible = "logicpd,dm3730-som-lv-devkit", "ti,omap3630", "ti,omap3"
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index 666864517069..55f388f954de 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -31,6 +31,10 @@ Rockchip platforms device tree bindings
or
- compatible = "firefly,firefly-rk3288-beta", "rockchip,rk3288";
+- Firefly Firefly-RK3288 Reload board:
+ Required root node properties:
+ - compatible = "firefly,firefly-rk3288-reload", "rockchip,rk3288";
+
- ChipSPARK PopMetal-RK3288 board:
Required root node properties:
- compatible = "chipspark,popmetal-rk3288", "rockchip,rk3288";
@@ -110,6 +114,14 @@ Rockchip platforms device tree bindings
- Rockchip RK3229 Evaluation board:
- compatible = "rockchip,rk3229-evb", "rockchip,rk3229";
+- Rockchip RK3288 Fennec board:
+ Required root node properties:
+ - compatible = "rockchip,rk3288-fennec", "rockchip,rk3288";
+
- Rockchip RK3399 evb:
Required root node properties:
- compatible = "rockchip,rk3399-evb", "rockchip,rk3399";
+
+- Tronsmart Orion R68 Meta
+ Required root node properties:
+ - compatible = "tronsmart,orion-r68-meta", "rockchip,rk3368";
diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
index 2d6356d8daf4..bf5fc59a6938 100644
--- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
@@ -10,6 +10,7 @@ Properties:
- "samsung,exynos5260-pmu" - for Exynos5260 SoC.
- "samsung,exynos5410-pmu" - for Exynos5410 SoC,
- "samsung,exynos5420-pmu" - for Exynos5420 SoC.
+ - "samsung,exynos5433-pmu" - for Exynos5433 SoC.
- "samsung,exynos7-pmu" - for Exynos7 SoC.
second value must be always "syscon".
diff --git a/Documentation/devicetree/bindings/arm/shmobile.txt b/Documentation/devicetree/bindings/arm/shmobile.txt
index 1df32d339da5..2f0b7169f132 100644
--- a/Documentation/devicetree/bindings/arm/shmobile.txt
+++ b/Documentation/devicetree/bindings/arm/shmobile.txt
@@ -49,6 +49,8 @@ Boards:
compatible = "renesas,genmai", "renesas,r7s72100"
- Gose
compatible = "renesas,gose", "renesas,r8a7793"
+ - H3ULCB (RTP0RC7795SKB00010S)
+ compatible = "renesas,h3ulcb", "renesas,r8a7795";
- Henninger
compatible = "renesas,henninger", "renesas,r8a7791"
- Koelsch (RTP0RC7791SEB00010S)
@@ -63,9 +65,13 @@ Boards:
compatible = "renesas,marzen", "renesas,r8a7779"
- Porter (M2-LCDP)
compatible = "renesas,porter", "renesas,r8a7791"
+ - RSKRZA1 (YR0K77210C000BE)
+ compatible = "renesas,rskrza1", "renesas,r7s72100"
- Salvator-X (RTP0RC7795SIPB0010S)
compatible = "renesas,salvator-x", "renesas,r8a7795";
- Salvator-X
compatible = "renesas,salvator-x", "renesas,r8a7796";
- SILK (RTP0RC7794LCB00011S)
compatible = "renesas,silk", "renesas,r8a7794"
+ - Wheat
+ compatible = "renesas,wheat", "renesas,r8a7792"
diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt
index 7e79fcc36b0d..3975d0a0e4c2 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.txt
+++ b/Documentation/devicetree/bindings/arm/sunxi.txt
@@ -14,3 +14,4 @@ using one of the following compatible strings:
allwinner,sun8i-a83t
allwinner,sun8i-h3
allwinner,sun9i-a80
+ nextthing,gr8
diff --git a/Documentation/devicetree/bindings/arm/technologic.txt b/Documentation/devicetree/bindings/arm/technologic.txt
index 842298894cf0..33797acad846 100644
--- a/Documentation/devicetree/bindings/arm/technologic.txt
+++ b/Documentation/devicetree/bindings/arm/technologic.txt
@@ -4,3 +4,9 @@ Technologic Systems Platforms Device Tree Bindings
TS-4800 board
Required root node properties:
- compatible = "technologic,imx51-ts4800", "fsl,imx51";
+
+TS-4900 is a System-on-Module based on the Freescale i.MX6 System-on-Chip.
+It can be mounted on a carrier board providing additional peripheral connectors.
+Required root node properties:
+ - compatible = "technologic,imx6dl-ts4900", "fsl,imx6dl"
+ - compatible = "technologic,imx6q-ts4900", "fsl,imx6q"
diff --git a/Documentation/devicetree/bindings/arm/zte.txt b/Documentation/devicetree/bindings/arm/zte.txt
index 3ff5c9e85c1c..83369785d29c 100644
--- a/Documentation/devicetree/bindings/arm/zte.txt
+++ b/Documentation/devicetree/bindings/arm/zte.txt
@@ -13,3 +13,27 @@ Low power management required properties:
Bus matrix required properties:
- compatible = "zte,zx-bus-matrix"
+
+
+---------------------------------------
+- ZX296718 SoC:
+ Required root node properties:
+ - compatible = "zte,zx296718"
+
+ZX296718 EVB board:
+ - "zte,zx296718-evb"
+
+System management required properties:
+ - compatible = "zte,zx296718-aon-sysctrl"
+ - compatible = "zte,zx296718-sysctrl"
+
+Example:
+aon_sysctrl: aon-sysctrl@116000 {
+ compatible = "zte,zx296718-aon-sysctrl", "syscon";
+ reg = <0x116000 0x1000>;
+};
+
+sysctrl: sysctrl@1463000 {
+ compatible = "zte,zx296718-sysctrl", "syscon";
+ reg = <0x1463000 0x1000>;
+};
diff --git a/Documentation/devicetree/bindings/bus/qcom,ebi2.txt b/Documentation/devicetree/bindings/bus/qcom,ebi2.txt
new file mode 100644
index 000000000000..920681f552db
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/qcom,ebi2.txt
@@ -0,0 +1,138 @@
+Qualcomm External Bus Interface 2 (EBI2)
+
+The EBI2 contains two peripheral blocks: XMEM and LCDC. The XMEM handles any
+external memory (such as NAND or other memory-mapped peripherals) whereas
+LCDC handles LCD displays.
+
+As it says it connects devices to an external bus interface, meaning address
+lines (up to 9 address lines so can only address 1KiB external memory space),
+data lines (16 bits), OE (output enable), ADV (address valid, used on some
+NOR flash memories), WE (write enable). This on top of 6 different chip selects
+(CS0 thru CS5) so that in theory 6 different devices can be connected.
+
+Apparently this bus is clocked at 64MHz. It has dedicated pins on the package
+and the bus can only come out on these pins, however if some of the pins are
+unused they can be left unconnected or remuxed to be used as GPIO or in some
+cases other orthogonal functions as well.
+
+Also CS1 and CS2 has -A and -B signals. Why they have that is unclear to me.
+
+The chip selects have the following memory range assignments. This region of
+memory is referred to as "Chip Peripheral SS FPB0" and is 168MB big.
+
+Chip Select Physical address base
+CS0 GPIO134 0x1a800000-0x1b000000 (8MB)
+CS1 GPIO39 (A) / GPIO123 (B) 0x1b000000-0x1b800000 (8MB)
+CS2 GPIO40 (A) / GPIO124 (B) 0x1b800000-0x1c000000 (8MB)
+CS3 GPIO133 0x1d000000-0x25000000 (128 MB)
+CS4 GPIO132 0x1c800000-0x1d000000 (8MB)
+CS5 GPIO131 0x1c000000-0x1c800000 (8MB)
+
+The APQ8060 Qualcomm Application Processor User Guide, 80-N7150-14 Rev. A,
+August 6, 2012 contains some incomplete documentation of the EBI2.
+
+FIXME: the manual mentions "write precharge cycles" and "precharge cycles".
+We have not been able to figure out which bit fields these correspond to
+in the hardware, or what valid values exist. The current hypothesis is that
+this is something just used on the FAST chip selects and that the SLOW
+chip selects are understood fully. There is also a "byte device enable"
+flag somewhere for 8bit memories.
+
+FIXME: The chipselects have SLOW and FAST configuration registers. It's a bit
+unclear what this means, if they are mutually exclusive or can be used
+together, or if some chip selects are hardwired to be FAST and others are SLOW
+by design.
+
+The XMEM registers are totally undocumented but could be partially decoded
+because the Cypress AN49576 Antioch Westbridge apparently has suspiciously
+similar register layout, see: http://www.cypress.com/file/105771/download
+
+Required properties:
+- compatible: should be one of:
+ "qcom,msm8660-ebi2"
+ "qcom,apq8060-ebi2"
+- #address-cells: shoule be <2>: the first cell is the chipselect,
+ the second cell is the offset inside the memory range
+- #size-cells: should be <1>
+- ranges: should be set to:
+ ranges = <0 0x0 0x1a800000 0x00800000>,
+ <1 0x0 0x1b000000 0x00800000>,
+ <2 0x0 0x1b800000 0x00800000>,
+ <3 0x0 0x1d000000 0x08000000>,
+ <4 0x0 0x1c800000 0x00800000>,
+ <5 0x0 0x1c000000 0x00800000>;
+- reg: two ranges of registers: EBI2 config and XMEM config areas
+- reg-names: should be "ebi2", "xmem"
+- clocks: two clocks, EBI_2X and EBI
+- clock-names: shoule be "ebi2x", "ebi2"
+
+Optional subnodes:
+- Nodes inside the EBI2 will be considered device nodes.
+
+The following optional properties are properties that can be tagged onto
+any device subnode. We are assuming that there can be only ONE device per
+chipselect subnode, else the properties will become ambigous.
+
+Optional properties arrays for SLOW chip selects:
+- qcom,xmem-recovery-cycles: recovery cycles is the time the memory continues to
+ drive the data bus after OE is de-asserted, in order to avoid contention on
+ the data bus. They are inserted when reading one CS and switching to another
+ CS or read followed by write on the same CS. Valid values 0 thru 15. Minimum
+ value is actually 1, so a value of 0 will still yield 1 recovery cycle.
+- qcom,xmem-write-hold-cycles: write hold cycles, these are extra cycles
+ inserted after every write minimum 1. The data out is driven from the time
+ WE is asserted until CS is asserted. With a hold of 1 (value = 0), the CS
+ stays active for 1 extra cycle etc. Valid values 0 thru 15.
+- qcom,xmem-write-delta-cycles: initial latency for write cycles inserted for
+ the first write to a page or burst memory. Valid values 0 thru 255.
+- qcom,xmem-read-delta-cycles: initial latency for read cycles inserted for the
+ first read to a page or burst memory. Valid values 0 thru 255.
+- qcom,xmem-write-wait-cycles: number of wait cycles for every write access, 0=1
+ cycle. Valid values 0 thru 15.
+- qcom,xmem-read-wait-cycles: number of wait cycles for every read access, 0=1
+ cycle. Valid values 0 thru 15.
+
+Optional properties arrays for FAST chip selects:
+- qcom,xmem-address-hold-enable: this is a boolean property stating that we
+ shall hold the address for an extra cycle to meet hold time requirements
+ with ADV assertion.
+- qcom,xmem-adv-to-oe-recovery-cycles: the number of cycles elapsed before an OE
+ assertion, with respect to the cycle where ADV (address valid) is asserted.
+ 2 means 2 cycles between ADV and OE. Valid values 0, 1, 2 or 3.
+- qcom,xmem-read-hold-cycles: the length in cycles of the first segment of a
+ read transfer. For a single read trandfer this will be the time from CS
+ assertion to OE assertion. Valid values 0 thru 15.
+
+
+Example:
+
+ebi2@1a100000 {
+ compatible = "qcom,apq8060-ebi2";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x1a800000 0x00800000>,
+ <1 0x0 0x1b000000 0x00800000>,
+ <2 0x0 0x1b800000 0x00800000>,
+ <3 0x0 0x1d000000 0x08000000>,
+ <4 0x0 0x1c800000 0x00800000>,
+ <5 0x0 0x1c000000 0x00800000>;
+ reg = <0x1a100000 0x1000>, <0x1a110000 0x1000>;
+ reg-names = "ebi2", "xmem";
+ clocks = <&gcc EBI2_2X_CLK>, <&gcc EBI2_CLK>;
+ clock-names = "ebi2x", "ebi2";
+ /* Make sure to set up the pin control for the EBI2 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&foo_ebi2_pins>;
+
+ foo-ebi2@2,0 {
+ compatible = "foo";
+ reg = <2 0x0 0x100>;
+ (...)
+ qcom,xmem-recovery-cycles = <0>;
+ qcom,xmem-write-hold-cycles = <3>;
+ qcom,xmem-write-delta-cycles = <31>;
+ qcom,xmem-read-delta-cycles = <28>;
+ qcom,xmem-write-wait-cycles = <9>;
+ qcom,xmem-read-wait-cycles = <9>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
index 670c2af3e931..eb985a633d59 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
@@ -52,6 +52,7 @@ 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,mv88f5181-core-clock" - for Orion MV88F5181 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
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 869a2f0e2ff6..3cf44217068e 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -23,6 +23,11 @@ Required properties :
Optional properties :
- #power-domain-cells : shall contain 1
+- Qualcomm TSENS (thermal sensor device) on some devices can
+be part of GCC and hence the TSENS properties can also be
+part of the GCC/clock-controller node.
+For more details on the TSENS properties please refer
+Documentation/devicetree/bindings/thermal/qcom-tsens.txt
Example:
clock-controller@900000 {
@@ -32,3 +37,14 @@ Example:
#reset-cells = <1>;
#power-domain-cells = <1>;
};
+
+Example of GCC with TSENS properties:
+ clock-controller@900000 {
+ compatible = "qcom,gcc-apq8064";
+ reg = <0x00900000 0x4000>;
+ nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #thermal-sensor-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
index fee3205cdff9..c209de6cfadb 100644
--- a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
+++ b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
@@ -1,16 +1,16 @@
STMicroelectronics STM32 Reset and Clock Controller
===================================================
-The RCC IP is both a reset and a clock controller. This documentation only
-describes the clock part.
+The RCC IP is both a reset and a clock controller.
-Please also refer to clock-bindings.txt in this directory for common clock
-controller binding usage.
+Please refer to clock-bindings.txt for common clock controller binding usage.
+Please also refer to reset.txt for common reset controller binding usage.
Required properties:
- compatible: Should be "st,stm32f42xx-rcc"
- reg: should be register base and length as documented in the
datasheet
+- #reset-cells: 1, see below
- #clock-cells: 2, device nodes should specify the clock in their "clocks"
property, containing a phandle to the clock device node, an index selecting
between gated clocks and other clocks and an index specifying the clock to
@@ -19,6 +19,7 @@ Required properties:
Example:
rcc: rcc@40023800 {
+ #reset-cells = <1>;
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
@@ -35,16 +36,23 @@ from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
+To simplify the usage and to share bit definition with the reset and clock
+drivers of the RCC IP, macros are available to generate the index in
+human-readble format.
+
+For STM32F4 series, the macro are available here:
+ - include/dt-bindings/mfd/stm32f4-rcc.h
+
Example:
/* Gated clock, AHB1 bit 0 (GPIOA) */
... {
- clocks = <&rcc 0 0>
+ clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>
};
/* Gated clock, AHB2 bit 4 (CRYP) */
... {
- clocks = <&rcc 0 36>
+ clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)>
};
Specifying other clocks
@@ -61,5 +69,25 @@ Example:
/* Misc clock, FCLK */
... {
- clocks = <&rcc 1 1>
+ clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)>
+ };
+
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use.
+The index is the bit number within the RCC registers bank, starting from RCC
+base address.
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register.
+For example, for CRC reset:
+ crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140
+
+example:
+
+ timer2 {
+ resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
};
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt b/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
index a2ec4c1c9382..6394ea9e3b9e 100644
--- a/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
+++ b/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
@@ -9,7 +9,7 @@ Required properties:
- reg: physical base address of the hdmi and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
-- hpd-gpio: following information about the hotplug gpio pin.
+- hpd-gpios: following information about the hotplug gpio pin.
a) phandle of the gpio controller node.
b) pin number within the gpio controller.
c) optional flags and pull up/down.
@@ -56,7 +56,7 @@ Example:
compatible = "samsung,exynos4212-hdmi";
reg = <0x14530000 0x100000>;
interrupts = <0 95 0>;
- hpd-gpio = <&gpx3 7 1>;
+ hpd-gpios = <&gpx3 7 1>;
ddc = <&hdmi_ddc_node>;
phy = <&hdmi_phy_node>;
samsung,syscon-phandle = <&pmu_system_controller>;
diff --git a/Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt b/Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt
new file mode 100644
index 000000000000..f5e3c6f2095a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt
@@ -0,0 +1,47 @@
+TPO TPG110 Panel
+================
+
+This binding builds on the DPI bindings, adding a few properties
+as a superset of a DPI. See panel-dpi.txt for the required DPI
+bindings.
+
+Required properties:
+- compatible : "tpo,tpg110"
+- grestb-gpios : panel reset GPIO
+- scen-gpios : serial control enable GPIO
+- scl-gpios : serial control clock line GPIO
+- sda-gpios : serial control data line GPIO
+
+Required nodes:
+- Video port for DPI input, see panel-dpi.txt
+- Panel timing for DPI setup, see panel-dpi.txt
+
+Example
+-------
+
+panel {
+ compatible = "tpo,tpg110", "panel-dpi";
+ grestb-gpios = <&stmpe_gpio44 5 GPIO_ACTIVE_LOW>;
+ scen-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+ scl-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+ backlight = <&bl>;
+
+ port {
+ nomadik_clcd_panel: endpoint {
+ remote-endpoint = <&nomadik_clcd_pads>;
+ };
+ };
+
+ panel-timing {
+ clock-frequency = <33200000>;
+ hactive = <800>;
+ hback-porch = <216>;
+ hfront-porch = <40>;
+ hsync-len = <1>;
+ vactive = <480>;
+ vback-porch = <35>;
+ vfront-porch = <10>;
+ vsync-len = <1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
index 175f0e44ed85..3c9a57a8443b 100644
--- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
@@ -8,6 +8,7 @@ Required properties:
"fsl,imx51-sdma"
"fsl,imx53-sdma"
"fsl,imx6q-sdma"
+ "fsl,imx7d-sdma"
The -to variants should be preferred since they allow to determine the
correct ROM script addresses needed for the driver to work without additional
firmware.
diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
index 5b902ac8d97e..5f2ce669789a 100644
--- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
+++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
@@ -1,4 +1,4 @@
-* Renesas R-Car DMA Controller Device Tree bindings
+* Renesas R-Car (RZ/G) DMA Controller Device Tree bindings
Renesas R-Car Generation 2 SoCs have multiple multi-channel DMA
controller instances named DMAC capable of serving multiple clients. Channels
@@ -16,6 +16,8 @@ Required Properties:
- compatible: "renesas,dmac-<soctype>", "renesas,rcar-dmac" as fallback.
Examples with soctypes are:
+ - "renesas,dmac-r8a7743" (RZ/G1M)
+ - "renesas,dmac-r8a7745" (RZ/G1E)
- "renesas,dmac-r8a7790" (R-Car H2)
- "renesas,dmac-r8a7791" (R-Car M2-W)
- "renesas,dmac-r8a7792" (R-Car V2H)
diff --git a/Documentation/devicetree/bindings/dma/sun6i-dma.txt b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
index d13c136cef8c..6b267045f522 100644
--- a/Documentation/devicetree/bindings/dma/sun6i-dma.txt
+++ b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
@@ -7,6 +7,7 @@ Required properties:
- compatible: Must be one of
"allwinner,sun6i-a31-dma"
"allwinner,sun8i-a23-dma"
+ "allwinner,sun8i-a83t-dma"
"allwinner,sun8i-h3-dma"
- reg: Should contain the registers base address and length
- interrupts: Should contain a reference to the interrupt used by this device
diff --git a/Documentation/devicetree/bindings/firmware/meson/meson_sm.txt b/Documentation/devicetree/bindings/firmware/meson/meson_sm.txt
new file mode 100644
index 000000000000..c248cd44f727
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/meson/meson_sm.txt
@@ -0,0 +1,15 @@
+* Amlogic Secure Monitor
+
+In the Amlogic SoCs the Secure Monitor code is used to provide access to the
+NVMEM, enable JTAG, set USB boot, etc...
+
+Required properties for the secure monitor node:
+- compatible: Should be "amlogic,meson-gxbb-sm"
+
+Example:
+
+ firmware {
+ sm: secure-monitor {
+ compatible = "amlogic,meson-gxbb-sm";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt
index 71191ff0e781..248a155414c2 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt
@@ -44,8 +44,7 @@ Required properties:
- our-claim-gpio: The GPIO that we use to claim the bus.
- their-claim-gpios: The GPIOs that the other sides use to claim the bus.
Note that some implementations may only support a single other master.
-- Standard I2C mux properties. See i2c-mux.txt in this directory.
-- Single I2C child bus node at reg 0. See i2c-mux.txt in this directory.
+- I2C arbitration bus node. See i2c-arb.txt in this directory.
Optional properties:
- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us.
@@ -63,8 +62,6 @@ Example:
i2c-arbitrator {
compatible = "i2c-arb-gpio-challenge";
- #address-cells = <1>;
- #size-cells = <0>;
i2c-parent = <&{/i2c@12CA0000}>;
@@ -74,8 +71,7 @@ Example:
wait-retry-us = <3000>;
wait-free-us = <50000>;
- i2c@0 {
- reg = <0>;
+ i2c-arb {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb.txt b/Documentation/devicetree/bindings/i2c/i2c-arb.txt
new file mode 100644
index 000000000000..59abf9277bdc
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-arb.txt
@@ -0,0 +1,35 @@
+Common i2c arbitration bus properties.
+
+- i2c-arb child node
+
+Required properties for the i2c-arb child node:
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties for i2c-arb child node:
+- Child nodes conforming to i2c bus binding
+
+
+Example :
+
+ /*
+ An NXP pca9541 I2C bus master selector at address 0x74
+ with a NXP pca8574 GPIO expander attached.
+ */
+
+ arb@74 {
+ compatible = "nxp,pca9541";
+ reg = <0x74>;
+
+ i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio@38 {
+ compatible = "nxp,pca8574";
+ reg = <0x38>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-gate.txt b/Documentation/devicetree/bindings/i2c/i2c-gate.txt
new file mode 100644
index 000000000000..1846d236e656
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-gate.txt
@@ -0,0 +1,41 @@
+An i2c gate is useful to e.g. reduce the digital noise for RF tuners connected
+to the i2c bus. Gates are similar to arbitrators in that you need to perform
+some kind of operation to access the i2c bus past the arbitrator/gate, but
+there are no competing masters to consider for gates and therefore there is
+no arbitration happening for gates.
+
+Common i2c gate properties.
+
+- i2c-gate child node
+
+Required properties for the i2c-gate child node:
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties for i2c-gate child node:
+- Child nodes conforming to i2c bus binding
+
+
+Example :
+
+ /*
+ An Invensense mpu9150 at address 0x68 featuring an on-chip Asahi
+ Kasei ak8975 compass behind a gate.
+ */
+
+ mpu9150@68 {
+ compatible = "invensense,mpu9150";
+ reg = <0x68>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <18 1>;
+
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ax8975@c {
+ compatible = "ak,ak8975";
+ reg = <0x0c>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-meson.txt b/Documentation/devicetree/bindings/i2c/i2c-meson.txt
index 682f9a6f766e..386357d1aab0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-meson.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-meson.txt
@@ -1,7 +1,7 @@
Amlogic Meson I2C controller
Required properties:
- - compatible: must be "amlogic,meson6-i2c"
+ - compatible: must be "amlogic,meson6-i2c" or "amlogic,meson-gxbb-i2c"
- reg: physical address and length of the device registers
- interrupts: a single interrupt specifier
- clocks: clock for the device
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux.txt b/Documentation/devicetree/bindings/i2c/i2c-mux.txt
index af84cce5cd7b..212e6779dc5c 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux.txt
@@ -2,19 +2,32 @@ Common i2c bus multiplexer/switch properties.
An i2c bus multiplexer/switch will have several child busses that are
numbered uniquely in a device dependent manner. The nodes for an i2c bus
-multiplexer/switch will have one child node for each child
-bus.
+multiplexer/switch will have one child node for each child bus.
-Required properties:
+Optional properties:
+- #address-cells = <1>;
+ This property is required is the i2c-mux child node does not exist.
+
+- #size-cells = <0>;
+ This property is required is the i2c-mux child node does not exist.
+
+- i2c-mux
+ For i2c multiplexers/switches that have child nodes that are a mixture
+ of both i2c child busses and other child nodes, the 'i2c-mux' subnode
+ can be used for populating the i2c child busses. If an 'i2c-mux'
+ subnode is present, only subnodes of this will be considered as i2c
+ child busses.
+
+Required properties for the i2c-mux child node:
- #address-cells = <1>;
- #size-cells = <0>;
-Required properties for child nodes:
+Required properties for i2c child bus nodes:
- #address-cells = <1>;
- #size-cells = <0>;
- reg : The sub-bus number.
-Optional properties for child nodes:
+Optional properties for i2c child bus nodes:
- Other properties specific to the multiplexer/switch hardware.
- Child nodes conforming to i2c bus binding
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
index 5f0cb502b1db..239632a0d709 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
@@ -11,6 +11,7 @@ Required properties:
"renesas,i2c-r8a7793"
"renesas,i2c-r8a7794"
"renesas,i2c-r8a7795"
+ "renesas,i2c-r8a7796"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt specifier.
diff --git a/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt b/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt
new file mode 100644
index 000000000000..0fbbc6970ec5
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt
@@ -0,0 +1,29 @@
+* NXP PCA9541 I2C bus master selector
+
+Required Properties:
+
+ - compatible: Must be "nxp,pca9541"
+
+ - reg: The I2C address of the device.
+
+ The following required properties are defined externally:
+
+ - I2C arbitration bus node. See i2c-arb.txt in this directory.
+
+
+Example:
+
+ i2c-arbitrator@74 {
+ compatible = "nxp,pca9541";
+ reg = <0x74>;
+
+ i2c-arb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eeprom@54 {
+ compatible = "at,24c08";
+ reg = <0x54>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt b/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
new file mode 100644
index 000000000000..f97993be2dcb
--- /dev/null
+++ b/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
@@ -0,0 +1,107 @@
+Hisilicon RoCE DT description
+
+Hisilicon RoCE engine is a part of network subsystem.
+It works depending on other part of network wubsytem, such as, gmac and
+dsa fabric.
+
+Additional properties are described here:
+
+Required properties:
+- compatible: Should contain "hisilicon,hns-roce-v1".
+- reg: Physical base address of the RoCE driver and
+length of memory mapped region.
+- eth-handle: phandle, specifies a reference to a node
+representing a ethernet device.
+- dsaf-handle: phandle, specifies a reference to a node
+representing a dsaf device.
+- #address-cells: must be 2
+- #size-cells: must be 2
+Optional properties:
+- dma-coherent: Present if DMA operations are coherent.
+- interrupt-parent: the interrupt parent of this device.
+- interrupts: should contain 32 completion event irq,1 async event irq
+and 1 event overflow irq.
+- interrupt-names:should be one of 34 irqs for roce device
+ - hns-roce-comp-0 ~ hns-roce-comp-31: 32 complete event irq
+ - hns-roce-async: 1 async event irq
+ - hns-roce-common: named common exception warning irq
+Example:
+ infiniband@c4000000 {
+ compatible = "hisilicon,hns-roce-v1";
+ reg = <0x0 0xc4000000 0x0 0x100000>;
+ dma-coherent;
+ eth-handle = <&eth2 &eth3 &eth4 &eth5 &eth6 &eth7>;
+ dsaf-handle = <&soc0_dsa>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mbigen_dsa>;
+ interrupts = <722 1>,
+ <723 1>,
+ <724 1>,
+ <725 1>,
+ <726 1>,
+ <727 1>,
+ <728 1>,
+ <729 1>,
+ <730 1>,
+ <731 1>,
+ <732 1>,
+ <733 1>,
+ <734 1>,
+ <735 1>,
+ <736 1>,
+ <737 1>,
+ <738 1>,
+ <739 1>,
+ <740 1>,
+ <741 1>,
+ <742 1>,
+ <743 1>,
+ <744 1>,
+ <745 1>,
+ <746 1>,
+ <747 1>,
+ <748 1>,
+ <749 1>,
+ <750 1>,
+ <751 1>,
+ <752 1>,
+ <753 1>,
+ <785 1>,
+ <754 4>;
+
+ interrupt-names = "hns-roce-comp-0",
+ "hns-roce-comp-1",
+ "hns-roce-comp-2",
+ "hns-roce-comp-3",
+ "hns-roce-comp-4",
+ "hns-roce-comp-5",
+ "hns-roce-comp-6",
+ "hns-roce-comp-7",
+ "hns-roce-comp-8",
+ "hns-roce-comp-9",
+ "hns-roce-comp-10",
+ "hns-roce-comp-11",
+ "hns-roce-comp-12",
+ "hns-roce-comp-13",
+ "hns-roce-comp-14",
+ "hns-roce-comp-15",
+ "hns-roce-comp-16",
+ "hns-roce-comp-17",
+ "hns-roce-comp-18",
+ "hns-roce-comp-19",
+ "hns-roce-comp-20",
+ "hns-roce-comp-21",
+ "hns-roce-comp-22",
+ "hns-roce-comp-23",
+ "hns-roce-comp-24",
+ "hns-roce-comp-25",
+ "hns-roce-comp-26",
+ "hns-roce-comp-27",
+ "hns-roce-comp-28",
+ "hns-roce-comp-29",
+ "hns-roce-comp-30",
+ "hns-roce-comp-31",
+ "hns-roce-async",
+ "hns-roce-common";
+ };
diff --git a/Documentation/devicetree/bindings/input/adc-keys.txt b/Documentation/devicetree/bindings/input/adc-keys.txt
new file mode 100644
index 000000000000..e551814629b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/adc-keys.txt
@@ -0,0 +1,49 @@
+ADC attached resistor ladder buttons
+------------------------------------
+
+Required properties:
+ - compatible: "adc-keys"
+ - io-channels: Phandle to an ADC channel
+ - io-channel-names = "buttons";
+ - keyup-threshold-microvolt: Voltage at which all the keys are considered up.
+
+Optional properties:
+ - poll-interval: Poll interval time in milliseconds
+ - autorepeat: Boolean, Enable auto repeat feature of Linux input
+ subsystem.
+
+Each button (key) is represented as a sub-node of "adc-keys":
+
+Required subnode-properties:
+ - label: Descriptive name of the key.
+ - linux,code: Keycode to emit.
+ - press-threshold-microvolt: Voltage ADC input when this key is pressed.
+
+Example:
+
+#include <dt-bindings/input/input.h>
+
+ adc-keys {
+ compatible = "adc-keys";
+ io-channels = <&lradc 0>;
+ io-channel-names = "buttons";
+ keyup-threshold-microvolt = <2000000>;
+
+ button-up {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ press-threshold-microvolt = <1500000>;
+ };
+
+ button-down {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ press-threshold-microvolt = <1000000>;
+ };
+
+ button-enter {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ press-threshold-microvolt = <500000>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/gpio-decoder.txt b/Documentation/devicetree/bindings/input/gpio-decoder.txt
new file mode 100644
index 000000000000..14a77fb96cf0
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-decoder.txt
@@ -0,0 +1,23 @@
+* GPIO Decoder DT bindings
+
+Required Properties:
+- compatible: should be "gpio-decoder"
+- gpios: a spec of gpios (at least two) to be decoded to a number with
+ first entry representing the MSB.
+
+Optional Properties:
+- decoder-max-value: Maximum possible value that can be reported by
+ the gpios.
+- linux,axis: the input subsystem axis to map to (ABS_X/ABS_Y).
+ Defaults to 0 (ABS_X).
+
+Example:
+ gpio-decoder0 {
+ compatible = "gpio-decoder";
+ gpios = <&pca9536 3 GPIO_ACTIVE_HIGH>,
+ <&pca9536 2 GPIO_ACTIVE_HIGH>,
+ <&pca9536 1 GPIO_ACTIVE_HIGH>,
+ <&pca9536 0 GPIO_ACTIVE_HIGH>;
+ linux,axis = <0>; /* ABS_X */
+ decoder-max-value = <9>;
+ };
diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
index 95d0fb11a787..4d9a3717eaaf 100644
--- a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
+++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
@@ -34,11 +34,10 @@ Example nodes:
gpio_keys_polled {
compatible = "gpio-keys-polled";
- #address-cells = <1>;
- #size-cells = <0>;
poll-interval = <100>;
autorepeat;
- button@21 {
+
+ button21 {
label = "GPIO Key UP";
linux,code = <103>;
gpios = <&gpio1 0 1>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
index f99528da1b1d..6db22103e2dd 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
@@ -19,6 +19,7 @@ Required properties:
or: "edt,edt-ft5306"
or: "edt,edt-ft5406"
or: "edt,edt-ft5506"
+ or: "focaltech,ft6236"
- reg: I2C slave address of the chip (0x38)
- interrupt-parent: a phandle pointing to the interrupt controller
@@ -43,6 +44,13 @@ Optional properties:
- offset: allows setting the edge compensation in the range from
0 to 31.
+ - touchscreen-size-x : See touchscreen.txt
+ - touchscreen-size-y : See touchscreen.txt
+ - touchscreen-fuzz-x : See touchscreen.txt
+ - touchscreen-fuzz-y : See touchscreen.txt
+ - touchscreen-inverted-x : See touchscreen.txt
+ - touchscreen-inverted-y : See touchscreen.txt
+ - touchscreen-swapped-x-y : See touchscreen.txt
Example:
polytouch: edt-ft5x06@38 {
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt
new file mode 100644
index 000000000000..5a19f4c3e9d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt
@@ -0,0 +1,27 @@
+* Elan eKTF2127 I2C touchscreen controller
+
+Required properties:
+ - compatible : "elan,ektf2127"
+ - reg : I2C slave address of the chip (0x40)
+ - interrupt-parent : a phandle pointing to the interrupt controller
+ serving the interrupt for this chip
+ - interrupts : interrupt specification for the ektf2127 interrupt
+ - power-gpios : GPIO specification for the pin connected to the
+ ektf2127's wake input. This needs to be driven high
+ to take ektf2127 out of it's low power state
+
+For additional optional properties see: touchscreen.txt
+
+Example:
+
+i2c@00000000 {
+ ektf2127: touchscreen@15 {
+ compatible = "elan,ektf2127";
+ reg = <0x15>;
+ interrupt-parent = <&pio>;
+ interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>
+ power-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>;
+ touchscreen-inverted-x;
+ touchscreen-swapped-x-y;
+ };
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt
deleted file mode 100644
index 777521da3da5..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-* FocalTech FT6236 I2C touchscreen controller
-
-Required properties:
- - compatible : "focaltech,ft6236"
- - reg : I2C slave address of the chip (0x38)
- - interrupt-parent : a phandle pointing to the interrupt controller
- serving the interrupt for this chip
- - interrupts : interrupt specification for the touch controller
- interrupt
- - reset-gpios : GPIO specification for the RSTN input
- - touchscreen-size-x : horizontal resolution of touchscreen (in pixels)
- - touchscreen-size-y : vertical resolution of touchscreen (in pixels)
-
-Optional properties:
- - touchscreen-fuzz-x : horizontal noise value of the absolute input
- device (in pixels)
- - touchscreen-fuzz-y : vertical noise value of the absolute input
- device (in pixels)
- - touchscreen-inverted-x : X axis is inverted (boolean)
- - touchscreen-inverted-y : Y axis is inverted (boolean)
- - touchscreen-swapped-x-y: X and Y axis are swapped (boolean)
- Swapping is done after inverting the axis
-
-Example:
-
- ft6x06@38 {
- compatible = "focaltech,ft6236";
- reg = <0x38>;
- interrupt-parent = <&gpio>;
- interrupts = <23 2>;
- touchscreen-size-x = <320>;
- touchscreen-size-y = <480>;
- touchscreen-inverted-x;
- touchscreen-swapped-x-y;
- };
diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt
index e30e0b93f2b3..3e5b9793341f 100644
--- a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt
+++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt
@@ -1,13 +1,24 @@
-Texas Instruments TPS65218 power button
+Texas Instruments TPS65217 and TPS65218 power button
+
+This module is part of the TPS65217/TPS65218. For more details about the whole
+TPS65217 chip see Documentation/devicetree/bindings/regulator/tps65217.txt.
This driver provides a simple power button event via an Interrupt.
Required properties:
-- compatible: should be "ti,tps65218-pwrbutton"
+- compatible: should be "ti,tps65217-pwrbutton" or "ti,tps65218-pwrbutton"
+
+Required properties for TPS65218:
- interrupts: should be one of the following
- <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218
-Example:
+Examples:
+
+&tps {
+ tps65217-pwrbutton {
+ compatible = "ti,tps65217-pwrbutton";
+ };
+};
&tps {
power-button {
diff --git a/Documentation/devicetree/bindings/mailbox/meson-mhu.txt b/Documentation/devicetree/bindings/mailbox/meson-mhu.txt
new file mode 100644
index 000000000000..a530310772b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/meson-mhu.txt
@@ -0,0 +1,34 @@
+Amlogic Meson MHU Mailbox Driver
+================================
+
+The Amlogic's Meson SoCs Message-Handling-Unit (MHU) is a mailbox controller
+that has 3 independent channels/links to communicate with remote processor(s).
+MHU links are hardwired on a platform. A link raises interrupt for any
+received data. However, there is no specified way of knowing if the sent
+data has been read by the remote. This driver assumes the sender polls
+STAT register and the remote clears it after having read the data.
+
+Mailbox Device Node:
+====================
+
+Required properties:
+--------------------
+- compatible: Shall be "amlogic,meson-gxbb-mhu"
+- reg: Contains the mailbox register address range (base
+ address and length)
+- #mbox-cells Shall be 1 - the index of the channel needed.
+- interrupts: Contains the interrupt information corresponding to
+ each of the 2 links of MHU.
+
+Example:
+--------
+
+ mailbox: mailbox@c883c404 {
+ #mbox-cells = <1>;
+ compatible = "amlogic,meson-gxbb-mhu";
+ reg = <0 0xc883c404 0 0x4c>;
+ interrupts = <0 208 IRQ_TYPE_EDGE_RISING>,
+ <0 209 IRQ_TYPE_EDGE_RISING>,
+ <0 210 IRQ_TYPE_EDGE_RISING>;
+ #mbox-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/media/meson-ir.txt b/Documentation/devicetree/bindings/media/meson-ir.txt
index 407848e85f31..e7e3f3c4fc8f 100644
--- a/Documentation/devicetree/bindings/media/meson-ir.txt
+++ b/Documentation/devicetree/bindings/media/meson-ir.txt
@@ -1,7 +1,10 @@
* Amlogic Meson IR remote control receiver
Required properties:
- - compatible : should be "amlogic,meson6-ir"
+ - compatible : depending on the platform this should be one of:
+ - "amlogic,meson6-ir"
+ - "amlogic,meson8b-ir"
+ - "amlogic,meson-gxbb-ir"
- reg : physical base address and length of the device registers
- interrupts : a single specifier for the interrupt from the device
diff --git a/Documentation/devicetree/bindings/mfd/ac100.txt b/Documentation/devicetree/bindings/mfd/ac100.txt
new file mode 100644
index 000000000000..b8ef00667599
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/ac100.txt
@@ -0,0 +1,54 @@
+X-Powers AC100 Codec/RTC IC Device Tree bindings
+
+AC100 is a audio codec and RTC subsystem combo IC. The 2 parts are
+separated, including power supplies and interrupt lines, but share
+a common register address space and host interface.
+
+Required properties:
+- compatible: "x-powers,ac100"
+- reg: The I2C slave address or RSB hardware address for the chip
+- sub-nodes:
+ - codec
+ - compatible: "x-powers,ac100-codec"
+ - interrupt-parent: The parent interrupt controller
+ - interrupts: SoC NMI / GPIO interrupt connected to the
+ IRQ_AUDIO pin
+ - #clock-cells: Shall be 0
+ - clock-output-names: "4M_adda"
+
+ - see clock/clock-bindings.txt for common clock bindings
+
+ - rtc
+ - compatible: "x-powers,ac100-rtc"
+ - interrupt-parent: The parent interrupt controller
+ - interrupts: SoC NMI / GPIO interrupt connected to the
+ IRQ_RTC pin
+ - clocks: A phandle to the codec's "4M_adda" clock
+ - #clock-cells: Shall be 1
+ - clock-output-names: "cko1_rtc", "cko2_rtc", "cko3_rtc"
+
+ - see clock/clock-bindings.txt for common clock bindings
+
+Example:
+
+ac100: codec@e89 {
+ compatible = "x-powers,ac100";
+ reg = <0xe89>;
+
+ ac100_codec: codec {
+ compatible = "x-powers,ac100-codec";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+ #clock-cells = <0>;
+ clock-output-names = "4M_adda";
+ };
+
+ ac100_rtc: rtc {
+ compatible = "x-powers,ac100-rtc";
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&ac100_codec>;
+ #clock-cells = <1>;
+ clock-output-names = "cko1_rtc", "cko2_rtc", "cko3_rtc";
+ };
+};
diff --git a/Documentation/devicetree/bindings/mfd/act8945a.txt b/Documentation/devicetree/bindings/mfd/act8945a.txt
index f71283055685..462819ac3da8 100644
--- a/Documentation/devicetree/bindings/mfd/act8945a.txt
+++ b/Documentation/devicetree/bindings/mfd/act8945a.txt
@@ -14,13 +14,6 @@ Example:
reg = <0x5b>;
status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_charger_chglev>;
- active-semi,chglev-gpio = <&pioA 12 GPIO_ACTIVE_HIGH>;
- active-semi,input-voltage-threshold-microvolt = <6600>;
- active-semi,precondition-timeout = <40>;
- active-semi,total-timeout = <3>;
-
active-semi,vsel-high;
regulators {
@@ -73,4 +66,19 @@ Example:
regulator-always-on;
};
};
+
+ charger {
+ compatible = "active-semi,act8945a-charger";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>;
+ interrupt-parent = <&pioA>;
+ interrupts = <45 GPIO_ACTIVE_LOW>;
+
+ active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>;
+ active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>;
+ active-semi,input-voltage-threshold-microvolt = <6600>;
+ active-semi,precondition-timeout = <40>;
+ active-semi,total-timeout = <3>;
+ status = "okay";
+ };
};
diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt
index a6e2ea41160c..8f2e2822238d 100644
--- a/Documentation/devicetree/bindings/mfd/arizona.txt
+++ b/Documentation/devicetree/bindings/mfd/arizona.txt
@@ -85,6 +85,24 @@ Optional properties:
present, the number of values should be less than or equal to the
number of inputs, unspecified inputs will use the chip default.
+ - wlf,max-channels-clocked : The maximum number of channels to be clocked on
+ each AIF, useful for I2S systems with multiple data lines being mastered.
+ Specify one cell for each AIF to be configured, specify zero for AIFs that
+ should be handled normally.
+ If present, number of cells must be less than or equal to the number of
+ AIFs. If less than the number of AIFs, for cells that have not been
+ specified the corresponding AIFs will be treated as default setting.
+
+ - wlf,spk-fmt : PDM speaker data format, must contain 2 cells (OUT5 and OUT6).
+ See the datasheet for values.
+ The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
+ wm8998, wm1814)
+
+ - wlf,spk-mute : PDM speaker mute setting, must contain 2 cells (OUT5 and OUT6).
+ See the datasheet for values.
+ The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
+ wm8998, wm1814)
+
- DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if
they are being externally supplied. As covered in
Documentation/devicetree/bindings/regulator/regulator.txt
diff --git a/Documentation/devicetree/bindings/mfd/aspeed-scu.txt b/Documentation/devicetree/bindings/mfd/aspeed-scu.txt
new file mode 100644
index 000000000000..4fc5b83726d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/aspeed-scu.txt
@@ -0,0 +1,18 @@
+The Aspeed System Control Unit manages the global behaviour of the SoC,
+configuring elements such as clocks, pinmux, and reset.
+
+Required properties:
+- compatible: One of:
+ "aspeed,ast2400-scu", "syscon", "simple-mfd"
+ "aspeed,g4-scu", "syscon", "simple-mfd"
+ "aspeed,ast2500-scu", "syscon", "simple-mfd"
+ "aspeed,g5-scu", "syscon", "simple-mfd"
+
+- reg: contains the offset and length of the SCU memory region
+
+Example:
+
+syscon: syscon@1e6e2000 {
+ compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
+ reg = <0x1e6e2000 0x1a8>;
+};
diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt
index 585a95546288..8f3ad9ab4637 100644
--- a/Documentation/devicetree/bindings/mfd/axp20x.txt
+++ b/Documentation/devicetree/bindings/mfd/axp20x.txt
@@ -10,7 +10,8 @@ axp809 (X-Powers)
Required properties:
- compatible: "x-powers,axp152", "x-powers,axp202", "x-powers,axp209",
- "x-powers,axp221", "x-powers,axp223", "x-powers,axp809"
+ "x-powers,axp221", "x-powers,axp223", "x-powers,axp806",
+ "x-powers,axp809"
- reg: The I2C slave address or RSB hardware address for the AXP chip
- interrupt-parent: The parent interrupt controller
- interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin
@@ -47,7 +48,6 @@ Optional properties for DCDC regulators:
probably makes sense for HiFi audio related
applications that aren't battery constrained.
-
AXP202/AXP209 regulators, type, and corresponding input supply names:
Regulator Type Supply Name Notes
@@ -86,6 +86,30 @@ LDO_IO1 : LDO : ips-supply : GPIO 1
RTC_LDO : LDO : ips-supply : always on
DRIVEVBUS : Enable output : drivevbus-supply : external regulator
+AXP806 regulators, type, and corresponding input supply names:
+
+Regulator Type Supply Name Notes
+--------- ---- ----------- -----
+DCDCA : DC-DC buck : vina-supply : poly-phase capable
+DCDCB : DC-DC buck : vinb-supply : poly-phase capable
+DCDCC : DC-DC buck : vinc-supply : poly-phase capable
+DCDCD : DC-DC buck : vind-supply : poly-phase capable
+DCDCE : DC-DC buck : vine-supply : poly-phase capable
+ALDO1 : LDO : aldoin-supply : shared supply
+ALDO2 : LDO : aldoin-supply : shared supply
+ALDO3 : LDO : aldoin-supply : shared supply
+BLDO1 : LDO : bldoin-supply : shared supply
+BLDO2 : LDO : bldoin-supply : shared supply
+BLDO3 : LDO : bldoin-supply : shared supply
+BLDO4 : LDO : bldoin-supply : shared supply
+CLDO1 : LDO : cldoin-supply : shared supply
+CLDO2 : LDO : cldoin-supply : shared supply
+CLDO3 : LDO : cldoin-supply : shared supply
+SW : On/Off Switch : swin-supply
+
+Additionally, the AXP806 DC-DC regulators support poly-phase arrangements
+for higher output current. The possible groupings are: A+B, A+B+C, D+E.
+
AXP809 regulators, type, and corresponding input supply names:
Regulator Type Supply Name Notes
diff --git a/Documentation/devicetree/bindings/mfd/lp873x.txt b/Documentation/devicetree/bindings/mfd/lp873x.txt
new file mode 100644
index 000000000000..52766c2035f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/lp873x.txt
@@ -0,0 +1,59 @@
+TI LP873X PMIC MFD driver
+
+Required properties:
+ - compatible: "ti,lp8732", "ti,lp8733"
+ - reg: I2C slave address.
+ - gpio-controller: Marks the device node as a GPIO Controller.
+ - #gpio-cells: Should be two. The first cell is the pin number and
+ the second cell is used to specify flags.
+ See ../gpio/gpio.txt for more information.
+ - regulators: List of child nodes that specify the regulator
+ initialization data.
+Example:
+
+pmic: lp8733@60 {
+ compatible = "ti,lp8733";
+ reg = <0x60>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ regulators {
+ lp8733_buck0: buck0 {
+ regulator-name = "lp8733-buck0";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-min-microamp = <1500000>;
+ regulator-max-microamp = <4000000>;
+ regulator-ramp-delay = <10000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ lp8733_buck1: buck1 {
+ regulator-name = "lp8733-buck1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-min-microamp = <1500000>;
+ regulator-max-microamp = <4000000>;
+ regulator-ramp-delay = <10000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ lp8733_ldo0: ldo0 {
+ regulator-name = "lp8733-ldo0";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ lp8733_ldo1: ldo1 {
+ regulator-name = "lp8733-ldo1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt
index f24f33409164..37a088f9a648 100644
--- a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt
+++ b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt
@@ -62,6 +62,7 @@ The below bindings specify the set of valid subnodes.
"qcom,pm8058-rtc"
"qcom,pm8921-rtc"
"qcom,pm8941-rtc"
+ "qcom,pm8018-rtc"
- reg:
Usage: required
diff --git a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt
index b98b291a31ba..485bc59fcc48 100644
--- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt
+++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt
@@ -13,6 +13,7 @@ frequencies.
"qcom,rpm-msm8660"
"qcom,rpm-msm8960"
"qcom,rpm-ipq8064"
+ "qcom,rpm-mdm9615"
- reg:
Usage: required
@@ -59,6 +60,7 @@ Regulator nodes are identified by their compatible:
"qcom,rpm-pm8058-regulators"
"qcom,rpm-pm8901-regulators"
"qcom,rpm-pm8921-regulators"
+ "qcom,rpm-pm8018-regulators"
- vdd_l0_l1_lvs-supply:
- vdd_l2_l11_l12-supply:
@@ -137,6 +139,15 @@ Regulator nodes are identified by their compatible:
Definition: reference to regulator supplying the input pin, as
described in the data sheet
+- vin_lvs1-supply:
+- vdd_l7-supply:
+- vdd_l8-supply:
+- vdd_l9_l10_l11_l12-supply:
+ Usage: optional (pm8018 only)
+ Value type: <phandle>
+ Definition: reference to regulator supplying the input pin, as
+ described in the data sheet
+
The regulator node houses sub-nodes for each regulator within the device. Each
sub-node is identified using the node's name, with valid values listed for each
of the pmics below.
@@ -156,6 +167,10 @@ pm8921:
l29, lvs1, lvs2, lvs3, lvs4, lvs5, lvs6, lvs7, usb-switch, hdmi-switch,
ncp
+pm8018:
+ s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
+ l12, l14, lvs1
+
The content of each sub-node is defined by the standard binding for regulators -
see regulator.txt - with additional custom properties described below:
diff --git a/Documentation/devicetree/bindings/mfd/rk808.txt b/Documentation/devicetree/bindings/mfd/rk808.txt
index 4ca6aab4273a..9636ae8d8d41 100644
--- a/Documentation/devicetree/bindings/mfd/rk808.txt
+++ b/Documentation/devicetree/bindings/mfd/rk808.txt
@@ -1,7 +1,11 @@
-RK808 Power Management Integrated Circuit
+RK8XX Power Management Integrated Circuit
+
+The rk8xx family current members:
+rk808
+rk818
Required properties:
-- compatible: "rockchip,rk808"
+- compatible: "rockchip,rk808", "rockchip,rk818"
- reg: I2C slave address
- interrupt-parent: The parent interrupt controller.
- interrupts: the interrupt outputs of the controller.
@@ -13,6 +17,8 @@ Optional properties:
default output clock name
- rockchip,system-power-controller: Telling whether or not this pmic is controlling
the system power.
+
+Optional RK808 properties:
- vcc1-supply: The input supply for DCDC_REG1
- vcc2-supply: The input supply for DCDC_REG2
- vcc3-supply: The input supply for DCDC_REG3
@@ -29,7 +35,20 @@ Optional properties:
the gpio controller. If DVS GPIOs aren't present, voltage changes will happen
very quickly with no slow ramp time.
-Regulators: All the regulators of RK808 to be instantiated shall be
+Optional RK818 properties:
+- vcc1-supply: The input supply for DCDC_REG1
+- vcc2-supply: The input supply for DCDC_REG2
+- vcc3-supply: The input supply for DCDC_REG3
+- vcc4-supply: The input supply for DCDC_REG4
+- boost-supply: The input supply for DCDC_BOOST
+- vcc6-supply: The input supply for LDO_REG1 and LDO_REG2
+- vcc7-supply: The input supply for LDO_REG3, LDO_REG5 and LDO_REG7
+- vcc8-supply: The input supply for LDO_REG4, LDO_REG6 and LDO_REG8
+- vcc9-supply: The input supply for LDO_REG9 and SWITCH_REG
+- h_5v-supply: The input supply for HDMI_SWITCH
+- usb-supply: The input supply for OTG_SWITCH
+
+Regulators: All the regulators of RK8XX to be instantiated shall be
listed in a child node named 'regulators'. Each regulator is represented
by a child node of the 'regulators' node.
@@ -48,6 +67,18 @@ number as described in RK808 datasheet.
- SWITCH_REGn
- valid values for n are 1 to 2
+Following regulators of the RK818 PMIC block are supported. Note that
+the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO
+number as described in RK818 datasheet.
+
+ - DCDC_REGn
+ - valid values for n are 1 to 4.
+ - LDO_REGn
+ - valid values for n are 1 to 9.
+ - SWITCH_REG
+ - HDMI_SWITCH
+ - OTG_SWITCH
+
Standard regulator bindings are used inside regulator subnodes. Check
Documentation/devicetree/bindings/regulator/regulator.txt
for more details
diff --git a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt
new file mode 100644
index 000000000000..c110e118b79f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt
@@ -0,0 +1,70 @@
+Samsung Exynos SoC Low Power Audio Subsystem (LPASS)
+
+Required properties:
+
+ - compatible : "samsung,exynos5433-lpass"
+ - reg : should contain the LPASS top SFR region location
+ and size
+ - samsung,pmu-syscon : the phandle to the Power Management Unit node
+ - #address-cells : should be 1
+ - #size-cells : should be 1
+ - ranges : must be present
+
+Each IP block of the Low Power Audio Subsystem should be specified as
+an optional sub-node. For "samsung,exynos5433-lpass" compatible this includes:
+UART, SLIMBUS, PCM, I2S, DMAC, Timers 0...4, VIC, WDT 0...1 devices.
+
+Bindings of the sub-nodes are described in:
+ ../serial/samsung_uart.txt
+ ../sound/samsung-i2s.txt
+ ../dma/arm-pl330.txt
+
+
+Example:
+
+audio-subsystem {
+ compatible = "samsung,exynos5433-lpass";
+ reg = <0x11400000 0x100>, <0x11500000 0x08>;
+ samsung,pmu-syscon = <&pmu_system_controller>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ adma: adma@11420000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x11420000 0x1000>;
+ interrupts = <0 73 0>;
+ clocks = <&cmu_aud CLK_ACLK_DMAC>;
+ clock-names = "apb_pclk";
+ #dma-cells = <1>;
+ #dma-channels = <8>;
+ #dma-requests = <32>;
+ };
+
+ i2s0: i2s0@11440000 {
+ compatible = "samsung,exynos7-i2s";
+ reg = <0x11440000 0x100>;
+ dmas = <&adma 0 &adma 2>;
+ dma-names = "tx", "rx";
+ interrupts = <0 70 0>;
+ clocks = <&cmu_aud CLK_PCLK_AUD_I2S>,
+ <&cmu_aud CLK_SCLK_AUD_I2S>,
+ <&cmu_aud CLK_SCLK_I2S_BCLK>;
+ clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_bus>;
+ status = "disabled";
+ };
+
+ serial_3: serial@11460000 {
+ compatible = "samsung,exynos5433-uart";
+ reg = <0x11460000 0x100>;
+ interrupts = <0 67 0>;
+ clocks = <&cmu_aud CLK_PCLK_AUD_UART>,
+ <&cmu_aud CLK_SCLK_AUD_UART>;
+ clock-names = "uart", "clk_uart_baud0";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_aud_bus>;
+ status = "disabled";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt
index e6afdfa3543d..9a98ee7c323d 100644
--- a/Documentation/devicetree/bindings/mfd/twl6040.txt
+++ b/Documentation/devicetree/bindings/mfd/twl6040.txt
@@ -12,6 +12,7 @@ Required properties:
- interrupt-parent: The parent interrupt controller
- gpio-controller:
- #gpio-cells = <1>: twl6040 provides GPO lines.
+- #clock-cells = <0>; twl6040 is a provider of pdmclk which is used by McPDM
- twl6040,audpwron-gpio: Power on GPIO line for the twl6040
- vio-supply: Regulator for the twl6040 VIO supply
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
index 3733300de8dd..b05601600083 100644
--- a/Documentation/devicetree/bindings/mtd/nand.txt
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -35,6 +35,15 @@ Optional NAND chip properties:
- nand-ecc-step-size: integer representing the number of data bytes
that are covered by a single ECC step.
+- nand-ecc-maximize: boolean used to specify that you want to maximize ECC
+ strength. The maximum ECC strength is both controller and
+ chip dependent. The controller side has to select the ECC
+ config providing the best strength and taking the OOB area
+ size constraint into account.
+ This is particularly useful when only the in-band area is
+ used by the upper layers, and you want to make your NAND
+ as reliable as possible.
+
The ECC strength and ECC step size properties define the correction capability
of a controller. Together, they say a controller can correct "{strength} bit
errors per {size} bytes".
diff --git a/Documentation/devicetree/bindings/net/brcm,amac.txt b/Documentation/devicetree/bindings/net/brcm,amac.txt
new file mode 100644
index 000000000000..ba5ecc1041a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,amac.txt
@@ -0,0 +1,24 @@
+Broadcom AMAC Ethernet Controller Device Tree Bindings
+-------------------------------------------------------------
+
+Required properties:
+ - compatible: "brcm,amac" or "brcm,nsp-amac"
+ - reg: Address and length of the GMAC registers,
+ Address and length of the GMAC IDM registers
+ - reg-names: Names of the registers. Must have both "amac_base" and
+ "idm_base"
+ - interrupts: Interrupt number
+
+Optional properties:
+- mac-address: See ethernet.txt file in the same directory
+
+Examples:
+
+amac0: ethernet@18022000 {
+ compatible = "brcm,nsp-amac";
+ reg = <0x18022000 0x1000>,
+ <0x18110000 0x1000>;
+ reg-names = "amac_base", "idm_base";
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt b/Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt
new file mode 100644
index 000000000000..022946caa7e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,bgmac-nsp.txt
@@ -0,0 +1,24 @@
+Broadcom GMAC Ethernet Controller Device Tree Bindings
+-------------------------------------------------------------
+
+Required properties:
+ - compatible: "brcm,bgmac-nsp"
+ - reg: Address and length of the GMAC registers,
+ Address and length of the GMAC IDM registers
+ - reg-names: Names of the registers. Must have both "gmac_base" and
+ "idm_base"
+ - interrupts: Interrupt number
+
+Optional properties:
+- mac-address: See ethernet.txt file in the same directory
+
+Examples:
+
+gmac0: ethernet@18022000 {
+ compatible = "brcm,bgmac-nsp";
+ reg = <0x18022000 0x1000>,
+ <0x18110000 0x1000>;
+ reg-names = "gmac_base", "idm_base";
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/net/meson-dwmac.txt b/Documentation/devicetree/bindings/net/meson-dwmac.txt
index ec633d74a8a8..89e62ddc69ca 100644
--- a/Documentation/devicetree/bindings/net/meson-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/meson-dwmac.txt
@@ -1,18 +1,32 @@
* Amlogic Meson DWMAC Ethernet controller
The device inherits all the properties of the dwmac/stmmac devices
-described in the file net/stmmac.txt with the following changes.
+described in the file stmmac.txt in the current directory with the
+following changes.
-Required properties:
+Required properties on all platforms:
-- compatible: should be "amlogic,meson6-dwmac" along with "snps,dwmac"
- and any applicable more detailed version number
- described in net/stmmac.txt
+- compatible: Depending on the platform this should be one of:
+ - "amlogic,meson6-dwmac"
+ - "amlogic,meson8b-dwmac"
+ - "amlogic,meson-gxbb-dwmac"
+ Additionally "snps,dwmac" and any applicable more
+ detailed version number described in net/stmmac.txt
+ should be used.
-- reg: should contain a register range for the dwmac controller and
- another one for the Amlogic specific configuration
+- reg: The first register range should be the one of the DWMAC
+ controller. The second range is is for the Amlogic specific
+ configuration (for example the PRG_ETHERNET register range
+ on Meson8b and newer)
-Example:
+Required properties on Meson8b and newer:
+- clock-names: Should contain the following:
+ - "stmmaceth" - see stmmac.txt
+ - "clkin0" - first parent clock of the internal mux
+ - "clkin1" - second parent clock of the internal mux
+
+
+Example for Meson6:
ethmac: ethernet@c9410000 {
compatible = "amlogic,meson6-dwmac", "snps,dwmac";
@@ -23,3 +37,18 @@ Example:
clocks = <&clk81>;
clock-names = "stmmaceth";
}
+
+Example for GXBB:
+ ethmac: ethernet@c9410000 {
+ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac";
+ reg = <0x0 0xc9410000 0x0 0x10000>,
+ <0x0 0xc8834540 0x0 0x8>;
+ interrupts = <0 8 1>;
+ interrupt-names = "macirq";
+ clocks = <&clkc CLKID_ETH>,
+ <&clkc CLKID_FCLK_DIV2>,
+ <&clkc CLKID_MPLL2>;
+ clock-names = "stmmaceth", "clkin0", "clkin1";
+ phy-mode = "rgmii";
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt
new file mode 100644
index 000000000000..fafd85bd67a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt
@@ -0,0 +1,39 @@
+= Amlogic eFuse device tree bindings =
+
+Required properties:
+- compatible: should be "amlogic,meson-gxbb-efuse"
+
+= Data cells =
+Are child nodes of eFuse, bindings of which as described in
+bindings/nvmem/nvmem.txt
+
+Example:
+
+ efuse: efuse {
+ compatible = "amlogic,meson-gxbb-efuse";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sn: sn@14 {
+ reg = <0x14 0x10>;
+ };
+
+ eth_mac: eth_mac@34 {
+ reg = <0x34 0x10>;
+ };
+
+ bid: bid@46 {
+ reg = <0x46 0x30>;
+ };
+ };
+
+= Data consumers =
+Are device nodes which consume nvmem data cells.
+
+For example:
+
+ eth_mac {
+ ...
+ nvmem-cells = <&eth_mac>;
+ nvmem-cell-names = "eth_mac";
+ };
diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index 6c5322c55411..1392c705ceca 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -17,6 +17,8 @@ Required properties:
- num-lanes: number of lanes to use
Optional properties:
+- num-viewport: number of view ports configured in hardware. If a platform
+ does not specify it, the driver assumes 2.
- num-lanes: number of lanes to use (this property should be specified unless
the link is brought already up in BIOS)
- reset-gpio: gpio pin number of power good signal
@@ -44,4 +46,5 @@ Example configuration:
interrupts = <25>, <24>;
#interrupt-cells = <1>;
num-lanes = <1>;
+ num-viewport = <3>;
};
diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
new file mode 100644
index 000000000000..ba67b39939c1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
@@ -0,0 +1,106 @@
+* Rockchip AXI PCIe Root Port Bridge DT description
+
+Required properties:
+- #address-cells: Address representation for root ports, set to <3>
+- #size-cells: Size representation for root ports, set to <2>
+- #interrupt-cells: specifies the number of cells needed to encode an
+ interrupt source. The value must be 1.
+- compatible: Should contain "rockchip,rk3399-pcie"
+- reg: Two register ranges as listed in the reg-names property
+- reg-names: Must include the following names
+ - "axi-base"
+ - "apb-base"
+- clocks: Must contain an entry for each entry in clock-names.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+ - "aclk"
+ - "aclk-perf"
+ - "hclk"
+ - "pm"
+- msi-map: Maps a Requester ID to an MSI controller and associated
+ msi-specifier data. See ./pci-msi.txt
+- phys: From PHY bindings: Phandle for the Generic PHY for PCIe.
+- phy-names: MUST be "pcie-phy".
+- interrupts: Three interrupt entries must be specified.
+- interrupt-names: Must include the following names
+ - "sys"
+ - "legacy"
+ - "client"
+- resets: Must contain five entries for each entry in reset-names.
+ See ../reset/reset.txt for details.
+- reset-names: Must include the following names
+ - "core"
+ - "mgmt"
+ - "mgmt-sticky"
+ - "pipe"
+- pinctrl-names : The pin control state names
+- pinctrl-0: The "default" pinctrl state
+- #interrupt-cells: specifies the number of cells needed to encode an
+ interrupt source. The value must be 1.
+- interrupt-map-mask and interrupt-map: standard PCI properties
+
+Optional Property:
+- ep-gpios: contain the entry for pre-reset gpio
+- num-lanes: number of lanes to use
+- vpcie3v3-supply: The phandle to the 3.3v regulator to use for PCIe.
+- vpcie1v8-supply: The phandle to the 1.8v regulator to use for PCIe.
+- vpcie0v9-supply: The phandle to the 0.9v regulator to use for PCIe.
+
+*Interrupt controller child node*
+The core controller provides a single interrupt for legacy INTx. The PCIe node
+should contain an interrupt controller node as a target for the PCI
+'interrupt-map' property. This node represents the domain at which the four
+INTx interrupts are decoded and routed.
+
+
+Required properties for Interrupt controller child node:
+- interrupt-controller: identifies the node as an interrupt controller
+- #address-cells: specifies the number of cells needed to encode an
+ address. The value must be 0.
+- #interrupt-cells: specifies the number of cells needed to encode an
+ interrupt source. The value must be 1.
+
+Example:
+
+pcie0: pcie@f8000000 {
+ compatible = "rockchip,rk3399-pcie";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
+ <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>;
+ clock-names = "aclk", "aclk-perf",
+ "hclk", "pm";
+ bus-range = <0x0 0x1>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "sys", "legacy", "client";
+ assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
+ assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
+ assigned-clock-rates = <100000000>;
+ ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
+ ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x600000
+ 0x81000000 0x0 0xfa600000 0x0 0xfa600000 0x0 0x100000>;
+ num-lanes = <4>;
+ msi-map = <0x0 &its 0x0 0x1000>;
+ reg = <0x0 0xf8000000 0x0 0x2000000>, <0x0 0xfd000000 0x0 0x1000000>;
+ reg-names = "axi-base", "apb-base";
+ resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
+ <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
+ reset-names = "core", "mgmt", "mgmt-sticky", "pipe";
+ phys = <&pcie_phy>;
+ phy-names = "pcie-phy";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_clkreq>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie0_intc 0>,
+ <0 0 0 2 &pcie0_intc 1>,
+ <0 0 0 3 &pcie0_intc 2>,
+ <0 0 0 4 &pcie0_intc 3>;
+ pcie0_intc: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt b/Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
new file mode 100644
index 000000000000..afb11cf693c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
@@ -0,0 +1,112 @@
+* APM X-Gene SoC PMU bindings
+
+This is APM X-Gene SoC PMU (Performance Monitoring Unit) module.
+The following PMU devices are supported:
+
+ L3C - L3 cache controller
+ IOB - IO bridge
+ MCB - Memory controller bridge
+ MC - Memory controller
+
+The following section describes the SoC PMU DT node binding.
+
+Required properties:
+- compatible : Shall be "apm,xgene-pmu" for revision 1 or
+ "apm,xgene-pmu-v2" for revision 2.
+- regmap-csw : Regmap of the CPU switch fabric (CSW) resource.
+- regmap-mcba : Regmap of the MCB-A (memory bridge) resource.
+- regmap-mcbb : Regmap of the MCB-B (memory bridge) resource.
+- reg : First resource shall be the CPU bus PMU resource.
+- interrupts : Interrupt-specifier for PMU IRQ.
+
+Required properties for L3C subnode:
+- compatible : Shall be "apm,xgene-pmu-l3c".
+- reg : First resource shall be the L3C PMU resource.
+
+Required properties for IOB subnode:
+- compatible : Shall be "apm,xgene-pmu-iob".
+- reg : First resource shall be the IOB PMU resource.
+
+Required properties for MCB subnode:
+- compatible : Shall be "apm,xgene-pmu-mcb".
+- reg : First resource shall be the MCB PMU resource.
+- enable-bit-index : The bit indicates if the according MCB is enabled.
+
+Required properties for MC subnode:
+- compatible : Shall be "apm,xgene-pmu-mc".
+- reg : First resource shall be the MC PMU resource.
+- enable-bit-index : The bit indicates if the according MC is enabled.
+
+Example:
+ csw: csw@7e200000 {
+ compatible = "apm,xgene-csw", "syscon";
+ reg = <0x0 0x7e200000 0x0 0x1000>;
+ };
+
+ mcba: mcba@7e700000 {
+ compatible = "apm,xgene-mcb", "syscon";
+ reg = <0x0 0x7e700000 0x0 0x1000>;
+ };
+
+ mcbb: mcbb@7e720000 {
+ compatible = "apm,xgene-mcb", "syscon";
+ reg = <0x0 0x7e720000 0x0 0x1000>;
+ };
+
+ pmu: pmu@78810000 {
+ compatible = "apm,xgene-pmu-v2";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ regmap-csw = <&csw>;
+ regmap-mcba = <&mcba>;
+ regmap-mcbb = <&mcbb>;
+ reg = <0x0 0x78810000 0x0 0x1000>;
+ interrupts = <0x0 0x22 0x4>;
+
+ pmul3c@7e610000 {
+ compatible = "apm,xgene-pmu-l3c";
+ reg = <0x0 0x7e610000 0x0 0x1000>;
+ };
+
+ pmuiob@7e940000 {
+ compatible = "apm,xgene-pmu-iob";
+ reg = <0x0 0x7e940000 0x0 0x1000>;
+ };
+
+ pmucmcb@7e710000 {
+ compatible = "apm,xgene-pmu-mcb";
+ reg = <0x0 0x7e710000 0x0 0x1000>;
+ enable-bit-index = <0>;
+ };
+
+ pmucmcb@7e730000 {
+ compatible = "apm,xgene-pmu-mcb";
+ reg = <0x0 0x7e730000 0x0 0x1000>;
+ enable-bit-index = <1>;
+ };
+
+ pmucmc@7e810000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e810000 0x0 0x1000>;
+ enable-bit-index = <0>;
+ };
+
+ pmucmc@7e850000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e850000 0x0 0x1000>;
+ enable-bit-index = <1>;
+ };
+
+ pmucmc@7e890000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e890000 0x0 0x1000>;
+ enable-bit-index = <2>;
+ };
+
+ pmucmc@7e8d0000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e8d0000 0x0 0x1000>;
+ enable-bit-index = <3>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
new file mode 100644
index 000000000000..9da5ea234154
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/meson-usb2-phy.txt
@@ -0,0 +1,27 @@
+* Amlogic USB2 PHY
+
+Required properties:
+- compatible: Depending on the platform this should be one of:
+ "amlogic,meson8b-usb2-phy"
+ "amlogic,meson-gxbb-usb2-phy"
+- reg: The base address and length of the registers
+- #phys-cells: should be 0 (see phy-bindings.txt in this directory)
+- clocks: phandle and clock identifier for the phy clocks
+- clock-names: "usb_general" and "usb"
+
+Optional properties:
+- resets: reference to the reset controller
+- phy-supply: see phy-bindings.txt in this directory
+
+
+Example:
+
+usb0_phy: usb_phy@0 {
+ compatible = "amlogic,meson-gxbb-usb2-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0x0 0x0 0x20>;
+ resets = <&reset RESET_USB_OTG>;
+ clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
+ clock-names = "usb_general", "usb";
+ phy-supply = <&usb_vbus>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt
index 27570a3a1741..ec8aa3c6936b 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,orion-pinctrl.txt
@@ -4,7 +4,9 @@ Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
part and usage.
Required properties:
-- compatible: "marvell,88f5181l-pinctrl", "marvell,88f5182-pinctrl",
+- compatible: "marvell,88f5181-pinctrl",
+ "marvell,88f5181l-pinctrl",
+ "marvell,88f5182-pinctrl",
"marvell,88f5281-pinctrl"
- reg: two register areas, the first one describing the first two
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index 6db16b90873a..d49e22d2a8b5 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -229,6 +229,8 @@ Example: A pin-controller node with pin banks:
Example 1: A pin-controller node with pin groups.
+ #include <dt-bindings/pinctrl/samsung.h>
+
pinctrl_0: pinctrl@11400000 {
compatible = "samsung,exynos4210-pinctrl";
reg = <0x11400000 0x1000>;
@@ -238,53 +240,53 @@ Example 1: A pin-controller node with pin groups.
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
sd4_bus8: sd4-bus-width8 {
part-1 {
samsung,pins = "gpk0-3", "gpk0-4",
"gpk0-5", "gpk0-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
part-2 {
samsung,pins = "gpk1-3", "gpk1-4",
"gpk1-5", "gpk1-6";
- samsung,pin-function = <4>;
- samsung,pin-pud = <4>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
};
};
diff --git a/Documentation/devicetree/bindings/power/act8945a-charger.txt b/Documentation/devicetree/bindings/power/act8945a-charger.txt
deleted file mode 100644
index bea254c9d136..000000000000
--- a/Documentation/devicetree/bindings/power/act8945a-charger.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-Device-Tree bindings for charger of Active-semi ACT8945A Multi-Function Device
-
-Required properties:
- - compatible: "active-semi,act8945a", please refer to ../mfd/act8945a.txt.
- - active-semi,chglev-gpios: charge current level phandle with args
- as described in ../gpio/gpio.txt.
-
-Optional properties:
- - active-semi,check-battery-temperature: boolean to check the battery
- temperature or not.
- - active-semi,input-voltage-threshold-microvolt: unit: mV;
- Specifies the charger's input over-voltage threshold value;
- The value can be: 6600, 7000, 7500, 8000; default: 6600
- - active-semi,precondition-timeout: unit: minutes;
- Specifies the charger's PRECONDITION safety timer setting value;
- The value can be: 40, 60, 80, 0; If 0, it means to disable this timer;
- default: 40.
- - active-semi,total-timeout: unit: hours;
- Specifies the charger's total safety timer setting value;
- The value can be: 3, 4, 5, 0; If 0, it means to disable this timer;
- default: 3.
-
-Example:
- pmic@5b {
- compatible = "active-semi,act8945a";
- reg = <0x5b>;
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_charger_chglev>;
- active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>;
- active-semi,input-voltage-threshold-microvolt = <6600>;
- active-semi,precondition-timeout = <40>;
- active-semi,total-timeout = <3>;
- };
diff --git a/Documentation/devicetree/bindings/power_supply/axxia-reset.txt b/Documentation/devicetree/bindings/power/reset/axxia-reset.txt
index 47e720d249d2..47e720d249d2 100644
--- a/Documentation/devicetree/bindings/power_supply/axxia-reset.txt
+++ b/Documentation/devicetree/bindings/power/reset/axxia-reset.txt
diff --git a/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt b/Documentation/devicetree/bindings/power/reset/imx-snvs-poweroff.txt
index dc7c9bad63ea..dc7c9bad63ea 100644
--- a/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt
+++ b/Documentation/devicetree/bindings/power/reset/imx-snvs-poweroff.txt
diff --git a/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt b/Documentation/devicetree/bindings/power/reset/msm-poweroff.txt
index ce44ad357565..ce44ad357565 100644
--- a/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt
+++ b/Documentation/devicetree/bindings/power/reset/msm-poweroff.txt
diff --git a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt b/Documentation/devicetree/bindings/power/reset/qnap-poweroff.txt
index af25e77c0e0c..af25e77c0e0c 100644
--- a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
+++ b/Documentation/devicetree/bindings/power/reset/qnap-poweroff.txt
diff --git a/Documentation/devicetree/bindings/power_supply/restart-poweroff.txt b/Documentation/devicetree/bindings/power/reset/restart-poweroff.txt
index 5776e684afda..5776e684afda 100644
--- a/Documentation/devicetree/bindings/power_supply/restart-poweroff.txt
+++ b/Documentation/devicetree/bindings/power/reset/restart-poweroff.txt
diff --git a/Documentation/devicetree/bindings/power/reset/st-reset.txt b/Documentation/devicetree/bindings/power/reset/st-reset.txt
index 809af54f02f3..83734dc3a389 100644
--- a/Documentation/devicetree/bindings/power/reset/st-reset.txt
+++ b/Documentation/devicetree/bindings/power/reset/st-reset.txt
@@ -1,11 +1,12 @@
*Device-Tree bindings for ST SW reset functionality
Required properties:
-- compatible: should be "st,<chip>-restart".
+- compatible: should be "stih407-restart".
- st,syscfg: should be a phandle of the syscfg node.
Example node:
restart {
- compatible = "st,stih416-restart";
- st,syscfg = <&syscfg_sbc>;
+ compatible = "st,stih407-restart";
+ st,syscfg = <&syscfg_sbc_reg>;
+ status = "okay";
};
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt b/Documentation/devicetree/bindings/power/supply/ab8500/btemp.txt
index 0ba1bcc7f33a..0ba1bcc7f33a 100644
--- a/Documentation/devicetree/bindings/power_supply/ab8500/btemp.txt
+++ b/Documentation/devicetree/bindings/power/supply/ab8500/btemp.txt
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt b/Documentation/devicetree/bindings/power/supply/ab8500/chargalg.txt
index ef5328371122..ef5328371122 100644
--- a/Documentation/devicetree/bindings/power_supply/ab8500/chargalg.txt
+++ b/Documentation/devicetree/bindings/power/supply/ab8500/chargalg.txt
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/charger.txt b/Documentation/devicetree/bindings/power/supply/ab8500/charger.txt
index 6bdbb08ea9e0..6bdbb08ea9e0 100644
--- a/Documentation/devicetree/bindings/power_supply/ab8500/charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/ab8500/charger.txt
diff --git a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt b/Documentation/devicetree/bindings/power/supply/ab8500/fg.txt
index ccafcb9112fb..ccafcb9112fb 100644
--- a/Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
+++ b/Documentation/devicetree/bindings/power/supply/ab8500/fg.txt
diff --git a/Documentation/devicetree/bindings/power/supply/act8945a-charger.txt b/Documentation/devicetree/bindings/power/supply/act8945a-charger.txt
new file mode 100644
index 000000000000..de78d761ce44
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/act8945a-charger.txt
@@ -0,0 +1,48 @@
+Device-Tree bindings for charger of Active-semi ACT8945A Multi-Function Device
+
+Required properties:
+ - compatible: "active-semi,act8945a-charger".
+ - active-semi,chglev-gpios: charge current level phandle with args
+ as described in ../gpio/gpio.txt.
+ - active-semi,lbo-gpios: specify the low battery voltage detect phandle
+ with args as as described in ../gpio/gpio.txt.
+ - interrupts: <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt.
+ - interrupt-parent: the phandle for the interrupt controller that
+ services interrupts for this device.
+
+Optional properties:
+ - active-semi,input-voltage-threshold-microvolt: unit: mV;
+ Specifies the charger's input over-voltage threshold value;
+ The value can be: 6600, 7000, 7500, 8000; default: 6600
+ - active-semi,precondition-timeout: unit: minutes;
+ Specifies the charger's PRECONDITION safety timer setting value;
+ The value can be: 40, 60, 80, 0; If 0, it means to disable this timer;
+ default: 40.
+ - active-semi,total-timeout: unit: hours;
+ Specifies the charger's total safety timer setting value;
+ The value can be: 3, 4, 5, 0; If 0, it means to disable this timer;
+ default: 3.
+
+Example:
+ pmic@5b {
+ compatible = "active-semi,act8945a";
+ reg = <0x5b>;
+ status = "okay";
+
+ charger {
+ compatible = "active-semi,act8945a-charger";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>;
+ interrupt-parent = <&pioA>;
+ interrupts = <45 GPIO_ACTIVE_LOW>;
+
+ active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>;
+ active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>;
+ active-semi,input-voltage-threshold-microvolt = <6600>;
+ active-semi,precondition-timeout = <40>;
+ active-semi,total-timeout = <3>;
+ status = "okay";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt b/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt
index f1d7beec45bf..f1d7beec45bf 100644
--- a/Documentation/devicetree/bindings/power_supply/axp20x_usb_power.txt
+++ b/Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt
diff --git a/Documentation/devicetree/bindings/power/bq2415x.txt b/Documentation/devicetree/bindings/power/supply/bq2415x.txt
index d0327f0b59ad..d0327f0b59ad 100644
--- a/Documentation/devicetree/bindings/power/bq2415x.txt
+++ b/Documentation/devicetree/bindings/power/supply/bq2415x.txt
diff --git a/Documentation/devicetree/bindings/power/bq24257.txt b/Documentation/devicetree/bindings/power/supply/bq24257.txt
index d693702c9c1e..d693702c9c1e 100644
--- a/Documentation/devicetree/bindings/power/bq24257.txt
+++ b/Documentation/devicetree/bindings/power/supply/bq24257.txt
diff --git a/Documentation/devicetree/bindings/power/bq25890.txt b/Documentation/devicetree/bindings/power/supply/bq25890.txt
index c9dd17d142ad..c9dd17d142ad 100644
--- a/Documentation/devicetree/bindings/power/bq25890.txt
+++ b/Documentation/devicetree/bindings/power/supply/bq25890.txt
diff --git a/Documentation/devicetree/bindings/power_supply/charger-manager.txt b/Documentation/devicetree/bindings/power/supply/charger-manager.txt
index ec4fe9de3137..ec4fe9de3137 100644
--- a/Documentation/devicetree/bindings/power_supply/charger-manager.txt
+++ b/Documentation/devicetree/bindings/power/supply/charger-manager.txt
diff --git a/Documentation/devicetree/bindings/power/da9150-charger.txt b/Documentation/devicetree/bindings/power/supply/da9150-charger.txt
index f3906663c454..f3906663c454 100644
--- a/Documentation/devicetree/bindings/power/da9150-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/da9150-charger.txt
diff --git a/Documentation/devicetree/bindings/power/da9150-fg.txt b/Documentation/devicetree/bindings/power/supply/da9150-fg.txt
index 00236fe3ea31..00236fe3ea31 100644
--- a/Documentation/devicetree/bindings/power/da9150-fg.txt
+++ b/Documentation/devicetree/bindings/power/supply/da9150-fg.txt
diff --git a/Documentation/devicetree/bindings/power_supply/gpio-charger.txt b/Documentation/devicetree/bindings/power/supply/gpio-charger.txt
index adbb5dc5b6e9..adbb5dc5b6e9 100644
--- a/Documentation/devicetree/bindings/power_supply/gpio-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/gpio-charger.txt
diff --git a/Documentation/devicetree/bindings/power/isp1704.txt b/Documentation/devicetree/bindings/power/supply/isp1704.txt
index fa3596907967..fa3596907967 100644
--- a/Documentation/devicetree/bindings/power/isp1704.txt
+++ b/Documentation/devicetree/bindings/power/supply/isp1704.txt
diff --git a/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt b/Documentation/devicetree/bindings/power/supply/lp8727_charger.txt
index 2246bc5c874b..2246bc5c874b 100644
--- a/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/lp8727_charger.txt
diff --git a/Documentation/devicetree/bindings/power/ltc2941.txt b/Documentation/devicetree/bindings/power/supply/ltc2941.txt
index ea42ae12d924..ea42ae12d924 100644
--- a/Documentation/devicetree/bindings/power/ltc2941.txt
+++ b/Documentation/devicetree/bindings/power/supply/ltc2941.txt
diff --git a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt b/Documentation/devicetree/bindings/power/supply/max17042_battery.txt
index 3f3894aaeebc..3f3894aaeebc 100644
--- a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/max17042_battery.txt
diff --git a/Documentation/devicetree/bindings/power_supply/max8925_batter.txt b/Documentation/devicetree/bindings/power/supply/max8925_batter.txt
index d7e3e0c0f71d..d7e3e0c0f71d 100644
--- a/Documentation/devicetree/bindings/power_supply/max8925_batter.txt
+++ b/Documentation/devicetree/bindings/power/supply/max8925_batter.txt
diff --git a/Documentation/devicetree/bindings/power_supply/olpc_battery.txt b/Documentation/devicetree/bindings/power/supply/olpc_battery.txt
index c8901b3992d9..c8901b3992d9 100644
--- a/Documentation/devicetree/bindings/power_supply/olpc_battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/olpc_battery.txt
diff --git a/Documentation/devicetree/bindings/power_supply/power_supply.txt b/Documentation/devicetree/bindings/power/supply/power_supply.txt
index 8391bfa0edac..8391bfa0edac 100644
--- a/Documentation/devicetree/bindings/power_supply/power_supply.txt
+++ b/Documentation/devicetree/bindings/power/supply/power_supply.txt
diff --git a/Documentation/devicetree/bindings/power/qcom,coincell-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom,coincell-charger.txt
index 747899223262..747899223262 100644
--- a/Documentation/devicetree/bindings/power/qcom,coincell-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom,coincell-charger.txt
diff --git a/Documentation/devicetree/bindings/power_supply/qcom_smbb.txt b/Documentation/devicetree/bindings/power/supply/qcom_smbb.txt
index 65b88fac854b..65b88fac854b 100644
--- a/Documentation/devicetree/bindings/power_supply/qcom_smbb.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom_smbb.txt
diff --git a/Documentation/devicetree/bindings/power/rt9455_charger.txt b/Documentation/devicetree/bindings/power/supply/rt9455_charger.txt
index 5d9ad5cf2c5a..5d9ad5cf2c5a 100644
--- a/Documentation/devicetree/bindings/power/rt9455_charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/rt9455_charger.txt
diff --git a/Documentation/devicetree/bindings/power/rx51-battery.txt b/Documentation/devicetree/bindings/power/supply/rx51-battery.txt
index 90438453db58..90438453db58 100644
--- a/Documentation/devicetree/bindings/power/rx51-battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/rx51-battery.txt
diff --git a/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt b/Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt
index c40e8926facf..c40e8926facf 100644
--- a/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt
diff --git a/Documentation/devicetree/bindings/power_supply/ti,bq24735.txt b/Documentation/devicetree/bindings/power/supply/ti,bq24735.txt
index 3bf55757ceec..3bf55757ceec 100644
--- a/Documentation/devicetree/bindings/power_supply/ti,bq24735.txt
+++ b/Documentation/devicetree/bindings/power/supply/ti,bq24735.txt
diff --git a/Documentation/devicetree/bindings/power_supply/tps65090.txt b/Documentation/devicetree/bindings/power/supply/tps65090.txt
index 8e5e0d3910df..8e5e0d3910df 100644
--- a/Documentation/devicetree/bindings/power_supply/tps65090.txt
+++ b/Documentation/devicetree/bindings/power/supply/tps65090.txt
diff --git a/Documentation/devicetree/bindings/power_supply/tps65217_charger.txt b/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt
index 98d131acee95..98d131acee95 100644
--- a/Documentation/devicetree/bindings/power_supply/tps65217_charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt
diff --git a/Documentation/devicetree/bindings/power/twl-charger.txt b/Documentation/devicetree/bindings/power/supply/twl-charger.txt
index 3b4ea1b73b38..3b4ea1b73b38 100644
--- a/Documentation/devicetree/bindings/power/twl-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/twl-charger.txt
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt
new file mode 100644
index 000000000000..0d2361ebe3d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt
@@ -0,0 +1,132 @@
+Qualcomm WCNSS Peripheral Image Loader
+
+This document defines the binding for a component that loads and boots firmware
+on the Qualcomm WCNSS core.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,riva-pil",
+ "qcom,pronto-v1-pil",
+ "qcom,pronto-v2-pil"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: must specify the base address and size of the CCU, DXE and
+ PMU register blocks
+
+- reg-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "ccu", "dxe", "pmu"
+
+- interrupts-extended:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: must list the watchdog and fatal IRQs and may specify the
+ ready, handover and stop-ack IRQs
+
+- interrupt-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: should be "wdog", "fatal", optionally followed by "ready",
+ "handover", "stop-ack"
+
+- vddmx-supply:
+- vddcx-supply:
+- vddpx-supply:
+ Usage: required
+ Value type: <phandle>
+ Definition: reference to the regulators to be held on behalf of the
+ booting of the WCNSS core
+
+- qcom,smem-states:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: reference to the SMEM state used to indicate to WCNSS that
+ it should shut down
+
+- qcom,smem-state-names:
+ Usage: optional
+ Value type: <stringlist>
+ Definition: should be "stop"
+
+- memory-region:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: reference to reserved-memory node for the remote processor
+ see ../reserved-memory/reserved-memory.txt
+
+= SUBNODES
+A single subnode of the WCNSS PIL describes the attached rf module and its
+resource dependencies.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,wcn3620",
+ "qcom,wcn3660",
+ "qcom,wcn3680"
+
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the xo clock and optionally the rf clock
+
+- clock-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: should be "xo", optionally followed by "rf"
+
+- vddxo-supply:
+- vddrfa-supply:
+- vddpa-supply:
+- vdddig-supply:
+ Usage: required
+ Value type: <phandle>
+ Definition: reference to the regulators to be held on behalf of the
+ booting of the WCNSS core
+
+= EXAMPLE
+The following example describes the resources needed to boot control the WCNSS,
+with attached WCN3680, as it is commonly found on MSM8974 boards.
+
+pronto@fb204000 {
+ compatible = "qcom,pronto-v2-pil";
+ reg = <0xfb204000 0x2000>, <0xfb202000 0x1000>, <0xfb21b000 0x3000>;
+ reg-names = "ccu", "dxe", "pmu";
+
+ interrupts-extended = <&intc 0 149 1>,
+ <&wcnss_smp2p_slave 0 0>,
+ <&wcnss_smp2p_slave 1 0>,
+ <&wcnss_smp2p_slave 2 0>,
+ <&wcnss_smp2p_slave 3 0>;
+ interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
+
+ vddmx-supply = <&pm8841_s1>;
+ vddcx-supply = <&pm8841_s2>;
+ vddpx-supply = <&pm8941_s3>;
+
+ qcom,smem-states = <&wcnss_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ memory-region = <&wcnss_region>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcnss_pin_a>;
+
+ iris {
+ compatible = "qcom,wcn3680";
+
+ clocks = <&rpmcc RPM_CXO_CLK_SRC>, <&rpmcc RPM_CXO_A2>;
+ clock-names = "xo", "rf";
+
+ vddxo-supply = <&pm8941_l6>;
+ vddrfa-supply = <&pm8941_l11>;
+ vddpa-supply = <&pm8941_l19>;
+ vdddig-supply = <&pm8941_s3>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
new file mode 100644
index 000000000000..01db34375192
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -0,0 +1,6 @@
+STMicroelectronics STM32 Peripheral Reset Controller
+====================================================
+
+The RCC IP is both a reset and a clock controller.
+
+Please see Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
diff --git a/Documentation/devicetree/bindings/reset/uniphier-reset.txt b/Documentation/devicetree/bindings/reset/uniphier-reset.txt
new file mode 100644
index 000000000000..e6bbfccd56c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/uniphier-reset.txt
@@ -0,0 +1,93 @@
+UniPhier reset controller
+
+
+System reset
+------------
+
+Required properties:
+- compatible: should be one of the following:
+ "socionext,uniphier-sld3-reset" - for PH1-sLD3 SoC.
+ "socionext,uniphier-ld4-reset" - for PH1-LD4 SoC.
+ "socionext,uniphier-pro4-reset" - for PH1-Pro4 SoC.
+ "socionext,uniphier-sld8-reset" - for PH1-sLD8 SoC.
+ "socionext,uniphier-pro5-reset" - for PH1-Pro5 SoC.
+ "socionext,uniphier-pxs2-reset" - for ProXstream2/PH1-LD6b SoC.
+ "socionext,uniphier-ld11-reset" - for PH1-LD11 SoC.
+ "socionext,uniphier-ld20-reset" - for PH1-LD20 SoC.
+- #reset-cells: should be 1.
+
+Example:
+
+ sysctrl@61840000 {
+ compatible = "socionext,uniphier-ld20-sysctrl",
+ "simple-mfd", "syscon";
+ reg = <0x61840000 0x4000>;
+
+ reset {
+ compatible = "socionext,uniphier-ld20-reset";
+ #reset-cells = <1>;
+ };
+
+ other nodes ...
+ };
+
+
+Media I/O (MIO) reset
+---------------------
+
+Required properties:
+- compatible: should be one of the following:
+ "socionext,uniphier-sld3-mio-reset" - for PH1-sLD3 SoC.
+ "socionext,uniphier-ld4-mio-reset" - for PH1-LD4 SoC.
+ "socionext,uniphier-pro4-mio-reset" - for PH1-Pro4 SoC.
+ "socionext,uniphier-sld8-mio-reset" - for PH1-sLD8 SoC.
+ "socionext,uniphier-pro5-mio-reset" - for PH1-Pro5 SoC.
+ "socionext,uniphier-pxs2-mio-reset" - for ProXstream2/PH1-LD6b SoC.
+ "socionext,uniphier-ld11-mio-reset" - for PH1-LD11 SoC.
+ "socionext,uniphier-ld20-mio-reset" - for PH1-LD20 SoC.
+- #reset-cells: should be 1.
+
+Example:
+
+ mioctrl@59810000 {
+ compatible = "socionext,uniphier-ld20-mioctrl",
+ "simple-mfd", "syscon";
+ reg = <0x59810000 0x800>;
+
+ reset {
+ compatible = "socionext,uniphier-ld20-mio-reset";
+ #reset-cells = <1>;
+ };
+
+ other nodes ...
+ };
+
+
+Peripheral reset
+----------------
+
+Required properties:
+- compatible: should be one of the following:
+ "socionext,uniphier-ld4-peri-reset" - for PH1-LD4 SoC.
+ "socionext,uniphier-pro4-peri-reset" - for PH1-Pro4 SoC.
+ "socionext,uniphier-sld8-peri-reset" - for PH1-sLD8 SoC.
+ "socionext,uniphier-pro5-peri-reset" - for PH1-Pro5 SoC.
+ "socionext,uniphier-pxs2-peri-reset" - for ProXstream2/PH1-LD6b SoC.
+ "socionext,uniphier-ld11-peri-reset" - for PH1-LD11 SoC.
+ "socionext,uniphier-ld20-peri-reset" - for PH1-LD20 SoC.
+- #reset-cells: should be 1.
+
+Example:
+
+ perictrl@59820000 {
+ compatible = "socionext,uniphier-ld20-perictrl",
+ "simple-mfd", "syscon";
+ reg = <0x59820000 0x200>;
+
+ reset {
+ compatible = "socionext,uniphier-ld20-peri-reset";
+ #reset-cells = <1>;
+ };
+
+ other nodes ...
+ };
diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt
index 7d16ebfaa5a1..455f2c310a1b 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.txt
+++ b/Documentation/devicetree/bindings/usb/dwc2.txt
@@ -10,6 +10,8 @@ Required properties:
- "rockchip,rk3288-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3288 Soc;
- "lantiq,arx100-usb": The DWC2 USB controller instance in Lantiq ARX SoCs;
- "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs;
+ - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs;
+ - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs;
- snps,dwc2: A generic DWC2 USB controller with default parameters.
- reg : Should contain 1 register range (address and length)
- interrupts : Should contain 1 interrupt
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 77e985f21707..24c6f658bce1 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -101,6 +101,7 @@ ezchip EZchip Semiconductor
fcs Fairchild Semiconductor
firefly Firefly
focaltech FocalTech Systems Co.,Ltd
+friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
fsl Freescale Semiconductor
ge General Electric Company
geekbuying GeekBuying
@@ -137,6 +138,7 @@ innolux Innolux Corporation
intel Intel Corporation
intercontrol Inter Control Group
invensense InvenSense Inc.
+inversepath Inverse Path
iom Iomega Corporation
isee ISEE 2007 S.L.
isil Intersil
@@ -280,6 +282,7 @@ toshiba Toshiba Corporation
toumaz Toumaz
tpk TPK U.S.A. LLC
tplink TP-LINK Technologies Co., Ltd.
+tpo TPO
tronfy Tronfy
tronsmart Tronsmart
truly Truly Semiconductors Limited
diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt
index 91ce82d5f0c4..c4fd47540b31 100644
--- a/Documentation/dmaengine/provider.txt
+++ b/Documentation/dmaengine/provider.txt
@@ -282,6 +282,17 @@ supported.
that is supposed to push the current
transaction descriptor to a pending queue, waiting
for issue_pending to be called.
+ - In this structure the function pointer callback_result can be
+ initialized in order for the submitter to be notified that a
+ transaction has completed. In the earlier code the function pointer
+ callback has been used. However it does not provide any status to the
+ transaction and will be deprecated. The result structure defined as
+ dmaengine_result that is passed in to callback_result has two fields:
+ + result: This provides the transfer result defined by
+ dmaengine_tx_result. Either success or some error
+ condition.
+ + residue: Provides the residue bytes of the transfer for those that
+ support residue.
* device_issue_pending
- Takes the first transaction descriptor in the pending queue,
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 75bc5b8add2f..167070895498 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -346,6 +346,10 @@ PINCTRL
devm_pinctrl_register()
devm_pinctrl_unregister()
+POWER
+ devm_reboot_mode_register()
+ devm_reboot_mode_unregister()
+
PWM
devm_pwm_get()
devm_pwm_put()
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index d30fb2cb5066..14cdc101d165 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -51,8 +51,6 @@ prototypes:
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
- int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
const char *(*get_link) (struct dentry *, struct inode *, void **);
@@ -61,10 +59,7 @@ prototypes:
int (*get_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
- int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
- ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
- int (*removexattr) (struct dentry *, const char *);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *,
@@ -83,31 +78,44 @@ symlink: yes
mkdir: yes
unlink: yes (both)
rmdir: yes (both) (see below)
-rename: yes (all) (see below)
-rename2: yes (all) (see below)
+rename: yes (all) (see below)
readlink: no
get_link: no
setattr: yes
permission: no (may not block if called in rcu-walk mode)
get_acl: no
getattr: no
-setxattr: yes
-getxattr: no
listxattr: no
-removexattr: yes
fiemap: no
update_time: no
atomic_open: yes
tmpfile: no
+
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
- cross-directory ->rename() and rename2() has (per-superblock)
-->s_vfs_rename_sem.
+ cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
See Documentation/filesystems/directory-locking for more detailed discussion
of the locking scheme for directory operations.
+----------------------- xattr_handler operations -----------------------
+prototypes:
+ bool (*list)(struct dentry *dentry);
+ int (*get)(const struct xattr_handler *handler, struct dentry *dentry,
+ struct inode *inode, const char *name, void *buffer,
+ size_t size);
+ int (*set)(const struct xattr_handler *handler, struct dentry *dentry,
+ struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags);
+
+locking rules:
+ all may block
+ i_mutex(inode)
+list: no
+get: no
+set: yes
+
--------------------------- super_operations ---------------------------
prototypes:
struct inode *(*alloc_inode)(struct super_block *sb);
diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt
index d6030aa33376..f5306ee40ea9 100644
--- a/Documentation/filesystems/ceph.txt
+++ b/Documentation/filesystems/ceph.txt
@@ -98,6 +98,10 @@ Mount Options
size.
rsize=X
+ Specify the maximum read size in bytes. By default there is no
+ maximum.
+
+ rasize=X
Specify the maximum readahead.
mount_timeout=X
diff --git a/Documentation/filesystems/directory-locking b/Documentation/filesystems/directory-locking
index c314badbcfc6..4e32cb961e5b 100644
--- a/Documentation/filesystems/directory-locking
+++ b/Documentation/filesystems/directory-locking
@@ -19,7 +19,7 @@ locks victim and calls the method. Locks are exclusive.
4) rename() that is _not_ cross-directory. Locking rules: caller locks
the parent and finds source and target. In case of exchange (with
-RENAME_EXCHANGE in rename2() flags argument) lock both. In any case,
+RENAME_EXCHANGE in flags argument) lock both. In any case,
if the target already exists, lock it. If the source is a non-directory,
lock it. If we need to lock both, lock them in inode pointer order.
Then call the method. All locks are exclusive.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index b1bd05ea66b2..bdd025ceb763 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -287,8 +287,8 @@ implementing on-disk size changes. Start with a copy of the old inode_setattr
and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
be in order of zeroing blocks using block_truncate_page or similar helpers,
size update and on finally on-disk truncation which should not fail.
-inode_change_ok now includes the size checks for ATTR_SIZE and must be called
-in the beginning of ->setattr unconditionally.
+setattr_prepare (which used to be inode_change_ok) now includes the size checks
+for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally.
[mandatory]
@@ -592,3 +592,7 @@ in your dentry operations instead.
work just as well; if it's something more complicated, use dentry->d_parent.
Just be careful not to assume that fetching it more than once will yield
the same value - in RCU mode it could change under you.
+--
+[mandatory]
+ ->rename() has an added flags argument. Any flags not handled by the
+ filesystem should result in EINVAL being returned.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index fcc1ac094282..219ffd41a911 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -515,6 +515,18 @@ be vanished or the reverse -- new added.
This file is only present if the CONFIG_MMU kernel configuration option is
enabled.
+Note: reading /proc/PID/maps or /proc/PID/smaps is inherently racy (consistent
+output can be achieved only in the single read call).
+This typically manifests when doing partial reads of these files while the
+memory map is being modified. Despite the races, we do provide the following
+guarantees:
+
+1) The mapped addresses never go backwards, which implies no two
+ regions will ever overlap.
+2) If there is something at a given vaddr during the entirety of the
+ life of the smaps/maps walk, there will be some output for it.
+
+
The /proc/PID/clear_refs is used to reset the PG_Referenced and ACCESSED/YOUNG
bits on both physical and virtual pages associated with a process, and the
soft-dirty bit on pte (see Documentation/vm/soft-dirty.txt for details).
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 9ace359d6cc5..d619c8d71966 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -323,6 +323,35 @@ Whoever sets up the inode is responsible for filling in the "i_op" field. This
is a pointer to a "struct inode_operations" which describes the methods that
can be performed on individual inodes.
+struct xattr_handlers
+---------------------
+
+On filesystems that support extended attributes (xattrs), the s_xattr
+superblock field points to a NULL-terminated array of xattr handlers. Extended
+attributes are name:value pairs.
+
+ name: Indicates that the handler matches attributes with the specified name
+ (such as "system.posix_acl_access"); the prefix field must be NULL.
+
+ prefix: Indicates that the handler matches all attributes with the specified
+ name prefix (such as "user."); the name field must be NULL.
+
+ list: Determine if attributes matching this xattr handler should be listed
+ for a particular dentry. Used by some listxattr implementations like
+ generic_listxattr.
+
+ get: Called by the VFS to get the value of a particular extended attribute.
+ This method is called by the getxattr(2) system call.
+
+ set: Called by the VFS to set the value of a particular extended attribute.
+ When the new value is NULL, called to remove a particular extended
+ attribute. This method is called by the the setxattr(2) and
+ removexattr(2) system calls.
+
+When none of the xattr handlers of a filesystem match the specified attribute
+name or when a filesystem doesn't support extended attributes, the various
+*xattr(2) system calls return -EOPNOTSUPP.
+
The Inode Object
================
@@ -346,8 +375,6 @@ struct inode_operations {
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
- int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
const char *(*get_link) (struct dentry *, struct inode *,
@@ -356,10 +383,7 @@ struct inode_operations {
int (*get_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
- int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
- ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
- int (*removexattr) (struct dentry *, const char *);
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode, int *opened);
@@ -416,11 +440,8 @@ otherwise noted.
rename: called by the rename(2) system call to rename the object to
have the parent and name given by the second inode and dentry.
- rename2: this has an additional flags argument compared to rename.
- If no flags are supported by the filesystem then this method
- need not be implemented. If some flags are supported then the
- filesystem must return -EINVAL for any unsupported or unknown
- flags. Currently the following flags are implemented:
+ The filesystem must return -EINVAL for any unsupported or
+ unknown flags. Currently the following flags are implemented:
(1) RENAME_NOREPLACE: this flag indicates that if the target
of the rename exists the rename should fail with -EEXIST
instead of replacing the target. The VFS already checks for
@@ -463,19 +484,8 @@ otherwise noted.
getattr: called by the VFS to get attributes of a file. This method
is called by stat(2) and related system calls.
- setxattr: called by the VFS to set an extended attribute for a file.
- Extended attribute is a name:value pair associated with an
- inode. This method is called by setxattr(2) system call.
-
- getxattr: called by the VFS to retrieve the value of an extended
- attribute name. This method is called by getxattr(2) function
- call.
-
listxattr: called by the VFS to list all extended attributes for a
- given file. This method is called by listxattr(2) system call.
-
- removexattr: called by the VFS to remove an extended attribute from
- a file. This method is called by removexattr(2) system call.
+ given file. This method is called by the listxattr(2) system call.
update_time: called by the VFS to update a specific time or the i_version of
an inode. If this is not defined the VFS will update the inode itself
@@ -722,7 +732,7 @@ struct address_space_operations {
The second case is when a request has been made to invalidate
some or all pages in an address_space. This can happen
- through the fadvice(POSIX_FADV_DONTNEED) system call or by the
+ through the fadvise(POSIX_FADV_DONTNEED) system call or by the
filesystem explicitly requesting it as nfs and 9fs do (when
they believe the cache may be out of date with storage) by
calling invalidate_inode_pages2().
diff --git a/Documentation/hid/intel-ish-hid.txt b/Documentation/hid/intel-ish-hid.txt
new file mode 100644
index 000000000000..d48b21c71ddd
--- /dev/null
+++ b/Documentation/hid/intel-ish-hid.txt
@@ -0,0 +1,454 @@
+Intel Integrated Sensor Hub (ISH)
+===============================
+
+A sensor hub enables the ability to offload sensor polling and algorithm
+processing to a dedicated low power co-processor. This allows the core
+processor to go into low power modes more often, resulting in the increased
+battery life.
+
+There are many vendors providing external sensor hubs confirming to HID
+Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
+and embedded products. Linux had this support since Linux 3.9.
+
+Intel® introduced integrated sensor hubs as a part of the SoC starting from
+Cherry Trail and now supported on multiple generations of CPU packages. There
+are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
+These ISH also comply to HID sensor specification, but the difference is the
+transport protocol used for communication. The current external sensor hubs
+mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
+
+1. Overview
+
+Using a analogy with a usbhid implementation, the ISH follows a similar model
+for a very high speed communication:
+
+ ----------------- ----------------------
+ | USB HID | --> | ISH HID |
+ ----------------- ----------------------
+ ----------------- ----------------------
+ | USB protocol | --> | ISH Transport |
+ ----------------- ----------------------
+ ----------------- ----------------------
+ | EHCI/XHCI | --> | ISH IPC |
+ ----------------- ----------------------
+ PCI PCI
+ ----------------- ----------------------
+ |Host controller| --> | ISH processor |
+ ----------------- ----------------------
+ USB Link
+ ----------------- ----------------------
+ | USB End points| --> | ISH Clients |
+ ----------------- ----------------------
+
+Like USB protocol provides a method for device enumeration, link management
+and user data encapsulation, the ISH also provides similar services. But it is
+very light weight tailored to manage and communicate with ISH client
+applications implemented in the firmware.
+
+The ISH allows multiple sensor management applications executing in the
+firmware. Like USB endpoints the messaging can be to/from a client. As part of
+enumeration process, these clients are identified. These clients can be simple
+HID sensor applications, sensor calibration application or senor firmware
+update application.
+
+The implementation model is similar, like USB bus, ISH transport is also
+implemented as a bus. Each client application executing in the ISH processor
+is registered as a device on this bus. The driver, which binds each device
+(ISH HID driver) identifies the device type and registers with the hid core.
+
+2. ISH Implementation: Block Diagram
+
+ ---------------------------
+ | User Space Applications |
+ ---------------------------
+
+----------------IIO ABI----------------
+ --------------------------
+ | IIO Sensor Drivers |
+ --------------------------
+ --------------------------
+ | IIO core |
+ --------------------------
+ --------------------------
+ | HID Sensor Hub MFD |
+ --------------------------
+ --------------------------
+ | HID Core |
+ --------------------------
+ --------------------------
+ | HID over ISH Client |
+ --------------------------
+ --------------------------
+ | ISH Transport (ISHTP) |
+ --------------------------
+ --------------------------
+ | IPC Drivers |
+ --------------------------
+OS
+---------------- PCI -----------------
+Hardware + Firmware
+ ----------------------------
+ | ISH Hardware/Firmware(FW) |
+ ----------------------------
+
+3. High level processing in above blocks
+
+3.1 Hardware Interface
+
+The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
+product and vendor IDs are changed from different generations of processors. So
+the source code which enumerate drivers needs to update from generation to
+generation.
+
+3.2 Inter Processor Communication (IPC) driver
+Location: drivers/hid/intel-ish-hid/ipc
+
+The IPC message used memory mapped I/O. The registers are defined in
+hw-ish-regs.h.
+
+3.2.1 IPC/FW message types
+
+There are two types of messages, one for management of link and other messages
+are to and from transport layers.
+
+TX and RX of Transport messages
+
+A set of memory mapped register offers support of multi byte messages TX and
+RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
+internal queues to sequence messages and send them in order to the FW.
+Optionally the caller can register handler to get notification of completion.
+A door bell mechanism is used in messaging to trigger processing in host and
+client firmware side. When ISH interrupt handler is called, the ISH2HOST
+doorbell register is used by host drivers to determine that the interrupt
+is for ISH.
+
+Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
+register has the following format:
+Bits 0..6: fragment length (7 bits are used)
+Bits 10..13: encapsulated protocol
+Bits 16..19: management command (for IPC management protocol)
+Bit 31: doorbell trigger (signal H/W interrupt to the other side)
+Other bits are reserved, should be 0.
+
+3.2.2 Transport layer interface
+
+To abstract HW level IPC communication, a set of callbacks are registered.
+The transport layer uses them to send and receive messages.
+Refer to struct ishtp_hw_ops for callbacks.
+
+3.3 ISH Transport layer
+Location: drivers/hid/intel-ish-hid/ishtp/
+
+3.3.1 A Generic Transport Layer
+
+The transport layer is a bi-directional protocol, which defines:
+- Set of commands to start, stop, connect, disconnect and flow control
+(ishtp/hbm.h) for details
+- A flow control mechanism to avoid buffer overflows
+
+This protocol resembles bus messages described in the following document:
+http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
+specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
+
+3.3.2 Connection and Flow Control Mechanism
+
+Each FW client and a protocol is identified by an UUID. In order to communicate
+to a FW client, a connection must be established using connect request and
+response bus messages. If successful, a pair (host_client_id and fw_client_id)
+will identify the connection.
+
+Once connection is established, peers send each other flow control bus messages
+independently. Every peer may send a message only if it has received a
+flow-control credit before. Once it sent a message, it may not send another one
+before receiving the next flow control credit.
+Either side can send disconnect request bus message to end communication. Also
+the link will be dropped if major FW reset occurs.
+
+3.3.3 Peer to Peer data transfer
+
+Peer to Peer data transfer can happen with or without using DMA. Depending on
+the sensor bandwidth requirement DMA can be enabled by using module parameter
+ishtp_use_dma under intel_ishtp.
+
+Each side (host and FW) manages its DMA transfer memory independently. When an
+ISHTP client from either host or FW side wants to send something, it decides
+whether to send over IPC or over DMA; for each transfer the decision is
+independent. The sending side sends DMA_XFER message when the message is in
+the respective host buffer (TX when host client sends, RX when FW client
+sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
+the sender that the memory region for that message may be reused.
+
+DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
+(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
+Additionally to DMA address communication, this sequence checks capabilities:
+if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
+send DMA; if FW doesn't support DMA then it won't respond with
+DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
+Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
+it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
+that it already did DMA and the message resides at host. Thus, DMA_XFER
+and DMA_XFER_ACK act as ownership indicators.
+
+At initial state all outgoing memory belongs to the sender (TX to host, RX to
+FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
+the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
+needs not wait for previous DMA_XFER to be ack'ed, and may send another message
+as long as remaining continuous memory in its ownership is enough.
+In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
+(up to IPC MTU), thus allowing for interrupt throttling.
+Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
+fragments and via IPC otherwise.
+
+3.3.4 Ring Buffers
+
+When a client initiate a connection, a ring or RX and TX buffers are allocated.
+The size of ring can be specified by the client. HID client set 16 and 32 for
+TX and RX buffers respectively. On send request from client, the data to be
+sent is copied to one of the send ring buffer and scheduled to be sent using
+bus message protocol. These buffers are required because the FW may have not
+have processed the last message and may not have enough flow control credits
+to send. Same thing holds true on receive side and flow control is required.
+
+3.3.5 Host Enumeration
+
+The host enumeration bus command allow discovery of clients present in the FW.
+There can be multiple sensor clients and clients for calibration function.
+
+To ease in implantation and allow independent driver handle each client
+this transport layer takes advantage of Linux Bus driver model. Each
+client is registered as device on the the transport bus (ishtp bus).
+
+Enumeration sequence of messages:
+- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
+- FW responds with HOST_START_RES_CMD
+- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
+- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
+client IDs
+- For each FW ID found in that bitmap host sends
+HOST_CLIENT_PROPERTIES_REQ_CMD
+- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
+max ISHTP message size, etc.
+- Once host received properties for that last discovered client, it considers
+ISHTP device fully functional (and allocates DMA buffers)
+
+3.4 HID over ISH Client
+Location: drivers/hid/intel-ish-hid
+
+The ISHTP client driver is responsible for:
+- enumerate HID devices under FW ISH client
+- Get Report descriptor
+- Register with HID core as a LL driver
+- Process Get/Set feature request
+- Get input reports
+
+3.5 HID Sensor Hub MFD and IIO sensor drivers
+
+The functionality in these drivers is the same as an external sensor hub.
+Refer to
+Documentation/hid/hid-sensor.txt for HID sensor
+Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
+
+3.6 End to End HID transport Sequence Diagram
+
+HID-ISH-CLN ISHTP IPC HW
+ | | | |
+ | | |-----WAKE UP------------------>|
+ | | | |
+ | | |-----HOST READY--------------->|
+ | | | |
+ | | |<----MNG_RESET_NOTIFY_ACK----- |
+ | | | |
+ | |<----ISHTP_START------ | |
+ | | | |
+ | |<-----------------HOST_START_RES_CMD-------------------|
+ | | | |
+ | |------------------QUERY_SUBSCRIBER-------------------->|
+ | | | |
+ | |------------------HOST_ENUM_REQ_CMD------------------->|
+ | | | |
+ | |<-----------------HOST_ENUM_RES_CMD--------------------|
+ | | | |
+ | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
+ | | | |
+ | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
+ | Create new device on in ishtp bus | |
+ | | | |
+ | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
+ | | | |
+ | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
+ | Create new device on in ishtp bus | |
+ | | | |
+ | |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
+ | | | |
+ probed()
+ |----ishtp_cl_connect-->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
+ | | | |
+ | |<----------------CLIENT_CONNECT_RES_CMD----------------|
+ | | | |
+ |register event callback| | |
+ | | | |
+ |ishtp_cl_send(
+ HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
+ | | | |
+ | | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
+ | | | |
+ |<--ENUM_DEVICE RSP-----| | |
+ | | | |
+for each enumerated device
+ |ishtp_cl_send(
+ HOSTIF_GET_HID_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW--- >|
+ | | | |
+ ...Response
+ | | | |
+for each enumerated device
+ |ishtp_cl_send(
+ HOSTIF_GET_REPORT_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW- >|
+ | | | |
+ | | | |
+ hid_allocate_device
+ | | | |
+ hid_add_device | | |
+ | | | |
+
+
+3.7 ISH Debugging
+
+To debug ISH, event tracing mechanism is used. To enable debug logs
+echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
+cat sys/kernel/debug/tracing/trace
+
+3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
+
+root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
+/sys/bus/iio/devices/
+├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
+│   ├── buffer
+│   │   ├── enable
+│   │   ├── length
+│   │   └── watermark
+...
+│   ├── in_accel_hysteresis
+│   ├── in_accel_offset
+│   ├── in_accel_sampling_frequency
+│   ├── in_accel_scale
+│   ├── in_accel_x_raw
+│   ├── in_accel_y_raw
+│   ├── in_accel_z_raw
+│   ├── name
+│   ├── scan_elements
+│   │   ├── in_accel_x_en
+│   │   ├── in_accel_x_index
+│   │   ├── in_accel_x_type
+│   │   ├── in_accel_y_en
+│   │   ├── in_accel_y_index
+│   │   ├── in_accel_y_type
+│   │   ├── in_accel_z_en
+│   │   ├── in_accel_z_index
+│   │   └── in_accel_z_type
+...
+│   │   ├── devices
+│   │   │   │   ├── buffer
+│   │   │   │   │   ├── enable
+│   │   │   │   │   ├── length
+│   │   │   │   │   └── watermark
+│   │   │   │   ├── dev
+│   │   │   │   ├── in_intensity_both_raw
+│   │   │   │   ├── in_intensity_hysteresis
+│   │   │   │   ├── in_intensity_offset
+│   │   │   │   ├── in_intensity_sampling_frequency
+│   │   │   │   ├── in_intensity_scale
+│   │   │   │   ├── name
+│   │   │   │   ├── scan_elements
+│   │   │   │   │   ├── in_intensity_both_en
+│   │   │   │   │   ├── in_intensity_both_index
+│   │   │   │   │   └── in_intensity_both_type
+│   │   │   │   ├── trigger
+│   │   │   │   │   └── current_trigger
+...
+│   │   │   │   ├── buffer
+│   │   │   │   │   ├── enable
+│   │   │   │   │   ├── length
+│   │   │   │   │   └── watermark
+│   │   │   │   ├── dev
+│   │   │   │   ├── in_magn_hysteresis
+│   │   │   │   ├── in_magn_offset
+│   │   │   │   ├── in_magn_sampling_frequency
+│   │   │   │   ├── in_magn_scale
+│   │   │   │   ├── in_magn_x_raw
+│   │   │   │   ├── in_magn_y_raw
+│   │   │   │   ├── in_magn_z_raw
+│   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_raw
+│   │   │   │   ├── in_rot_hysteresis
+│   │   │   │   ├── in_rot_offset
+│   │   │   │   ├── in_rot_sampling_frequency
+│   │   │   │   ├── in_rot_scale
+│   │   │   │   ├── name
+...
+│   │   │   │   ├── scan_elements
+│   │   │   │   │   ├── in_magn_x_en
+│   │   │   │   │   ├── in_magn_x_index
+│   │   │   │   │   ├── in_magn_x_type
+│   │   │   │   │   ├── in_magn_y_en
+│   │   │   │   │   ├── in_magn_y_index
+│   │   │   │   │   ├── in_magn_y_type
+│   │   │   │   │   ├── in_magn_z_en
+│   │   │   │   │   ├── in_magn_z_index
+│   │   │   │   │   ├── in_magn_z_type
+│   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_en
+│   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_index
+│   │   │   │   │   └── in_rot_from_north_magnetic_tilt_comp_type
+│   │   │   │   ├── trigger
+│   │   │   │   │   └── current_trigger
+...
+│   │   │   │   ├── buffer
+│   │   │   │   │   ├── enable
+│   │   │   │   │   ├── length
+│   │   │   │   │   └── watermark
+│   │   │   │   ├── dev
+│   │   │   │   ├── in_anglvel_hysteresis
+│   │   │   │   ├── in_anglvel_offset
+│   │   │   │   ├── in_anglvel_sampling_frequency
+│   │   │   │   ├── in_anglvel_scale
+│   │   │   │   ├── in_anglvel_x_raw
+│   │   │   │   ├── in_anglvel_y_raw
+│   │   │   │   ├── in_anglvel_z_raw
+│   │   │   │   ├── name
+│   │   │   │   ├── scan_elements
+│   │   │   │   │   ├── in_anglvel_x_en
+│   │   │   │   │   ├── in_anglvel_x_index
+│   │   │   │   │   ├── in_anglvel_x_type
+│   │   │   │   │   ├── in_anglvel_y_en
+│   │   │   │   │   ├── in_anglvel_y_index
+│   │   │   │   │   ├── in_anglvel_y_type
+│   │   │   │   │   ├── in_anglvel_z_en
+│   │   │   │   │   ├── in_anglvel_z_index
+│   │   │   │   │   └── in_anglvel_z_type
+│   │   │   │   ├── trigger
+│   │   │   │   │   └── current_trigger
+...
+│   │   │   │   ├── buffer
+│   │   │   │   │   ├── enable
+│   │   │   │   │   ├── length
+│   │   │   │   │   └── watermark
+│   │   │   │   ├── dev
+│   │   │   │   ├── in_anglvel_hysteresis
+│   │   │   │   ├── in_anglvel_offset
+│   │   │   │   ├── in_anglvel_sampling_frequency
+│   │   │   │   ├── in_anglvel_scale
+│   │   │   │   ├── in_anglvel_x_raw
+│   │   │   │   ├── in_anglvel_y_raw
+│   │   │   │   ├── in_anglvel_z_raw
+│   │   │   │   ├── name
+│   │   │   │   ├── scan_elements
+│   │   │   │   │   ├── in_anglvel_x_en
+│   │   │   │   │   ├── in_anglvel_x_index
+│   │   │   │   │   ├── in_anglvel_x_type
+│   │   │   │   │   ├── in_anglvel_y_en
+│   │   │   │   │   ├── in_anglvel_y_index
+│   │   │   │   │   ├── in_anglvel_y_type
+│   │   │   │   │   ├── in_anglvel_z_en
+│   │   │   │   │   ├── in_anglvel_z_index
+│   │   │   │   │   └── in_anglvel_z_type
+│   │   │   │   ├── trigger
+│   │   │   │   │   └── current_trigger
+...
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index ec8d81417dc8..705fb915cbf7 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1666,6 +1666,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
initrd= [BOOT] Specify the location of the initial ramdisk
+ init_pkru= [x86] Specify the default memory protection keys rights
+ register contents for all processes. 0x55555554 by
+ default (disallow access to all but pkey 0). Can
+ override in debugfs after boot.
+
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
Format: <irq>
diff --git a/Documentation/livepatch/module-elf-format.txt b/Documentation/livepatch/module-elf-format.txt
index eedbdcf8ba50..f21a5289a09c 100644
--- a/Documentation/livepatch/module-elf-format.txt
+++ b/Documentation/livepatch/module-elf-format.txt
@@ -25,7 +25,8 @@ Table of Contents
3.3.2 Required name format
3.3.3 Example livepatch symbol names
3.3.4 Example `readelf --symbols` output
-4. Symbol table and Elf section access
+4. Architecture-specific sections
+5. Symbol table and Elf section access
----------------------------
0. Background and motivation
@@ -46,7 +47,7 @@ architecture.
Since apply_relocate_add() requires access to a module's section header
table, symbol table, and relocation section indices, Elf information is
-preserved for livepatch modules (see section 4). Livepatch manages its own
+preserved for livepatch modules (see section 5). Livepatch manages its own
relocation sections and symbols, which are described in this document. The
Elf constants used to mark livepatch symbols and relocation sections were
selected from OS-specific ranges according to the definitions from glibc.
@@ -117,7 +118,7 @@ also possible for a livepatch module to have no livepatch relocation
sections, as in the case of the sample livepatch module (see
samples/livepatch).
-Since Elf information is preserved for livepatch modules (see Section 4), a
+Since Elf information is preserved for livepatch modules (see Section 5), a
livepatch relocation section can be applied simply by passing in the
appropriate section index to apply_relocate_add(), which then uses it to
access the relocation section and apply the relocations.
@@ -292,8 +293,19 @@ Symbol table '.symtab' contains 127 entries:
[*] Note that the 'Ndx' (Section index) for these symbols is SHN_LIVEPATCH (0xff20).
"OS" means OS-specific.
+---------------------------------
+4. Architecture-specific sections
+---------------------------------
+Architectures may override arch_klp_init_object_loaded() to perform
+additional arch-specific tasks when a target module loads, such as applying
+arch-specific sections. On x86 for example, we must apply per-object
+.altinstructions and .parainstructions sections when a target module loads.
+These sections must be prefixed with ".klp.arch.$objname." so that they can
+be easily identified when iterating through a patch module's Elf sections
+(See arch/x86/kernel/livepatch.c for a complete example).
+
--------------------------------------
-4. Symbol table and Elf section access
+5. Symbol table and Elf section access
--------------------------------------
A livepatch module's symbol table is accessible through module->symtab.
diff --git a/Documentation/perf/xgene-pmu.txt b/Documentation/perf/xgene-pmu.txt
new file mode 100644
index 000000000000..d7cff4454e5b
--- /dev/null
+++ b/Documentation/perf/xgene-pmu.txt
@@ -0,0 +1,48 @@
+APM X-Gene SoC Performance Monitoring Unit (PMU)
+================================================
+
+X-Gene SoC PMU consists of various independent system device PMUs such as
+L3 cache(s), I/O bridge(s), memory controller bridge(s) and memory
+controller(s). These PMU devices are loosely architected to follow the
+same model as the PMU for ARM cores. The PMUs share the same top level
+interrupt and status CSR region.
+
+PMU (perf) driver
+-----------------
+
+The xgene-pmu driver registers several perf PMU drivers. Each of the perf
+driver provides description of its available events and configuration options
+in sysfs, see /sys/devices/<l3cX/iobX/mcbX/mcX>/.
+
+The "format" directory describes format of the config (event ID),
+config1 (agent ID) fields of the perf_event_attr structure. The "events"
+directory provides configuration templates for all supported event types that
+can be used with perf tool. For example, "l3c0/bank-fifo-full/" is an
+equivalent of "l3c0/config=0x0b/".
+
+Most of the SoC PMU has a specific list of agent ID used for monitoring
+performance of a specific datapath. For example, agents of a L3 cache can be
+a specific CPU or an I/O bridge. Each PMU has a set of 2 registers capable of
+masking the agents from which the request come from. If the bit with
+the bit number corresponding to the agent is set, the event is counted only if
+it is caused by a request from that agent. Each agent ID bit is inversely mapped
+to a corresponding bit in "config1" field. By default, the event will be
+counted for all agent requests (config1 = 0x0). For all the supported agents of
+each PMU, please refer to APM X-Gene User Manual.
+
+Each perf driver also provides a "cpumask" sysfs attribute, which contains a
+single CPU ID of the processor which will be used to handle all the PMU events.
+
+Example for perf tool use:
+
+ / # perf list | grep -e l3c -e iob -e mcb -e mc
+ l3c0/ackq-full/ [Kernel PMU event]
+ <...>
+ mcb1/mcb-csw-stall/ [Kernel PMU event]
+
+ / # perf stat -a -e l3c0/read-miss/,mcb1/csw-write-request/ sleep 1
+
+ / # perf stat -a -e l3c0/read-miss,config1=0xfffffffffffffffe/ sleep 1
+
+The driver does not support sampling, therefore "perf record" will
+not work. Per-task (without "-a") perf sessions are not supported.
diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 82dacc06e355..0c72588bd967 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -39,8 +39,8 @@ kind of power supply, and can process/present them to a user in consistent
manner. Results for different power supplies and machines are also directly
comparable.
-See drivers/power/ds2760_battery.c and drivers/power/pda_power.c for the
-example how to declare and handle attributes.
+See drivers/power/supply/ds2760_battery.c and drivers/power/supply/pda_power.c
+for the example how to declare and handle attributes.
Units
diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt
index 4202d1bc583c..6d9a2ed32cad 100644
--- a/Documentation/powerpc/cxlflash.txt
+++ b/Documentation/powerpc/cxlflash.txt
@@ -121,7 +121,7 @@ Block library API
below.
The block library can be found on GitHub:
- http://www.github.com/mikehollinger/ibmcapikv
+ http://github.com/open-power/capiflash
CXL Flash Driver IOCTLs
@@ -171,11 +171,30 @@ DK_CXLFLASH_ATTACH
destroyed, the tokens are to be considered stale and subsequent
usage will result in errors.
+ - A valid adapter file descriptor (fd2 >= 0) is only returned on
+ the initial attach for a context. Subsequent attaches to an
+ existing context (DK_CXLFLASH_ATTACH_REUSE_CONTEXT flag present)
+ do not provide the adapter file descriptor as it was previously
+ made known to the application.
+
- When a context is no longer needed, the user shall detach from
- the context via the DK_CXLFLASH_DETACH ioctl.
+ the context via the DK_CXLFLASH_DETACH ioctl. When this ioctl
+ returns with a valid adapter file descriptor and the return flag
+ DK_CXLFLASH_APP_CLOSE_ADAP_FD is present, the application _must_
+ close the adapter file descriptor following a successful detach.
+
+ - When this ioctl returns with a valid fd2 and the return flag
+ DK_CXLFLASH_APP_CLOSE_ADAP_FD is present, the application _must_
+ close fd2 in the following circumstances:
+
+ + Following a successful detach of the last user of the context
+ + Following a successful recovery on the context's original fd2
+ + In the child process of a fork(), following a clone ioctl,
+ on the fd2 associated with the source context
- - A close on fd2 will invalidate the tokens. This operation is not
- required by the user.
+ - At any time, a close on fd2 will invalidate the tokens. Applications
+ should exercise caution to only close fd2 when appropriate (outlined
+ in the previous bullet) to avoid premature loss of I/O.
DK_CXLFLASH_USER_DIRECT
-----------------------
@@ -254,6 +273,10 @@ DK_CXLFLASH_DETACH
success, all "tokens" which had been provided to the user from the
DK_CXLFLASH_ATTACH onward are no longer valid.
+ When the DK_CXLFLASH_APP_CLOSE_ADAP_FD flag was returned on a successful
+ attach, the application _must_ close the fd2 associated with the context
+ following the detach of the final user of the context.
+
DK_CXLFLASH_VLUN_CLONE
----------------------
This ioctl is responsible for cloning a previously created
@@ -261,7 +284,7 @@ DK_CXLFLASH_VLUN_CLONE
support maintaining user space access to storage after a process
forks. Upon success, the child process (which invoked the ioctl)
will have access to the same LUNs via the same resource handle(s)
- and fd2 as the parent, but under a different context.
+ as the parent, but under a different context.
Context sharing across processes is not supported with CXL and
therefore each fork must be met with establishing a new context
@@ -275,6 +298,12 @@ DK_CXLFLASH_VLUN_CLONE
translation tables are copied from the parent context to the child's
and then synced with the AFU.
+ When the DK_CXLFLASH_APP_CLOSE_ADAP_FD flag was returned on a successful
+ attach, the application _must_ close the fd2 associated with the source
+ context (still resident/accessible in the parent process) following the
+ clone. This is to avoid a stale entry in the file descriptor table of the
+ child process.
+
DK_CXLFLASH_VERIFY
------------------
This ioctl is used to detect various changes such as the capacity of
@@ -309,6 +338,11 @@ DK_CXLFLASH_RECOVER_AFU
at which time the context/resources they held will be freed as part of
the release fop.
+ When the DK_CXLFLASH_APP_CLOSE_ADAP_FD flag was returned on a successful
+ attach, the application _must_ unmap and close the fd2 associated with the
+ original context following this ioctl returning success and indicating that
+ the context was recovered (DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET).
+
DK_CXLFLASH_MANAGE_LUN
----------------------
This ioctl is used to switch a LUN from a mode where it is available
diff --git a/Documentation/powerpc/syscall64-abi.txt b/Documentation/powerpc/syscall64-abi.txt
new file mode 100644
index 000000000000..fa716a0d88bd
--- /dev/null
+++ b/Documentation/powerpc/syscall64-abi.txt
@@ -0,0 +1,105 @@
+===============================================
+Power Architecture 64-bit Linux system call ABI
+===============================================
+
+syscall
+=======
+
+syscall calling sequence[*] matches the Power Architecture 64-bit ELF ABI
+specification C function calling sequence, including register preservation
+rules, with the following differences.
+
+[*] Some syscalls (typically low-level management functions) may have
+ different calling sequences (e.g., rt_sigreturn).
+
+Parameters and return value
+---------------------------
+The system call number is specified in r0.
+
+There is a maximum of 6 integer parameters to a syscall, passed in r3-r8.
+
+Both a return value and a return error code are returned. cr0.SO is the return
+error code, and r3 is the return value or error code. When cr0.SO is clear,
+the syscall succeeded and r3 is the return value. When cr0.SO is set, the
+syscall failed and r3 is the error code that generally corresponds to errno.
+
+Stack
+-----
+System calls do not modify the caller's stack frame. For example, the caller's
+stack frame LR and CR save fields are not used.
+
+Register preservation rules
+---------------------------
+Register preservation rules match the ELF ABI calling sequence with the
+following differences:
+
+r0: Volatile. (System call number.)
+r3: Volatile. (Parameter 1, and return value.)
+r4-r8: Volatile. (Parameters 2-6.)
+cr0: Volatile (cr0.SO is the return error condition)
+cr1, cr5-7: Nonvolatile.
+lr: Nonvolatile.
+
+All floating point and vector data registers as well as control and status
+registers are nonvolatile.
+
+Invocation
+----------
+The syscall is performed with the sc instruction, and returns with execution
+continuing at the instruction following the sc instruction.
+
+Transactional Memory
+--------------------
+Syscall behavior can change if the processor is in transactional or suspended
+transaction state, and the syscall can affect the behavior of the transaction.
+
+If the processor is in suspended state when a syscall is made, the syscall
+will be performed as normal, and will return as normal. The syscall will be
+performed in suspended state, so its side effects will be persistent according
+to the usual transactional memory semantics. A syscall may or may not result
+in the transaction being doomed by hardware.
+
+If the processor is in transactional state when a syscall is made, then the
+behavior depends on the presence of PPC_FEATURE2_HTM_NOSC in the AT_HWCAP2 ELF
+auxiliary vector.
+
+- If present, which is the case for newer kernels, then the syscall will not
+ be performed and the transaction will be doomed by the kernel with the
+ failure code TM_CAUSE_SYSCALL | TM_CAUSE_PERSISTENT in the TEXASR SPR.
+
+- If not present (older kernels), then the kernel will suspend the
+ transactional state and the syscall will proceed as in the case of a
+ suspended state syscall, and will resume the transactional state before
+ returning to the caller. This case is not well defined or supported, so this
+ behavior should not be relied upon.
+
+
+vsyscall
+========
+
+vsyscall calling sequence matches the syscall calling sequence, with the
+following differences. Some vsyscalls may have different calling sequences.
+
+Parameters and return value
+---------------------------
+r0 is not used as an input. The vsyscall is selected by its address.
+
+Stack
+-----
+The vsyscall may or may not use the caller's stack frame save areas.
+
+Register preservation rules
+---------------------------
+r0: Volatile.
+cr1, cr5-7: Volatile.
+lr: Volatile.
+
+Invocation
+----------
+The vsyscall is performed with a branch-with-link instruction to the vsyscall
+function address.
+
+Transactional Memory
+--------------------
+vsyscalls will run in the same transactional state as the caller. A vsyscall
+may or may not result in the transaction being doomed by hardware.
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index ef0219fa4bb4..f07597482351 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -101,9 +101,9 @@ int dummy_rproc_example(struct rproc *my_rproc)
On success, the new rproc is returned, and on failure, NULL.
Note: _never_ directly deallocate @rproc, even if it was not registered
- yet. Instead, when you need to unroll rproc_alloc(), use rproc_put().
+ yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().
- void rproc_put(struct rproc *rproc)
+ void rproc_free(struct rproc *rproc)
- Free an rproc handle that was allocated by rproc_alloc.
This function essentially unrolls rproc_alloc(), by decrementing the
rproc's refcount. It doesn't directly free rproc; that would happen
@@ -131,7 +131,7 @@ int dummy_rproc_example(struct rproc *my_rproc)
has completed successfully.
After rproc_del() returns, @rproc is still valid, and its
- last refcount should be decremented by calling rproc_put().
+ last refcount should be decremented by calling rproc_free().
Returns 0 on success and -EINVAL if @rproc isn't valid.
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index c4b978a72f78..bb4a76f823e1 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -64,8 +64,6 @@ hpsa.txt
- HP Smart Array Controller SCSI driver.
hptiop.txt
- HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
-in2000.txt
- - info on in2000 driver
libsas.txt
- Serial Attached SCSI management layer.
link_power_management_policy.txt
diff --git a/Documentation/scsi/dtc3x80.txt b/Documentation/scsi/dtc3x80.txt
deleted file mode 100644
index 1d7af9f9a8ed..000000000000
--- a/Documentation/scsi/dtc3x80.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-README file for the Linux DTC3180/3280 scsi driver.
-by Ray Van Tassle (rayvt@comm.mot.com) March 1996
-Based on the generic & core NCR5380 code by Drew Eckhard
-
-SCSI device driver for the DTC 3180/3280.
-Data Technology Corp---a division of Qume.
-
-The 3280 has a standard floppy interface.
-
-The 3180 does not. Otherwise, they are identical.
-
-The DTC3x80 does not support DMA but it does have Pseudo-DMA which is
-supported by the driver.
-
-Its DTC406 scsi chip is supposedly compatible with the NCR 53C400.
-It is memory mapped, uses an IRQ, but no dma or io-port. There is
-internal DMA, between SCSI bus and an on-chip 128-byte buffer. Double
-buffering is done automagically by the chip. Data is transferred
-between the on-chip buffer and CPU/RAM via memory moves.
-
-The driver detects the possible memory addresses (jumper selectable):
- CC00, DC00, C800, and D800
-The possible IRQ's (jumper selectable) are:
- IRQ 10, 11, 12, 15
-Parity is supported by the chip, but not by this driver.
-Information can be obtained from /proc/scsi/dtc3c80/N.
-
-Note on interrupts:
-
-The documentation says that it can be set to interrupt whenever the
-on-chip buffer needs CPU attention. I couldn't get this to work. So
-the driver polls for data-ready in the pseudo-DMA transfer routine.
-The interrupt support routines in the NCR3280.c core modules handle
-scsi disconnect/reconnect, and this (mostly) works. However..... I
-have tested it with 4 totally different hard drives (both SCSI-1 and
-SCSI-2), and one CDROM drive. Interrupts works great for all but one
-specific hard drive. For this one, the driver will eventually hang in
-the transfer state. I have tested with: "dd bs=4k count=2k
-of=/dev/null if=/dev/sdb". It reads ok for a while, then hangs.
-After beating my head against this for a couple of weeks, getting
-nowhere, I give up. So.....This driver does NOT use interrupts, even
-if you have the card jumpered to an IRQ. Probably nobody will ever
-care.
diff --git a/Documentation/scsi/in2000.txt b/Documentation/scsi/in2000.txt
deleted file mode 100644
index c3e2a90475d2..000000000000
--- a/Documentation/scsi/in2000.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
-UPDATE NEWS: version 1.33 - 26 Aug 98
-
- Interrupt management in this driver has become, over
- time, increasingly odd and difficult to explain - this
- has been mostly due to my own mental inadequacies. In
- recent kernels, it has failed to function at all when
- compiled for SMP. I've fixed that problem, and after
- taking a fresh look at interrupts in general, greatly
- reduced the number of places where they're fiddled
- with. Done some heavy testing and it looks very good.
- The driver now makes use of the __initfunc() and
- __initdata macros to save about 4k of kernel memory.
- Once again, the same code works for both 2.0.xx and
- 2.1.xx kernels.
-
-UPDATE NEWS: version 1.32 - 28 Mar 98
-
- Removed the check for legal IN2000 hardware versions:
- It appears that the driver works fine with serial
- EPROMs (the 8-pin chip that defines hardware rev) as
- old as 2.1, so we'll assume that all cards are OK.
-
-UPDATE NEWS: version 1.31 - 6 Jul 97
-
- Fixed a bug that caused incorrect SCSI status bytes to be
- returned from commands sent to LUNs greater than 0. This
- means that CDROM changers work now! Fixed a bug in the
- handling of command-line arguments when loaded as a module.
- Also put all the header data in in2000.h where it belongs.
- There are no longer any differences between this driver in
- the 2.1.xx source tree and the 2.0.xx tree, as of 2.0.31
- and 2.1.45 (or is it .46?) - this makes things much easier
- for me...
-
-UPDATE NEWS: version 1.30 - 14 Oct 96
-
- Fixed a bug in the code that sets the transfer direction
- bit (DESTID_DPD in the WD_DESTINATION_ID register). There
- are quite a few SCSI commands that do a write-to-device;
- now we deal with all of them correctly. Thanks to Joerg
- Dorchain for catching this one.
-
-UPDATE NEWS: version 1.29 - 24 Sep 96
-
- The memory-mapped hardware on the card is now accessed via
- the 'readb()' and 'readl()' macros - required by the new
- memory management scheme in the 2.1.x kernel series.
- As suggested by Andries Brouwer, 'bios_param()' no longer
- forces an artificial 1023 track limit on drives. Also
- removed some kludge-code left over from struggles with
- older (buggy) compilers.
-
-UPDATE NEWS: version 1.28 - 07 May 96
-
- Tightened up the "interrupts enabled/disabled" discipline
- in 'in2000_queuecommand()' and maybe 1 or 2 other places.
- I _think_ it may have been a little too lax, causing an
- occasional crash during full moon. A fully functional
- /proc interface is now in place - if you want to play
- with it, start by doing 'cat /proc/scsi/in2000/0'. You
- can also use it to change a few run-time parameters on
- the fly, but it's mostly for debugging. The curious
- should take a good look at 'in2000_proc_info()' in the
- in2000.c file to get an understanding of what it's all
- about; I figure that people who are really into it will
- want to add features suited to their own needs...
- Also, sync is now DISABLED by default.
-
-UPDATE NEWS: version 1.27 - 10 Apr 96
-
- Fixed a well-hidden bug in the adaptive-disconnect code
- that would show up every now and then during extreme
- heavy loads involving 2 or more simultaneously active
- devices. Thanks to Joe Mack for keeping my nose to the
- grindstone on this one.
-
-UPDATE NEWS: version 1.26 - 07 Mar 96
-
- 1.25 had a nasty bug that bit people with swap partitions
- and tape drives. Also, in my attempt to guess my way
- through Intel assembly language, I made an error in the
- inline code for IO writes. Made a few other changes and
- repairs - this version (fingers crossed) should work well.
-
-UPDATE NEWS: version 1.25 - 05 Mar 96
-
- Kernel 1.3.70 interrupt mods added; old kernels still OK.
- Big help from Bill Earnest and David Willmore on speed
- testing and optimizing: I think there's a real improvement
- in this area.
- New! User-friendly command-line interface for LILO and
- module loading - the old method is gone, so you'll need
- to read the comments for 'setup_strings' near the top
- of in2000.c. For people with CDROM's or other devices
- that have a tough time with sync negotiation, you can
- now selectively disable sync on individual devices -
- search for the 'nosync' keyword in the command-line
- comments. Some of you disable the BIOS on the card, which
- caused the auto-detect function to fail; there is now a
- command-line option to force detection of a ROM-less card.
-
-UPDATE NEWS: version 1.24a - 24 Feb 96
-
- There was a bug in the synchronous transfer code. Only
- a few people downloaded before I caught it - could have
- been worse.
-
-UPDATE NEWS: version 1.24 - 23 Feb 96
-
- Lots of good changes. Advice from Bill Earnest resulted
- in much better detection of cards, more efficient usage
- of the fifo, and (hopefully) faster data transfers. The
- jury is still out on speed - I hope it's improved some.
- One nifty new feature is a cool way of doing disconnect/
- reselect. The driver defaults to what I'm calling
- 'adaptive disconnect' - meaning that each command is
- evaluated individually as to whether or not it should be
- run with the option to disconnect/reselect (if the device
- chooses), or as a "SCSI-bus-hog". When several devices
- are operating simultaneously, disconnects are usually an
- advantage. In a single device system, or if only 1 device
- is being accessed, transfers usually go faster if disconnects
- are not allowed.
-
-
-
-The default arguments (you get these when you don't give an 'in2000'
-command-line argument, or you give a blank argument) will cause
-the driver to do adaptive disconnect, synchronous transfers, and a
-minimum of debug messages. If you want to fool with the options,
-search for 'setup_strings' near the top of the in2000.c file and
-check the 'hostdata->args' section in in2000.h - but be warned! Not
-everything is working yet (some things will never work, probably).
-I believe that disabling disconnects (DIS_NEVER) will allow you
-to choose a LEVEL2 value higher than 'L2_BASIC', but I haven't
-spent a lot of time testing this. You might try 'ENABLE_CLUSTERING'
-to see what happens: my tests showed little difference either way.
-There's also a define called 'DEFAULT_SX_PER'; this sets the data
-transfer speed for the asynchronous mode. I've put it at 500 ns
-despite the fact that the card could handle settings of 376 or
-252, because higher speeds may be a problem with poor quality
-cables or improper termination; 500 ns is a compromise. You can
-choose your own default through the command-line with the
-'period' keyword.
-
-
-------------------------------------------------
-*********** DIP switch settings **************
-------------------------------------------------
-
- sw1-1 sw1-2 BIOS address (hex)
- -----------------------------------------
- off off C8000 - CBFF0
- on off D8000 - DBFF0
- off on D0000 - D3FF0
- on on BIOS disabled
-
- sw1-3 sw1-4 IO port address (hex)
- ------------------------------------
- off off 220 - 22F
- on off 200 - 20F
- off on 110 - 11F
- on on 100 - 10F
-
- sw1-5 sw1-6 sw1-7 Interrupt
- ------------------------------
- off off off 15
- off on off 14
- off off on 11
- off on on 10
- on - - disabled
-
- sw1-8 function depends on BIOS version. In earlier versions this
- controlled synchronous data transfer support for MSDOS:
- off = disabled
- on = enabled
- In later ROMs (starting with 01.3 in April 1994) sw1-8 controls
- the "greater than 2 disk drive" feature that first appeared in
- MSDOS 5.0 (ignored by Linux):
- off = 2 drives maximum
- on = 7 drives maximum
-
- sw1-9 Floppy controller
- --------------------------
- off disabled
- on enabled
-
-------------------------------------------------
-
- I should mention that Drew Eckhardt's 'Generic NCR5380' sources
- were my main inspiration, with lots of reference to the IN2000
- driver currently distributed in the kernel source. I also owe
- much to a driver written by Hamish Macdonald for Linux-m68k(!).
- And to Eric Wright for being an ALPHA guinea pig. And to Bill
- Earnest for 2 tons of great input and information. And to David
- Willmore for extensive 'bonnie' testing. And to Joe Mack for
- continual testing and feedback.
-
-
- John Shifflett jshiffle@netcom.com
-
diff --git a/Documentation/scsi/scsi-parameters.txt b/Documentation/scsi/scsi-parameters.txt
index d5ae6ced6be3..8e66dafa41e1 100644
--- a/Documentation/scsi/scsi-parameters.txt
+++ b/Documentation/scsi/scsi-parameters.txt
@@ -34,9 +34,6 @@ parameters may be changed at runtime by the command
See drivers/scsi/BusLogic.c, comment before function
BusLogic_ParseDriverOptions().
- dtc3181e= [HW,SCSI]
- See Documentation/scsi/g_NCR5380.txt.
-
eata= [HW,SCSI]
fdomain= [HW,SCSI]
@@ -47,9 +44,6 @@ parameters may be changed at runtime by the command
gvp11= [HW,SCSI]
- in2000= [HW,SCSI]
- See header of drivers/scsi/in2000.c.
-
ips= [HW,SCSI] Adaptec / IBM ServeRAID controller
See header of drivers/scsi/ips.c.
@@ -83,9 +77,6 @@ parameters may be changed at runtime by the command
Format: <buffer_size>,<write_threshold>
See also Documentation/scsi/st.txt.
- pas16= [HW,SCSI]
- See header of drivers/scsi/pas16.c.
-
scsi_debug_*= [SCSI]
See drivers/scsi/scsi_debug.c.
@@ -119,18 +110,9 @@ parameters may be changed at runtime by the command
sym53c416= [HW,SCSI]
See header of drivers/scsi/sym53c416.c.
- t128= [HW,SCSI]
- See header of drivers/scsi/t128.c.
-
tmscsim= [HW,SCSI]
See comment before function dc390_setup() in
drivers/scsi/tmscsim.c.
- u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter
- See header of drivers/scsi/u14-34f.c.
-
wd33c93= [HW,SCSI]
See header of drivers/scsi/wd33c93.c.
-
- wd7000= [HW,SCSI]
- See header of drivers/scsi/wd7000.c.
diff --git a/Documentation/scsi/smartpqi.txt b/Documentation/scsi/smartpqi.txt
new file mode 100644
index 000000000000..ab377d9e5d1b
--- /dev/null
+++ b/Documentation/scsi/smartpqi.txt
@@ -0,0 +1,80 @@
+
+SMARTPQI - Microsemi Smart PQI Driver
+-----------------------------------------
+
+This file describes the smartpqi SCSI driver for Microsemi
+(http://www.microsemi.com) PQI controllers. The smartpqi driver
+is the next generation SCSI driver for Microsemi Corp. The smartpqi
+driver is the first SCSI driver to implement the PQI queuing model.
+
+The smartpqi driver will replace the aacraid driver for Adaptec Series 9
+controllers. Customers running an older kernel (Pre-4.9) using an Adaptec
+Series 9 controller will have to configure the smartpqi driver or their
+volumes will not be added to the OS.
+
+For Microsemi smartpqi controller support, enable the smartpqi driver
+when configuring the kernel.
+
+For more information on the PQI Queuing Interface, please see:
+http://www.t10.org/drafts.htm
+http://www.t10.org/members/w_pqi2.htm
+
+Supported devices:
+------------------
+<Controller names to be added as they become publically available.>
+
+smartpqi specific entries in /sys
+-----------------------------
+
+ smartpqi host attributes:
+ -------------------------
+ /sys/class/scsi_host/host*/rescan
+ /sys/class/scsi_host/host*/version
+
+ The host rescan attribute is a write only attribute. Writing to this
+ attribute will trigger the driver to scan for new, changed, or removed
+ devices and notify the SCSI mid-layer of any changes detected.
+
+ The version attribute is read-only and will return the driver version
+ and the controller firmware version.
+ For example:
+ driver: 0.9.13-370
+ firmware: 0.01-522
+
+ smartpqi sas device attributes
+ ------------------------------
+ HBA devices are added to the SAS transport layer. These attributes are
+ automatically added by the SAS transport layer.
+
+ /sys/class/sas_device/end_device-X:X/sas_address
+ /sys/class/sas_device/end_device-X:X/enclosure_identifier
+ /sys/class/sas_device/end_device-X:X/scsi_target_id
+
+smartpqi specific ioctls:
+-------------------------
+
+ For compatibility with applications written for the cciss protocol.
+
+ CCISS_DEREGDISK
+ CCISS_REGNEWDISK
+ CCISS_REGNEWD
+
+ The above three ioctls all do exactly the same thing, which is to cause the driver
+ to rescan for new devices. This does exactly the same thing as writing to the
+ smartpqi specific host "rescan" attribute.
+
+ CCISS_GETPCIINFO
+
+ Returns PCI domain, bus, device and function and "board ID" (PCI subsystem ID).
+
+ CCISS_GETDRIVVER
+
+ Returns driver version in three bytes encoded as:
+ (DRIVER_MAJOR << 28) | (DRIVER_MINOR << 24) | (DRIVER_RELEASE << 16) | DRIVER_REVISION;
+
+ CCISS_PASSTHRU
+
+ Allows "BMIC" and "CISS" commands to be passed through to the Smart Storage Array.
+ These are used extensively by the SSA Array Configuration Utility, SNMP storage
+ agents, etc.
+
diff --git a/Documentation/x86/protection-keys.txt b/Documentation/x86/protection-keys.txt
index c281ded1ba16..b64304540821 100644
--- a/Documentation/x86/protection-keys.txt
+++ b/Documentation/x86/protection-keys.txt
@@ -18,10 +18,68 @@ even though there is theoretically space in the PAE PTEs. These
permissions are enforced on data access only and have no effect on
instruction fetches.
-=========================== Config Option ===========================
+=========================== Syscalls ===========================
-This config option adds approximately 1.5kb of text. and 50 bytes of
-data to the executable. A workload which does large O_DIRECT reads
-of holes in XFS files was run to exercise get_user_pages_fast(). No
-performance delta was observed with the config option
-enabled or disabled.
+There are 3 system calls which directly interact with pkeys:
+
+ int pkey_alloc(unsigned long flags, unsigned long init_access_rights)
+ int pkey_free(int pkey);
+ int pkey_mprotect(unsigned long start, size_t len,
+ unsigned long prot, int pkey);
+
+Before a pkey can be used, it must first be allocated with
+pkey_alloc(). An application calls the WRPKRU instruction
+directly in order to change access permissions to memory covered
+with a key. In this example WRPKRU is wrapped by a C function
+called pkey_set().
+
+ int real_prot = PROT_READ|PROT_WRITE;
+ pkey = pkey_alloc(0, PKEY_DENY_WRITE);
+ ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey);
+ ... application runs here
+
+Now, if the application needs to update the data at 'ptr', it can
+gain access, do the update, then remove its write access:
+
+ pkey_set(pkey, 0); // clear PKEY_DENY_WRITE
+ *ptr = foo; // assign something
+ pkey_set(pkey, PKEY_DENY_WRITE); // set PKEY_DENY_WRITE again
+
+Now when it frees the memory, it will also free the pkey since it
+is no longer in use:
+
+ munmap(ptr, PAGE_SIZE);
+ pkey_free(pkey);
+
+(Note: pkey_set() is a wrapper for the RDPKRU and WRPKRU instructions.
+ An example implementation can be found in
+ tools/testing/selftests/x86/protection_keys.c)
+
+=========================== Behavior ===========================
+
+The kernel attempts to make protection keys consistent with the
+behavior of a plain mprotect(). For instance if you do this:
+
+ mprotect(ptr, size, PROT_NONE);
+ something(ptr);
+
+you can expect the same effects with protection keys when doing this:
+
+ pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);
+ pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey);
+ something(ptr);
+
+That should be true whether something() is a direct access to 'ptr'
+like:
+
+ *ptr = foo;
+
+or when the kernel does the access on the application's behalf like
+with a read():
+
+ read(fd, ptr, 1);
+
+The kernel will send a SIGSEGV in both cases, but si_code will be set
+to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when
+the plain mprotect() permissions are violated.
diff --git a/MAINTAINERS b/MAINTAINERS
index 274d2a020a1a..8b58a86988aa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -866,6 +866,13 @@ F: drivers/net/phy/mdio-xgene.c
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
+APPLIED MICRO (APM) X-GENE SOC PMU
+M: Tai Nguyen <ttnguyen@apm.com>
+S: Supported
+F: drivers/perf/xgene_pmu.c
+F: Documentation/perf/xgene-pmu.txt
+F: Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
+
APTINA CAMERA SENSOR PLL
M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
@@ -1003,6 +1010,7 @@ M: Chen-Yu Tsai <wens@csie.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
N: sun[x456789]i
+F: arch/arm/boot/dts/ntc-gr8*
ARM/Allwinner SoC Clock Support
M: Emilio López <emilio@elopez.com.ar>
@@ -1459,6 +1467,7 @@ F: arch/arm/mach-orion5x/ts78xx-*
ARM/OXNAS platform support
M: Neil Armstrong <narmstrong@baylibre.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-oxnas@lists.tuxfamily.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-oxnas/
F: arch/arm/boot/dts/oxnas*
@@ -1859,6 +1868,7 @@ F: drivers/bus/uniphier-system-bus.c
F: drivers/clk/uniphier/
F: drivers/i2c/busses/i2c-uniphier*
F: drivers/pinctrl/uniphier/
+F: drivers/reset/reset-uniphier.c
F: drivers/tty/serial/8250/8250_uniphier.c
N: uniphier
@@ -2472,6 +2482,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
S: Maintained
F: block/
F: kernel/trace/blktrace.c
+F: lib/sbitmap.c
BLOCK2MTD DRIVER
M: Joern Engel <joern@lazybastard.org>
@@ -2595,6 +2606,13 @@ F: arch/arm/mach-bcm/bcm_5301x.c
F: arch/arm/boot/dts/bcm5301x*.dtsi
F: arch/arm/boot/dts/bcm470*
+BROADCOM BCM53573 ARM ARCHITECTURE
+M: Rafał Miłecki <rafal@milecki.pl>
+L: linux-arm-kernel@lists.infradead.org
+S: Maintained
+F: arch/arm/boot/dts/bcm53573*
+F: arch/arm/boot/dts/bcm47189*
+
BROADCOM BCM63XX ARM ARCHITECTURE
M: Florian Fainelli <f.fainelli@gmail.com>
M: bcm-kernel-feedback-list@broadcom.com
@@ -2908,6 +2926,14 @@ S: Maintained
F: drivers/iio/light/cm*
F: Documentation/devicetree/bindings/i2c/trivial-devices.txt
+CAVIUM I2C DRIVER
+M: Jan Glauber <jglauber@cavium.com>
+M: David Daney <david.daney@cavium.com>
+W: http://www.cavium.com
+S: Supported
+F: drivers/i2c/busses/i2c-octeon*
+F: drivers/i2c/busses/i2c-thunderx*
+
CAVIUM LIQUIDIO NETWORK DRIVER
M: Derek Chickles <derek.chickles@caviumnetworks.com>
M: Satanand Burla <satananda.burla@caviumnetworks.com>
@@ -3483,6 +3509,7 @@ L: linux-rdma@vger.kernel.org
W: http://www.openfabrics.org
S: Supported
F: drivers/infiniband/hw/cxgb3/
+F: include/uapi/rdma/cxgb3-abi.h
CXGB4 ETHERNET DRIVER (CXGB4)
M: Hariprasad S <hariprasad@chelsio.com>
@@ -3504,6 +3531,7 @@ L: linux-rdma@vger.kernel.org
W: http://www.openfabrics.org
S: Supported
F: drivers/infiniband/hw/cxgb4/
+F: include/uapi/rdma/cxgb4-abi.h
CXGB4VF ETHERNET DRIVER (CXGB4VF)
M: Casey Leedom <leedom@chelsio.com>
@@ -3514,14 +3542,14 @@ F: drivers/net/ethernet/chelsio/cxgb4vf/
CXL (IBM Coherent Accelerator Processor Interface CAPI) DRIVER
M: Ian Munsie <imunsie@au1.ibm.com>
-M: Michael Neuling <mikey@neuling.org>
+M: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
L: linuxppc-dev@lists.ozlabs.org
S: Supported
+F: arch/powerpc/platforms/powernv/pci-cxl.c
F: drivers/misc/cxl/
F: include/misc/cxl*
F: include/uapi/misc/cxl.h
F: Documentation/powerpc/cxl.txt
-F: Documentation/powerpc/cxl.txt
F: Documentation/ABI/testing/sysfs-class-cxl
CXLFLASH (IBM Coherent Accelerator Processor Interface CAPI Flash) SCSI DRIVER
@@ -3784,8 +3812,8 @@ F: drivers/leds/leds-da90??.c
F: drivers/mfd/da903x.c
F: drivers/mfd/da90??-*.c
F: drivers/mfd/da91??-*.c
-F: drivers/power/da9052-battery.c
-F: drivers/power/da91??-*.c
+F: drivers/power/supply/da9052-battery.c
+F: drivers/power/supply/da91??-*.c
F: drivers/regulator/da903x.c
F: drivers/regulator/da9???-regulator.[ch]
F: drivers/rtc/rtc-da90??.c
@@ -5693,6 +5721,14 @@ S: Maintained
F: drivers/net/ethernet/hisilicon/
F: Documentation/devicetree/bindings/net/hisilicon*.txt
+HISILICON ROCE DRIVER
+M: Lijun Ou <oulijun@huawei.com>
+M: Wei Hu(Xavier) <xavier.huwei@huawei.com>
+L: linux-rdma@vger.kernel.org
+S: Maintained
+F: drivers/infiniband/hw/hns/
+F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
+
HISILICON SAS Controller
M: John Garry <john.garry@huawei.com>
W: http://www.hisilicon.com
@@ -5795,6 +5831,8 @@ S: Maintained
F: Documentation/i2c/i2c-topology
F: Documentation/i2c/muxes/
F: Documentation/devicetree/bindings/i2c/i2c-mux*
+F: Documentation/devicetree/bindings/i2c/i2c-arb*
+F: Documentation/devicetree/bindings/i2c/i2c-gate*
F: drivers/i2c/i2c-mux.c
F: drivers/i2c/muxes/
F: include/linux/i2c-mux.h
@@ -6111,6 +6149,12 @@ M: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
S: Maintained
F: drivers/dma/dma-jz4780.c
+INGENIC JZ4780 NAND DRIVER
+M: Harvey Hunt <harveyhuntnexus@gmail.com>
+L: linux-mtd@lists.infradead.org
+S: Maintained
+F: drivers/mtd/nand/jz4780_*
+
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
@@ -6212,6 +6256,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
S: Supported
F: drivers/idle/intel_idle.c
+INTEL INTEGRATED SENSOR HUB DRIVER
+M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+M: Jiri Kosina <jikos@kernel.org>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: drivers/hid/intel-ish-hid/
+
INTEL PSTATE DRIVER
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
M: Len Brown <lenb@kernel.org>
@@ -7586,8 +7637,8 @@ M: Krzysztof Kozlowski <krzk@kernel.org>
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-pm@vger.kernel.org
S: Supported
-F: drivers/power/max14577_charger.c
-F: drivers/power/max77693_charger.c
+F: drivers/power/supply/max14577_charger.c
+F: drivers/power/supply/max77693_charger.c
MAXIM MAX77802 MULTIFUNCTION PMIC DEVICE DRIVERS
M: Javier Martinez Canillas <javier@osg.samsung.com>
@@ -7942,6 +7993,7 @@ Q: http://patchwork.ozlabs.org/project/netdev/list/
S: Supported
F: drivers/net/ethernet/mellanox/mlx4/
F: include/linux/mlx4/
+F: include/uapi/rdma/mlx4-abi.h
MELLANOX MLX4 IB driver
M: Yishai Hadas <yishaih@mellanox.com>
@@ -7962,6 +8014,7 @@ Q: http://patchwork.ozlabs.org/project/netdev/list/
S: Supported
F: drivers/net/ethernet/mellanox/mlx5/core/
F: include/linux/mlx5/
+F: include/uapi/rdma/mlx5-abi.h
MELLANOX MLX5 IB driver
M: Matan Barak <matanb@mellanox.com>
@@ -7980,6 +8033,18 @@ W: http://www.melexis.com
S: Supported
F: drivers/iio/temperature/mlx90614.c
+MICROSEMI SMART ARRAY SMARTPQI DRIVER (smartpqi)
+M: Don Brace <don.brace@microsemi.com>
+L: esc.storagedev@microsemi.com
+L: linux-scsi@vger.kernel.org
+S: Supported
+F: drivers/scsi/smartpqi/smartpqi*.[ch]
+F: drivers/scsi/smartpqi/Kconfig
+F: drivers/scsi/smartpqi/Makefile
+F: include/linux/cciss*.h
+F: include/uapi/linux/cciss*.h
+F: Documentation/scsi/smartpqi.txt
+
MN88472 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
@@ -8105,6 +8170,7 @@ MULTIFUNCTION DEVICES (MFD)
M: Lee Jones <lee.jones@linaro.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
S: Supported
+F: Documentation/devicetree/bindings/mfd/
F: drivers/mfd/
F: include/linux/mfd/
@@ -8191,20 +8257,16 @@ M: Michael Schmitz <schmitzmic@gmail.com>
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/scsi/g_NCR5380.txt
-F: Documentation/scsi/dtc3x80.txt
F: drivers/scsi/NCR5380.*
F: drivers/scsi/arm/cumana_1.c
F: drivers/scsi/arm/oak.c
F: drivers/scsi/atari_scsi.*
F: drivers/scsi/dmx3191d.c
-F: drivers/scsi/dtc.*
F: drivers/scsi/g_NCR5380.*
F: drivers/scsi/g_NCR5380_mmio.c
F: drivers/scsi/mac_scsi.*
-F: drivers/scsi/pas16.*
F: drivers/scsi/sun3_scsi.*
F: drivers/scsi/sun3_scsi_vme.c
-F: drivers/scsi/t128.*
NCR DUAL 700 SCSI DRIVER (MICROCHANNEL)
M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
@@ -8225,6 +8287,7 @@ L: linux-rdma@vger.kernel.org
W: http://www.intel.com/Products/Server/Adapters/Server-Cluster/Server-Cluster-overview.htm
S: Supported
F: drivers/infiniband/hw/nes/
+F: include/uapi/rdma/nes-abi.h
NETEM NETWORK EMULATOR
M: Stephen Hemminger <stephen@networkplumber.org>
@@ -8493,11 +8556,11 @@ R: Pali Rohár <pali.rohar@gmail.com>
F: include/linux/power/bq2415x_charger.h
F: include/linux/power/bq27xxx_battery.h
F: include/linux/power/isp1704_charger.h
-F: drivers/power/bq2415x_charger.c
-F: drivers/power/bq27xxx_battery.c
-F: drivers/power/bq27xxx_battery_i2c.c
-F: drivers/power/isp1704_charger.c
-F: drivers/power/rx51_battery.c
+F: drivers/power/supply/bq2415x_charger.c
+F: drivers/power/supply/bq27xxx_battery.c
+F: drivers/power/supply/bq27xxx_battery_i2c.c
+F: drivers/power/supply/isp1704_charger.c
+F: drivers/power/supply/rx51_battery.c
NTB DRIVER CORE
M: Jon Mason <jdmason@kudzu.us>
@@ -9254,6 +9317,15 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
F: drivers/pci/host/pcie-hisi.c
+PCIE DRIVER FOR ROCKCHIP
+M: Shawn Lin <shawn.lin@rock-chips.com>
+M: Wenrui Li <wenrui.li@rock-chips.com>
+L: linux-pci@vger.kernel.org
+L: linux-rockchip@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/pci/rockchip-pcie.txt
+F: drivers/pci/host/pcie-rockchip.c
+
PCIE DRIVER FOR QUALCOMM MSM
M: Stanimir Varbanov <svarbanov@mm-sol.com>
L: linux-pci@vger.kernel.org
@@ -9407,6 +9479,8 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/pinctrl/samsung/
+F: include/dt-bindings/pinctrl/samsung.h
+F: Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
PIN CONTROLLER - SINGLE
M: Tony Lindgren <tony@atomide.com>
@@ -9497,16 +9571,12 @@ F: drivers/powercap/
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
M: Sebastian Reichel <sre@kernel.org>
-M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-M: David Woodhouse <dwmw2@infradead.org>
L: linux-pm@vger.kernel.org
-T: git git://git.infradead.org/battery-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
S: Maintained
-F: Documentation/devicetree/bindings/power/
-F: Documentation/devicetree/bindings/power_supply/
+F: Documentation/devicetree/bindings/power/supply/
F: include/linux/power_supply.h
-F: drivers/power/
-X: drivers/power/avs/
+F: drivers/power/supply/
POWER STATE COORDINATION INTERFACE (PSCI)
M: Mark Rutland <mark.rutland@arm.com>
@@ -10521,8 +10591,8 @@ F: drivers/thunderbolt/
TI BQ27XXX POWER SUPPLY DRIVER
R: Andrew F. Davis <afd@ti.com>
F: include/linux/power/bq27xxx_battery.h
-F: drivers/power/bq27xxx_battery.c
-F: drivers/power/bq27xxx_battery_i2c.c
+F: drivers/power/supply/bq27xxx_battery.c
+F: drivers/power/supply/bq27xxx_battery_i2c.c
TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
M: John Stultz <john.stultz@linaro.org>
@@ -10750,12 +10820,12 @@ S: Maintained
F: drivers/misc/phantom.c
F: include/uapi/linux/phantom.h
-SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
-M: Jayamohan Kallickal <jayamohan.kallickal@avagotech.com>
-M: Ketan Mukadam <ketan.mukadam@avagotech.com>
-M: John Soni Jose <sony.john@avagotech.com>
+Emulex 10Gbps iSCSI - OneConnect DRIVER
+M: Subbu Seetharaman <subbu.seetharaman@broadcom.com>
+M: Ketan Mukadam <ketan.mukadam@broadcom.com>
+M: Jitendra Bhivare <jitendra.bhivare@broadcom.com>
L: linux-scsi@vger.kernel.org
-W: http://www.avagotech.com
+W: http://www.broadcom.com
S: Supported
F: drivers/scsi/be2iscsi/
@@ -10777,6 +10847,7 @@ L: linux-rdma@vger.kernel.org
W: http://www.emulex.com
S: Supported
F: drivers/infiniband/hw/ocrdma/
+F: include/uapi/rdma/ocrdma-abi.h
SFC NETWORK DRIVER
M: Solarflare linux maintainers <linux-net-drivers@solarflare.com>
@@ -11519,6 +11590,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
S: Supported
F: drivers/mfd/syscon.c
+SYSTEM RESET/SHUTDOWN DRIVERS
+M: Sebastian Reichel <sre@kernel.org>
+L: linux-pm@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
+S: Maintained
+F: Documentation/devicetree/bindings/power/reset/
+F: drivers/power/reset/
+
SYSV FILESYSTEM
M: Christoph Hellwig <hch@infradead.org>
S: Maintained
@@ -11867,7 +11946,7 @@ F: include/linux/platform_data/lp855x.h
TI LP8727 CHARGER DRIVER
M: Milo Kim <milo.kim@ti.com>
S: Maintained
-F: drivers/power/lp8727_charger.c
+F: drivers/power/supply/lp8727_charger.c
F: include/linux/platform_data/lp8727.h
TI LP8788 MFD DRIVER
@@ -11876,7 +11955,7 @@ S: Maintained
F: drivers/iio/adc/lp8788_adc.c
F: drivers/leds/leds-lp8788.c
F: drivers/mfd/lp8788*.c
-F: drivers/power/lp8788-charger.c
+F: drivers/power/supply/lp8788-charger.c
F: drivers/regulator/lp8788-*.c
F: include/linux/mfd/lp8788*.h
@@ -12145,12 +12224,6 @@ S: Maintained
F: drivers/tc/
F: include/linux/tc.h
-U14-34F SCSI DRIVER
-M: Dario Ballabio <ballabio_dario@emc.com>
-L: linux-scsi@vger.kernel.org
-S: Maintained
-F: drivers/scsi/u14-34f.c
-
UBI FILE SYSTEM (UBIFS)
M: Richard Weinberger <richard@nod.at>
M: Artem Bityutskiy <dedekind1@gmail.com>
@@ -12878,12 +12951,6 @@ F: drivers/watchdog/
F: include/linux/watchdog.h
F: include/uapi/linux/watchdog.h
-WD7000 SCSI DRIVER
-M: Miroslav Zagorac <zaga@fly.cc.fer.hr>
-L: linux-scsi@vger.kernel.org
-S: Maintained
-F: drivers/scsi/wd7000.c
-
WIIMOTE HID DRIVER
M: David Herrmann <dh.herrmann@googlemail.com>
L: linux-input@vger.kernel.org
@@ -12953,7 +13020,7 @@ F: drivers/input/touchscreen/wm97*.c
F: drivers/mfd/arizona*
F: drivers/mfd/wm*.c
F: drivers/mfd/cs47l24*
-F: drivers/power/wm83*.c
+F: drivers/power/supply/wm83*.c
F: drivers/rtc/rtc-wm83*.c
F: drivers/regulator/wm8*.c
F: drivers/video/backlight/wm83*_bl.c
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 7f312d80b43b..0e49d39ea74a 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -15,7 +15,6 @@ config ALPHA
select GENERIC_IRQ_SHOW
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_HAVE_NMI_SAFE_CMPXCHG
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select AUDIT_ARCH
select GENERIC_CLOCKEVENTS
select GENERIC_SMP_IDLE_THREAD
diff --git a/arch/alpha/include/uapi/asm/mman.h b/arch/alpha/include/uapi/asm/mman.h
index fec1947b8dbc..02760f6e6ca4 100644
--- a/arch/alpha/include/uapi/asm/mman.h
+++ b/arch/alpha/include/uapi/asm/mman.h
@@ -78,4 +78,9 @@
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
#endif /* __ALPHA_MMAN_H__ */
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 647b84c15382..cebecfb76fbf 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -22,6 +22,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index 0b10ef2a4372..c332604606dd 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -25,6 +25,7 @@ generic-y += mcs_spinlock.h
generic-y += mm-arch-hooks.h
generic-y += mman.h
generic-y += msgbuf.h
+generic-y += msi.h
generic-y += param.h
generic-y += parport.h
generic-y += pci.h
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index 36611072305f..f35ed578e007 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -89,6 +89,7 @@ SECTIONS
_text = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.fixup)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3cd9042fbb62..b5d529fdffab 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2,7 +2,6 @@ config ARM
bool
default y
select ARCH_CLOCKSOURCE_DATA
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
@@ -279,10 +278,9 @@ config PHYS_OFFSET
ARCH_INTEGRATOR || \
ARCH_IOP13XX || \
ARCH_KS8695 || \
- (ARCH_REALVIEW && !REALVIEW_HIGH_PHYS_OFFSET)
+ ARCH_REALVIEW
default 0x10000000 if ARCH_OMAP1 || ARCH_RPC
default 0x20000000 if ARCH_S5PV210
- default 0x70000000 if REALVIEW_HIGH_PHYS_OFFSET
default 0xc0000000 if ARCH_SA1100
help
Please provide the physical address corresponding to the
@@ -338,6 +336,7 @@ config ARCH_MULTIPLATFORM
select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_PCI
select MULTI_IRQ_HANDLER
+ select PCI_DOMAINS if PCI
select SPARSE_IRQ
select USE_OF
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index a9693b6987a6..d83f7c369e51 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -186,10 +186,11 @@ choice
config DEBUG_BRCMSTB_UART
bool "Use BRCMSTB UART for low-level debug"
depends on ARCH_BRCMSTB
- select DEBUG_UART_8250
help
Say Y here if you want the debug print routines to direct
- their output to the first serial port on these devices.
+ their output to the first serial port on these devices. The
+ UART physical and virtual address is automatically provided
+ based on the chip identification register value.
If you have a Broadcom STB chip and would like early print
messages to appear over the UART, select this option.
@@ -861,12 +862,12 @@ choice
via SCIF2 on Renesas R-Car H1 (R8A7779).
config DEBUG_RCAR_GEN2_SCIF0
- bool "Kernel low-level debugging messages via SCIF0 on R8A7790/R8A7791/R8A7793"
- depends on ARCH_R8A7790 || ARCH_R8A7791 || ARCH_R8A7793
+ bool "Kernel low-level debugging messages via SCIF0 on R8A7790/R8A7791/R8A7792/R8A7793"
+ depends on ARCH_R8A7790 || ARCH_R8A7791 || ARCH_R8A7792 || ARCH_R8A7793
help
Say Y here if you want kernel low-level debugging support
- via SCIF0 on Renesas R-Car H2 (R8A7790), M2-W (R8A7791), or
- M2-N (R8A7793).
+ via SCIF0 on Renesas R-Car H2 (R8A7790), M2-W (R8A7791), V2H
+ (R8A7792), or M2-N (R8A7793).
config DEBUG_RCAR_GEN2_SCIF2
bool "Kernel low-level debugging messages via SCIF2 on R8A7794"
@@ -1430,6 +1431,7 @@ config DEBUG_LL_INCLUDE
default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART
default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0
+ default "debug/brcmstb.S" if DEBUG_BRCMSTB_UART
default "mach/debug-macro.S"
# Compatibility options for PL01x
@@ -1520,7 +1522,6 @@ config DEBUG_UART_PHYS
default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0
default 0xe8008000 if DEBUG_R7S72100_SCIF2
default 0xf0000be0 if ARCH_EBSA110
- default 0xf040ab00 if DEBUG_BRCMSTB_UART
default 0xf1012000 if DEBUG_MVEBU_UART0_ALTERNATE
default 0xf1012100 if DEBUG_MVEBU_UART1_ALTERNATE
default 0xf7fc9000 if DEBUG_BERLIN_UART
@@ -1604,7 +1605,6 @@ config DEBUG_UART_VIRT
default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
default 0xfb00c000 if DEBUG_AT91_SAMA5D4_USART3
default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
- default 0xfc40ab00 if DEBUG_BRCMSTB_UART
default 0xfc705000 if DEBUG_ZTE_ZX
default 0xfcfe8600 if DEBUG_BCM63XX_UART
default 0xfd000000 if DEBUG_SPEAR3XX || DEBUG_SPEAR13XX
@@ -1677,8 +1677,7 @@ config DEBUG_UART_8250_WORD
DEBUG_ALPINE_UART0 || \
DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
DEBUG_DAVINCI_DA8XX_UART2 || \
- DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \
- DEBUG_BRCMSTB_UART
+ DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2
config DEBUG_UART_8250_PALMCHIP
bool "8250 UART is Palmchip BK-310x"
@@ -1697,7 +1696,8 @@ config DEBUG_UNCOMPRESS
bool
depends on ARCH_MULTIPLATFORM || PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \
- (!DEBUG_TEGRA_UART || !ZBOOT_ROM)
+ (!DEBUG_TEGRA_UART || !ZBOOT_ROM) && \
+ !DEBUG_BRCMSTB_UART
help
This option influences the normal decompressor output for
multiplatform kernels. Normally, multiplatform kernels disable
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index faacd52370d2..befcd2619902 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -69,7 +69,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
bcm2835-rpi-b-rev2.dtb \
bcm2835-rpi-b-plus.dtb \
bcm2835-rpi-a-plus.dtb \
- bcm2836-rpi-2-b.dtb
+ bcm2836-rpi-2-b.dtb \
+ bcm2835-rpi-zero.dtb
dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4708-asus-rt-ac56u.dtb \
bcm4708-asus-rt-ac68u.dtb \
@@ -102,8 +103,13 @@ dtb-$(CONFIG_ARCH_BCM_MOBILE) += \
bcm21664-garnet.dtb \
bcm23550-sparrow.dtb
dtb-$(CONFIG_ARCH_BCM_NSP) += \
+ bcm958522er.dtb \
+ bcm958525er.dtb \
bcm958525xmc.dtb \
+ bcm958622hr.dtb \
+ bcm958623hr.dtb \
bcm958625hr.dtb \
+ bcm988312hr.dtb \
bcm958625k.dtb
dtb-$(CONFIG_ARCH_BERLIN) += \
berlin2-sony-nsz-gs7.dtb \
@@ -114,6 +120,7 @@ dtb-$(CONFIG_ARCH_BRCMSTB) += \
dtb-$(CONFIG_ARCH_CLPS711X) += \
ep7211-edb7211.dtb
dtb-$(CONFIG_ARCH_DAVINCI) += \
+ da850-lcdk.dtb \
da850-enbw-cmc.dtb \
da850-evm.dtb
dtb-$(CONFIG_ARCH_DIGICOLOR) += \
@@ -315,6 +322,7 @@ dtb-$(CONFIG_SOC_IMX53) += \
imx53-smd.dtb \
imx53-tx53-x03x.dtb \
imx53-tx53-x13x.dtb \
+ imx53-usbarmory.dtb \
imx53-voipac-bsb.dtb
dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-apf6dev.dtb \
@@ -330,6 +338,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-gw54xx.dtb \
imx6dl-gw551x.dtb \
imx6dl-gw552x.dtb \
+ imx6dl-gw553x.dtb \
imx6dl-hummingboard.dtb \
imx6dl-nit6xlite.dtb \
imx6dl-nitrogen6x.dtb \
@@ -339,6 +348,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-sabreauto.dtb \
imx6dl-sabrelite.dtb \
imx6dl-sabresd.dtb \
+ imx6dl-ts4900.dtb \
imx6dl-tx6dl-comtft.dtb \
imx6dl-tx6s-8034.dtb \
imx6dl-tx6s-8035.dtb \
@@ -368,6 +378,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-gw54xx.dtb \
imx6q-gw551x.dtb \
imx6q-gw552x.dtb \
+ imx6q-gw553x.dtb \
imx6q-h100.dtb \
imx6q-hummingboard.dtb \
imx6q-icore-rqs.dtb \
@@ -382,6 +393,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-sabresd.dtb \
imx6q-sbc6x.dtb \
imx6q-tbs2910.dtb \
+ imx6q-ts4900.dtb \
imx6q-tx6q-1010.dtb \
imx6q-tx6q-1010-comtft.dtb \
imx6q-tx6q-1020.dtb \
@@ -407,6 +419,7 @@ dtb-$(CONFIG_SOC_IMX6SX) += \
imx6sx-sdb.dtb
dtb-$(CONFIG_SOC_IMX6UL) += \
imx6ul-14x14-evk.dtb \
+ imx6ul-geam-kit.dtb \
imx6ul-pico-hobbit.dtb \
imx6ul-tx6ul-0010.dtb \
imx6ul-tx6ul-0011.dtb \
@@ -417,7 +430,8 @@ dtb-$(CONFIG_SOC_IMX7D) += \
imx7d-nitrogen7.dtb \
imx7d-sbc-imx7.dtb \
imx7d-sdb.dtb \
- imx7s-colibri-eval-v3.dtb
+ imx7s-colibri-eval-v3.dtb \
+ imx7s-warp.dtb
dtb-$(CONFIG_SOC_LS1021A) += \
ls1021a-qds.dtb \
ls1021a-twr.dtb
@@ -570,6 +584,7 @@ dtb-$(CONFIG_SOC_OMAP5) += \
omap5-uevm.dtb
dtb-$(CONFIG_SOC_DRA7XX) += \
am57xx-beagle-x15.dtb \
+ am57xx-beagle-x15-revb1.dtb \
am57xx-cl-som-am57x.dtb \
am57xx-sbc-am57x.dtb \
am572x-idk.dtb \
@@ -584,6 +599,7 @@ dtb-$(CONFIG_ARCH_ORION5X) += \
orion5x-linkstation-lswtgl.dtb \
orion5x-lswsgl.dtb \
orion5x-maxtor-shared-storage-2.dtb \
+ orion5x-netgear-wnr854t.dtb \
orion5x-rd88f5182-nas.dtb
dtb-$(CONFIG_ARCH_PRIMA2) += \
prima2-evb.dtb
@@ -603,14 +619,19 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-ipq8064-ap148.dtb \
qcom-msm8660-surf.dtb \
qcom-msm8960-cdp.dtb \
+ qcom-msm8974-lge-nexus5-hammerhead.dtb \
qcom-msm8974-sony-xperia-honami.dtb
dtb-$(CONFIG_ARCH_REALVIEW) += \
arm-realview-pb1176.dtb \
arm-realview-pb11mp.dtb \
arm-realview-eb.dtb \
+ arm-realview-eb-bbrevd.dtb \
arm-realview-eb-11mp.dtb \
- arm-realview-eb-11mp-revb.dtb \
+ arm-realview-eb-11mp-bbrevd.dtb \
+ arm-realview-eb-11mp-ctrevb.dtb \
+ arm-realview-eb-11mp-bbrevd-ctrevb.dtb \
arm-realview-eb-a9mp.dtb \
+ arm-realview-eb-a9mp-bbrevd.dtb \
arm-realview-pba8.dtb \
arm-realview-pbx-a9.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += \
@@ -624,8 +645,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rk3229-evb.dtb \
rk3288-evb-act8846.dtb \
rk3288-evb-rk808.dtb \
+ rk3288-fennec.dtb \
rk3288-firefly-beta.dtb \
rk3288-firefly.dtb \
+ rk3288-firefly-reload.dtb \
rk3288-miqi.dtb \
rk3288-popmetal.dtb \
rk3288-r89.dtb \
@@ -651,6 +674,7 @@ dtb-$(CONFIG_ARCH_S5PV210) += \
dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
emev2-kzm9d.dtb \
r7s72100-genmai.dtb \
+ r7s72100-rskrza1.dtb \
r8a73a4-ape6evm.dtb \
r8a7740-armadillo800eva.dtb \
r8a7778-bockw.dtb \
@@ -659,6 +683,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
r8a7791-koelsch.dtb \
r8a7791-porter.dtb \
r8a7792-blanche.dtb \
+ r8a7792-wheat.dtb \
r8a7793-gose.dtb \
r8a7794-alt.dtb \
r8a7794-silk.dtb \
@@ -686,6 +711,7 @@ dtb-$(CONFIG_ARCH_SPEAR6XX) += \
dtb-$(CONFIG_ARCH_STI) += \
stih407-b2120.dtb \
stih410-b2120.dtb \
+ stih410-b2260.dtb \
stih415-b2000.dtb \
stih415-b2020.dtb \
stih416-b2000.dtb \
@@ -719,6 +745,7 @@ dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-pcduino2.dtb \
sun4i-a10-pov-protab2-ips9.dtb
dtb-$(CONFIG_MACH_SUN5I) += \
+ ntc-gr8-evb.dtb \
sun5i-a10s-auxtek-t003.dtb \
sun5i-a10s-auxtek-t004.dtb \
sun5i-a10s-mk802.dtb \
@@ -727,6 +754,7 @@ dtb-$(CONFIG_MACH_SUN5I) += \
sun5i-a10s-wobo-i5.dtb \
sun5i-a13-difrnce-dit4350.dtb \
sun5i-a13-empire-electronix-d709.dtb \
+ sun5i-a13-empire-electronix-m712.dtb \
sun5i-a13-hsg-h702.dtb \
sun5i-a13-inet-98v-rev2.dtb \
sun5i-a13-olinuxino.dtb \
@@ -743,6 +771,7 @@ dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-mele-a1000g-quad.dtb \
sun6i-a31s-colorfly-e708-q1.dtb \
sun6i-a31s-cs908.dtb \
+ sun6i-a31s-inet-q972.dtb \
sun6i-a31s-primo81.dtb \
sun6i-a31s-sina31s.dtb \
sun6i-a31s-sinovoip-bpi-m2.dtb \
@@ -782,16 +811,22 @@ dtb-$(CONFIG_MACH_SUN8I) += \
sun8i-a23-q8-tablet.dtb \
sun8i-a33-et-q8-v1.6.dtb \
sun8i-a33-ga10h-v1.1.dtb \
+ sun8i-a33-inet-d978-rev2.dtb \
sun8i-a33-ippo-q8h-v1.2.dtb \
+ sun8i-a33-olinuxino.dtb \
sun8i-a33-q8-tablet.dtb \
sun8i-a33-sinlinx-sina33.dtb \
sun8i-a83t-allwinner-h8homlet-v2.dtb \
sun8i-a83t-cubietruck-plus.dtb \
sun8i-h3-bananapi-m2-plus.dtb \
+ sun8i-h3-nanopi-neo.dtb \
sun8i-h3-orangepi-2.dtb \
+ sun8i-h3-orangepi-lite.dtb \
sun8i-h3-orangepi-one.dtb \
sun8i-h3-orangepi-pc.dtb \
+ sun8i-h3-orangepi-pc-plus.dtb \
sun8i-h3-orangepi-plus.dtb \
+ sun8i-h3-orangepi-plus2e.dtb \
sun8i-r16-parrot.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
@@ -836,15 +871,15 @@ dtb-$(CONFIG_ARCH_U8500) += \
ste-ccu8540.dtb \
ste-ccu9540.dtb
dtb-$(CONFIG_ARCH_UNIPHIER) += \
- uniphier-ph1-ld4-ref.dtb \
- uniphier-ph1-ld6b-ref.dtb \
- uniphier-ph1-pro4-ace.dtb \
- uniphier-ph1-pro4-ref.dtb \
- uniphier-ph1-pro4-sanji.dtb \
- uniphier-ph1-sld3-ref.dtb \
- uniphier-ph1-sld8-ref.dtb \
- uniphier-proxstream2-gentil.dtb \
- uniphier-proxstream2-vodka.dtb
+ uniphier-ld4-ref.dtb \
+ uniphier-ld6b-ref.dtb \
+ uniphier-pro4-ace.dtb \
+ uniphier-pro4-ref.dtb \
+ uniphier-pro4-sanji.dtb \
+ uniphier-pxs2-gentil.dtb \
+ uniphier-pxs2-vodka.dtb \
+ uniphier-sld3-ref.dtb \
+ uniphier-sld8-ref.dtb
dtb-$(CONFIG_ARCH_VERSATILE) += \
versatile-ab.dtb \
versatile-pb.dtb
diff --git a/arch/arm/boot/dts/am335x-baltos.dtsi b/arch/arm/boot/dts/am335x-baltos.dtsi
index b689172632ef..dd45d172a892 100644
--- a/arch/arm/boot/dts/am335x-baltos.dtsi
+++ b/arch/arm/boot/dts/am335x-baltos.dtsi
@@ -24,12 +24,12 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -37,7 +37,7 @@
regulator-boot-on;
};
- wl12xx_vmmc: fixedregulator@2 {
+ wl12xx_vmmc: fixedregulator2 {
pinctrl-names = "default";
pinctrl-0 = <&wl12xx_gpio>;
compatible = "regulator-fixed";
diff --git a/arch/arm/boot/dts/am335x-base0033.dts b/arch/arm/boot/dts/am335x-base0033.dts
index 58a05f7d0b7c..c2bee452dab8 100644
--- a/arch/arm/boot/dts/am335x-base0033.dts
+++ b/arch/arm/boot/dts/am335x-base0033.dts
@@ -29,13 +29,13 @@
compatible = "gpio-leds";
- led@0 {
+ led0 {
label = "base:red:user";
gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>; /* gpio1_21 */
default-state = "off";
};
- led@1 {
+ led1 {
label = "base:green:user";
gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>; /* gpio2_0 */
default-state = "off";
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index e247c15e5176..007b5e5a51a9 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -13,7 +13,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
@@ -28,28 +28,28 @@
compatible = "gpio-leds";
- led@2 {
+ led2 {
label = "beaglebone:green:heartbeat";
gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
default-state = "off";
};
- led@3 {
+ led3 {
label = "beaglebone:green:mmc0";
gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "mmc0";
default-state = "off";
};
- led@4 {
+ led4 {
label = "beaglebone:green:usr2";
gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "cpu0";
default-state = "off";
};
- led@5 {
+ led5 {
label = "beaglebone:green:usr3";
gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "mmc1";
@@ -57,7 +57,7 @@
};
};
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
index ca721670bd91..55c0e954b146 100644
--- a/arch/arm/boot/dts/am335x-boneblack.dts
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
@@ -33,17 +33,6 @@
status = "okay";
};
-&cpu0_opp_table {
- /*
- * All PG 2.0 silicon may not support 1GHz but some of the early
- * BeagleBone Blacks have PG 2.0 silicon which is guaranteed
- * to support 1GHz OPP so enable it for PG 2.0 on this board.
- */
- oppnitro@1000000000 {
- opp-supported-hw = <0x06 0x0100>;
- };
-};
-
&am33xx_pinmux {
nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
pinctrl-single,pins = <
diff --git a/arch/arm/boot/dts/am335x-chilisom.dtsi b/arch/arm/boot/dts/am335x-chilisom.dtsi
index 1d647358f1c1..f9ee5859c154 100644
--- a/arch/arm/boot/dts/am335x-chilisom.dtsi
+++ b/arch/arm/boot/dts/am335x-chilisom.dtsi
@@ -19,7 +19,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/am335x-cm-t335.dts b/arch/arm/boot/dts/am335x-cm-t335.dts
index 817b1dec0683..947c81b7aaaf 100644
--- a/arch/arm/boot/dts/am335x-cm-t335.dts
+++ b/arch/arm/boot/dts/am335x-cm-t335.dts
@@ -17,7 +17,7 @@
model = "CompuLab CM-T335";
compatible = "compulab,cm-t335", "ti,am33xx";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x8000000>; /* 128 MB */
};
@@ -26,7 +26,7 @@
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&gpio_led_pins>;
- led@0 {
+ led0 {
label = "cm_t335:green";
gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; /* gpio2_0 */
linux,default-trigger = "heartbeat";
@@ -34,7 +34,7 @@
};
/* regulator for mmc */
- vmmc_fixed: fixedregulator@0 {
+ vmmc_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmc_fixed";
regulator-min-microvolt = <3300000>;
@@ -42,7 +42,7 @@
};
/* Regulator for WiFi */
- vwlan_fixed: fixedregulator@2 {
+ vwlan_fixed: fixedregulator2 {
compatible = "regulator-fixed";
regulator-name = "vwlan_fixed";
gpio = <&gpio0 20 GPIO_ACTIVE_HIGH>; /* gpio0_20 */
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 5d28712ad253..e82432c79f85 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -20,12 +20,12 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -33,13 +33,13 @@
regulator-boot-on;
};
- lis3_reg: fixedregulator@1 {
+ lis3_reg: fixedregulator1 {
compatible = "regulator-fixed";
regulator-name = "lis3_reg";
regulator-boot-on;
};
- wlan_en_reg: fixedregulator@2 {
+ wlan_en_reg: fixedregulator2 {
compatible = "regulator-fixed";
regulator-name = "wlan-en-regulator";
regulator-min-microvolt = <1800000>;
@@ -53,7 +53,7 @@
enable-active-high;
};
- matrix_keypad: matrix_keypad@0 {
+ matrix_keypad: matrix_keypad0 {
compatible = "gpio-matrix-keypad";
debounce-delay-ms = <5>;
col-scan-delay-us = <2>;
@@ -73,20 +73,20 @@
0x0201006c>; /* DOWN */
};
- gpio_keys: volume_keys@0 {
+ gpio_keys: volume_keys0 {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
- switch@9 {
+ switch9 {
label = "volume-up";
linux,code = <115>;
gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
wakeup-source;
};
- switch@10 {
+ switch10 {
label = "volume-down";
linux,code = <114>;
gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
@@ -497,6 +497,8 @@
&lcdc {
status = "okay";
+
+ blue-and-red-wiring = "crossed";
};
&elm {
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 09308d66645b..975c36e332a2 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -27,12 +27,12 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -40,13 +40,13 @@
regulator-boot-on;
};
- lis3_reg: fixedregulator@1 {
+ lis3_reg: fixedregulator1 {
compatible = "regulator-fixed";
regulator-name = "lis3_reg";
regulator-boot-on;
};
- wl12xx_vmmc: fixedregulator@2 {
+ wl12xx_vmmc: fixedregulator2 {
pinctrl-names = "default";
pinctrl-0 = <&wl12xx_gpio>;
compatible = "regulator-fixed";
@@ -58,7 +58,7 @@
enable-active-high;
};
- vtt_fixed: fixedregulator@3 {
+ vtt_fixed: fixedregulator3 {
compatible = "regulator-fixed";
regulator-name = "vtt";
regulator-min-microvolt = <1500000>;
@@ -75,26 +75,26 @@
compatible = "gpio-leds";
- led@1 {
+ led1 {
label = "evmsk:green:usr0";
gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@2 {
+ led2 {
label = "evmsk:green:usr1";
gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@3 {
+ led3 {
label = "evmsk:green:mmc0";
gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "mmc0";
default-state = "off";
};
- led@4 {
+ led4 {
label = "evmsk:green:heartbeat";
gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
@@ -102,31 +102,31 @@
};
};
- gpio_buttons: gpio_buttons@0 {
+ gpio_buttons: gpio_buttons0 {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
- switch@1 {
+ switch1 {
label = "button0";
linux,code = <0x100>;
gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
};
- switch@2 {
+ switch2 {
label = "button1";
linux,code = <0x101>;
gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
};
- switch@3 {
+ switch3 {
label = "button2";
linux,code = <0x102>;
gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
wakeup-source;
};
- switch@4 {
+ switch4 {
label = "button3";
linux,code = <0x103>;
gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
@@ -170,29 +170,29 @@
pinctrl-1 = <&lcd_pins_sleep>;
status = "okay";
panel-info {
- ac-bias = <255>;
- ac-bias-intrpt = <0>;
- dma-burst-sz = <16>;
- bpp = <32>;
- fdd = <0x80>;
- sync-edge = <0>;
- sync-ctrl = <1>;
- raster-order = <0>;
- fifo-th = <0>;
+ ac-bias = <255>;
+ ac-bias-intrpt = <0>;
+ dma-burst-sz = <16>;
+ bpp = <32>;
+ fdd = <0x80>;
+ sync-edge = <0>;
+ sync-ctrl = <1>;
+ raster-order = <0>;
+ fifo-th = <0>;
};
display-timings {
480x272 {
- hactive = <480>;
- vactive = <272>;
- hback-porch = <43>;
- hfront-porch = <8>;
- hsync-len = <4>;
- vback-porch = <12>;
- vfront-porch = <4>;
- vsync-len = <10>;
+ hactive = <480>;
+ vactive = <272>;
+ hback-porch = <43>;
+ hfront-porch = <8>;
+ hsync-len = <4>;
+ vback-porch = <12>;
+ vfront-porch = <4>;
+ vsync-len = <10>;
clock-frequency = <9000000>;
- hsync-active = <0>;
- vsync-active = <0>;
+ hsync-active = <0>;
+ vsync-active = <0>;
};
};
};
@@ -711,5 +711,7 @@
};
&lcdc {
- status = "okay";
+ status = "okay";
+
+ blue-and-red-wiring = "crossed";
};
diff --git a/arch/arm/boot/dts/am335x-icev2.dts b/arch/arm/boot/dts/am335x-icev2.dts
index 7d8b8fefdf08..85e04c205542 100644
--- a/arch/arm/boot/dts/am335x-icev2.dts
+++ b/arch/arm/boot/dts/am335x-icev2.dts
@@ -19,12 +19,12 @@
model = "TI AM3359 ICE-V2";
compatible = "ti,am3359-icev2", "ti,am33xx";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -32,7 +32,7 @@
regulator-boot-on;
};
- vtt_fixed: fixedregulator@1 {
+ vtt_fixed: fixedregulator1 {
compatible = "regulator-fixed";
regulator-name = "vtt";
regulator-min-microvolt = <1500000>;
@@ -43,52 +43,52 @@
enable-active-high;
};
- leds@0 {
+ leds0 {
compatible = "gpio-leds";
- led@0 {
+ led0 {
label = "out0";
gpios = <&tpic2810 0 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@1 {
+ led1 {
label = "out1";
gpios = <&tpic2810 1 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@2 {
+ led2 {
label = "out2";
gpios = <&tpic2810 2 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@3 {
+ led3 {
label = "out3";
gpios = <&tpic2810 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@4 {
+ led4 {
label = "out4";
gpios = <&tpic2810 4 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@5 {
+ led5 {
label = "out5";
gpios = <&tpic2810 5 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@6 {
+ led6 {
label = "out6";
gpios = <&tpic2810 6 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@7 {
+ led7 {
label = "out7";
gpios = <&tpic2810 7 GPIO_ACTIVE_HIGH>;
default-state = "off";
@@ -96,49 +96,58 @@
};
/* Tricolor status LEDs */
- leds@1 {
+ leds1 {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&user_leds>;
- led@0 {
+ led0 {
label = "status0:red:cpu0";
gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
default-state = "off";
linux,default-trigger = "cpu0";
};
- led@1 {
+ led1 {
label = "status0:green:usr";
gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@2 {
+ led2 {
label = "status0:yellow:usr";
gpios = <&gpio3 9 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@3 {
+ led3 {
label = "status1:red:mmc0";
gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>;
default-state = "off";
linux,default-trigger = "mmc0";
};
- led@4 {
+ led4 {
label = "status1:green:usr";
gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@5 {
+ led5 {
label = "status1:yellow:usr";
gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
+ gpio-decoder {
+ compatible = "gpio-decoder";
+ gpios = <&pca9536 3 GPIO_ACTIVE_HIGH>,
+ <&pca9536 2 GPIO_ACTIVE_HIGH>,
+ <&pca9536 1 GPIO_ACTIVE_HIGH>,
+ <&pca9536 0 GPIO_ACTIVE_HIGH>;
+ linux,axis = <0>; /* ABS_X */
+ decoder-max-value = <9>;
+ };
};
&am33xx_pinmux {
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index e7d9ca1305fa..a5769a8f5fc8 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -20,7 +20,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
@@ -31,14 +31,14 @@
compatible = "gpio-leds";
- led@0 {
+ led0 {
label = "com:green:user";
gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -46,7 +46,7 @@
regulator-boot-on;
};
- vmmc: fixedregulator@0 {
+ vmmc: fixedregulator1 {
compatible = "regulator-fixed";
regulator-name = "vmmc";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/am335x-lxm.dts b/arch/arm/boot/dts/am335x-lxm.dts
index d97b0efa43f3..1d6c6fa703e4 100644
--- a/arch/arm/boot/dts/am335x-lxm.dts
+++ b/arch/arm/boot/dts/am335x-lxm.dts
@@ -19,13 +19,13 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
/* Power supply provides a fixed 5V @2A */
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -34,7 +34,7 @@
};
/* Power supply provides a fixed 3.3V @3A */
- vmmcsd_fixed: fixedregulator@1 {
+ vmmcsd_fixed: fixedregulator1 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/am335x-nano.dts b/arch/arm/boot/dts/am335x-nano.dts
index f313999c503e..483d585c8908 100644
--- a/arch/arm/boot/dts/am335x-nano.dts
+++ b/arch/arm/boot/dts/am335x-nano.dts
@@ -19,7 +19,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
@@ -27,7 +27,7 @@
leds {
compatible = "gpio-leds";
- led@0 {
+ led0 {
label = "nanobone:green:usr1";
gpios = <&gpio1 5 0>;
default-state = "off";
diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts
index 8867aaaec54d..30e2f8770aaf 100644
--- a/arch/arm/boot/dts/am335x-pepper.dts
+++ b/arch/arm/boot/dts/am335x-pepper.dts
@@ -20,7 +20,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
@@ -41,15 +41,15 @@
compatible = "ti,da830-evm-audio";
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
};
- v3v3c_reg: fixedregulator@1 {
+ v3v3c_reg: fixedregulator1 {
compatible = "regulator-fixed";
};
- vdd5_reg: fixedregulator@2 {
+ vdd5_reg: fixedregulator2 {
compatible = "regulator-fixed";
};
};
@@ -595,14 +595,14 @@
pinctrl-names = "default";
pinctrl-0 = <&user_leds_pins>;
- led@0 {
+ led0 {
label = "pepper:user0:blue";
gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "none";
default-state = "off";
};
- led@1 {
+ led1 {
label = "pepper:user1:red";
gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "none";
@@ -616,21 +616,21 @@
#address-cells = <1>;
#size-cells = <0>;
- button@0 {
+ button0 {
label = "home";
linux,code = <KEY_HOME>;
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
wakeup-source;
};
- button@1 {
+ button1 {
label = "menu";
linux,code = <KEY_MENU>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
wakeup-source;
};
- buttons@2 {
+ buttons2 {
label = "power";
linux,code = <KEY_POWER>;
gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm/boot/dts/am335x-phycore-som.dtsi b/arch/arm/boot/dts/am335x-phycore-som.dtsi
index 1263c9d4cba3..75e24add3f13 100644
--- a/arch/arm/boot/dts/am335x-phycore-som.dtsi
+++ b/arch/arm/boot/dts/am335x-phycore-som.dtsi
@@ -25,7 +25,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
@@ -33,7 +33,7 @@
regulators {
compatible = "simple-bus";
- vcc5v: fixedregulator@0 {
+ vcc5v: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vcc5v";
regulator-min-microvolt = <5000000>;
diff --git a/arch/arm/boot/dts/am335x-shc.dts b/arch/arm/boot/dts/am335x-shc.dts
index 837d5b80ea1d..bf8727a19ece 100644
--- a/arch/arm/boot/dts/am335x-shc.dts
+++ b/arch/arm/boot/dts/am335x-shc.dts
@@ -64,50 +64,50 @@
compatible = "gpio-leds";
- led@1 {
+ led1 {
label = "shc:power:red";
gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@2 {
+ led2 {
label = "shc:power:bl";
gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "timer";
default-state = "on";
};
- led@3 {
+ led3 {
label = "shc:lan:red";
gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@4 {
+ led4 {
label = "shc:lan:bl";
gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@5 {
+ led5 {
label = "shc:cloud:red";
gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
- led@6 {
+ led6 {
label = "shc:cloud:bl";
gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/am335x-sl50.dts b/arch/arm/boot/dts/am335x-sl50.dts
index a6efbe6eda3b..b0dfa6f14cd5 100644
--- a/arch/arm/boot/dts/am335x-sl50.dts
+++ b/arch/arm/boot/dts/am335x-sl50.dts
@@ -19,6 +19,11 @@
};
};
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>; /* 512 MB */
+ };
+
chosen {
stdout-path = &uart0;
};
@@ -28,25 +33,25 @@
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- led@0 {
+ led0 {
label = "sl50:green:usr0";
gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- led@1 {
+ led1 {
label = "sl50:red:usr1";
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- led@2 {
+ led2 {
label = "sl50:green:usr2";
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- led@3 {
+ led3 {
label = "sl50:red:usr3";
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
default-state = "off";
@@ -103,7 +108,7 @@
reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
};
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/am335x-wega.dtsi b/arch/arm/boot/dts/am335x-wega.dtsi
index 282f6d4b27bc..02c67365c4e1 100644
--- a/arch/arm/boot/dts/am335x-wega.dtsi
+++ b/arch/arm/boot/dts/am335x-wega.dtsi
@@ -11,10 +11,14 @@
model = "Phytec AM335x phyBOARD-WEGA";
compatible = "phytec,am335x-wega", "phytec,am335x-phycore-som", "ti,am33xx";
+ sound: sound_iface {
+ compatible = "ti,da830-evm-audio";
+ };
+
regulators {
compatible = "simple-bus";
- vcc3v3: fixedregulator@1 {
+ vcc3v3: fixedregulator1 {
compatible = "regulator-fixed";
regulator-name = "vcc3v3";
regulator-min-microvolt = <3300000>;
@@ -24,6 +28,58 @@
};
};
+/* Audio */
+&am33xx_pinmux {
+ mcasp0_pins: pinmux_mcasp0 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x9AC, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_ahclkx.mcasp0_ahclkx */
+ AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
+ AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
+ AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr0.mcasp0_axr0 */
+ AM33XX_IOPAD(0x9A8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr1.mcasp0_axr1 */
+ >;
+ };
+};
+
+&i2c0 {
+ tlv320aic3007: tlv320aic3007@18 {
+ compatible = "ti,tlv320aic3007";
+ reg = <0x18>;
+ AVDD-supply = <&vcc3v3>;
+ IOVDD-supply = <&vcc3v3>;
+ DRVDD-supply = <&vcc3v3>;
+ DVDD-supply = <&vdig1_reg>;
+ status = "okay";
+ };
+};
+
+&mcasp0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcasp0_pins>;
+ op-mode = <0>; /* DAVINCI_MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ serial-dir = <
+ 2 1 0 0 /* # 0: INACTIVE, 1: TX, 2: RX */
+ >;
+ tx-num-evt = <16>;
+ rt-num-evt = <16>;
+ status = "okay";
+};
+
+&sound {
+ ti,model = "AM335x-Wega";
+ ti,audio-codec = <&tlv320aic3007>;
+ ti,mcasp-controller = <&mcasp0>;
+ ti,audio-routing =
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT",
+ "LINE1L", "Line In",
+ "LINE1R", "Line In";
+ clocks = <&mcasp0_fck>;
+ clock-names = "mclk";
+ status = "okay";
+};
+
/* CAN Busses */
&am33xx_pinmux {
dcan1_pins: pinmux_dcan1 {
@@ -99,6 +155,12 @@
status = "okay";
};
+/* Power */
+&vdig1_reg {
+ regulator-boot-on;
+ regulator-always-on;
+};
+
/* UARTs */
&am33xx_pinmux {
uart0_pins: pinmux_uart0 {
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 98748c61ed99..194d884c9de1 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -11,11 +11,11 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/am33xx.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,am33xx";
interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
i2c0 = &i2c0;
@@ -45,9 +45,19 @@
device_type = "cpu";
reg = <0>;
- operating-points-v2 = <&cpu0_opp_table>;
- ti,syscon-efuse = <&scm_conf 0x7fc 0x1fff 0>;
- ti,syscon-rev = <&scm_conf 0x600>;
+ /*
+ * To consider voltage drop between PMIC and SoC,
+ * tolerance value is reduced to 2% from 4% and
+ * voltage value is increased as a precaution.
+ */
+ operating-points = <
+ /* kHz uV */
+ 720000 1285000
+ 600000 1225000
+ 500000 1125000
+ 275000 1125000
+ >;
+ voltage-tolerance = <2>; /* 2 percentage */
clocks = <&dpll_mpu_ck>;
clock-names = "cpu";
@@ -56,78 +66,6 @@
};
};
- cpu0_opp_table: opp_table0 {
- compatible = "operating-points-v2";
-
- /*
- * The three following nodes are marked with opp-suspend
- * because the can not be enabled simultaneously on a
- * single SoC.
- */
- opp50@300000000 {
- opp-hz = /bits/ 64 <300000000>;
- opp-microvolt = <950000 931000 969000>;
- opp-supported-hw = <0x06 0x0010>;
- opp-suspend;
- };
-
- opp100@275000000 {
- opp-hz = /bits/ 64 <275000000>;
- opp-microvolt = <1100000 1078000 1122000>;
- opp-supported-hw = <0x01 0x00FF>;
- opp-suspend;
- };
-
- opp100@300000000 {
- opp-hz = /bits/ 64 <300000000>;
- opp-microvolt = <1100000 1078000 1122000>;
- opp-supported-hw = <0x06 0x0020>;
- opp-suspend;
- };
-
- opp100@500000000 {
- opp-hz = /bits/ 64 <500000000>;
- opp-microvolt = <1100000 1078000 1122000>;
- opp-supported-hw = <0x01 0xFFFF>;
- };
-
- opp100@600000000 {
- opp-hz = /bits/ 64 <600000000>;
- opp-microvolt = <1100000 1078000 1122000>;
- opp-supported-hw = <0x06 0x0040>;
- };
-
- opp120@600000000 {
- opp-hz = /bits/ 64 <600000000>;
- opp-microvolt = <1200000 1176000 1224000>;
- opp-supported-hw = <0x01 0xFFFF>;
- };
-
- opp120@720000000 {
- opp-hz = /bits/ 64 <720000000>;
- opp-microvolt = <1200000 1176000 1224000>;
- opp-supported-hw = <0x06 0x0080>;
- };
-
- oppturbo@720000000 {
- opp-hz = /bits/ 64 <720000000>;
- opp-microvolt = <1260000 1234800 1285200>;
- opp-supported-hw = <0x01 0xFFFF>;
- };
-
- oppturbo@800000000 {
- opp-hz = /bits/ 64 <800000000>;
- opp-microvolt = <1260000 1234800 1285200>;
- opp-supported-hw = <0x06 0x0100>;
- };
-
- oppnitro@1000000000 {
- opp-hz = /bits/ 64 <1000000000>;
- opp-microvolt = <1325000 1298500 1351500>;
- opp-supported-hw = <0x04 0x0200>;
- };
- };
-
pmu {
compatible = "arm,cortex-a8-pmu";
interrupts = <3>;
diff --git a/arch/arm/boot/dts/am3517-craneboard.dts b/arch/arm/boot/dts/am3517-craneboard.dts
index f9d8f3948c4a..083ff5073435 100644
--- a/arch/arm/boot/dts/am3517-craneboard.dts
+++ b/arch/arm/boot/dts/am3517-craneboard.dts
@@ -15,7 +15,7 @@
model = "TI AM3517 CraneBoard (TMDSEVM3517)";
compatible = "ti,am3517-craneboard", "ti,am3517", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/am3517-evm.dts b/arch/arm/boot/dts/am3517-evm.dts
index b4127c6493a2..0e4a125f78e3 100644
--- a/arch/arm/boot/dts/am3517-evm.dts
+++ b/arch/arm/boot/dts/am3517-evm.dts
@@ -13,7 +13,7 @@
model = "TI AM3517 EVM (AM3517/05 TMDSEVM3517)";
compatible = "ti,am3517-evm", "ti,am3517", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi
index 5e3f5e86ffcf..0db19d39d24c 100644
--- a/arch/arm/boot/dts/am3517.dtsi
+++ b/arch/arm/boot/dts/am3517.dtsi
@@ -15,7 +15,7 @@
serial3 = &uart4;
};
- ocp {
+ ocp@68000000 {
am35x_otg_hs: am35x_otg_hs@5c040000 {
compatible = "ti,omap3-musb";
ti,hwmods = "am35x_otg_hs";
diff --git a/arch/arm/boot/dts/am3517_mt_ventoux.dts b/arch/arm/boot/dts/am3517_mt_ventoux.dts
index fdf5ce63c8e6..3395783c5b4e 100644
--- a/arch/arm/boot/dts/am3517_mt_ventoux.dts
+++ b/arch/arm/boot/dts/am3517_mt_ventoux.dts
@@ -13,7 +13,7 @@
model = "TeeJet Mt.Ventoux";
compatible = "teejet,mt_ventoux", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index 0fadae5396e1..a275fa956813 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -11,12 +11,16 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,am4372", "ti,am43";
interrupt-parent = <&wakeupgen>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ memory@0 {
+ device_type = "memory";
+ reg = <0 0>;
+ };
aliases {
i2c0 = &i2c0;
@@ -132,7 +136,7 @@
cache-level = <2>;
};
- ocp {
+ ocp@44000000 {
compatible = "ti,am4372-l3-noc", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/am437x-cm-t43.dts b/arch/arm/boot/dts/am437x-cm-t43.dts
index 9551c4713173..9e92d480576b 100644
--- a/arch/arm/boot/dts/am437x-cm-t43.dts
+++ b/arch/arm/boot/dts/am437x-cm-t43.dts
@@ -209,7 +209,6 @@
#interrupt-cells = <2>;
dcdc1: regulator-dcdc1 {
- compatible = "ti,tps65218-dcdc1";
regulator-name = "vdd_core";
regulator-min-microvolt = <912000>;
regulator-max-microvolt = <1144000>;
@@ -218,7 +217,6 @@
};
dcdc2: regulator-dcdc2 {
- compatible = "ti,tps65218-dcdc2";
regulator-name = "vdd_mpu";
regulator-min-microvolt = <912000>;
regulator-max-microvolt = <1378000>;
@@ -227,7 +225,6 @@
};
dcdc3: regulator-dcdc3 {
- compatible = "ti,tps65218-dcdc3";
regulator-name = "vdcdc3";
regulator-suspend-enable;
regulator-min-microvolt = <1500000>;
@@ -237,7 +234,6 @@
};
dcdc5: regulator-dcdc5 {
- compatible = "ti,tps65218-dcdc5";
regulator-name = "v1_0bat";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
@@ -246,7 +242,6 @@
};
dcdc6: regulator-dcdc6 {
- compatible = "ti,tps65218-dcdc6";
regulator-name = "v1_8bat";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -255,7 +250,6 @@
};
ldo1: regulator-ldo1 {
- compatible = "ti,tps65218-ldo1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index 14677d599595..957840cc7b78 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -58,7 +58,7 @@
default-brightness-level = <8>;
};
- matrix_keypad: matrix_keypad@0 {
+ matrix_keypad: matrix_keypad0 {
compatible = "gpio-matrix-keypad";
debounce-delay-ms = <5>;
col-scan-delay-us = <2>;
@@ -513,7 +513,6 @@
#interrupt-cells = <2>;
dcdc1: regulator-dcdc1 {
- compatible = "ti,tps65218-dcdc1";
regulator-name = "vdd_core";
regulator-min-microvolt = <912000>;
regulator-max-microvolt = <1144000>;
@@ -522,7 +521,6 @@
};
dcdc2: regulator-dcdc2 {
- compatible = "ti,tps65218-dcdc2";
regulator-name = "vdd_mpu";
regulator-min-microvolt = <912000>;
regulator-max-microvolt = <1378000>;
@@ -531,33 +529,42 @@
};
dcdc3: regulator-dcdc3 {
- compatible = "ti,tps65218-dcdc3";
regulator-name = "vdcdc3";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
regulator-boot-on;
regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ regulator-state-disk {
+ regulator-off-in-suspend;
+ };
};
+
dcdc5: regulator-dcdc5 {
- compatible = "ti,tps65218-dcdc5";
regulator-name = "v1_0bat";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-boot-on;
regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
};
dcdc6: regulator-dcdc6 {
- compatible = "ti,tps65218-dcdc6";
regulator-name = "v1_8bat";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
};
ldo1: regulator-ldo1 {
- compatible = "ti,tps65218-ldo1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts
index 12a69518383e..25ce611c6568 100644
--- a/arch/arm/boot/dts/am437x-idk-evm.dts
+++ b/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -104,7 +104,7 @@
#address-cells = <1>;
#size-cells = <0>;
- switch@0 {
+ switch0 {
label = "power-button";
linux,code = <KEY_POWER>;
gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 5687d6b4da60..319d94205350 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -64,7 +64,7 @@
};
};
- matrix_keypad: matrix_keypad@0 {
+ matrix_keypad: matrix_keypad0 {
compatible = "gpio-matrix-keypad";
pinctrl-names = "default";
@@ -93,28 +93,28 @@
pinctrl-names = "default";
pinctrl-0 = <&leds_pins>;
- led@0 {
+ led0 {
label = "am437x-sk:red:heartbeat";
gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>; /* Bank 5, pin 0 */
linux,default-trigger = "heartbeat";
default-state = "off";
};
- led@1 {
+ led1 {
label = "am437x-sk:green:mmc1";
gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; /* Bank 5, pin 1 */
linux,default-trigger = "mmc0";
default-state = "off";
};
- led@2 {
+ led2 {
label = "am437x-sk:blue:cpu0";
gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; /* Bank 5, pin 2 */
linux,default-trigger = "cpu0";
default-state = "off";
};
- led@3 {
+ led3 {
label = "am437x-sk:blue:usr3";
gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>; /* Bank 5, pin 3 */
default-state = "off";
@@ -428,7 +428,6 @@
#interrupt-cells = <2>;
dcdc1: regulator-dcdc1 {
- compatible = "ti,tps65218-dcdc1";
/* VDD_CORE limits min of OPP50 and max of OPP100 */
regulator-name = "vdd_core";
regulator-min-microvolt = <912000>;
@@ -438,7 +437,6 @@
};
dcdc2: regulator-dcdc2 {
- compatible = "ti,tps65218-dcdc2";
/* VDD_MPU limits min of OPP50 and max of OPP_NITRO */
regulator-name = "vdd_mpu";
regulator-min-microvolt = <912000>;
@@ -448,16 +446,20 @@
};
dcdc3: regulator-dcdc3 {
- compatible = "ti,tps65218-dcdc3";
regulator-name = "vdds_ddr";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
regulator-boot-on;
regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ regulator-state-disk {
+ regulator-off-in-suspend;
+ };
};
dcdc4: regulator-dcdc4 {
- compatible = "ti,tps65218-dcdc4";
regulator-name = "v3_3d";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
@@ -465,8 +467,31 @@
regulator-always-on;
};
+ dcdc5: regulator-dcdc5 {
+ compatible = "ti,tps65218-dcdc5";
+ regulator-name = "v1_0bat";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ dcdc6: regulator-dcdc6 {
+ compatible = "ti,tps65218-dcdc6";
+ regulator-name = "v1_8bat";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
ldo1: regulator-ldo1 {
- compatible = "ti,tps65218-ldo1";
regulator-name = "v1_8d";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index ad32e55532f8..9d35c3f07cad 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -32,7 +32,7 @@
enable-active-high;
};
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -67,7 +67,7 @@
};
};
- matrix_keypad: matrix_keypad@0 {
+ matrix_keypad: matrix_keypad0 {
compatible = "gpio-matrix-keypad";
debounce-delay-ms = <5>;
col-scan-delay-us = <2>;
@@ -421,7 +421,6 @@
#interrupt-cells = <2>;
dcdc1: regulator-dcdc1 {
- compatible = "ti,tps65218-dcdc1";
regulator-name = "vdd_core";
regulator-min-microvolt = <912000>;
regulator-max-microvolt = <1144000>;
@@ -430,7 +429,6 @@
};
dcdc2: regulator-dcdc2 {
- compatible = "ti,tps65218-dcdc2";
regulator-name = "vdd_mpu";
regulator-min-microvolt = <912000>;
regulator-max-microvolt = <1378000>;
@@ -439,7 +437,6 @@
};
dcdc3: regulator-dcdc3 {
- compatible = "ti,tps65218-dcdc3";
regulator-name = "vdcdc3";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
@@ -448,7 +445,6 @@
};
dcdc4: regulator-dcdc4 {
- compatible = "ti,tps65218-dcdc4";
regulator-name = "vdcdc4";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
@@ -457,21 +453,18 @@
};
dcdc5: regulator-dcdc5 {
- compatible = "ti,tps65218-dcdc5";
regulator-name = "v1_0bat";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
dcdc6: regulator-dcdc6 {
- compatible = "ti,tps65218-dcdc6";
regulator-name = "v1_8bat";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo1: regulator-ldo1 {
- compatible = "ti,tps65218-ldo1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
diff --git a/arch/arm/boot/dts/am572x-idk.dts b/arch/arm/boot/dts/am572x-idk.dts
index e3acb99703e1..87bbc66f0f21 100644
--- a/arch/arm/boot/dts/am572x-idk.dts
+++ b/arch/arm/boot/dts/am572x-idk.dts
@@ -18,7 +18,7 @@
compatible = "ti,am5728-idk", "ti,am5728", "ti,dra742", "ti,dra74",
"ti,dra7";
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x80000000>;
};
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
new file mode 100644
index 000000000000..6df7829a2c15
--- /dev/null
+++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2014-2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+#include "dra74x.dtsi"
+#include "am57xx-commercial-grade.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ compatible = "ti,am572x-beagle-x15", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7";
+
+ aliases {
+ rtc0 = &mcp_rtc;
+ rtc1 = &tps659038_rtc;
+ rtc2 = &rtc;
+ display0 = &hdmi0;
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x0 0x80000000>;
+ };
+
+ vdd_3v3: fixedregulator-vdd_3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_3v3";
+ vin-supply = <&regen1>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ aic_dvdd: fixedregulator-aic_dvdd {
+ compatible = "regulator-fixed";
+ regulator-name = "aic_dvdd_fixed";
+ vin-supply = <&vdd_3v3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vtt_fixed: fixedregulator-vtt {
+ /* TPS51200 */
+ compatible = "regulator-fixed";
+ regulator-name = "vtt_fixed";
+ vin-supply = <&smps3_reg>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led0 {
+ label = "beagle-x15:usr0";
+ gpios = <&gpio7 9 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led1 {
+ label = "beagle-x15:usr1";
+ gpios = <&gpio7 8 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "cpu0";
+ default-state = "off";
+ };
+
+ led2 {
+ label = "beagle-x15:usr2";
+ gpios = <&gpio7 14 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+
+ led3 {
+ label = "beagle-x15:usr3";
+ gpios = <&gpio7 15 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "disk-activity";
+ default-state = "off";
+ };
+ };
+
+ gpio_fan: gpio_fan {
+ /* Based on 5v 500mA AFB02505HHB */
+ compatible = "gpio-fan";
+ gpios = <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>;
+ gpio-fan,speed-map = <0 0>,
+ <13000 1>;
+ #cooling-cells = <2>;
+ };
+
+ hdmi0: connector {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+
+ type = "a";
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&tpd12s015_out>;
+ };
+ };
+ };
+
+ tpd12s015: encoder {
+ compatible = "ti,tpd12s015";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ tpd12s015_in: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tpd12s015_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+ };
+ };
+
+ sound0: sound0 {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "BeagleBoard-X15";
+ simple-audio-card,widgets =
+ "Line", "Line Out",
+ "Line", "Line In";
+ simple-audio-card,routing =
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT",
+ "MIC2L", "Line In",
+ "MIC2R", "Line In";
+ simple-audio-card,format = "dsp_b";
+ simple-audio-card,bitclock-master = <&sound0_master>;
+ simple-audio-card,frame-master = <&sound0_master>;
+ simple-audio-card,bitclock-inversion;
+
+ simple-audio-card,cpu {
+ sound-dai = <&mcasp3>;
+ };
+
+ sound0_master: simple-audio-card,codec {
+ sound-dai = <&tlv320aic3104>;
+ clocks = <&clkout2_clk>;
+ };
+ };
+};
+
+&dra7_pmx_core {
+ mmc1_pins_default: mmc1_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x376c, PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
+ DRA7XX_CORE_IOPAD(0x3754, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
+ DRA7XX_CORE_IOPAD(0x3758, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
+ DRA7XX_CORE_IOPAD(0x375c, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
+ DRA7XX_CORE_IOPAD(0x3760, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
+ DRA7XX_CORE_IOPAD(0x3764, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
+ DRA7XX_CORE_IOPAD(0x3768, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
+ >;
+ };
+
+ mmc2_pins_default: mmc2_pins_default {
+ pinctrl-single,pins = <
+ DRA7XX_CORE_IOPAD(0x349c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+ DRA7XX_CORE_IOPAD(0x34b0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+ DRA7XX_CORE_IOPAD(0x34a0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+ DRA7XX_CORE_IOPAD(0x34a4, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+ DRA7XX_CORE_IOPAD(0x34a8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+ DRA7XX_CORE_IOPAD(0x34ac, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+ DRA7XX_CORE_IOPAD(0x348c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+ DRA7XX_CORE_IOPAD(0x3490, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+ DRA7XX_CORE_IOPAD(0x3494, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+ DRA7XX_CORE_IOPAD(0x3498, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+ >;
+ };
+};
+&i2c1 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ tps659038: tps659038@58 {
+ compatible = "ti,tps659038";
+ reg = <0x58>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ #interrupt-cells = <2>;
+ interrupt-controller;
+
+ ti,system-power-controller;
+
+ tps659038_pmic {
+ compatible = "ti,tps659038-pmic";
+
+ regulators {
+ smps12_reg: smps12 {
+ /* VDD_MPU */
+ regulator-name = "smps12";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps3_reg: smps3 {
+ /* VDD_DDR */
+ regulator-name = "smps3";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps45_reg: smps45 {
+ /* VDD_DSPEVE, VDD_IVA, VDD_GPU */
+ regulator-name = "smps45";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps6_reg: smps6 {
+ /* VDD_CORE */
+ regulator-name = "smps6";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* SMPS7 unused */
+
+ smps8_reg: smps8 {
+ /* VDD_1V8 */
+ regulator-name = "smps8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* SMPS9 unused */
+
+ ldo1_reg: ldo1 {
+ /* VDD_SD / VDDSHV8 */
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2_reg: ldo2 {
+ /* VDD_SHV5 */
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo3_reg: ldo3 {
+ /* VDDA_1V8_PHYA */
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo4_reg: ldo4 {
+ /* VDDA_1V8_PHYB */
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo9_reg: ldo9 {
+ /* VDD_RTC */
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldoln_reg: ldoln {
+ /* VDDA_1V8_PLL */
+ regulator-name = "ldoln";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldousb_reg: ldousb {
+ /* VDDA_3V_USB: VDDA_USBHS33 */
+ regulator-name = "ldousb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ regen1: regen1 {
+ /* VDD_3V3_ON */
+ regulator-name = "regen1";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+
+ tps659038_rtc: tps659038_rtc {
+ compatible = "ti,palmas-rtc";
+ interrupt-parent = <&tps659038>;
+ interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
+ };
+
+ tps659038_pwr_button: tps659038_pwr_button {
+ compatible = "ti,palmas-pwrbutton";
+ interrupt-parent = <&tps659038>;
+ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
+ ti,palmas-long-press-seconds = <12>;
+ };
+
+ tps659038_gpio: tps659038_gpio {
+ compatible = "ti,palmas-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ extcon_usb2: tps659038_usb {
+ compatible = "ti,palmas-usb-vid";
+ ti,enable-vbus-detection;
+ vbus-gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
+ };
+
+ };
+
+ tmp102: tmp102@48 {
+ compatible = "ti,tmp102";
+ reg = <0x48>;
+ interrupt-parent = <&gpio7>;
+ interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+ #thermal-sensor-cells = <1>;
+ };
+
+ tlv320aic3104: tlv320aic3104@18 {
+ #sound-dai-cells = <0>;
+ compatible = "ti,tlv320aic3104";
+ reg = <0x18>;
+ assigned-clocks = <&clkoutmux2_clk_mux>;
+ assigned-clock-parents = <&sys_clk2_dclk_div>;
+
+ status = "okay";
+ adc-settle-ms = <40>;
+
+ AVDD-supply = <&vdd_3v3>;
+ IOVDD-supply = <&vdd_3v3>;
+ DRVDD-supply = <&vdd_3v3>;
+ DVDD-supply = <&aic_dvdd>;
+ };
+
+ eeprom: eeprom@50 {
+ compatible = "at,24c32";
+ reg = <0x50>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ mcp_rtc: rtc@6f {
+ compatible = "microchip,mcp7941x";
+ reg = <0x6f>;
+ interrupts-extended = <&crossbar_mpu GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
+ <&dra7_pmx_core 0x424>;
+ interrupt-names = "irq", "wakeup";
+
+ vcc-supply = <&vdd_3v3>;
+ wakeup-source;
+ };
+};
+
+&gpio7 {
+ ti,no-reset-on-init;
+ ti,no-idle-on-init;
+};
+
+&cpu0 {
+ cpu0-supply = <&smps12_reg>;
+ voltage-tolerance = <1>;
+};
+
+&uart3 {
+ status = "okay";
+ interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+ <&dra7_pmx_core 0x3f8>;
+};
+
+&mac {
+ status = "okay";
+ dual_emac;
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii";
+ dual_emac_res_vlan = <1>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <2>;
+ phy-mode = "rgmii";
+ dual_emac_res_vlan = <2>;
+};
+
+&mmc1 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_default>;
+
+ bus-width = <4>;
+ cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>; /* gpio 219 */
+};
+
+&mmc2 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_default>;
+
+ vmmc-supply = <&vdd_3v3>;
+ bus-width = <8>;
+ ti,non-removable;
+ cap-mmc-dual-data-rate;
+};
+
+&sata {
+ status = "okay";
+};
+
+&usb2_phy1 {
+ phy-supply = <&ldousb_reg>;
+};
+
+&usb2_phy2 {
+ phy-supply = <&ldousb_reg>;
+};
+
+&usb1 {
+ dr_mode = "host";
+};
+
+&omap_dwc3_2 {
+ extcon = <&extcon_usb2>;
+};
+
+&usb2 {
+ /*
+ * Stand alone usage is peripheral only.
+ * However, with some resistor modifications
+ * this port can be used via expansion connectors
+ * as "host" or "dual-role". If so, provide
+ * the necessary dr_mode override in the expansion
+ * board's DT.
+ */
+ dr_mode = "peripheral";
+};
+
+&cpu_trips {
+ cpu_alert1: cpu_alert1 {
+ temperature = <50000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "active";
+ };
+};
+
+&cpu_cooling_maps {
+ map1 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&gpio_fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+};
+
+&thermal_zones {
+ board_thermal: board_thermal {
+ polling-delay-passive = <1250>; /* milliseconds */
+ polling-delay = <1500>; /* milliseconds */
+
+ /* sensor ID */
+ thermal-sensors = <&tmp102 0>;
+
+ board_trips: trips {
+ board_alert0: board_alert {
+ temperature = <40000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "active";
+ };
+
+ board_crit: board_crit {
+ temperature = <105000>; /* millicelsius */
+ hysteresis = <0>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ board_cooling_maps: cooling-maps {
+ map0 {
+ trip = <&board_alert0>;
+ cooling-device =
+ <&gpio_fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+};
+
+&dss {
+ status = "ok";
+
+ vdda_video-supply = <&ldoln_reg>;
+};
+
+&hdmi {
+ status = "ok";
+ vdda-supply = <&ldo4_reg>;
+
+ port {
+ hdmi_out: endpoint {
+ remote-endpoint = <&tpd12s015_in>;
+ };
+ };
+};
+
+&pcie1 {
+ gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
+};
+
+&mcasp3 {
+ #sound-dai-cells = <0>;
+ assigned-clocks = <&mcasp3_ahclkx_mux>;
+ assigned-clock-parents = <&sys_clkin2>;
+ status = "okay";
+
+ op-mode = <0>; /* MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ /* 4 serializers */
+ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
+ 1 2 0 0
+ >;
+ tx-num-evt = <32>;
+ rx-num-evt = <32>;
+};
+
+&mailbox5 {
+ status = "okay";
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ status = "okay";
+ };
+};
+
+&mailbox6 {
+ status = "okay";
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp2_ipc3x: mbox_dsp2_ipc3x {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-revb1.dts b/arch/arm/boot/dts/am57xx-beagle-x15-revb1.dts
new file mode 100644
index 000000000000..ca85570629fd
--- /dev/null
+++ b/arch/arm/boot/dts/am57xx-beagle-x15-revb1.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014-2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "am57xx-beagle-x15-common.dtsi"
+
+/ {
+ model = "TI AM5728 BeagleBoard-X15 rev B1";
+};
+
+&tpd12s015 {
+ gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>, /* gpio7_10, CT CP HPD */
+ <&gpio2 30 GPIO_ACTIVE_HIGH>, /* gpio2_30, LS OE */
+ <&gpio7 12 GPIO_ACTIVE_HIGH>; /* gpio7_12/sp1_cs2, HPD */
+};
+
+&mmc1 {
+ vmmc-supply = <&vdd_3v3>;
+ vmmc-aux-supply = <&ldo1_reg>;
+};
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
index c4d04c5293b9..8c66f2efd283 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -1,822 +1,24 @@
/*
- * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2014-2016 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-/dts-v1/;
-#include "dra74x.dtsi"
-#include "am57xx-commercial-grade.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/interrupt-controller/irq.h>
+#include "am57xx-beagle-x15-common.dtsi"
/ {
+ /* NOTE: This describes the "original" pre-production A2 revision */
model = "TI AM5728 BeagleBoard-X15";
- compatible = "ti,am572x-beagle-x15", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7";
-
- aliases {
- rtc0 = &mcp_rtc;
- rtc1 = &tps659038_rtc;
- rtc2 = &rtc;
- display0 = &hdmi0;
- };
-
- memory {
- device_type = "memory";
- reg = <0x0 0x80000000 0x0 0x80000000>;
- };
-
- vdd_3v3: fixedregulator-vdd_3v3 {
- compatible = "regulator-fixed";
- regulator-name = "vdd_3v3";
- vin-supply = <&regen1>;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- aic_dvdd: fixedregulator-aic_dvdd {
- compatible = "regulator-fixed";
- regulator-name = "aic_dvdd_fixed";
- vin-supply = <&vdd_3v3>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vtt_fixed: fixedregulator-vtt {
- /* TPS51200 */
- compatible = "regulator-fixed";
- regulator-name = "vtt_fixed";
- vin-supply = <&smps3_reg>;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
- enable-active-high;
- gpio = <&gpio7 11 GPIO_ACTIVE_HIGH>;
- };
-
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&leds_pins_default>;
-
- led@0 {
- label = "beagle-x15:usr0";
- gpios = <&gpio7 9 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "heartbeat";
- default-state = "off";
- };
-
- led@1 {
- label = "beagle-x15:usr1";
- gpios = <&gpio7 8 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "cpu0";
- default-state = "off";
- };
-
- led@2 {
- label = "beagle-x15:usr2";
- gpios = <&gpio7 14 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "mmc0";
- default-state = "off";
- };
-
- led@3 {
- label = "beagle-x15:usr3";
- gpios = <&gpio7 15 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "disk-activity";
- default-state = "off";
- };
- };
-
- gpio_fan: gpio_fan {
- /* Based on 5v 500mA AFB02505HHB */
- compatible = "gpio-fan";
- gpios = <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>;
- gpio-fan,speed-map = <0 0>,
- <13000 1>;
- #cooling-cells = <2>;
- };
-
- hdmi0: connector {
- compatible = "hdmi-connector";
- label = "hdmi";
-
- type = "a";
-
- port {
- hdmi_connector_in: endpoint {
- remote-endpoint = <&tpd12s015_out>;
- };
- };
- };
-
- tpd12s015: encoder {
- compatible = "ti,tpd12s015";
-
- pinctrl-names = "default";
- pinctrl-0 = <&tpd12s015_pins>;
-
- gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>, /* gpio7_10, CT CP HPD */
- <&gpio6 28 GPIO_ACTIVE_HIGH>, /* gpio6_28, LS OE */
- <&gpio7 12 GPIO_ACTIVE_HIGH>; /* gpio7_12/sp1_cs2, HPD */
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
-
- tpd12s015_in: endpoint {
- remote-endpoint = <&hdmi_out>;
- };
- };
-
- port@1 {
- reg = <1>;
-
- tpd12s015_out: endpoint {
- remote-endpoint = <&hdmi_connector_in>;
- };
- };
- };
- };
-
- sound0: sound0 {
- compatible = "simple-audio-card";
- simple-audio-card,name = "BeagleBoard-X15";
- simple-audio-card,widgets =
- "Line", "Line Out",
- "Line", "Line In";
- simple-audio-card,routing =
- "Line Out", "LLOUT",
- "Line Out", "RLOUT",
- "MIC2L", "Line In",
- "MIC2R", "Line In";
- simple-audio-card,format = "dsp_b";
- simple-audio-card,bitclock-master = <&sound0_master>;
- simple-audio-card,frame-master = <&sound0_master>;
- simple-audio-card,bitclock-inversion;
-
- simple-audio-card,cpu {
- sound-dai = <&mcasp3>;
- };
-
- sound0_master: simple-audio-card,codec {
- sound-dai = <&tlv320aic3104>;
- clocks = <&clkout2_clk>;
- };
- };
};
-&dra7_pmx_core {
- leds_pins_default: leds_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x37a8, PIN_OUTPUT | MUX_MODE14) /* spi1_d1.gpio7_8 */
- DRA7XX_CORE_IOPAD(0x37ac, PIN_OUTPUT | MUX_MODE14) /* spi1_d0.gpio7_9 */
- DRA7XX_CORE_IOPAD(0x37c0, PIN_OUTPUT | MUX_MODE14) /* spi2_sclk.gpio7_14 */
- DRA7XX_CORE_IOPAD(0x37c4, PIN_OUTPUT | MUX_MODE14) /* spi2_d1.gpio7_15 */
- >;
- };
-
- i2c1_pins_default: i2c1_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3800, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda.sda */
- DRA7XX_CORE_IOPAD(0x3804, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl.scl */
- >;
- };
-
- hdmi_pins: pinmux_hdmi_pins {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3808, PIN_INPUT | MUX_MODE1) /* i2c2_sda.hdmi1_ddc_scl */
- DRA7XX_CORE_IOPAD(0x380c, PIN_INPUT | MUX_MODE1) /* i2c2_scl.hdmi1_ddc_sda */
- >;
- };
-
- i2c3_pins_default: i2c3_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x36a4, PIN_INPUT| MUX_MODE10) /* mcasp1_aclkx.i2c3_sda */
- DRA7XX_CORE_IOPAD(0x36a8, PIN_INPUT| MUX_MODE10) /* mcasp1_fsx.i2c3_scl */
- >;
- };
-
- uart3_pins_default: uart3_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x37f8, PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
- DRA7XX_CORE_IOPAD(0x37fc, PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
- >;
- };
-
- mmc1_pins_default: mmc1_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x376c, PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
- DRA7XX_CORE_IOPAD(0x3754, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
- DRA7XX_CORE_IOPAD(0x3758, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
- DRA7XX_CORE_IOPAD(0x375c, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
- DRA7XX_CORE_IOPAD(0x3760, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
- DRA7XX_CORE_IOPAD(0x3764, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
- DRA7XX_CORE_IOPAD(0x3768, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
- >;
- };
-
- mmc2_pins_default: mmc2_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x349c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
- DRA7XX_CORE_IOPAD(0x34b0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
- DRA7XX_CORE_IOPAD(0x34a0, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
- DRA7XX_CORE_IOPAD(0x34a4, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
- DRA7XX_CORE_IOPAD(0x34a8, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
- DRA7XX_CORE_IOPAD(0x34ac, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
- DRA7XX_CORE_IOPAD(0x348c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
- DRA7XX_CORE_IOPAD(0x3490, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
- DRA7XX_CORE_IOPAD(0x3494, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
- DRA7XX_CORE_IOPAD(0x3498, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
- >;
- };
-
- cpsw_pins_default: cpsw_pins_default {
- pinctrl-single,pins = <
- /* Slave 1 */
- DRA7XX_CORE_IOPAD(0x3650, PIN_OUTPUT | MUX_MODE0) /* rgmii1_tclk */
- DRA7XX_CORE_IOPAD(0x3654, PIN_OUTPUT | MUX_MODE0) /* rgmii1_tctl */
- DRA7XX_CORE_IOPAD(0x3658, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td3 */
- DRA7XX_CORE_IOPAD(0x365c, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td2 */
- DRA7XX_CORE_IOPAD(0x3660, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td1 */
- DRA7XX_CORE_IOPAD(0x3664, PIN_OUTPUT | MUX_MODE0) /* rgmii1_td0 */
- DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT | MUX_MODE0) /* rgmii1_rclk */
- DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT | MUX_MODE0) /* rgmii1_rctl */
- DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT | MUX_MODE0) /* rgmii1_rd3 */
- DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT | MUX_MODE0) /* rgmii1_rd2 */
- DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT | MUX_MODE0) /* rgmii1_rd1 */
- DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT | MUX_MODE0) /* rgmii1_rd0 */
-
- /* Slave 2 */
- DRA7XX_CORE_IOPAD(0x3598, PIN_OUTPUT | MUX_MODE3) /* rgmii2_tclk */
- DRA7XX_CORE_IOPAD(0x359c, PIN_OUTPUT | MUX_MODE3) /* rgmii2_tctl */
- DRA7XX_CORE_IOPAD(0x35a0, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td3 */
- DRA7XX_CORE_IOPAD(0x35a4, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td2 */
- DRA7XX_CORE_IOPAD(0x35a8, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td1 */
- DRA7XX_CORE_IOPAD(0x35ac, PIN_OUTPUT | MUX_MODE3) /* rgmii2_td0 */
- DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE3) /* rgmii2_rclk */
- DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE3) /* rgmii2_rctl */
- DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE3) /* rgmii2_rd3 */
- DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE3) /* rgmii2_rd2 */
- DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE3) /* rgmii2_rd1 */
- DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE3) /* rgmii2_rd0 */
- >;
-
- };
-
- cpsw_pins_sleep: cpsw_pins_sleep {
- pinctrl-single,pins = <
- /* Slave 1 */
- DRA7XX_CORE_IOPAD(0x3650, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3654, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3658, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x365c, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3660, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3664, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3668, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x366c, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3670, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3674, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3678, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x367c, PIN_INPUT | MUX_MODE15)
-
- /* Slave 2 */
- DRA7XX_CORE_IOPAD(0x3598, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x359c, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35a0, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35a4, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35a8, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35ac, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35b0, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35b4, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT | MUX_MODE15)
- >;
- };
-
- davinci_mdio_pins_default: davinci_mdio_pins_default {
- pinctrl-single,pins = <
- /* MDIO */
- DRA7XX_CORE_IOPAD(0x363c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_mclk */
- DRA7XX_CORE_IOPAD(0x3640, PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_d */
- >;
- };
-
- davinci_mdio_pins_sleep: davinci_mdio_pins_sleep {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x363c, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3640, PIN_INPUT | MUX_MODE15)
- >;
- };
-
- tps659038_pins_default: tps659038_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3818, PIN_INPUT_PULLUP | MUX_MODE14) /* wakeup0.gpio1_0 */
- >;
- };
-
- tmp102_pins_default: tmp102_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x37c8, PIN_INPUT_PULLUP | MUX_MODE14) /* spi2_d0.gpio7_16 */
- >;
- };
-
- mcp79410_pins_default: mcp79410_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3824, PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
- >;
- };
-
- usb1_pins: pinmux_usb1_pins {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3680, PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
- >;
- };
-
- tpd12s015_pins: pinmux_tpd12s015_pins {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x37b0, PIN_OUTPUT | MUX_MODE14) /* gpio7_10 CT_CP_HPD */
- DRA7XX_CORE_IOPAD(0x37b8, PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
- DRA7XX_CORE_IOPAD(0x3770, PIN_OUTPUT | MUX_MODE14) /* gpio6_28 LS_OE */
- >;
- };
-
- clkout2_pins_default: clkout2_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3694, PIN_OUTPUT_PULLDOWN | MUX_MODE9) /* xref_clk0.clkout2 */
- >;
- };
-
- clkout2_pins_sleep: clkout2_pins_sleep {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3694, PIN_INPUT | MUX_MODE15) /* xref_clk0.clkout2 */
- >;
- };
-
- mcasp3_pins_default: mcasp3_pins_default {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx.mcasp3_aclkx */
- DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx.mcasp3_fsx */
- DRA7XX_CORE_IOPAD(0x372c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0.mcasp3_axr0 */
- DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1.mcasp3_axr1 */
- >;
- };
-
- mcasp3_pins_sleep: mcasp3_pins_sleep {
- pinctrl-single,pins = <
- DRA7XX_CORE_IOPAD(0x3724, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3728, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x372c, PIN_INPUT | MUX_MODE15)
- DRA7XX_CORE_IOPAD(0x3730, PIN_INPUT | MUX_MODE15)
- >;
- };
-};
-
-&i2c1 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_default>;
- clock-frequency = <400000>;
-
- tps659038: tps659038@58 {
- compatible = "ti,tps659038";
- reg = <0x58>;
- interrupt-parent = <&gpio1>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&tps659038_pins_default>;
-
- #interrupt-cells = <2>;
- interrupt-controller;
-
- ti,system-power-controller;
-
- tps659038_pmic {
- compatible = "ti,tps659038-pmic";
-
- regulators {
- smps12_reg: smps12 {
- /* VDD_MPU */
- regulator-name = "smps12";
- regulator-min-microvolt = < 850000>;
- regulator-max-microvolt = <1250000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps3_reg: smps3 {
- /* VDD_DDR */
- regulator-name = "smps3";
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps45_reg: smps45 {
- /* VDD_DSPEVE, VDD_IVA, VDD_GPU */
- regulator-name = "smps45";
- regulator-min-microvolt = < 850000>;
- regulator-max-microvolt = <1250000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps6_reg: smps6 {
- /* VDD_CORE */
- regulator-name = "smps6";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1150000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- /* SMPS7 unused */
-
- smps8_reg: smps8 {
- /* VDD_1V8 */
- regulator-name = "smps8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- /* SMPS9 unused */
-
- ldo1_reg: ldo1 {
- /* VDD_SD / VDDSHV8 */
- regulator-name = "ldo1";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- regulator-always-on;
- };
-
- ldo2_reg: ldo2 {
- /* VDD_SHV5 */
- regulator-name = "ldo2";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldo3_reg: ldo3 {
- /* VDDA_1V8_PHYA */
- regulator-name = "ldo3";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldo4_reg: ldo4 {
- /* VDDA_1V8_PHYB */
- regulator-name = "ldo4";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldo9_reg: ldo9 {
- /* VDD_RTC */
- regulator-name = "ldo9";
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldoln_reg: ldoln {
- /* VDDA_1V8_PLL */
- regulator-name = "ldoln";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldousb_reg: ldousb {
- /* VDDA_3V_USB: VDDA_USBHS33 */
- regulator-name = "ldousb";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
- regen1: regen1 {
- /* VDD_3V3_ON */
- regulator-name = "regen1";
- regulator-boot-on;
- regulator-always-on;
- };
- };
- };
-
- tps659038_rtc: tps659038_rtc {
- compatible = "ti,palmas-rtc";
- interrupt-parent = <&tps659038>;
- interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
- wakeup-source;
- };
-
- tps659038_pwr_button: tps659038_pwr_button {
- compatible = "ti,palmas-pwrbutton";
- interrupt-parent = <&tps659038>;
- interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
- wakeup-source;
- ti,palmas-long-press-seconds = <12>;
- };
-
- tps659038_gpio: tps659038_gpio {
- compatible = "ti,palmas-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- extcon_usb2: tps659038_usb {
- compatible = "ti,palmas-usb-vid";
- ti,enable-vbus-detection;
- vbus-gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
- };
-
- };
-
- tmp102: tmp102@48 {
- compatible = "ti,tmp102";
- reg = <0x48>;
- pinctrl-names = "default";
- pinctrl-0 = <&tmp102_pins_default>;
- interrupt-parent = <&gpio7>;
- interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
- #thermal-sensor-cells = <1>;
- };
-
- tlv320aic3104: tlv320aic3104@18 {
- #sound-dai-cells = <0>;
- compatible = "ti,tlv320aic3104";
- reg = <0x18>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&clkout2_pins_default>;
- pinctrl-1 = <&clkout2_pins_sleep>;
- assigned-clocks = <&clkoutmux2_clk_mux>;
- assigned-clock-parents = <&sys_clk2_dclk_div>;
-
- status = "okay";
- adc-settle-ms = <40>;
-
- AVDD-supply = <&vdd_3v3>;
- IOVDD-supply = <&vdd_3v3>;
- DRVDD-supply = <&vdd_3v3>;
- DVDD-supply = <&aic_dvdd>;
- };
-
- eeprom: eeprom@50 {
- compatible = "at,24c32";
- reg = <0x50>;
- };
-};
-
-&i2c3 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c3_pins_default>;
- clock-frequency = <400000>;
-
- mcp_rtc: rtc@6f {
- compatible = "microchip,mcp7941x";
- reg = <0x6f>;
- interrupts-extended = <&crossbar_mpu GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
- <&dra7_pmx_core 0x424>;
- interrupt-names = "irq", "wakeup";
-
- pinctrl-names = "default";
- pinctrl-0 = <&mcp79410_pins_default>;
-
- vcc-supply = <&vdd_3v3>;
- wakeup-source;
- };
-};
-
-&gpio7 {
- ti,no-reset-on-init;
- ti,no-idle-on-init;
-};
-
-&cpu0 {
- cpu0-supply = <&smps12_reg>;
- voltage-tolerance = <1>;
-};
-
-&uart3 {
- status = "okay";
- interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
- <&dra7_pmx_core 0x3f8>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins_default>;
-};
-
-&mac {
- status = "okay";
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&cpsw_pins_default>;
- pinctrl-1 = <&cpsw_pins_sleep>;
- dual_emac;
-};
-
-&cpsw_emac0 {
- phy_id = <&davinci_mdio>, <1>;
- phy-mode = "rgmii";
- dual_emac_res_vlan = <1>;
-};
-
-&cpsw_emac1 {
- phy_id = <&davinci_mdio>, <2>;
- phy-mode = "rgmii";
- dual_emac_res_vlan = <2>;
-};
-
-&davinci_mdio {
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&davinci_mdio_pins_default>;
- pinctrl-1 = <&davinci_mdio_pins_sleep>;
+&tpd12s015 {
+ gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>, /* gpio7_10, CT CP HPD */
+ <&gpio6 28 GPIO_ACTIVE_HIGH>, /* gpio6_28, LS OE */
+ <&gpio7 12 GPIO_ACTIVE_HIGH>; /* gpio7_12/sp1_cs2, HPD */
};
&mmc1 {
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&mmc1_pins_default>;
-
vmmc-supply = <&ldo1_reg>;
- bus-width = <4>;
- cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>; /* gpio 219 */
-};
-
-&mmc2 {
- status = "okay";
-
- pinctrl-names = "default";
- pinctrl-0 = <&mmc2_pins_default>;
-
- vmmc-supply = <&vdd_3v3>;
- bus-width = <8>;
- ti,non-removable;
- cap-mmc-dual-data-rate;
-};
-
-&sata {
- status = "okay";
-};
-
-&usb2_phy1 {
- phy-supply = <&ldousb_reg>;
-};
-
-&usb2_phy2 {
- phy-supply = <&ldousb_reg>;
-};
-
-&usb1 {
- dr_mode = "host";
- pinctrl-names = "default";
- pinctrl-0 = <&usb1_pins>;
-};
-
-&omap_dwc3_2 {
- extcon = <&extcon_usb2>;
-};
-
-&usb2 {
- /*
- * Stand alone usage is peripheral only.
- * However, with some resistor modifications
- * this port can be used via expansion connectors
- * as "host" or "dual-role". If so, provide
- * the necessary dr_mode override in the expansion
- * board's DT.
- */
- dr_mode = "peripheral";
-};
-
-&cpu_trips {
- cpu_alert1: cpu_alert1 {
- temperature = <50000>; /* millicelsius */
- hysteresis = <2000>; /* millicelsius */
- type = "active";
- };
-};
-
-&cpu_cooling_maps {
- map1 {
- trip = <&cpu_alert1>;
- cooling-device = <&gpio_fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
-};
-
-&thermal_zones {
- board_thermal: board_thermal {
- polling-delay-passive = <1250>; /* milliseconds */
- polling-delay = <1500>; /* milliseconds */
-
- /* sensor ID */
- thermal-sensors = <&tmp102 0>;
-
- board_trips: trips {
- board_alert0: board_alert {
- temperature = <40000>; /* millicelsius */
- hysteresis = <2000>; /* millicelsius */
- type = "active";
- };
-
- board_crit: board_crit {
- temperature = <105000>; /* millicelsius */
- hysteresis = <0>; /* millicelsius */
- type = "critical";
- };
- };
-
- board_cooling_maps: cooling-maps {
- map0 {
- trip = <&board_alert0>;
- cooling-device =
- <&gpio_fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-};
-
-&dss {
- status = "ok";
-
- vdda_video-supply = <&ldoln_reg>;
-};
-
-&hdmi {
- status = "ok";
- vdda-supply = <&ldo4_reg>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_pins>;
-
- port {
- hdmi_out: endpoint {
- remote-endpoint = <&tpd12s015_in>;
- };
- };
-};
-
-&pcie1 {
- gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
-};
-
-&mcasp3 {
- #sound-dai-cells = <0>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&mcasp3_pins_default>;
- pinctrl-1 = <&mcasp3_pins_sleep>;
- assigned-clocks = <&mcasp3_ahclkx_mux>;
- assigned-clock-parents = <&sys_clkin2>;
- status = "okay";
-
- op-mode = <0>; /* MCASP_IIS_MODE */
- tdm-slots = <2>;
- /* 4 serializers */
- serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
- 1 2 0 0
- >;
- tx-num-evt = <32>;
- rx-num-evt = <32>;
-};
-
-&mailbox5 {
- status = "okay";
- mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
- status = "okay";
- };
- mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
- status = "okay";
- };
-};
-
-&mailbox6 {
- status = "okay";
- mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
- status = "okay";
- };
- mbox_dsp2_ipc3x: mbox_dsp2_ipc3x {
- status = "okay";
- };
};
diff --git a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
index 378b142ef88c..203266f88480 100644
--- a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
+++ b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
@@ -19,7 +19,7 @@
model = "CompuLab CL-SOM-AM57x";
compatible = "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7";
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x20000000>; /* 512 MB - minimal configuration */
};
@@ -29,7 +29,7 @@
pinctrl-names = "default";
pinctrl-0 = <&leds_pins_default>;
- led@0 {
+ led0 {
label = "cl-som-am57x:green";
gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi
index 0e63b9dff6e7..03cec62260e1 100644
--- a/arch/arm/boot/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi
@@ -304,3 +304,52 @@
ti,non-removable;
max-frequency = <96000000>;
};
+
+&qspi {
+ status = "okay";
+
+ spi-max-frequency = <76800000>;
+ m25p80@0 {
+ compatible = "s25fl256s1", "jedec,spi-nor";
+ spi-max-frequency = <76800000>;
+ reg = <0>;
+ spi-tx-bus-width = <1>;
+ spi-rx-bus-width = <4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* MTD partition table.
+ * The ROM checks the first four physical blocks
+ * for a valid file to boot and the flash here is
+ * 64KiB block size.
+ */
+ partition@0 {
+ label = "QSPI.SPL";
+ reg = <0x00000000 0x000040000>;
+ };
+ partition@1 {
+ label = "QSPI.u-boot";
+ reg = <0x00040000 0x00100000>;
+ };
+ partition@2 {
+ label = "QSPI.u-boot-spl-os";
+ reg = <0x00140000 0x00080000>;
+ };
+ partition@3 {
+ label = "QSPI.u-boot-env";
+ reg = <0x001c0000 0x00010000>;
+ };
+ partition@4 {
+ label = "QSPI.u-boot-env.backup1";
+ reg = <0x001d0000 0x0010000>;
+ };
+ partition@5 {
+ label = "QSPI.kernel";
+ reg = <0x001e0000 0x0800000>;
+ };
+ partition@6 {
+ label = "QSPI.file-system";
+ reg = <0x009e0000 0x01620000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd-ctrevb.dts b/arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd-ctrevb.dts
new file mode 100644
index 000000000000..e18769df9fd9
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd-ctrevb.dts
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "arm-realview-eb-11mp-ctrevb.dts"
+#include "arm-realview-eb-bbrevd.dtsi"
+
+/*
+ * This is the EB with the new Revision D baseboard with SMSC9118 ethernet and
+ * the Rev B core tile.
+ */
+/ {
+ model = "ARM RealView Emulation Baseboard Rev D with ARM11MPCore Core Tile Rev B";
+};
diff --git a/arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd.dts b/arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd.dts
new file mode 100644
index 000000000000..26b1c69e9f43
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-eb-11mp-bbrevd.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "arm-realview-eb-11mp.dts"
+#include "arm-realview-eb-bbrevd.dtsi"
+
+/ {
+ model = "ARM RealView Emulation Baseboard Rev D with ARM11MPCore Rev C Core Tile";
+};
diff --git a/arch/arm/boot/dts/arm-realview-eb-11mp-revb.dts b/arch/arm/boot/dts/arm-realview-eb-11mp-ctrevb.dts
index e68527b0d552..e68527b0d552 100644
--- a/arch/arm/boot/dts/arm-realview-eb-11mp-revb.dts
+++ b/arch/arm/boot/dts/arm-realview-eb-11mp-ctrevb.dts
diff --git a/arch/arm/boot/dts/arm-realview-eb-11mp.dts b/arch/arm/boot/dts/arm-realview-eb-11mp.dts
index 87ff602a2a2d..aac1edd4b227 100644
--- a/arch/arm/boot/dts/arm-realview-eb-11mp.dts
+++ b/arch/arm/boot/dts/arm-realview-eb-11mp.dts
@@ -24,7 +24,7 @@
#include "arm-realview-eb-mp.dtsi"
/ {
- model = "ARM RealView Emulation Baseboard with ARM11MPCore Rev C";
+ model = "ARM RealView Emulation Baseboard with ARM11MPCore Rev C Core Tile";
arm,hbi = <0x146>;
/*
diff --git a/arch/arm/boot/dts/arm-realview-eb-a9mp-bbrevd.dts b/arch/arm/boot/dts/arm-realview-eb-a9mp-bbrevd.dts
new file mode 100644
index 000000000000..42efac7496ef
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-eb-a9mp-bbrevd.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "arm-realview-eb-a9mp.dts"
+#include "arm-realview-eb-bbrevd.dtsi"
+
+/ {
+ model = "ARM RealView EB Baseboard Rev D Cortex A9 MPCore";
+};
diff --git a/arch/arm/boot/dts/arm-realview-eb-bbrevd.dts b/arch/arm/boot/dts/arm-realview-eb-bbrevd.dts
new file mode 100644
index 000000000000..f533c8b49d97
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-eb-bbrevd.dts
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This derives from the Realview Baseboard, and overlays the new ethernet */
+#include "arm-realview-eb.dts"
+#include "arm-realview-eb-bbrevd.dtsi"
+
+/ {
+ model = "ARM RealView Emulation Baseboard Rev D";
+};
diff --git a/arch/arm/boot/dts/arm-realview-eb-bbrevd.dtsi b/arch/arm/boot/dts/arm-realview-eb-bbrevd.dtsi
new file mode 100644
index 000000000000..a79e1d1d30a7
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-eb-bbrevd.dtsi
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE 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.
+ */
+
+/ {
+ /* Introduce a fixed regulator for the new ethernet controller */
+ veth: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "veth";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+};
+
+/*
+ * The revision D has a different ethernet controller that the elder boards:
+ * the older board uses LAN91C111 but the new one uses LAN9118.
+ */
+&ethernet {
+ compatible = "smsc,lan9118", "smsc,lan9115";
+ phy-mode = "mii";
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
+ vdd33a-supply = <&veth>;
+ vddvario-supply = <&veth>;
+};
diff --git a/arch/arm/boot/dts/arm-realview-eb.dtsi b/arch/arm/boot/dts/arm-realview-eb.dtsi
index 1c6a040218e3..e2e9599596e2 100644
--- a/arch/arm/boot/dts/arm-realview-eb.dtsi
+++ b/arch/arm/boot/dts/arm-realview-eb.dtsi
@@ -51,14 +51,6 @@
regulator-boot-on;
};
- veth: fixedregulator@0 {
- compatible = "regulator-fixed";
- regulator-name = "veth";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
xtal24mhz: xtal24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -134,16 +126,15 @@
bank-width = <4>;
};
- /* SMSC 9118 ethernet with PHY and EEPROM */
+ /* SMSC LAN91C111 ethernet with PHY and EEPROM */
ethernet: ethernet@4e000000 {
- compatible = "smsc,lan9118", "smsc,lan9115";
+ compatible = "smsc,lan91c111";
reg = <0x4e000000 0x10000>;
- phy-mode = "mii";
- reg-io-width = <4>;
- smsc,irq-active-high;
- smsc,irq-push-pull;
- vdd33a-supply = <&veth>;
- vddvario-supply = <&veth>;
+ /*
+ * This means the adapter can be accessed with 8, 16 or
+ * 32 bit reads/writes.
+ */
+ reg-io-width = <7>;
};
usb: usb@4f000000 {
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index 2364fc56ae13..033fa63544f7 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -155,20 +155,6 @@
status = "okay";
};
- spi0: spi@10600 {
- pinctrl-0 = <&spi0_pins2>;
- pinctrl-names = "default";
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "mx25l25635e", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <50000000>;
- };
- };
-
nand@d0000 {
status = "okay";
num-cs = <1>;
@@ -274,3 +260,18 @@
compatible = "linux,spdif-dir";
};
};
+
+&spi0 {
+ pinctrl-0 = <&spi0_pins2>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "mx25l25635e", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <50000000>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
index 1aba08e4377c..01cded310cbc 100644
--- a/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
+++ b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
@@ -68,26 +68,6 @@
phy-mode = "rgmii-id";
};
- spi@10600 {
- status = "okay";
- pinctrl-0 = <&spi0_pins2>;
- pinctrl-names = "default";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- /* MX25L8006E */
- compatible = "mxicy,mx25l8005", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <50000000>;
-
- partition@0 {
- label = "u-boot";
- reg = <0x0 0x100000>;
- };
- };
- };
-
usb@50000 {
status = "okay";
};
@@ -176,3 +156,23 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ status = "okay";
+ pinctrl-0 = <&spi0_pins2>;
+ pinctrl-names = "default";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* MX25L8006E */
+ compatible = "mxicy,mx25l8005", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <50000000>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x100000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
index 8ca7a4340c0f..a9cc42776874 100644
--- a/arch/arm/boot/dts/armada-370-synology-ds213j.dts
+++ b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
@@ -87,62 +87,6 @@
status = "disabled";
};
- spi0: spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "micron,n25q064", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <20000000>;
-
- /*
- * Warning!
- *
- * Synology u-boot uses its compiled-in environment
- * and it seems Synology did not care to change u-boot
- * default configuration in order to allow saving a
- * modified environment at a sensible location. So,
- * if you do a 'saveenv' under u-boot, your modified
- * environment will be saved at 1MB after the start
- * of the flash, i.e. in the middle of the uImage.
- * For that reason, it is strongly advised not to
- * change the default environment, unless you know
- * what you are doing.
- */
- partition@00000000 { /* u-boot */
- label = "RedBoot";
- reg = <0x00000000 0x000c0000>; /* 768KB */
- };
-
- partition@000c0000 { /* uImage */
- label = "zImage";
- reg = <0x000c0000 0x002d0000>; /* 2880KB */
- };
-
- partition@00390000 { /* uInitramfs */
- label = "rd.gz";
- reg = <0x00390000 0x00440000>; /* 4250KB */
- };
-
- partition@007d0000 { /* MAC address and serial number */
- label = "vendor";
- reg = <0x007d0000 0x00010000>; /* 64KB */
- };
-
- partition@007e0000 {
- label = "RedBoot config";
- reg = <0x007e0000 0x00010000>; /* 64KB */
- };
-
- partition@007f0000 {
- label = "FIS directory";
- reg = <0x007f0000 0x00010000>; /* 64KB */
- };
- };
- };
-
i2c@11000 {
compatible = "marvell,mv64xxx-i2c";
pinctrl-0 = <&i2c0_pins>;
@@ -347,3 +291,59 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q064", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <20000000>;
+
+ /*
+ * Warning!
+ *
+ * Synology u-boot uses its compiled-in environment
+ * and it seems Synology did not care to change u-boot
+ * default configuration in order to allow saving a
+ * modified environment at a sensible location. So,
+ * if you do a 'saveenv' under u-boot, your modified
+ * environment will be saved at 1MB after the start
+ * of the flash, i.e. in the middle of the uImage.
+ * For that reason, it is strongly advised not to
+ * change the default environment, unless you know
+ * what you are doing.
+ */
+ partition@00000000 { /* u-boot */
+ label = "RedBoot";
+ reg = <0x00000000 0x000c0000>; /* 768KB */
+ };
+
+ partition@000c0000 { /* uImage */
+ label = "zImage";
+ reg = <0x000c0000 0x002d0000>; /* 2880KB */
+ };
+
+ partition@00390000 { /* uInitramfs */
+ label = "rd.gz";
+ reg = <0x00390000 0x00440000>; /* 4250KB */
+ };
+
+ partition@007d0000 { /* MAC address and serial number */
+ label = "vendor";
+ reg = <0x007d0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007e0000 {
+ label = "RedBoot config";
+ reg = <0x007e0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007f0000 {
+ label = "FIS directory";
+ reg = <0x007f0000 0x00010000>; /* 64KB */
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index a718866ba52d..3ccedc9dffb2 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -148,26 +148,6 @@
interrupts = <50>;
};
- spi0: spi@10600 {
- reg = <0x10600 0x28>;
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <0>;
- interrupts = <30>;
- clocks = <&coreclk 0>;
- status = "disabled";
- };
-
- spi1: spi@10680 {
- reg = <0x10680 0x28>;
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- interrupts = <92>;
- clocks = <&coreclk 0>;
- status = "disabled";
- };
-
i2c0: i2c@11000 {
compatible = "marvell,mv64xxx-i2c";
#address-cells = <1>;
@@ -320,6 +300,42 @@
status = "disabled";
};
};
+
+ spi0: spi@10600 {
+ reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x28>, /* control */
+ <MBUS_ID(0x01, 0x1e) 0 0xffffffff>, /* CS0 */
+ <MBUS_ID(0x01, 0x5e) 0 0xffffffff>, /* CS1 */
+ <MBUS_ID(0x01, 0x9e) 0 0xffffffff>, /* CS2 */
+ <MBUS_ID(0x01, 0xde) 0 0xffffffff>, /* CS3 */
+ <MBUS_ID(0x01, 0x1f) 0 0xffffffff>, /* CS4 */
+ <MBUS_ID(0x01, 0x5f) 0 0xffffffff>, /* CS5 */
+ <MBUS_ID(0x01, 0x9f) 0 0xffffffff>, /* CS6 */
+ <MBUS_ID(0x01, 0xdf) 0 0xffffffff>; /* CS7 */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ interrupts = <30>;
+ clocks = <&coreclk 0>;
+ status = "disabled";
+ };
+
+ spi1: spi@10680 {
+ reg = <MBUS_ID(0xf0, 0x01) 0x10680 0x28>, /* control */
+ <MBUS_ID(0x01, 0x1a) 0 0xffffffff>, /* CS0 */
+ <MBUS_ID(0x01, 0x5a) 0 0xffffffff>, /* CS1 */
+ <MBUS_ID(0x01, 0x9a) 0 0xffffffff>, /* CS2 */
+ <MBUS_ID(0x01, 0xda) 0 0xffffffff>, /* CS3 */
+ <MBUS_ID(0x01, 0x1b) 0 0xffffffff>, /* CS4 */
+ <MBUS_ID(0x01, 0x5b) 0 0xffffffff>, /* CS5 */
+ <MBUS_ID(0x01, 0x9b) 0 0xffffffff>, /* CS6 */
+ <MBUS_ID(0x01, 0xdb) 0 0xffffffff>; /* CS7 */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ interrupts = <92>;
+ clocks = <&coreclk 0>;
+ status = "disabled";
+ };
};
clocks {
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 3b06aa835448..b4258105e91f 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -134,24 +134,6 @@
wt-override;
};
- /*
- * Default SPI pinctrl setting, can be overwritten on
- * board level if a different configuration is used.
- */
- spi0: spi@10600 {
- compatible = "marvell,armada-370-spi",
- "marvell,orion-spi";
- pinctrl-0 = <&spi0_pins1>;
- pinctrl-names = "default";
- };
-
- spi1: spi@10680 {
- compatible = "marvell,armada-370-spi",
- "marvell,orion-spi";
- pinctrl-0 = <&spi1_pins>;
- pinctrl-names = "default";
- };
-
i2c0: i2c@11000 {
reg = <0x11000 0x20>;
};
@@ -447,3 +429,19 @@
marvell,function = "ge1";
};
};
+
+/*
+ * Default SPI pinctrl setting, can be overwritten on
+ * board level if a different configuration is used.
+ */
+&spi0 {
+ compatible = "marvell,armada-370-spi", "marvell,orion-spi";
+ pinctrl-0 = <&spi0_pins1>;
+ pinctrl-names = "default";
+};
+
+&spi1 {
+ compatible = "marvell,armada-370-spi", "marvell,orion-spi";
+ pinctrl-0 = <&spi1_pins>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts
index 2d3fd6e76e2c..db5b9f6b615d 100644
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
@@ -65,20 +65,6 @@
MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
internal-regs {
- spi1: spi@10680 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi1_pins>;
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,m25p128", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <54000000>;
- };
- };
-
i2c0: i2c@11000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
@@ -155,6 +141,10 @@
bm,pool-short = <3>;
};
+ usb@58000 {
+ status = "okay";
+ };
+
/* CON4 */
ethernet@70000 {
pinctrl-names = "default";
@@ -178,15 +168,35 @@
nfc: flash@d0000 {
status = "okay";
- #address-cells = <1>;
- #size-cells = <1>;
-
num-cs = <1>;
nand-ecc-strength = <4>;
nand-ecc-step-size = <512>;
marvell,nand-keep-config;
marvell,nand-enable-arbiter;
nand-on-flash-bbt;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0x00000000 0x00800000>;
+ read-only;
+ };
+
+ partition@800000 {
+ label = "uImage";
+ reg = <0x00800000 0x00400000>;
+ read-only;
+ };
+
+ partition@c00000 {
+ label = "Root";
+ reg = <0x00c00000 0x3f400000>;
+ };
+ };
};
usb3@f0000 {
@@ -239,3 +249,17 @@
gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
};
};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins>;
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p128", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <54000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index 22f7a13e20b4..8f0e508f64ae 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -62,11 +62,6 @@
MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
internal-regs {
-
- spi@10600 {
- status = "disabled";
- };
-
i2c@11000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
@@ -332,3 +327,7 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/armada-388-clearfog.dts b/arch/arm/boot/dts/armada-388-clearfog.dts
index d3e6bd805006..71ce201c903e 100644
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
@@ -315,30 +315,6 @@
status = "okay";
};
- spi@10680 {
- /*
- * We don't seem to have the W25Q32 on the
- * A1 Rev 2.0 boards, so disable SPI.
- * CS0: W25Q32 (doesn't appear to be present)
- * CS1:
- * CS2: mikrobus
- */
- pinctrl-0 = <&spi1_pins
- &clearfog_spi1_cs_pins
- &mikro_spi_pins>;
- pinctrl-names = "default";
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "w25q32", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <3000000>;
- status = "disabled";
- };
- };
-
usb@58000 {
/* CON3, nearest power. */
status = "okay";
@@ -444,3 +420,27 @@
};
};
};
+
+&spi1 {
+ /*
+ * We don't seem to have the W25Q32 on the
+ * A1 Rev 2.0 boards, so disable SPI.
+ * CS0: W25Q32 (doesn't appear to be present)
+ * CS1:
+ * CS2: mikrobus
+ */
+ pinctrl-0 = <&spi1_pins
+ &clearfog_spi1_cs_pins
+ &mikro_spi_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "w25q32", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <3000000>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-388-db.dts b/arch/arm/boot/dts/armada-388-db.dts
index ea93ed727030..de26c762239c 100644
--- a/arch/arm/boot/dts/armada-388-db.dts
+++ b/arch/arm/boot/dts/armada-388-db.dts
@@ -70,18 +70,6 @@
MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
internal-regs {
- spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "w25q32", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <108000000>;
- };
- };
-
i2c@11000 {
status = "okay";
clock-frequency = <100000>;
@@ -201,3 +189,16 @@
};
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "w25q32", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <108000000>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index fd75e5e9550f..895fa6cfa15a 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -64,21 +64,6 @@
MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
internal-regs {
- spi@10600 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi0_pins>;
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,m25p128", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <50000000>;
- m25p,fast-read;
- };
- };
-
i2c@11000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
@@ -433,3 +418,18 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins>;
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p128", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <50000000>;
+ m25p,fast-read;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-388-rd.dts b/arch/arm/boot/dts/armada-388-rd.dts
index 853f9735cc70..dd3462ddb6b9 100644
--- a/arch/arm/boot/dts/armada-388-rd.dts
+++ b/arch/arm/boot/dts/armada-388-rd.dts
@@ -70,18 +70,6 @@
MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
internal-regs {
- spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,m25p128", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <108000000>;
- };
- };
-
i2c@11000 {
status = "okay";
clock-frequency = <100000>;
@@ -142,3 +130,16 @@
};
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p128", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <108000000>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index 3312be6c82cc..2d7668848c5a 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -170,30 +170,6 @@
<0xc100 0x100>;
};
- spi0: spi@10600 {
- compatible = "marvell,armada-380-spi",
- "marvell,orion-spi";
- reg = <0x10600 0x50>;
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <0>;
- interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&coreclk 0>;
- status = "disabled";
- };
-
- spi1: spi@10680 {
- compatible = "marvell,armada-380-spi",
- "marvell,orion-spi";
- reg = <0x10680 0x50>;
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&coreclk 0>;
- status = "disabled";
- };
-
i2c0: i2c@11000 {
compatible = "marvell,mv64xxx-i2c";
reg = <0x11000 0x20>;
@@ -287,6 +263,15 @@
marvell,function = "spi1";
};
+ nand_pins: nand-pins {
+ marvell,pins = "mpp22", "mpp34", "mpp23",
+ "mpp33", "mpp38", "mpp28",
+ "mpp40", "mpp42", "mpp35",
+ "mpp36", "mpp25", "mpp30",
+ "mpp32";
+ marvell,function = "dev";
+ };
+
uart0_pins: uart-pins-0 {
marvell,pins = "mpp0", "mpp1";
marvell,function = "ua0";
@@ -649,6 +634,30 @@
no-memory-wc;
status = "disabled";
};
+
+ spi0: spi@10600 {
+ compatible = "marvell,armada-380-spi",
+ "marvell,orion-spi";
+ reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&coreclk 0>;
+ status = "disabled";
+ };
+
+ spi1: spi@10680 {
+ compatible = "marvell,armada-380-spi",
+ "marvell,orion-spi";
+ reg = <MBUS_ID(0xf0, 0x01) 0x10680 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&coreclk 0>;
+ status = "disabled";
+ };
};
clocks {
diff --git a/arch/arm/boot/dts/armada-390-db.dts b/arch/arm/boot/dts/armada-390-db.dts
new file mode 100644
index 000000000000..34e279d973c8
--- /dev/null
+++ b/arch/arm/boot/dts/armada-390-db.dts
@@ -0,0 +1,175 @@
+/*
+ * Device Tree file for Marvell Armada 390 Development Board
+ * (DB-88F6920)
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Grzegorz Jaszczyk <jaz@semihalf.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , 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.
+ */
+
+/dts-v1/;
+#include "armada-390.dtsi"
+
+/ {
+ model = "Marvell Armada 390 Development Board";
+ compatible = "marvell,a390-db", "marvell,armada390";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000>; /* 2 GB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+ internal-regs {
+ i2c@11000 {
+ status = "okay";
+ clock-frequency = <100000>;
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+ };
+
+ /* CON104 */
+ serial@12000 {
+ status = "okay";
+ };
+
+ /* CON97 */
+ usb@58000 {
+ status = "okay";
+ };
+
+ flash@d0000 {
+ status = "okay";
+ pinctrl-0 = <&nand_pins>;
+ pinctrl-names = "default";
+ num-cs = <1>;
+ marvell,nand-keep-config;
+ marvell,nand-enable-arbiter;
+ nand-on-flash-bbt;
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0 0x800000>;
+ };
+ partition@800000 {
+ label = "Linux";
+ reg = <0x800000 0x800000>;
+ };
+ partition@1000000 {
+ label = "Filesystem";
+ reg = <0x1000000 0x3f000000>;
+ };
+ };
+ };
+
+ /* CON98 */
+ usb3@f8000 {
+ status = "okay";
+ };
+ };
+
+ pcie-controller {
+ status = "okay";
+
+ /* CON30 */
+ pcie@1,0 {
+ status = "okay";
+ };
+
+ /* CON44 */
+ pcie@2,0 {
+ status = "okay";
+ };
+
+ /* CON61 */
+ pcie@3,0 {
+ status = "okay";
+ };
+ };
+ };
+};
+
+&spi1 {
+ status = "okay";
+ pinctrl-0 = <&spi1_pins>;
+ pinctrl-names = "default";
+
+ spi-flash@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "n25q128a13",
+ "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <108000000>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0 0x400000>;
+ };
+ partition@400000 {
+ label = "Filesystem";
+ reg = <0x400000 0xc00000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-390.dtsi b/arch/arm/boot/dts/armada-390.dtsi
index 094e39c66039..6cd18d8aaac7 100644
--- a/arch/arm/boot/dts/armada-390.dtsi
+++ b/arch/arm/boot/dts/armada-390.dtsi
@@ -47,6 +47,8 @@
#include "armada-39x.dtsi"
/ {
+ compatible = "marvell,armada390";
+
soc {
internal-regs {
pinctrl@18000 {
@@ -54,4 +56,5 @@
reg = <0x18000 0x20>;
};
};
+ };
};
diff --git a/arch/arm/boot/dts/armada-395-gp.dts b/arch/arm/boot/dts/armada-395-gp.dts
new file mode 100644
index 000000000000..2cdbba804c1e
--- /dev/null
+++ b/arch/arm/boot/dts/armada-395-gp.dts
@@ -0,0 +1,163 @@
+/*
+ * Device Tree file for Marvell Armada 395 GP board
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Grzegorz Jaszczyk <jaz@semihalf.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "armada-395.dtsi"
+
+/ {
+ model = "Marvell Armada 395 GP Board";
+ compatible = "marvell,a395-gp", "marvell,armada395",
+ "marvell,armada390";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x40000000>; /* 1 GB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+ internal-regs {
+ i2c@11000 {
+ status = "okay";
+ clock-frequency = <100000>;
+
+ eeprom@57 {
+ compatible = "atmel,24c64";
+ reg = <0x57>;
+ };
+ };
+
+ serial@12000 {
+ /*
+ * Exported on the micro USB connector CON17
+ * through an FTDI
+ */
+ status = "okay";
+ };
+
+ /* CON1 */
+ usb@58000 {
+ status = "okay";
+ };
+
+ /* CON2 */
+ sata@a8000 {
+ status = "okay";
+ };
+
+ flash@d0000 {
+ status = "okay";
+ pinctrl-0 = <&nand_pins>;
+ pinctrl-names = "default";
+ num-cs = <1>;
+ marvell,nand-keep-config;
+ marvell,nand-enable-arbiter;
+ nand-on-flash-bbt;
+ nand-ecc-strength = <4>;
+ nand-ecc-step-size = <512>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0x00000000 0x00600000>;
+ read-only;
+ };
+
+ partition@800000 {
+ label = "uImage";
+ reg = <0x00600000 0x00400000>;
+ read-only;
+ };
+
+ partition@1000000 {
+ label = "Root";
+ reg = <0x00a00000 0x3f600000>;
+ };
+ };
+ };
+
+ /* CON18 */
+ sdhci@d8000 {
+ clock-frequency = <200000000>;
+ broken-cd;
+ wp-inverted;
+ bus-width = <8>;
+ status = "okay";
+ no-1-8-v;
+ };
+
+ /* CON4 */
+ usb3@f0000 {
+ status = "okay";
+ };
+ };
+
+ pcie-controller {
+ status = "okay";
+
+ /*
+ * The two PCIe units are accessible through
+ * mini PCIe slot on the board.
+ */
+
+ /* CON7 */
+ pcie@2,0 {
+ /* Port 1, Lane 0 */
+ status = "okay";
+ };
+
+ /* CON8 */
+ pcie@4,0 {
+ /* Port 3, Lane 0 */
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-395.dtsi b/arch/arm/boot/dts/armada-395.dtsi
new file mode 100644
index 000000000000..ab5dc49f2bff
--- /dev/null
+++ b/arch/arm/boot/dts/armada-395.dtsi
@@ -0,0 +1,76 @@
+/*
+ * Device Tree Include file for Marvell Armada 395 SoC.
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Grzegorz Jaszczyk <jaz@semihalf.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "armada-39x.dtsi"
+
+/ {
+ compatible = "marvell,armada395", "marvell,armada390";
+
+ soc {
+ internal-regs {
+ pinctrl@18000 {
+ compatible = "marvell,mv88f6925-pinctrl";
+ reg = <0x18000 0x20>;
+ };
+
+ sata@a8000 {
+ compatible = "marvell,armada-380-ahci";
+ reg = <0xa8000 0x2000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gateclk 15>;
+ status = "disabled";
+ };
+
+ usb3@f0000 {
+ compatible = "marvell,armada-380-xhci";
+ reg = <0xf0000 0x4000>,<0xf4000 0x4000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-398-db.dts b/arch/arm/boot/dts/armada-398-db.dts
index 788c3badb681..268c8349c884 100644
--- a/arch/arm/boot/dts/armada-398-db.dts
+++ b/arch/arm/boot/dts/armada-398-db.dts
@@ -65,30 +65,6 @@
MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
internal-regs {
- spi@10680 {
- status = "okay";
- pinctrl-0 = <&spi1_pins>;
- pinctrl-names = "default";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "n25q128a13", "jedec,spi-nor";
- reg = <0>;
- spi-max-frequency = <108000000>;
-
- partition@0 {
- label = "U-Boot";
- reg = <0 0x400000>;
- };
-
- partition@400000 {
- label = "Filesystem";
- reg = <0x400000 0x1000000>;
- };
- };
- };
-
i2c@11000 {
pinctrl-0 = <&i2c0_pins>;
pinctrl-names = "default";
@@ -108,6 +84,10 @@
status = "okay";
};
+ usb@58000 {
+ status = "okay";
+ };
+
flash@d0000 {
status = "okay";
pinctrl-0 = <&nand_pins>;
@@ -132,6 +112,10 @@
reg = <0x1000000 0x3f000000>;
};
};
+
+ usb3@f8000 {
+ status = "okay";
+ };
};
pcie-controller {
@@ -151,3 +135,27 @@
};
};
};
+
+&spi1 {
+ status = "okay";
+ pinctrl-0 = <&spi1_pins>;
+ pinctrl-names = "default";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "n25q128a13", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <108000000>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0 0x400000>;
+ };
+
+ partition@400000 {
+ label = "Filesystem";
+ reg = <0x400000 0x1000000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-398.dtsi b/arch/arm/boot/dts/armada-398.dtsi
index fdc25914e3a3..234a99891a29 100644
--- a/arch/arm/boot/dts/armada-398.dtsi
+++ b/arch/arm/boot/dts/armada-398.dtsi
@@ -44,7 +44,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "armada-39x.dtsi"
+#include "armada-395.dtsi"
/ {
compatible = "marvell,armada398", "marvell,armada390";
@@ -55,6 +55,14 @@
compatible = "marvell,mv88f6928-pinctrl";
reg = <0x18000 0x20>;
};
+
+ sata@e0000 {
+ compatible = "marvell,armada-380-ahci";
+ reg = <0xe0000 0x2000>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gateclk 30>;
+ status = "disabled";
+ };
};
};
};
diff --git a/arch/arm/boot/dts/armada-39x.dtsi b/arch/arm/boot/dts/armada-39x.dtsi
index dc6efd386dbc..34cba87f9200 100644
--- a/arch/arm/boot/dts/armada-39x.dtsi
+++ b/arch/arm/boot/dts/armada-39x.dtsi
@@ -55,6 +55,8 @@
compatible = "marvell,armada390";
aliases {
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
@@ -78,6 +80,11 @@
};
};
+ pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupts-extended = <&mpic 3>;
+ };
+
soc {
compatible = "marvell,armada390-mbus", "marvell,armadaxp-mbus",
"simple-bus";
@@ -131,30 +138,6 @@
<0xc100 0x100>;
};
- spi0: spi@10600 {
- compatible = "marvell,armada-390-spi",
- "marvell,orion-spi";
- reg = <0x10600 0x50>;
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <0>;
- interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&coreclk 0>;
- status = "disabled";
- };
-
- spi1: spi@10680 {
- compatible = "marvell,armada-390-spi",
- "marvell,orion-spi";
- reg = <0x10680 0x50>;
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&coreclk 0>;
- status = "disabled";
- };
-
i2c0: i2c@11000 {
compatible = "marvell,mv64xxx-i2c";
reg = <0x11000 0x20>;
@@ -269,6 +252,34 @@
};
};
+ gpio0: gpio@18100 {
+ compatible = "marvell,orion-gpio";
+ reg = <0x18100 0x40>;
+ ngpios = <32>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gpio1: gpio@18140 {
+ compatible = "marvell,orion-gpio";
+ reg = <0x18140 0x40>;
+ ngpios = <28>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
system-controller@18200 {
compatible = "marvell,armada-390-system-controller",
"marvell,armada-370-xp-system-controller";
@@ -317,11 +328,29 @@
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>;
};
+ mpcore-soc-ctrl@20d20 {
+ compatible = "marvell,armada-380-mpcore-soc-ctrl";
+ reg = <0x20d20 0x6c>;
+ };
+
+ coherency-fabric@21010 {
+ compatible = "marvell,armada-380-coherency-fabric";
+ reg = <0x21010 0x1c>;
+ };
+
pmsu@22000 {
compatible = "marvell,armada-390-pmsu",
"marvell,armada-380-pmsu";
@@ -368,6 +397,13 @@
};
};
+ rtc@a3800 {
+ compatible = "marvell,armada-380-rtc";
+ reg = <0xa3800 0x20>, <0x184a0 0x0c>;
+ reg-names = "rtc", "rtc-soc";
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
flash@d0000 {
compatible = "marvell,armada370-nand";
reg = <0xd0000 0x54>;
@@ -380,7 +416,10 @@
sdhci@d8000 {
compatible = "marvell,armada-380-sdhci";
- reg = <0xd8000 0x1000>, <0xdc000 0x100>;
+ reg-names = "sdhci", "mbus", "conf-sdio3";
+ reg = <0xd8000 0x1000>,
+ <0xdc000 0x100>,
+ <0x18454 0x4>;
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gateclk 17>;
mrvl,clk-delay-cycles = <0x1F>;
@@ -395,6 +434,12 @@
clocks = <&mainpll>;
clock-output-names = "nand";
};
+
+ thermal@e8078 {
+ compatible = "marvell,armada380-thermal";
+ reg = <0xe4078 0x4>, <0xe4074 0x4>;
+ status = "okay";
+ };
};
pcie-controller {
@@ -501,6 +546,30 @@
status = "disabled";
};
};
+
+ spi0: spi@10600 {
+ compatible = "marvell,armada-390-spi",
+ "marvell,orion-spi";
+ reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&coreclk 0>;
+ status = "disabled";
+ };
+
+ spi1: spi@10680 {
+ compatible = "marvell,armada-390-spi",
+ "marvell,orion-spi";
+ reg = <MBUS_ID(0xf0, 0x01) 0x10680 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&coreclk 0>;
+ status = "disabled";
+ };
};
clocks {
@@ -510,5 +579,12 @@
#clock-cells = <0>;
clock-frequency = <1000000000>;
};
+
+ /* 25 MHz reference crystal */
+ refclk: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
index 5c21b236721f..ce152719bc28 100644
--- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts
+++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
@@ -135,18 +135,6 @@
phy = <&phy1>;
phy-mode = "rgmii-id";
};
-
- spi0: spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "n25q128a13", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <108000000>;
- };
- };
};
};
@@ -179,3 +167,15 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "n25q128a13", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <108000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index 62422a90aeb2..075120bc3ec4 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -231,18 +231,6 @@
status = "okay";
};
- spi0: spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "m25p64", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <20000000>;
- };
- };
-
nand@d0000 {
status = "okay";
num-cs = <1>;
@@ -277,3 +265,15 @@
};
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "m25p64", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <20000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 061f4237760e..190e4eccb180 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -232,18 +232,6 @@
status = "okay";
};
- spi0: spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "n25q128a13", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <108000000>;
- };
- };
-
bm@c0000 {
status = "okay";
};
@@ -262,3 +250,15 @@
};
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "n25q128a13", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <108000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index 7a461541ce50..076f27f22c3b 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -279,18 +279,6 @@
reg = <0x180000 0x780000>; /* 7.5MB */
};
};
-
- spi0: spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "everspin,mr25h256";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <40000000>;
- };
- };
};
};
@@ -398,3 +386,15 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "everspin,mr25h256";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <40000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-synology-ds414.dts b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
index d17dab0a6f51..ae286736b90a 100644
--- a/arch/arm/boot/dts/armada-xp-synology-ds414.dts
+++ b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
@@ -110,62 +110,6 @@
status = "disabled";
};
- spi0: spi@10600 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "micron,n25q064", "jedec,spi-nor";
- reg = <0>; /* Chip select 0 */
- spi-max-frequency = <20000000>;
-
- /*
- * Warning!
- *
- * Synology u-boot uses its compiled-in environment
- * and it seems Synology did not care to change u-boot
- * default configuration in order to allow saving a
- * modified environment at a sensible location. So,
- * if you do a 'saveenv' under u-boot, your modified
- * environment will be saved at 1MB after the start
- * of the flash, i.e. in the middle of the uImage.
- * For that reason, it is strongly advised not to
- * change the default environment, unless you know
- * what you are doing.
- */
- partition@00000000 { /* u-boot */
- label = "RedBoot";
- reg = <0x00000000 0x000d0000>; /* 832KB */
- };
-
- partition@000c0000 { /* uImage */
- label = "zImage";
- reg = <0x000d0000 0x002d0000>; /* 2880KB */
- };
-
- partition@003a0000 { /* uInitramfs */
- label = "rd.gz";
- reg = <0x003a0000 0x00430000>; /* 4250KB */
- };
-
- partition@007d0000 { /* MAC address and serial number */
- label = "vendor";
- reg = <0x007d0000 0x00010000>; /* 64KB */
- };
-
- partition@007e0000 {
- label = "RedBoot config";
- reg = <0x007e0000 0x00010000>; /* 64KB */
- };
-
- partition@007f0000 {
- label = "FIS directory";
- reg = <0x007f0000 0x00010000>; /* 64KB */
- };
- };
- };
-
i2c@11000 {
clock-frequency = <400000>;
status = "okay";
@@ -362,3 +306,59 @@
marvell,function = "gpio";
};
};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q064", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <20000000>;
+
+ /*
+ * Warning!
+ *
+ * Synology u-boot uses its compiled-in environment
+ * and it seems Synology did not care to change u-boot
+ * default configuration in order to allow saving a
+ * modified environment at a sensible location. So,
+ * if you do a 'saveenv' under u-boot, your modified
+ * environment will be saved at 1MB after the start
+ * of the flash, i.e. in the middle of the uImage.
+ * For that reason, it is strongly advised not to
+ * change the default environment, unless you know
+ * what you are doing.
+ */
+ partition@00000000 { /* u-boot */
+ label = "RedBoot";
+ reg = <0x00000000 0x000d0000>; /* 832KB */
+ };
+
+ partition@000c0000 { /* uImage */
+ label = "zImage";
+ reg = <0x000d0000 0x002d0000>; /* 2880KB */
+ };
+
+ partition@003a0000 { /* uInitramfs */
+ label = "rd.gz";
+ reg = <0x003a0000 0x00430000>; /* 4250KB */
+ };
+
+ partition@007d0000 { /* MAC address and serial number */
+ label = "vendor";
+ reg = <0x007d0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007e0000 {
+ label = "RedBoot config";
+ reg = <0x007e0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007f0000 {
+ label = "FIS directory";
+ reg = <0x007f0000 0x00010000>; /* 64KB */
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 553349c07f28..4a5f99e65b51 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -84,19 +84,6 @@
wt-override;
};
- spi0: spi@10600 {
- compatible = "marvell,armada-xp-spi",
- "marvell,orion-spi";
- pinctrl-0 = <&spi0_pins>;
- pinctrl-names = "default";
- };
-
- spi1: spi@10680 {
- compatible = "marvell,armada-xp-spi",
- "marvell,orion-spi";
- };
-
-
i2c0: i2c@11000 {
compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
reg = <0x11000 0x100>;
@@ -362,6 +349,12 @@
marvell,function = "spi0";
};
+ spi1_pins: spi1-pins {
+ marvell,pins = "mpp13", "mpp14",
+ "mpp16", "mpp17";
+ marvell,function = "spi1";
+ };
+
uart2_pins: uart2-pins {
marvell,pins = "mpp42", "mpp43";
marvell,function = "uart2";
@@ -372,3 +365,15 @@
marvell,function = "uart3";
};
};
+
+&spi0 {
+ compatible = "marvell,armada-xp-spi", "marvell,orion-spi";
+ pinctrl-0 = <&spi0_pins>;
+ pinctrl-names = "default";
+};
+
+&spi1 {
+ compatible = "marvell,armada-xp-spi", "marvell,orion-spi";
+ pinctrl-0 = <&spi1_pins>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 16331aa79775..ba332e399be4 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -1,5 +1,3 @@
-#include "skeleton.dtsi"
-
/ {
nvic: interrupt-controller@e000e100 {
compatible = "arm,armv7m-nvic";
diff --git a/arch/arm/boot/dts/artpec6.dtsi b/arch/arm/boot/dts/artpec6.dtsi
index 3fac4c4d0007..3489019cc0dc 100644
--- a/arch/arm/boot/dts/artpec6.dtsi
+++ b/arch/arm/boot/dts/artpec6.dtsi
@@ -41,6 +41,7 @@
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/axis,artpec6-clkctrl.h>
#include "skeleton.dtsi"
/ {
@@ -109,14 +110,14 @@
compatible = "arm,cortex-a9-global-timer";
reg = <0xfaf00200 0x20>;
interrupts = <GIC_PPI 11 0xf01>;
- clocks = <&clkctrl 1>;
+ clocks = <&clkctrl ARTPEC6_CLK_CPU_PERIPH>;
};
timer@faf00600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0xfaf00600 0x20>;
interrupts = <GIC_PPI 13 0xf04>;
- clocks = <&clkctrl 1>;
+ clocks = <&clkctrl ARTPEC6_CLK_CPU_PERIPH>;
status = "disabled";
};
@@ -136,12 +137,20 @@
arm,data-latency = <1 1 1>;
arm,tag-latency = <1 1 1>;
arm,filter-ranges = <0x0 0x80000000>;
+ arm,double-linefill = <1>;
+ arm,double-linefill-incr = <0>;
+ arm,double-linefill-wrap = <0>;
+ prefetch-data = <1>;
+ prefetch-instr = <1>;
+ arm,prefetch-offset = <0>;
+ arm,prefetch-drop = <1>;
};
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>;
interrupt-parent = <&intc>;
};
@@ -157,7 +166,7 @@
ethernet: ethernet@f8010000 {
clock-names = "phy_ref_clk", "apb_pclk";
clocks = <&eth_phy_ref_clk>,
- <&clkctrl 4>;
+ <&clkctrl ARTPEC6_CLK_ETH_ACLK>;
compatible = "snps,dwc-qos-ethernet-4.10";
interrupt-parent = <&intc>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
@@ -175,8 +184,8 @@
compatible = "arm,pl011", "arm,primecell";
reg = <0xf8036000 0x1000>;
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clkctrl 13>,
- <&clkctrl 12>;
+ clocks = <&clkctrl ARTPEC6_CLK_UART_REFCLK>,
+ <&clkctrl ARTPEC6_CLK_UART_PCLK>;
clock-names = "uart_clk", "apb_pclk";
status = "disabled";
};
@@ -184,8 +193,8 @@
compatible = "arm,pl011", "arm,primecell";
reg = <0xf8037000 0x1000>;
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clkctrl 13>,
- <&clkctrl 12>;
+ clocks = <&clkctrl ARTPEC6_CLK_UART_REFCLK>,
+ <&clkctrl ARTPEC6_CLK_UART_PCLK>;
clock-names = "uart_clk", "apb_pclk";
status = "disabled";
};
@@ -193,8 +202,8 @@
compatible = "arm,pl011", "arm,primecell";
reg = <0xf8038000 0x1000>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clkctrl 13>,
- <&clkctrl 12>;
+ clocks = <&clkctrl ARTPEC6_CLK_UART_REFCLK>,
+ <&clkctrl ARTPEC6_CLK_UART_PCLK>;
clock-names = "uart_clk", "apb_pclk";
status = "disabled";
};
@@ -202,8 +211,8 @@
compatible = "arm,pl011", "arm,primecell";
reg = <0xf8039000 0x1000>;
interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clkctrl 13>,
- <&clkctrl 12>;
+ clocks = <&clkctrl ARTPEC6_CLK_UART_REFCLK>,
+ <&clkctrl ARTPEC6_CLK_UART_PCLK>;
clock-names = "uart_clk", "apb_pclk";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi
index afbe89c01df5..675bb0f30825 100644
--- a/arch/arm/boot/dts/axp209.dtsi
+++ b/arch/arm/boot/dts/axp209.dtsi
@@ -53,6 +53,12 @@
interrupt-controller;
#interrupt-cells = <1>;
+ axp_gpio: gpio {
+ compatible = "x-powers,axp209-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
regulators {
/* Default work frequency for buck regulators */
x-powers,dcdc-freq = <1500>;
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index c3bf7d23f136..7c9e0fae9bb9 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -209,6 +209,24 @@
#dma-cells = <1>;
};
+ amac0: ethernet@22000 {
+ compatible = "brcm,nsp-amac";
+ reg = <0x022000 0x1000>,
+ <0x110000 0x1000>;
+ reg-names = "amac_base", "idm_base";
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ amac1: ethernet@23000 {
+ compatible = "brcm,nsp-amac";
+ reg = <0x023000 0x1000>,
+ <0x111000 0x1000>;
+ reg-names = "amac_base", "idm_base";
+ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
nand: nand@26000 {
compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
reg = <0x026000 0x600>,
@@ -223,6 +241,14 @@
brcm,nand-has-wp;
};
+ pwm: pwm@31000 {
+ compatible = "brcm,iproc-pwm";
+ reg = <0x31000 0x28>;
+ clocks = <&osc>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
rng: rng@33000 {
compatible = "brcm,bcm-nsp-rng";
reg = <0x33000 0x14>;
@@ -246,6 +272,17 @@
clock-names = "apb_pclk";
};
+ srab: srab@36000 {
+ compatible = "brcm,nsp-srab";
+ reg = <0x36000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+
+ /* ports are defined in board DTS */
+ };
+
i2c0: i2c@38000 {
compatible = "brcm,iproc-i2c";
reg = <0x38000 0x50>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
index 35ff4e7a4aac..f7f9db355d98 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
@@ -1,6 +1,7 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
/ {
compatible = "raspberrypi,model-a-plus", "brcm,bcm2835";
diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts
index 306a84ee9898..8be102f5d826 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
@@ -1,6 +1,7 @@
/dts-v1/;
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
/ {
compatible = "raspberrypi,model-a", "brcm,bcm2835";
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
index d5fdb8e761a3..35cde65c975e 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
@@ -2,6 +2,7 @@
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
#include "bcm283x-rpi-smsc9514.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
/ {
compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
index bfc4bd9b7733..84df85ea6296 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
@@ -2,6 +2,7 @@
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
#include "bcm283x-rpi-smsc9512.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
/ {
compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835";
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index 0371bb7374b8..8e626a80fe24 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -2,6 +2,7 @@
#include "bcm2835.dtsi"
#include "bcm2835-rpi.dtsi"
#include "bcm283x-rpi-smsc9512.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
/ {
compatible = "raspberrypi,model-b", "brcm,bcm2835";
diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero.dts b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
new file mode 100644
index 000000000000..60e359fafc5b
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 Stefan Wahren <stefan.wahren@i2se.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include "bcm2835.dtsi"
+#include "bcm2835-rpi.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
+
+/ {
+ compatible = "raspberrypi,model-zero", "brcm,bcm2835";
+ model = "Raspberry Pi Zero";
+
+ leds {
+ act {
+ gpios = <&gpio 47 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&gpio {
+ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
+
+ /* I2S interface */
+ i2s_alt0: i2s_alt0 {
+ brcm,pins = <18 19 20 21>;
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+};
+
+&hdmi {
+ hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
+};
diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
index 29e1cfe8eb14..39dccf62ac96 100644
--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
@@ -2,6 +2,7 @@
#include "bcm2836.dtsi"
#include "bcm2835-rpi.dtsi"
#include "bcm283x-rpi-smsc9514.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
/ {
compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
diff --git a/arch/arm/boot/dts/bcm283x-rpi-usb-host.dtsi b/arch/arm/boot/dts/bcm283x-rpi-usb-host.dtsi
new file mode 100644
index 000000000000..73f4ece8dcd0
--- /dev/null
+++ b/arch/arm/boot/dts/bcm283x-rpi-usb-host.dtsi
@@ -0,0 +1,3 @@
+&usb {
+ dr_mode = "host";
+};
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index 445624a1a1de..46d46d894a44 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -290,6 +290,8 @@
interrupts = <1 9>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&clk_usb>;
+ clock-names = "otg";
};
v3d: v3d@7ec00000 {
@@ -317,5 +319,12 @@
clock-frequency = <19200000>;
};
+ clk_usb: clock@4 {
+ compatible = "fixed-clock";
+ reg = <4>;
+ #clock-cells = <0>;
+ clock-output-names = "otg";
+ clock-frequency = <480000000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
index 8af47913b3b4..ae4b3880616d 100644
--- a/arch/arm/boot/dts/bcm5301x.dtsi
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
@@ -140,6 +140,15 @@
};
};
+ usb2_phy: usb2-phy {
+ compatible = "brcm,ns-usb2-phy";
+ reg = <0x1800c000 0x1000>;
+ reg-names = "dmu";
+ #phy-cells = <0>;
+ clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
+ clock-names = "phy-ref-clk";
+ };
+
axi@18000000 {
compatible = "brcm,bus-axi";
reg = <0x18000000 0x1000>;
@@ -232,6 +241,8 @@
#address-cells = <1>;
#size-cells = <1>;
+
+ phys = <&usb2_phy>;
};
usb3: usb3@23000 {
diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts
new file mode 100644
index 000000000000..a21b0fd21f4e
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958522er.dts
@@ -0,0 +1,130 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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.
+ */
+
+/dts-v1/;
+
+#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "NorthStar Plus SVK (BCM958522ER)";
+ compatible = "brcm,bcm58522", "brcm,nsp";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
+
+/* USB 2/3 support needed to be complete */
+
+&amac0 {
+ status = "okay";
+};
+
+
+&amac1 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+
+ partition@0 {
+ label = "nboot";
+ reg = <0x00000000 0x00200000>;
+ read-only;
+ };
+ partition@200000 {
+ label = "nenv";
+ reg = <0x00200000 0x00400000>;
+ };
+ partition@600000 {
+ label = "nsystem";
+ reg = <0x00600000 0x00a00000>;
+ };
+ partition@1000000 {
+ label = "nrootfs";
+ reg = <0x01000000 0x03000000>;
+ };
+ partition@4000000 {
+ label = "ncustfs";
+ reg = <0x04000000 0x3c000000>;
+ };
+ };
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts
new file mode 100644
index 000000000000..be7f2f8ecf39
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958525er.dts
@@ -0,0 +1,142 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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.
+ */
+
+/dts-v1/;
+
+#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "NorthStar Plus SVK (BCM958525ER)";
+ compatible = "brcm,bcm58525", "brcm,nsp";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
+
+/* USB 2/3 support needed to be complete */
+
+&amac0 {
+ status = "okay";
+};
+
+
+&amac1 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+
+ partition@0 {
+ label = "nboot";
+ reg = <0x00000000 0x00200000>;
+ read-only;
+ };
+ partition@200000 {
+ label = "nenv";
+ reg = <0x00200000 0x00400000>;
+ };
+ partition@600000 {
+ label = "nsystem";
+ reg = <0x00600000 0x00a00000>;
+ };
+ partition@1000000 {
+ label = "nrootfs";
+ reg = <0x01000000 0x03000000>;
+ };
+ partition@4000000 {
+ label = "ncustfs";
+ reg = <0x04000000 0x3c000000>;
+ };
+ };
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
+
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts
index d257e83dedfc..959cde911c3c 100644
--- a/arch/arm/boot/dts/bcm958525xmc.dts
+++ b/arch/arm/boot/dts/bcm958525xmc.dts
@@ -33,6 +33,7 @@
/dts-v1/;
#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "NorthStar Plus XMC (BCM958525xmc)";
@@ -45,6 +46,35 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x40000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 31 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
+
+&i2c0 {
+ temperature-sensor@4c {
+ compatible = "adi,adt7461a";
+ reg = <0x4c>;
+ };
+
+ eeprom@52 {
+ compatible = "atmel,24c02";
+ reg = <0x52>;
+ pagesize = <16>;
+ };
+
+ rtc@68 {
+ compatible = "st,m41t81";
+ reg = <0x68>;
+ };
};
&nand {
@@ -85,7 +115,7 @@
};
};
-/* XHCI, SATA, MMC, and Ethernet support needed to be complete */
+/* XHCI, MMC, and Ethernet support needed to be complete */
&uart0 {
status = "okay";
@@ -99,6 +129,18 @@
status = "okay";
};
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
&pinctrl {
pinctrl-names = "default";
pinctrl-0 = <&nand_sel>;
diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts
new file mode 100644
index 000000000000..ad2aa87dd15a
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958622hr.dts
@@ -0,0 +1,170 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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.
+ */
+
+/dts-v1/;
+
+#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "NorthStar Plus SVK (BCM958622HR)";
+ compatible = "brcm,bcm58622", "brcm,nsp";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
+
+/* USB 2/3 and SLIC support needed to be complete */
+
+&amac0 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+
+ partition@0 {
+ label = "nboot";
+ reg = <0x00000000 0x00200000>;
+ read-only;
+ };
+ partition@200000 {
+ label = "nenv";
+ reg = <0x00200000 0x00400000>;
+ };
+ partition@600000 {
+ label = "nsystem";
+ reg = <0x00600000 0x00a00000>;
+ };
+ partition@1000000 {
+ label = "nrootfs";
+ reg = <0x01000000 0x03000000>;
+ };
+ partition@4000000 {
+ label = "ncustfs";
+ reg = <0x04000000 0x3c000000>;
+ };
+ };
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
+
+&srab {
+ compatible = "brcm,bcm58622-srab", "brcm,nsp-srab";
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ label = "port0";
+ reg = <0>;
+ };
+
+ port@1 {
+ label = "port1";
+ reg = <1>;
+ };
+
+ port@2 {
+ label = "port2";
+ reg = <2>;
+ };
+
+ port@3 {
+ label = "port3";
+ reg = <3>;
+ };
+
+ port@4 {
+ label = "port4";
+ reg = <4>;
+ };
+
+ port@5 {
+ ethernet = <&amac0>;
+ label = "cpu";
+ reg = <5>;
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts
new file mode 100644
index 000000000000..4ceb8fef8041
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958623hr.dts
@@ -0,0 +1,178 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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.
+ */
+
+/dts-v1/;
+
+#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "NorthStar Plus SVK (BCM958623HR)";
+ compatible = "brcm,bcm58623", "brcm,nsp";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
+
+/* USB 2/3 and SLIC support needed to be complete */
+
+&amac0 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+
+ partition@0 {
+ label = "nboot";
+ reg = <0x00000000 0x00200000>;
+ read-only;
+ };
+ partition@200000 {
+ label = "nenv";
+ reg = <0x00200000 0x00400000>;
+ };
+ partition@600000 {
+ label = "nsystem";
+ reg = <0x00600000 0x00a00000>;
+ };
+ partition@1000000 {
+ label = "nrootfs";
+ reg = <0x01000000 0x03000000>;
+ };
+ partition@4000000 {
+ label = "ncustfs";
+ reg = <0x04000000 0x3c000000>;
+ };
+ };
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
+
+&srab {
+ compatible = "brcm,bcm58623-srab", "brcm,nsp-srab";
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ label = "port0";
+ reg = <0>;
+ };
+
+ port@1 {
+ label = "port1";
+ reg = <1>;
+ };
+
+ port@2 {
+ label = "port2";
+ reg = <2>;
+ };
+
+ port@3 {
+ label = "port3";
+ reg = <3>;
+ };
+
+ port@4 {
+ label = "port4";
+ reg = <4>;
+ };
+
+ port@5 {
+ ethernet = <&amac0>;
+ label = "cpu";
+ reg = <5>;
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
+
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts
index 03b8bbeb694f..442002597063 100644
--- a/arch/arm/boot/dts/bcm958625hr.dts
+++ b/arch/arm/boot/dts/bcm958625hr.dts
@@ -33,6 +33,7 @@
/dts-v1/;
#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "NorthStar Plus SVK (BCM958625HR)";
@@ -47,7 +48,14 @@
};
memory {
- reg = <0x60000000 0x20000000>;
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+ priority = <200>;
};
};
@@ -109,3 +117,64 @@
groups = "nand_grp";
};
};
+
+&amac0 {
+ status = "okay";
+};
+
+&srab {
+ compatible = "brcm,bcm58625-srab", "brcm,nsp-srab";
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ label = "port0";
+ reg = <0>;
+ };
+
+ port@1 {
+ label = "port1";
+ reg = <1>;
+ };
+
+ port@2 {
+ label = "port2";
+ reg = <2>;
+ };
+
+ port@3 {
+ label = "port3";
+ reg = <3>;
+ };
+
+ port@4 {
+ label = "port4";
+ reg = <4>;
+ };
+
+ port@5 {
+ ethernet = <&amac0>;
+ label = "cpu";
+ reg = <5>;
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
+
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
index 2d8422632b2b..05c5f98c8782 100644
--- a/arch/arm/boot/dts/bcm958625k.dts
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -46,6 +46,11 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
};
&uart0 {
@@ -56,6 +61,14 @@
status = "okay";
};
+&amac0 {
+ status = "okay";
+};
+
+&amac1 {
+ status = "okay";
+};
+
&pcie0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts
new file mode 100644
index 000000000000..104afe98a43b
--- /dev/null
+++ b/arch/arm/boot/dts/bcm988312hr.dts
@@ -0,0 +1,182 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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.
+ */
+
+/dts-v1/;
+
+#include "bcm-nsp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "NorthStar Plus SVK (BCM988312HR)";
+ compatible = "brcm,bcm88312", "brcm,nsp";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
+
+/* USB 2/3 support needed to be complete */
+
+&amac0 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+
+ partition@0 {
+ label = "nboot";
+ reg = <0x00000000 0x00200000>;
+ read-only;
+ };
+ partition@200000 {
+ label = "nenv";
+ reg = <0x00200000 0x00400000>;
+ };
+ partition@600000 {
+ label = "nsystem";
+ reg = <0x00600000 0x00a00000>;
+ };
+ partition@1000000 {
+ label = "nrootfs";
+ reg = <0x01000000 0x03000000>;
+ };
+ partition@4000000 {
+ label = "ncustfs";
+ reg = <0x04000000 0x3c000000>;
+ };
+ };
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pinctrl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_sel>;
+ nand_sel: nand_sel {
+ function = "nand";
+ groups = "nand_grp";
+ };
+};
+
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&srab {
+ compatible = "brcm,bcm88312-srab", "brcm,nsp-srab";
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ label = "port0";
+ reg = <0>;
+ };
+
+ port@1 {
+ label = "port1";
+ reg = <1>;
+ };
+
+ port@2 {
+ label = "port2";
+ reg = <2>;
+ };
+
+ port@3 {
+ label = "port3";
+ reg = <3>;
+ };
+
+ port@4 {
+ label = "port4";
+ reg = <4>;
+ };
+
+ port@5 {
+ ethernet = <&amac0>;
+ label = "cpu";
+ reg = <5>;
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
index 3c0907b87fd6..1c475796d17f 100644
--- a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
+++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
@@ -49,7 +49,7 @@
stdout-path = "serial0:115200n8";
};
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x00000000 0x40000000>; /* 1 GB */
};
diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index ae81009741ff..425c48971abe 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -39,13 +39,14 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "skeleton.dtsi"
#include <dt-bindings/clock/berlin2.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
model = "Marvell Armada 1500 (BG2) SoC";
compatible = "marvell,berlin2", "marvell,berlin";
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
serial0 = &uart0;
@@ -89,7 +90,7 @@
clock-frequency = <25000000>;
};
- soc {
+ soc@f7000000 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
@@ -447,7 +448,6 @@
reg = <0x2000 0x100>;
clocks = <&refclk>;
interrupts = <1>;
- status = "disabled";
};
wdt2: watchdog@3000 {
@@ -455,7 +455,6 @@
reg = <0x3000 0x100>;
clocks = <&refclk>;
interrupts = <2>;
- status = "disabled";
};
sm_gpio1: gpio@5000 {
diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 8ba8b50ce997..ca24def0ce13 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -50,7 +50,7 @@
stdout-path = "serial0:115200n8";
};
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x00000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index 6d06b6118d83..4fe1574d08c3 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -39,13 +39,14 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "skeleton.dtsi"
#include <dt-bindings/clock/berlin2.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
model = "Marvell Armada 1500-mini (BG2CD) SoC";
compatible = "marvell,berlin2cd", "marvell,berlin";
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
serial0 = &uart0;
@@ -78,7 +79,7 @@
clock-frequency = <25000000>;
};
- soc {
+ soc@f7000000 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index 33b28757b8f6..f485308840ab 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -43,7 +43,7 @@
model = "Marvell BG2-Q DMP";
compatible = "marvell,berlin2q-dmp", "marvell,berlin2q", "marvell,berlin";
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x00000000 0x80000000>;
};
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index 2c34bfb13632..e548229697fc 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -37,11 +37,11 @@
#include <dt-bindings/clock/berlin2q.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include "skeleton.dtsi"
-
/ {
model = "Marvell Armada 1500 pro (BG2-Q) SoC";
compatible = "marvell,berlin2q", "marvell,berlin";
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
serial0 = &uart0;
@@ -99,7 +99,7 @@
clock-frequency = <25000000>;
};
- soc {
+ soc@f7000000 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
@@ -525,7 +525,6 @@
reg = <0x2000 0x100>;
clocks = <&refclk>;
interrupts = <1>;
- status = "disabled";
};
wdt2: watchdog@3000 {
@@ -533,7 +532,6 @@
reg = <0x3000 0x100>;
clocks = <&refclk>;
interrupts = <2>;
- status = "disabled";
};
sm_gpio1: gpio@5000 {
diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts
index 1a15db8e376b..41de15fe15a2 100644
--- a/arch/arm/boot/dts/da850-evm.dts
+++ b/arch/arm/boot/dts/da850-evm.dts
@@ -29,6 +29,20 @@
0x04 0x00011000 0x000ff000
>;
};
+ nand_pins: nand_pins {
+ pinctrl-single,bits = <
+ /* EMA_WAIT[0], EMA_OE, EMA_WE, EMA_CS[4], EMA_CS[3] */
+ 0x1c 0x10110110 0xf0ff0ff0
+ /*
+ * EMA_D[0], EMA_D[1], EMA_D[2],
+ * EMA_D[3], EMA_D[4], EMA_D[5],
+ * EMA_D[6], EMA_D[7]
+ */
+ 0x24 0x11111111 0xffffffff
+ /* EMA_A[1], EMA_A[2] */
+ 0x30 0x01100000 0x0ff00000
+ >;
+ };
};
serial0: serial@42000 {
status = "okay";
@@ -131,12 +145,7 @@
status = "okay";
};
};
- nand_cs3@62000000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&nand_cs3_pins>;
- };
- vbat: fixedregulator@0 {
+ vbat: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vbat";
regulator-min-microvolt = <5000000>;
@@ -250,3 +259,33 @@
&edma1 {
ti,edma-reserved-slot-ranges = <32 90>;
};
+
+&aemif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins>;
+ status = "ok";
+ cs3 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-ranges;
+ ranges;
+
+ ti,cs-chipselect = <3>;
+
+ nand@2000000,0 {
+ compatible = "ti,davinci-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0 0x02000000 0x02000000
+ 1 0x00000000 0x00008000>;
+
+ ti,davinci-chipselect = <1>;
+ ti,davinci-mask-ale = <0>;
+ ti,davinci-mask-cle = <0>;
+ ti,davinci-mask-chipsel = <0>;
+ ti,davinci-ecc-mode = "hw";
+ ti,davinci-ecc-bits = <4>;
+ ti,davinci-nand-use-bbt;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts
new file mode 100644
index 000000000000..7b8ab21fed6c
--- /dev/null
+++ b/arch/arm/boot/dts/da850-lcdk.dts
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2016 BayLibre, Inc.
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+#include "da850.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "DA850/AM1808/OMAP-L138 LCDK";
+ compatible = "ti,da850-lcdk", "ti,da850";
+
+ aliases {
+ serial2 = &serial2;
+ };
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0xc0000000 0x08000000>;
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "DA850/OMAP-L138 LCDK";
+ simple-audio-card,widgets =
+ "Line", "Line In",
+ "Line", "Line Out";
+ simple-audio-card,routing =
+ "LINE1L", "Line In",
+ "LINE1R", "Line In",
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT";
+ simple-audio-card,format = "dsp_b";
+ simple-audio-card,bitclock-master = <&link0_codec>;
+ simple-audio-card,frame-master = <&link0_codec>;
+ simple-audio-card,bitclock-inversion;
+
+ simple-audio-card,cpu {
+ sound-dai = <&mcasp0>;
+ system-clock-frequency = <24576000>;
+ };
+
+ link0_codec: simple-audio-card,codec {
+ sound-dai = <&tlv320aic3106>;
+ system-clock-frequency = <24576000>;
+ };
+ };
+};
+
+&pmx_core {
+ status = "okay";
+
+ mcasp0_pins: pinmux_mcasp0_pins {
+ pinctrl-single,bits = <
+ /* AHCLKX AFSX ACLKX */
+ 0x00 0x00101010 0x00f0f0f0
+ /* ARX13 ARX14 */
+ 0x04 0x00000110 0x00000ff0
+ >;
+ };
+
+ nand_pins: nand_pins {
+ pinctrl-single,bits = <
+ /* EMA_WAIT[0], EMA_OE, EMA_WE, EMA_CS[3] */
+ 0x1c 0x10110010 0xf0ff00f0
+ /*
+ * EMA_D[0], EMA_D[1], EMA_D[2],
+ * EMA_D[3], EMA_D[4], EMA_D[5],
+ * EMA_D[6], EMA_D[7]
+ */
+ 0x24 0x11111111 0xffffffff
+ /*
+ * EMA_D[8], EMA_D[9], EMA_D[10],
+ * EMA_D[11], EMA_D[12], EMA_D[13],
+ * EMA_D[14], EMA_D[15]
+ */
+ 0x20 0x11111111 0xffffffff
+ /* EMA_A[1], EMA_A[2] */
+ 0x30 0x01100000 0x0ff00000
+ >;
+ };
+};
+
+&serial2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&serial2_rxtx_pins>;
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
+
+&rtc0 {
+ status = "okay";
+};
+
+&gpio {
+ status = "okay";
+};
+
+&mdio {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mdio_pins>;
+ bus_freq = <2200000>;
+ status = "okay";
+};
+
+&eth0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mii_pins>;
+ status = "okay";
+};
+
+&mmc0 {
+ max-frequency = <50000000>;
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>;
+ cd-gpios = <&gpio 64 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ clock-frequency = <100000>;
+ status = "okay";
+
+ tlv320aic3106: tlv320aic3106@18 {
+ #sound-dai-cells = <0>;
+ compatible = "ti,tlv320aic3106";
+ reg = <0x18>;
+ status = "okay";
+ };
+};
+
+&mcasp0 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcasp0_pins>;
+ status = "okay";
+
+ op-mode = <0>; /* DAVINCI_MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 1 2 0
+ >;
+ tx-num-evt = <32>;
+ rx-num-evt = <32>;
+};
+
+&aemif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins>;
+ status = "okay";
+ cs3 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-ranges;
+ ranges;
+
+ ti,cs-chipselect = <3>;
+
+ nand@2000000,0 {
+ compatible = "ti,davinci-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0 0x02000000 0x02000000
+ 1 0x00000000 0x00008000>;
+
+ ti,davinci-chipselect = <1>;
+ ti,davinci-mask-ale = <0>;
+ ti,davinci-mask-cle = <0>;
+ ti,davinci-mask-chipsel = <0>;
+
+ ti,davinci-nand-buswidth = <16>;
+ ti,davinci-ecc-mode = "hw";
+ ti,davinci-ecc-bits = <4>;
+ ti,davinci-nand-use-bbt;
+
+ /*
+ * The OMAP-L132/L138 Bootloader doc SPRAB41E reads:
+ * "To boot from NAND Flash, the AIS should be written
+ * to NAND block 1 (NAND block 0 is not used by default)".
+ * The same doc mentions that for ROM "Silicon Revision 2.1",
+ * "Updated NAND boot mode to offer boot from block 0 or block 1".
+ * However the limitaion is left here by default for compatibility
+ * with older silicon and because it needs new boot pin settings
+ * not possible in stock LCDK.
+ */
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot env";
+ reg = <0 0x020000>;
+ };
+ partition@0x020000 {
+ /* The LCDK defaults to booting from this partition */
+ label = "u-boot";
+ reg = <0x020000 0x080000>;
+ };
+ partition@0x0a0000 {
+ label = "free space";
+ reg = <0x0a0000 0>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 25f0f8e6dde5..f79e1b91c680 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -41,20 +41,40 @@
pinctrl-single,function-mask = <0xf>;
status = "disabled";
- nand_cs3_pins: pinmux_nand_pins {
+ serial0_rtscts_pins: pinmux_serial0_rtscts_pins {
pinctrl-single,bits = <
- /* EMA_OE, EMA_WE */
- 0x1c 0x00110000 0x00ff0000
- /* EMA_CS[4],EMA_CS[3]*/
- 0x1c 0x00000110 0x00000ff0
- /*
- * EMA_D[0], EMA_D[1], EMA_D[2],
- * EMA_D[3], EMA_D[4], EMA_D[5],
- * EMA_D[6], EMA_D[7]
- */
- 0x24 0x11111111 0xffffffff
- /* EMA_A[1], EMA_A[2] */
- 0x30 0x01100000 0x0ff00000
+ /* UART0_RTS UART0_CTS */
+ 0x0c 0x22000000 0xff000000
+ >;
+ };
+ serial0_rxtx_pins: pinmux_serial0_rxtx_pins {
+ pinctrl-single,bits = <
+ /* UART0_TXD UART0_RXD */
+ 0x0c 0x00220000 0x00ff0000
+ >;
+ };
+ serial1_rtscts_pins: pinmux_serial1_rtscts_pins {
+ pinctrl-single,bits = <
+ /* UART1_CTS UART1_RTS */
+ 0x00 0x00440000 0x00ff0000
+ >;
+ };
+ serial1_rxtx_pins: pinmux_serial1_rxtx_pins {
+ pinctrl-single,bits = <
+ /* UART1_TXD UART1_RXD */
+ 0x10 0x22000000 0xff000000
+ >;
+ };
+ serial2_rtscts_pins: pinmux_serial2_rtscts_pins {
+ pinctrl-single,bits = <
+ /* UART2_CTS UART2_RTS */
+ 0x00 0x44000000 0xff000000
+ >;
+ };
+ serial2_rxtx_pins: pinmux_serial2_rxtx_pins {
+ pinctrl-single,bits = <
+ /* UART2_TXD UART2_RXD */
+ 0x10 0x00220000 0x00ff0000
>;
};
i2c0_pins: pinmux_i2c0_pins {
@@ -274,31 +294,36 @@
status = "disabled";
};
ehrpwm0: pwm@300000 {
- compatible = "ti,da850-ehrpwm", "ti,am33xx-ehrpwm";
+ compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm",
+ "ti,am33xx-ehrpwm";
#pwm-cells = <3>;
reg = <0x300000 0x2000>;
status = "disabled";
};
ehrpwm1: pwm@302000 {
- compatible = "ti,da850-ehrpwm", "ti,am33xx-ehrpwm";
+ compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm",
+ "ti,am33xx-ehrpwm";
#pwm-cells = <3>;
reg = <0x302000 0x2000>;
status = "disabled";
};
ecap0: ecap@306000 {
- compatible = "ti,da850-ecap", "ti,am33xx-ecap";
+ compatible = "ti,da850-ecap", "ti,am3352-ecap",
+ "ti,am33xx-ecap";
#pwm-cells = <3>;
reg = <0x306000 0x80>;
status = "disabled";
};
ecap1: ecap@307000 {
- compatible = "ti,da850-ecap", "ti,am33xx-ecap";
+ compatible = "ti,da850-ecap", "ti,am3352-ecap",
+ "ti,am33xx-ecap";
#pwm-cells = <3>;
reg = <0x307000 0x80>;
status = "disabled";
};
ecap2: ecap@308000 {
- compatible = "ti,da850-ecap", "ti,am33xx-ecap";
+ compatible = "ti,da850-ecap", "ti,am3352-ecap",
+ "ti,am33xx-ecap";
#pwm-cells = <3>;
reg = <0x308000 0x80>;
status = "disabled";
@@ -375,17 +400,14 @@
dma-names = "tx", "rx";
};
};
- nand_cs3@62000000 {
- compatible = "ti,davinci-nand";
- reg = <0x62000000 0x807ff
- 0x68000000 0x8000>;
- ti,davinci-chipselect = <1>;
- ti,davinci-mask-ale = <0>;
- ti,davinci-mask-cle = <0>;
- ti,davinci-mask-chipsel = <0>;
- ti,davinci-ecc-mode = "hw";
- ti,davinci-ecc-bits = <4>;
- ti,davinci-nand-use-bbt;
+ aemif: aemif@68000000 {
+ compatible = "ti,da850-aemif";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ reg = <0x68000000 0x00008000>;
+ ranges = <0 0 0x60000000 0x08000000
+ 1 0 0x68000000 0x00008000>;
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/dm8148-evm.dts b/arch/arm/boot/dts/dm8148-evm.dts
index 4128fa91823c..d6657b3bae84 100644
--- a/arch/arm/boot/dts/dm8148-evm.dts
+++ b/arch/arm/boot/dts/dm8148-evm.dts
@@ -12,13 +12,13 @@
model = "DM8148 EVM";
compatible = "ti,dm8148-evm", "ti,dm8148";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
/* MIC94060YC6 controlled by SD1_POW pin */
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/dm8148-t410.dts b/arch/arm/boot/dts/dm8148-t410.dts
index 3f184863e0c5..63883b3479f9 100644
--- a/arch/arm/boot/dts/dm8148-t410.dts
+++ b/arch/arm/boot/dts/dm8148-t410.dts
@@ -11,7 +11,7 @@
model = "HP t410 Smart Zero Client";
compatible = "hp,t410", "ti,dm8148";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
@@ -27,7 +27,7 @@
regulator-always-on;
};
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/dm814x.dtsi b/arch/arm/boot/dts/dm814x.dtsi
index 68e412c9863c..ff90a6ce6bdc 100644
--- a/arch/arm/boot/dts/dm814x.dtsi
+++ b/arch/arm/boot/dts/dm814x.dtsi
@@ -7,11 +7,11 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/dm814x.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,dm814";
interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
i2c0 = &i2c1;
diff --git a/arch/arm/boot/dts/dm8168-evm.dts b/arch/arm/boot/dts/dm8168-evm.dts
index f50348bdd857..0bf55fa72dea 100644
--- a/arch/arm/boot/dts/dm8168-evm.dts
+++ b/arch/arm/boot/dts/dm8168-evm.dts
@@ -12,14 +12,14 @@
model = "DM8168 EVM";
compatible = "ti,dm8168-evm", "ti,dm8168";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000 /* 1 GB */
0xc0000000 0x40000000>; /* 1 GB */
};
/* FDC6331L controlled by SD_POW pin */
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi
index 44e39c743b53..f1e0f771ff29 100644
--- a/arch/arm/boot/dts/dm816x.dtsi
+++ b/arch/arm/boot/dts/dm816x.dtsi
@@ -7,11 +7,11 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/omap.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,dm816";
interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
i2c0 = &i2c1;
diff --git a/arch/arm/boot/dts/dra62x-j5eco-evm.dts b/arch/arm/boot/dts/dra62x-j5eco-evm.dts
index f820573f4a4a..155eb32ee213 100644
--- a/arch/arm/boot/dts/dra62x-j5eco-evm.dts
+++ b/arch/arm/boot/dts/dra62x-j5eco-evm.dts
@@ -12,13 +12,13 @@
model = "DRA62x J5 Eco EVM";
compatible = "ti,dra62x-j5eco-evm", "ti,dra62x", "ti,dm8148";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
/* MIC94060YC6 controlled by SD1_POW pin */
- vmmcsd_fixed: fixedregulator@0 {
+ vmmcsd_fixed: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "vmmcsd_fixed";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index bafcfac067ec..132f2be10889 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -16,7 +16,7 @@
model = "TI DRA742";
compatible = "ti,dra7-evm", "ti,dra742", "ti,dra74", "ti,dra7";
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x60000000>; /* 1536 MB */
};
@@ -105,25 +105,25 @@
leds {
compatible = "gpio-leds";
- led@0 {
+ led0 {
label = "dra7:usr1";
gpios = <&pcf_lcd 4 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- led@1 {
+ led1 {
label = "dra7:usr2";
gpios = <&pcf_lcd 5 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- led@2 {
+ led2 {
label = "dra7:usr3";
gpios = <&pcf_lcd 6 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- led@3 {
+ led3 {
label = "dra7:usr4";
gpios = <&pcf_lcd 7 GPIO_ACTIVE_LOW>;
default-state = "off";
@@ -664,10 +664,10 @@
&qspi {
status = "okay";
- spi-max-frequency = <64000000>;
+ spi-max-frequency = <76800000>;
m25p80@0 {
compatible = "s25fl256s1";
- spi-max-frequency = <64000000>;
+ spi-max-frequency = <76800000>;
reg = <0>;
spi-tx-bus-width = <1>;
spi-rx-bus-width = <4>;
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index d9bfb94a2992..d4fcd68f6349 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -10,8 +10,6 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/dra.h>
-#include "skeleton.dtsi"
-
#define MAX_SOURCES 400
/ {
@@ -82,9 +80,11 @@
compatible = "arm,cortex-a15";
reg = <0>;
- operating-points-v2 = <&cpu0_opp_table>;
- ti,syscon-efuse = <&scm_wkup 0x20c 0xf80000 19>;
- ti,syscon-rev = <&scm_wkup 0x204>;
+ operating-points = <
+ /* kHz uV */
+ 1000000 1060000
+ 1176000 1160000
+ >;
clocks = <&dpll_mpu_ck>;
clock-names = "cpu";
@@ -98,24 +98,6 @@
};
};
- cpu0_opp_table: opp_table0 {
- compatible = "operating-points-v2";
- opp-shared;
-
- opp_nom@1000000000 {
- opp-hz = /bits/ 64 <1000000000>;
- opp-microvolt = <1060000 850000 1150000>;
- opp-supported-hw = <0xFF 0x01>;
- opp-suspend;
- };
-
- opp_od@1176000000 {
- opp-hz = /bits/ 64 <1176000000>;
- opp-microvolt = <1160000 885000 1160000>;
- opp-supported-hw = <0xFF 0x02>;
- };
- };
-
/*
* The soc node represents the soc top level view. It is used for IPs
* that are not memory mapped in the MPU view or for the MPU itself.
@@ -301,6 +283,7 @@
0x82000000 0 0x20013000 0x13000 0 0xffed000>;
#interrupt-cells = <1>;
num-lanes = <1>;
+ linux,pci-domain = <0>;
ti,hwmods = "pcie1";
phys = <&pcie1_phy>;
phy-names = "pcie-phy0";
@@ -336,6 +319,7 @@
0x82000000 0 0x30013000 0x13000 0 0xffed000>;
#interrupt-cells = <1>;
num-lanes = <1>;
+ linux,pci-domain = <1>;
ti,hwmods = "pcie2";
phys = <&pcie2_phy>;
phy-names = "pcie-phy0";
@@ -1413,7 +1397,7 @@
ti,hwmods = "ocp2scp1";
usb2_phy1: phy@4a084000 {
- compatible = "ti,omap-usb2";
+ compatible = "ti,dra7x-usb2", "ti,omap-usb2";
reg = <0x4a084000 0x400>;
syscon-phy-power = <&scm_conf 0x300>;
clocks = <&usb_phy1_always_on_clk32k>,
@@ -1717,7 +1701,7 @@
mac: ethernet@48484000 {
compatible = "ti,dra7-cpsw","ti,cpsw";
ti,hwmods = "gmac";
- clocks = <&dpll_gmac_ck>, <&gmac_gmii_ref_clk_div>;
+ clocks = <&gmac_main_clk>, <&gmac_rft_clk_mux>;
clock-names = "fck", "cpts";
cpdma_channels = <8>;
ale_entries = <1024>;
@@ -1726,7 +1710,7 @@
mac_control = <0x20>;
slaves = <2>;
active_slave = <0>;
- cpts_clock_mult = <0x80000000>;
+ cpts_clock_mult = <0x784CFE14>;
cpts_clock_shift = <29>;
reg = <0x48484000 0x1000
0x48485200 0x2E00>;
diff --git a/arch/arm/boot/dts/dra72-evm-common.dtsi b/arch/arm/boot/dts/dra72-evm-common.dtsi
index 9d3cf50ca37e..c94d8d64710d 100644
--- a/arch/arm/boot/dts/dra72-evm-common.dtsi
+++ b/arch/arm/boot/dts/dra72-evm-common.dtsi
@@ -681,10 +681,10 @@
&qspi {
status = "okay";
- spi-max-frequency = <64000000>;
+ spi-max-frequency = <76800000>;
m25p80@0 {
compatible = "s25fl256s1";
- spi-max-frequency = <64000000>;
+ spi-max-frequency = <76800000>;
reg = <0>;
spi-tx-bus-width = <1>;
spi-rx-bus-width = <4>;
diff --git a/arch/arm/boot/dts/dra72-evm-revc.dts b/arch/arm/boot/dts/dra72-evm-revc.dts
index f9cfd3bb4dc2..064b322a7a04 100644
--- a/arch/arm/boot/dts/dra72-evm-revc.dts
+++ b/arch/arm/boot/dts/dra72-evm-revc.dts
@@ -11,7 +11,7 @@
/ {
model = "TI DRA722 Rev C EVM";
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x80000000>; /* 2GB */
};
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index cc1d32ca4a8a..e3a9b6985693 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -9,7 +9,7 @@
/ {
model = "TI DRA722";
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x40000000>; /* 1024 MB */
};
diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi
index 8987b3e180a1..0a78347e6615 100644
--- a/arch/arm/boot/dts/dra74x.dtsi
+++ b/arch/arm/boot/dts/dra74x.dtsi
@@ -17,7 +17,6 @@
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <1>;
- operating-points-v2 = <&cpu0_opp_table>;
};
};
diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi
index 8378b44ee567..3330738e4c6e 100644
--- a/arch/arm/boot/dts/dra7xx-clocks.dtsi
+++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi
@@ -1003,6 +1003,14 @@
ti,index-power-of-two;
};
+ gmac_main_clk: gmac_main_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&gmac_250m_dclk_div>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+
l3init_480m_dclk_div: l3init_480m_dclk_div@1ac {
#clock-cells = <0>;
compatible = "ti,divider-clock";
@@ -1718,13 +1726,12 @@
reg = <0x0c00>;
};
- gmac_gmii_ref_clk_div: gmac_gmii_ref_clk_div@13d0 {
+ rmii_50mhz_clk_mux: rmii_50mhz_clk_mux@13d0 {
#clock-cells = <0>;
- compatible = "ti,divider-clock";
- clocks = <&dpll_gmac_m2_ck>;
+ compatible = "ti,mux-clock";
+ clocks = <&dpll_gmac_h11x2_ck>, <&rmii_clk_ck>;
ti,bit-shift = <24>;
reg = <0x13d0>;
- ti,dividers = <2>;
};
gmac_rft_clk_mux: gmac_rft_clk_mux@13d0 {
diff --git a/arch/arm/boot/dts/efm32gg-dk3750.dts b/arch/arm/boot/dts/efm32gg-dk3750.dts
index 504cf45d3cb8..98fc667d22c7 100644
--- a/arch/arm/boot/dts/efm32gg-dk3750.dts
+++ b/arch/arm/boot/dts/efm32gg-dk3750.dts
@@ -16,7 +16,8 @@
bootargs = "console=ttyefm4,115200 init=/linuxrc ignore_loglevel ihash_entries=64 dhash_entries=64 earlyprintk uclinux.physaddr=0x8c400000 root=/dev/mtdblock0";
};
- memory {
+ memory@88000000 {
+ device_type = "memory";
reg = <0x88000000 0x400000>;
};
@@ -74,7 +75,7 @@
status = "ok";
};
- boardfpga: boardfpga {
+ boardfpga: boardfpga@80000000 {
compatible = "efm32board";
reg = <0x80000000 0x400>;
irq-gpios = <&gpio 64 1>;
diff --git a/arch/arm/boot/dts/efm32gg.dtsi b/arch/arm/boot/dts/efm32gg.dtsi
index c747983771c7..b78c57e51ed5 100644
--- a/arch/arm/boot/dts/efm32gg.dtsi
+++ b/arch/arm/boot/dts/efm32gg.dtsi
@@ -4,10 +4,14 @@
* Documentation available from
* http://www.silabs.com/Support%20Documents/TechnicalDocs/EFM32GG-RM.pdf
*/
+
#include "armv7-m.dtsi"
#include "dt-bindings/clock/efm32-cmu.h"
/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
aliases {
i2c0 = &i2c0;
i2c1 = &i2c1;
diff --git a/arch/arm/boot/dts/exynos3250-artik5.dtsi b/arch/arm/boot/dts/exynos3250-artik5.dtsi
index 130e946f1414..a70819b1b739 100644
--- a/arch/arm/boot/dts/exynos3250-artik5.dtsi
+++ b/arch/arm/boot/dts/exynos3250-artik5.dtsi
@@ -24,7 +24,8 @@
stdout-path = &serial_2;
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x1ff00000>;
};
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 8c8906266310..66f04f6ba6bb 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -27,7 +27,8 @@
i2c7 = &i2c_max77836;
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x1ff00000>;
};
diff --git a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
index 40ea7de44933..ec331169c3d9 100644
--- a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
@@ -12,58 +12,46 @@
* published by the Free Software Foundation.
*/
-#define PIN_PULL_NONE 0
-#define PIN_PULL_DOWN 1
-#define PIN_PULL_UP 3
-
-#define PIN_DRV_LV1 0
-#define PIN_DRV_LV2 2
-#define PIN_DRV_LV3 1
-#define PIN_DRV_LV4 3
-
-#define PIN_PDN_OUT0 0
-#define PIN_PDN_OUT1 1
-#define PIN_PDN_INPUT 2
-#define PIN_PDN_PREV 3
-
-#define PIN_IN(_pin, _pull, _drv) \
- _pin { \
- samsung,pins = #_pin; \
- samsung,pin-function = <0>; \
- samsung,pin-pud = <PIN_PULL_ ##_pull>; \
- samsung,pin-drv = <PIN_DRV_ ##_drv>; \
+#include <dt-bindings/pinctrl/samsung.h>
+
+#define PIN_IN(_pin, _pull, _drv) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>; \
+ samsung,pin-pud = <EXYNOS_PIN_PULL_ ##_pull>; \
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_ ##_drv>; \
}
-#define PIN_OUT(_pin, _drv) \
- _pin { \
- samsung,pins = #_pin; \
- samsung,pin-function = <1>; \
- samsung,pin-pud = <0>; \
- samsung,pin-drv = <PIN_DRV_ ##_drv>; \
+#define PIN_OUT(_pin, _drv) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>; \
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>; \
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_ ##_drv>; \
}
-#define PIN_OUT_SET(_pin, _val, _drv) \
- _pin { \
- samsung,pins = #_pin; \
- samsung,pin-function = <1>; \
- samsung,pin-pud = <0>; \
- samsung,pin-drv = <PIN_DRV_ ##_drv>; \
- samsung,pin-val = <_val>; \
+#define PIN_OUT_SET(_pin, _val, _drv) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>; \
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>; \
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_ ##_drv>; \
+ samsung,pin-val = <_val>; \
}
-#define PIN_CFG(_pin, _sel, _pull, _drv) \
- _pin { \
- samsung,pins = #_pin; \
- samsung,pin-function = <_sel>; \
- samsung,pin-pud = <PIN_PULL_ ##_pull>; \
- samsung,pin-drv = <PIN_DRV_ ##_drv>; \
+#define PIN_CFG(_pin, _sel, _pull, _drv) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-function = <_sel>; \
+ samsung,pin-pud = <EXYNOS_PIN_PULL_ ##_pull>; \
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_ ##_drv>; \
}
-#define PIN_SLP(_pin, _mode, _pull) \
- _pin { \
- samsung,pins = #_pin; \
- samsung,pin-con-pdn = <PIN_PDN_ ##_mode>; \
- samsung,pin-pud-pdn = <PIN_PULL_ ##_pull>; \
+#define PIN_SLP(_pin, _mode, _pull) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-con-pdn = <EXYNOS_PIN_PDN_ ##_mode>; \
+ samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_ ##_pull>; \
}
&pinctrl_0 {
@@ -125,158 +113,158 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpb-0", "gpb-2", "gpb-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c4_bus: i2c4-bus {
samsung,pins = "gpb-0", "gpb-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpb-4", "gpb-6", "gpb-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c5_bus: i2c5-bus {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c6_bus: i2c6-bus {
samsung,pins = "gpc1-3", "gpc1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpd0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpd0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c7_bus: i2c7-bus {
samsung,pins = "gpd0-2", "gpd0-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpd0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpd0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
mipi0_clk: mipi0-clk {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpd1-2", "gpd1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -408,164 +396,164 @@
sd0_clk: sd0-clk {
samsung,pins = "gpk0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpk0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpk0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_rdqs: sd0-rdqs {
samsung,pins = "gpk0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpk0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpk0-4", "gpk0-5", "gpk0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpl0-0", "gpl0-1", "gpl0-2", "gpl0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpk1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpk1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpk1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpk1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpk2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpk2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpk2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpk2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpk2-4", "gpk2-5", "gpk2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_io: cam-port-b-io {
samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
"gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
"gpm1-0", "gpm1-1", "gpm2-0", "gpm2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_b_clk_active: cam-port-b-clk-active {
samsung,pins = "gpm2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_clk_idle: cam-port-b-clk-idle {
samsung,pins = "gpm2-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_i2c0: fimc-is-i2c0 {
samsung,pins = "gpm4-0", "gpm4-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_i2c1: fimc-is-i2c1 {
samsung,pins = "gpm4-2", "gpm4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_uart: fimc-is-uart {
samsung,pins = "gpm3-5", "gpm3-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index a92181368e5b..3967ee5f7752 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -27,7 +27,8 @@
i2c7 = &i2c_max77836;
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x1ff00000>;
};
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 70e3aceab3a9..e9d2556c0dfd 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -17,7 +17,6 @@
* published by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
#include "exynos4-cpu-thermal.dtsi"
#include "exynos-syscon-restart.dtsi"
#include <dt-bindings/clock/exynos3250.h>
@@ -25,6 +24,8 @@
/ {
compatible = "samsung,exynos3250";
interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
pinctrl0 = &pinctrl_0;
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 32f22e12c70b..5f034eb5a5e2 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -21,11 +21,12 @@
#include <dt-bindings/clock/exynos4.h>
#include <dt-bindings/clock/exynos-audss-clk.h>
-#include "skeleton.dtsi"
#include "exynos-syscon-restart.dtsi"
/ {
interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
spi0 = &spi_0;
diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
index be2751eebaf8..a2c6a13fe67b 100644
--- a/arch/arm/boot/dts/exynos4210-origen.dts
+++ b/arch/arm/boot/dts/exynos4210-origen.dts
@@ -24,7 +24,8 @@
model = "Insignal Origen evaluation board based on Exynos4210";
compatible = "insignal,origen", "samsung,exynos4210", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x10000000
0x50000000 0x10000000
0x60000000 0x10000000
diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
index 9331c6252eff..d9b6d25e4abe 100644
--- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
@@ -14,6 +14,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
/ {
pinctrl@11400000 {
gpa0: gpa0 {
@@ -146,245 +148,245 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart_audio_a: uart-audio-a {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart_audio_b: uart-audio-b {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpb-0", "gpb-2", "gpb-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c4_bus: i2c4-bus {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpb-4", "gpb-6", "gpb-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c5_bus: i2c5-bus {
samsung,pins = "gpb-6", "gpb-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
ac97_bus: ac97-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spdif_bus: spdif-bus {
samsung,pins = "gpc1-0", "gpc1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c6_bus: i2c6-bus {
samsung,pins = "gpc1-3", "gpc1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4";
- samsung,pin-function = <5>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c7_bus: i2c7-bus {
samsung,pins = "gpd0-2", "gpd0-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpd1-2", "gpd1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpd0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpd0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpd0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpd0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_ctrl: lcd-ctrl {
samsung,pins = "gpd0-0", "gpd0-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_sync: lcd-sync {
samsung,pins = "gpf0-0", "gpf0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_en: lcd-en {
samsung,pins = "gpe3-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_clk: lcd-clk {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data16: lcd-data-width16 {
@@ -392,9 +394,9 @@
"gpf1-3", "gpf1-6", "gpf1-7", "gpf2-0",
"gpf2-1", "gpf2-2", "gpf2-3", "gpf2-7",
"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data18: lcd-data-width18 {
@@ -403,9 +405,9 @@
"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
"gpf2-6", "gpf2-7", "gpf3-0", "gpf3-1",
"gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data24: lcd-data-width24 {
@@ -415,9 +417,9 @@
"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -569,263 +571,263 @@
sd0_clk: sd0-clk {
samsung,pins = "gpk0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpk0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpk0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpk0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_clk: sd4-clk {
samsung,pins = "gpk0-0";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_cmd: sd4-cmd {
samsung,pins = "gpk0-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_cd: sd4-cd {
samsung,pins = "gpk0-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_bus1: sd4-bus-width1 {
samsung,pins = "gpk0-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_bus4: sd4-bus-width4 {
samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_bus8: sd4-bus-width8 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <4>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpk1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpk1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpk1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpk1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpk2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpk2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpk2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpk2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus8: sd2-bus-width8 {
samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_clk: sd3-clk {
samsung,pins = "gpk3-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cmd: sd3-cmd {
samsung,pins = "gpk3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cd: sd3-cd {
samsung,pins = "gpk3-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus1: sd3-bus-width1 {
samsung,pins = "gpk3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus4: sd3-bus-width4 {
samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
eint0: ext-int0 {
samsung,pins = "gpx0-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint8: ext-int8 {
samsung,pins = "gpx1-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint15: ext-int15 {
samsung,pins = "gpx1-7";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint16: ext-int16 {
samsung,pins = "gpx2-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint31: ext-int31 {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a_io: cam-port-a-io {
samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a_clk_active: cam-port-a-clk-active {
samsung,pins = "gpj1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_a_clk_idle: cam-port-a-clk-idle {
samsung,pins = "gpj1-3";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
hdmi_cec: hdmi-cec {
samsung,pins = "gpx3-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -838,17 +840,17 @@
i2s0_bus: i2s0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4", "gpz-5", "gpz-6";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm0_bus: pcm0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4";
- samsung,pin-function = <0x3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
};
diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts
index 847fae3dd1f1..9c98a3724396 100644
--- a/arch/arm/boot/dts/exynos4210-smdkv310.dts
+++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts
@@ -23,7 +23,8 @@
model = "Samsung smdkv310 evaluation board based on Exynos4210";
compatible = "samsung,smdkv310", "samsung,exynos4210", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x80000000>;
};
@@ -136,17 +137,17 @@
&pinctrl_1 {
keypad_rows: keypad-rows {
samsung,pins = "gpx2-0", "gpx2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_cols: keypad-cols {
samsung,pins = "gpx1-0", "gpx1-1", "gpx1-2", "gpx1-3",
"gpx1-4", "gpx1-5", "gpx1-6", "gpx1-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 79d983036560..0ca1b4d355f2 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -20,7 +20,8 @@
model = "Samsung Trats based on Exynos4210";
compatible = "samsung,trats", "samsung,exynos4210", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x10000000
0x50000000 0x10000000
0x60000000 0x10000000
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index 9a75e3effbc9..0c89ea99de54 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -20,7 +20,8 @@
model = "Samsung Universal C210 based on Exynos4210 rev0";
compatible = "samsung,universal_c210", "samsung,exynos4210", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x10000000
0x50000000 0x10000000>;
};
@@ -269,7 +270,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd>;
hdmi-en-supply = <&hdmi_en>;
@@ -521,16 +522,16 @@
&pinctrl_1 {
hdmi_hpd: hdmi-hpd {
samsung,pins = "gpx3-7";
- samsung,pin-pud = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
};
};
&pinctrl_0 {
i2c_ddc_bus: i2c-ddc-bus {
samsung,pins = "gpe4-2", "gpe4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 58ad48e7b8f7..8aa19ba14436 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -163,26 +163,26 @@
/* RSTN signal for eMMC */
&sd1_cd {
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&pinctrl_1 {
gpio_power_key: power_key {
samsung,pins = "gpx1-3";
- samsung,pin-pud = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
};
max77686_irq: max77686-irq {
samsung,pins = "gpx3-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
hdmi_hpd: hdmi-hpd {
samsung,pins = "gpx3-7";
- samsung,pin-pud = <1>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
};
};
@@ -227,7 +227,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd>;
vdd-supply = <&ldo8_reg>;
diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts
index d73aa6c58fe3..99634c54dca9 100644
--- a/arch/arm/boot/dts/exynos4412-odroidu3.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts
@@ -18,7 +18,8 @@
model = "Hardkernel ODROID-U3 board based on Exynos4412";
compatible = "hardkernel,odroid-u3", "samsung,exynos4412", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x7FF00000>;
};
diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts
index 2af235151301..61906b35ea7a 100644
--- a/arch/arm/boot/dts/exynos4412-odroidx.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidx.dts
@@ -18,7 +18,8 @@
model = "Hardkernel ODROID-X board based on Exynos4412";
compatible = "hardkernel,odroid-x", "samsung,exynos4412", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x3FF00000>;
};
@@ -83,7 +84,7 @@
&pinctrl_1 {
gpio_home_key: home_key {
samsung,pins = "gpx2-2";
- samsung,pin-pud = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
};
};
diff --git a/arch/arm/boot/dts/exynos4412-odroidx2.dts b/arch/arm/boot/dts/exynos4412-odroidx2.dts
index 3e3584270e00..4d228858f172 100644
--- a/arch/arm/boot/dts/exynos4412-odroidx2.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidx2.dts
@@ -17,7 +17,8 @@
model = "Hardkernel ODROID-X2 board based on Exynos4412";
compatible = "hardkernel,odroid-x2", "samsung,exynos4412", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x7FF00000>;
};
};
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index 26a36fed9652..a1ab6f94bb64 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -22,7 +22,8 @@
model = "Insignal Origen evaluation board based on Exynos4412";
compatible = "insignal,origen4412", "samsung,exynos4412", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x40000000>;
};
@@ -500,16 +501,16 @@
&pinctrl_1 {
keypad_rows: keypad-rows {
samsung,pins = "gpx2-0", "gpx2-1", "gpx2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_cols: keypad-cols {
samsung,pins = "gpx1-0", "gpx1-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts
index 231ffbdbf9d0..7fcb43431b59 100644
--- a/arch/arm/boot/dts/exynos4412-smdk4412.dts
+++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts
@@ -20,7 +20,8 @@
model = "Samsung SMDK evaluation board based on Exynos4412";
compatible = "samsung,smdk4412", "samsung,exynos4412", "samsung,exynos4";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x40000000>;
};
@@ -115,17 +116,17 @@
&pinctrl_1 {
keypad_rows: keypad-rows {
samsung,pins = "gpx2-0", "gpx2-1", "gpx2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_cols: keypad-cols {
samsung,pins = "gpx1-0", "gpx1-1", "gpx1-2", "gpx1-3",
"gpx1-4", "gpx1-5", "gpx1-6", "gpx1-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
index 4840bbdaa9ec..5504398e6e37 100644
--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
@@ -23,7 +23,8 @@
stdout-path = &serial_0;
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x40000000>;
};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 129e973a06a6..41ecd6d465a7 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -30,7 +30,8 @@
i2c12 = &i2c_max77693_fuel;
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x40000000>;
};
diff --git a/arch/arm/boot/dts/exynos4415-pinctrl.dtsi b/arch/arm/boot/dts/exynos4415-pinctrl.dtsi
index 75af9c56123e..76cfd872ead3 100644
--- a/arch/arm/boot/dts/exynos4415-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4415-pinctrl.dtsi
@@ -11,6 +11,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
&pinctrl_0 {
gpa0: gpa0 {
gpio-controller;
@@ -94,180 +96,180 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpb-0", "gpb-2", "gpb-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c4_bus: i2c4-bus {
samsung,pins = "gpb-0", "gpb-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpb-4", "gpb-6", "gpb-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c5_bus: i2c5-bus {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c6_bus: i2c6-bus {
samsung,pins = "gpc1-3", "gpc1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpc1-1", "gpc1-3", "gpc1-4";
- samsung,pin-function = <5>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpd0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpd0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpd0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpd0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c7_bus: i2c7-bus {
samsung,pins = "gpd0-2", "gpd0-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpd1-2", "gpd1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -392,165 +394,165 @@
sd0_clk: sd0-clk {
samsung,pins = "gpk0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpk0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpk0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_rdqs: sd0-rdqs {
samsung,pins = "gpk0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpk0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpk0-4", "gpk0-5", "gpk0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpl0-0", "gpl0-1", "gpl0-2", "gpl0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpk1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpk1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpk1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpk1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpk2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <4>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpk2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <4>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpk2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpk2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <4>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpk2-4", "gpk2-5", "gpk2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <4>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_io: cam-port-b-io {
samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
"gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
"gpm1-0", "gpm1-1", "gpm2-0", "gpm2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_b_clk_active: cam-port-b-clk-active {
samsung,pins = "gpm2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_clk_idle: cam-port-b-clk-idle {
samsung,pins = "gpm2-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_i2c0: fimc-is-i2c0 {
samsung,pins = "gpm4-0", "gpm4-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_i2c1: fimc-is-i2c1 {
samsung,pins = "gpm4-2", "gpm4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_uart: fimc-is-uart {
samsung,pins = "gpm3-5", "gpm3-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -566,8 +568,8 @@
i2s0_bus: i2s0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4", "gpz-5", "gpz-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos4415.dtsi b/arch/arm/boot/dts/exynos4415.dtsi
index 28b04b6795c9..3c40f8a956dd 100644
--- a/arch/arm/boot/dts/exynos4415.dtsi
+++ b/arch/arm/boot/dts/exynos4415.dtsi
@@ -16,13 +16,14 @@
* published by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
#include <dt-bindings/clock/exynos4415.h>
#include <dt-bindings/clock/exynos-audss-clk.h>
/ {
compatible = "samsung,exynos4415";
interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
pinctrl0 = &pinctrl_0;
diff --git a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
index 856b29254374..a56bf9b1a412 100644
--- a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
@@ -12,20 +12,13 @@
* published by the Free Software Foundation.
*/
-#define PIN_PULL_NONE 0
-#define PIN_PULL_DOWN 1
-#define PIN_PULL_UP 3
-
-#define PIN_PDN_OUT0 0
-#define PIN_PDN_OUT1 1
-#define PIN_PDN_INPUT 2
-#define PIN_PDN_PREV 3
-
-#define PIN_SLP(_pin, _mode, _pull) \
- _pin { \
- samsung,pins = #_pin; \
- samsung,pin-con-pdn = <PIN_PDN_ ##_mode>; \
- samsung,pin-pud-pdn = <PIN_PULL_ ##_pull>; \
+#include <dt-bindings/pinctrl/samsung.h>
+
+#define PIN_SLP(_pin, _mode, _pull) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-con-pdn = <EXYNOS_PIN_PDN_ ##_mode>; \
+ samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_ ##_pull>; \
}
/ {
@@ -136,245 +129,245 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart_audio_a: uart-audio-a {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart_audio_b: uart-audio-b {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpb-0", "gpb-2", "gpb-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c4_bus: i2c4-bus {
samsung,pins = "gpb-0", "gpb-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpb-4", "gpb-6", "gpb-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c5_bus: i2c5-bus {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
ac97_bus: ac97-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spdif_bus: spdif-bus {
samsung,pins = "gpc1-0", "gpc1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c6_bus: i2c6-bus {
samsung,pins = "gpc1-3", "gpc1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpc1-1", "gpc1-3", "gpc1-4";
- samsung,pin-function = <5>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpd0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpd0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_ctrl: lcd-ctrl {
samsung,pins = "gpd0-0", "gpd0-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c7_bus: i2c7-bus {
samsung,pins = "gpd0-2", "gpd0-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpd0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpd0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
mipi0_clk: mipi0-clk {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpd1-2", "gpd1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
mipi1_clk: mipi1-clk {
samsung,pins = "gpd1-2", "gpd1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_clk: lcd-clk {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data16: lcd-data-width16 {
@@ -382,9 +375,9 @@
"gpf1-3", "gpf1-6", "gpf1-7", "gpf2-0",
"gpf2-1", "gpf2-2", "gpf2-3", "gpf2-7",
"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data18: lcd-data-width18 {
@@ -393,9 +386,9 @@
"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
"gpf2-6", "gpf2-7", "gpf3-0", "gpf3-1",
"gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data24: lcd-data-width24 {
@@ -405,39 +398,39 @@
"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_ldi: lcd-ldi {
samsung,pins = "gpf3-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a_io: cam-port-a-io {
samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a_clk_active: cam-port-a-clk-active {
samsung,pins = "gpj1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_a_clk_idle: cam-port-a-clk-idle {
samsung,pins = "gpj1-3";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -613,284 +606,284 @@
sd0_clk: sd0-clk {
samsung,pins = "gpk0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpk0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpk0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpk0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_clk: sd4-clk {
samsung,pins = "gpk0-0";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_cmd: sd4-cmd {
samsung,pins = "gpk0-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_cd: sd4-cd {
samsung,pins = "gpk0-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_bus1: sd4-bus-width1 {
samsung,pins = "gpk0-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_bus4: sd4-bus-width4 {
samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd4_bus8: sd4-bus-width8 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpk1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpk1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpk1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpk1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpk2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpk2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpk2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpk2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus8: sd2-bus-width8 {
samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_clk: sd3-clk {
samsung,pins = "gpk3-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cmd: sd3-cmd {
samsung,pins = "gpk3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cd: sd3-cd {
samsung,pins = "gpk3-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus1: sd3-bus-width1 {
samsung,pins = "gpk3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus4: sd3-bus-width4 {
samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_io: cam-port-b-io {
samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
"gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
"gpm1-0", "gpm1-1", "gpm2-0", "gpm2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_b_clk_active: cam-port-b-clk-active {
samsung,pins = "gpm2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_clk_idle: cam-port-b-clk-idle {
samsung,pins = "gpm2-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint0: ext-int0 {
samsung,pins = "gpx0-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint8: ext-int8 {
samsung,pins = "gpx1-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint15: ext-int15 {
samsung,pins = "gpx1-7";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint16: ext-int16 {
samsung,pins = "gpx2-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint31: ext-int31 {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_i2c0: fimc-is-i2c0 {
samsung,pins = "gpm4-0", "gpm4-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_i2c1: fimc-is-i2c1 {
samsung,pins = "gpm4-2", "gpm4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
fimc_is_uart: fimc-is-uart {
samsung,pins = "gpm3-5", "gpm3-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
hdmi_cec: hdmi-cec {
samsung,pins = "gpx3-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -906,17 +899,17 @@
i2s0_bus: i2s0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4", "gpz-5", "gpz-6";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm0_bus: pcm0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4";
- samsung,pin-function = <0x3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -971,9 +964,9 @@
"gpv3-0", "gpv3-1", "gpv3-2", "gpv3-3",
"gpv3-4", "gpv3-5", "gpv3-6", "gpv3-7",
"gpv4-0", "gpv4-1";
- samsung,pin-function = <0x2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
};
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index c452499ae8c9..3394bdcf10ae 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -157,7 +157,9 @@
<&clock CLK_MOUT_MPLL_USER_T>,
<&clock CLK_FIMC_ISP>, <&clock CLK_FIMC_DRC>,
<&clock CLK_FIMC_FD>, <&clock CLK_MCUISP>,
- <&clock CLK_DIV_ISP0>,<&clock CLK_DIV_ISP1>,
+ <&clock CLK_GICISP>, <&clock CLK_MCUCTL_ISP>,
+ <&clock CLK_PWM_ISP>,
+ <&clock CLK_DIV_ISP0>, <&clock CLK_DIV_ISP1>,
<&clock CLK_DIV_MCUISP0>,
<&clock CLK_DIV_MCUISP1>,
<&clock CLK_UART_ISP_SCLK>,
@@ -167,6 +169,7 @@
clock-names = "lite0", "lite1", "ppmuispx",
"ppmuispmx", "mpll", "isp",
"drc", "fd", "mcuisp",
+ "gicisp", "mcuctl_isp", "pwm_isp",
"ispdiv0", "ispdiv1", "mcuispdiv0",
"mcuispdiv1", "uart", "aclk200",
"div_aclk200", "aclk400mcuisp",
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi
index cab91782e20c..8f06609879f5 100644
--- a/arch/arm/boot/dts/exynos5.dtsi
+++ b/arch/arm/boot/dts/exynos5.dtsi
@@ -13,11 +13,12 @@
* published by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
#include "exynos-syscon-restart.dtsi"
/ {
interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
i2c0 = &i2c_0;
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index ea70603f660d..6098dacd09f1 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -20,7 +20,8 @@
model = "Insignal Arndale evaluation board based on EXYNOS5250";
compatible = "insignal,arndale", "samsung,exynos5250", "samsung,exynos5";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x80000000>;
};
@@ -152,7 +153,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_LOW>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_LOW>;
vdd_osc-supply = <&ldo10_reg>;
vdd_pll-supply = <&ldo8_reg>;
vdd-supply = <&ldo8_reg>;
diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi
index 880917e508b2..2f6ab32b5954 100644
--- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi
@@ -12,6 +12,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
&pinctrl_0 {
gpa0: gpa0 {
gpio-controller;
@@ -200,392 +202,392 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_hs_bus: i2c2-hs-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c3_hs_bus: i2c3-hs-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-4", "gpa1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpa2-0", "gpa2-2", "gpa2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c4_bus: i2c4-bus {
samsung,pins = "gpa2-0", "gpa2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c5_bus: i2c5-bus {
samsung,pins = "gpa2-2", "gpa2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpa2-4", "gpa2-6", "gpa2-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
ac97_bus: ac97-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpb1-0", "gpb1-1", "gpb1-2", "gpb1-3",
"gpb1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpb1-0", "gpb1-1", "gpb1-2", "gpb1-3",
"gpb1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spdif_bus: spdif-bus {
samsung,pins = "gpb1-0", "gpb1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpb1-1", "gpb1-3", "gpb1-4";
- samsung,pin-function = <5>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c6_bus: i2c6-bus {
samsung,pins = "gpb1-3", "gpb1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpb2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpb2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpb2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpb2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c7_bus: i2c7-bus {
samsung,pins = "gpb2-2", "gpb2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpb3-0", "gpb3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpb3-2", "gpb3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_hs_bus: i2c0-hs-bus {
samsung,pins = "gpb3-0", "gpb3-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_hs_bus: i2c1-hs-bus {
samsung,pins = "gpb3-2", "gpb3-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
sd0_clk: sd0-clk {
samsung,pins = "gpc0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpc0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpc0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpc0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpc0-3", "gpc0-4", "gpc0-5", "gpc0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpc2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpc2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpc2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpc2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpc2-3", "gpc2-4", "gpc2-5", "gpc2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpc3-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpc3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpc3-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpc3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpc3-3", "gpc3-4", "gpc3-5", "gpc3-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus8: sd2-bus-width8 {
samsung,pins = "gpc4-3", "gpc4-4", "gpc4-5", "gpc4-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_clk: sd3-clk {
samsung,pins = "gpc4-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cmd: sd3-cmd {
samsung,pins = "gpc4-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cd: sd3-cd {
samsung,pins = "gpc4-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus1: sd3-bus-width1 {
samsung,pins = "gpc4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus4: sd3-bus-width4 {
samsung,pins = "gpc4-3", "gpc4-4", "gpc4-5", "gpc4-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
uart1_data: uart1-data {
samsung,pins = "gpd0-0", "gpd0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpd0-2", "gpd0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
dp_hpd: dp_hpd {
samsung,pins = "gpx0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -666,52 +668,52 @@
samsung,pins = "gpe0-0", "gpe0-1", "gpe0-2", "gpe0-3",
"gpe0-4", "gpe0-5", "gpe0-6", "gpe0-7",
"gpe1-0", "gpe1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_gpio_b: cam-gpio-b {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3",
"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_i2c2_bus: cam-i2c2-bus {
samsung,pins = "gpe0-6", "gpe1-0";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_spi1_bus: cam-spi1-bus {
samsung,pins = "gpe0-4", "gpe0-5", "gpf0-2", "gpf0-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_i2c1_bus: cam-i2c1-bus {
samsung,pins = "gpf0-2", "gpf0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_i2c0_bus: cam-i2c0-bus {
samsung,pins = "gpf0-0", "gpf0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_spi0_bus: cam-spi0-bus {
samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_bayrgb_bus: cam-bayrgb-bus {
@@ -720,18 +722,18 @@
"gpg1-0", "gpg1-1", "gpg1-2", "gpg1-3",
"gpg1-4", "gpg1-5", "gpg1-6", "gpg1-7",
"gpg2-0", "gpg2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a: cam-port-a {
samsung,pins = "gph0-0", "gph0-1", "gph0-2", "gph0-3",
"gph1-0", "gph1-1", "gph1-2", "gph1-3",
"gph1-4", "gph1-5", "gph1-6", "gph1-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -781,9 +783,9 @@
"gpv0-4", "gpv0-5", "gpv0-6", "gpv0-7",
"gpv1-0", "gpv1-1", "gpv1-2", "gpv1-3",
"gpv1-4", "gpv1-5", "gpv1-6", "gpv1-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
c2c_txd: c2c-txd {
@@ -791,9 +793,9 @@
"gpv2-4", "gpv2-5", "gpv2-6", "gpv2-7",
"gpv3-0", "gpv3-1", "gpv3-2", "gpv3-3",
"gpv3-4", "gpv3-5", "gpv3-6", "gpv3-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -809,8 +811,8 @@
i2s0_bus: i2s0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4", "gpz-5", "gpz-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 381af134c4c8..a97a785ccc6b 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -22,7 +22,8 @@
aliases {
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x80000000>;
};
@@ -116,7 +117,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
};
&i2c_0 {
@@ -416,8 +417,8 @@
&pinctrl_0 {
max77686_irq: max77686-irq {
samsung,pins = "gpx3-2";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi
index fadbea744e1a..d5d51916bb74 100644
--- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi
+++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi
@@ -19,7 +19,8 @@
i2c104 = &i2c_104;
};
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x80000000>;
};
@@ -260,7 +261,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
phy = <&hdmiphy>;
@@ -440,7 +441,7 @@
* double-pulling gets us out of spec in some cases.
*/
&i2c2_bus {
- samsung,pin-pud = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
};
&i2c_2 {
@@ -572,81 +573,81 @@
&pinctrl_0 {
wifi_en: wifi-en {
samsung,pins = "gpx0-1";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
wifi_rst: wifi-rst {
samsung,pins = "gpx0-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
power_key_irq: power-key-irq {
samsung,pins = "gpx1-3";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
ec_irq: ec-irq {
samsung,pins = "gpx1-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
tps65090_irq: tps65090-irq {
samsung,pins = "gpx2-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
usb3_vbus_en: usb3-vbus-en {
samsung,pins = "gpx2-7";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
max77686_irq: max77686-irq {
samsung,pins = "gpx3-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lid_irq: lid-irq {
samsung,pins = "gpx3-5";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
&pinctrl_1 {
arb_their_claim: arb-their-claim {
samsung,pins = "gpe0-4";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
arb_our_claim: arb-our-claim {
samsung,pins = "gpf0-3";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
@@ -657,16 +658,16 @@
};
&sd3_bus4 {
- samsung,pin-drv = <0>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&sd3_clk {
- samsung,pin-drv = <0>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&sd3_cmd {
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&spi_1 {
diff --git a/arch/arm/boot/dts/exynos5250-snow-rev5.dts b/arch/arm/boot/dts/exynos5250-snow-rev5.dts
index f811dc800660..90560c316f64 100644
--- a/arch/arm/boot/dts/exynos5250-snow-rev5.dts
+++ b/arch/arm/boot/dts/exynos5250-snow-rev5.dts
@@ -40,8 +40,8 @@
&pinctrl_0 {
max98090_irq: max98090-irq {
samsung,pins = "gpx0-4";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index 995c7ce6c12b..df48f2cc96f7 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -36,8 +36,8 @@
&pinctrl_0 {
max98095_en: max98095-en {
samsung,pins = "gpx1-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts
index 44f4292bfef6..4d7bdb735ed3 100644
--- a/arch/arm/boot/dts/exynos5250-spring.dts
+++ b/arch/arm/boot/dts/exynos5250-spring.dts
@@ -20,7 +20,8 @@
model = "Google Spring";
compatible = "google,spring", "samsung,exynos5250", "samsung,exynos5";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x80000000>;
};
@@ -91,7 +92,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
phy = <&hdmiphy>;
@@ -357,7 +358,7 @@
* double-pulling gets us out of spec in some cases.
*/
&i2c2_bus {
- samsung,pin-pud = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
};
&i2c_2 {
@@ -460,92 +461,92 @@
&pinctrl_0 {
s5m8767_dvs: s5m8767-dvs {
samsung,pins = "gpd1-0", "gpd1-1", "gpd1-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
dp_hpd_gpio: dp-hpd-gpio {
samsung,pins = "gpc3-0";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
trackpad_irq: trackpad-irq {
samsung,pins = "gpx1-2";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
power_key_irq: power-key-irq {
samsung,pins = "gpx1-3";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
ec_irq: ec-irq {
samsung,pins = "gpx1-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
s5m8767_ds: s5m8767-ds {
samsung,pins = "gpx2-3", "gpx2-4", "gpx2-5";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
s5m8767_irq: s5m8767-irq {
samsung,pins = "gpx3-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lid_irq: lid-irq {
samsung,pins = "gpx3-5";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
&pinctrl_1 {
hsic_reset: hsic-reset {
samsung,pins = "gpe1-0";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
&sd1_bus4 {
- samsung,pin-drv = <0>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&sd1_cd {
- samsung,pin-drv = <0>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&sd1_clk {
- samsung,pin-drv = <0>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&sd1_cmd {
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
&spi_1 {
diff --git a/arch/arm/boot/dts/exynos5260-pinctrl.dtsi b/arch/arm/boot/dts/exynos5260-pinctrl.dtsi
index f6ee55ea0708..1b911a219a27 100644
--- a/arch/arm/boot/dts/exynos5260-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos5260-pinctrl.dtsi
@@ -12,9 +12,7 @@
* published by the Free Software Foundation.
*/
-#define PIN_PULL_NONE 0
-#define PIN_PULL_DOWN 1
-#define PIN_PULL_UP 3
+#include <dt-bindings/pinctrl/samsung.h>
&pinctrl_0 {
gpa0: gpa0 {
@@ -187,217 +185,217 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpa2-0", "gpa2-2", "gpa2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpa2-4", "gpa2-6", "gpa2-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
usb3_vbus0_en: usb3-vbus0-en {
samsung,pins = "gpa2-4";
- samsung,pin-function = <1>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
spdif1_bus: spdif1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpb1-0", "gpb1-2", "gpb1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c0_hs_bus: i2c0-hs-bus {
samsung,pins = "gpb3-0", "gpb3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c1_hs_bus: i2c1-hs-bus {
samsung,pins = "gpb3-2", "gpb3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c2_hs_bus: i2c2-hs-bus {
samsung,pins = "gpb3-4", "gpb3-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c3_hs_bus: i2c3-hs-bus {
samsung,pins = "gpb3-6", "gpb3-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c4_bus: i2c4-bus {
samsung,pins = "gpb4-0", "gpb4-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c5_bus: i2c5-bus {
samsung,pins = "gpb4-2", "gpb4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c6_bus: i2c6-bus {
samsung,pins = "gpb4-4", "gpb4-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c7_bus: i2c7-bus {
samsung,pins = "gpb4-6", "gpb4-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c8_bus: i2c8-bus {
samsung,pins = "gpb5-0", "gpb5-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c9_bus: i2c9-bus {
samsung,pins = "gpb5-2", "gpb5-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c10_bus: i2c10-bus {
samsung,pins = "gpb5-4", "gpb5-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
i2c11_bus: i2c11-bus {
samsung,pins = "gpb5-6", "gpb5-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
cam_gpio_a: cam-gpio-a {
samsung,pins = "gpe0-0", "gpe0-1", "gpe0-2", "gpe0-3",
"gpe0-4", "gpe0-5", "gpe0-6", "gpe0-7",
"gpe1-0", "gpe1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
cam_gpio_b: cam-gpio-b {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3",
"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
cam_i2c1_bus: cam-i2c1-bus {
samsung,pins = "gpf0-2", "gpf0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
cam_i2c0_bus: cam-i2c0-bus {
samsung,pins = "gpf0-0", "gpf0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
cam_spi0_bus: cam-spi0-bus {
samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
cam_spi1_bus: cam-spi1-bus {
samsung,pins = "gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
};
@@ -444,114 +442,114 @@
sd0_clk: sd0-clk {
samsung,pins = "gpc0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpc0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpc0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpc0-3", "gpc0-4", "gpc0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpc3-0", "gpc3-1", "gpc3-2", "gpc3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd0_rdqs: sd0-rdqs {
samsung,pins = "gpc0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpc1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpc1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpc1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpc1-3", "gpc1-4", "gpc1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd1_bus8: sd1-bus-width8 {
samsung,pins = "gpc4-0", "gpc4-1", "gpc4-2", "gpc4-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpc2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpc2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpc2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpc2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpc2-4", "gpc2-5", "gpc2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV6>;
};
};
diff --git a/arch/arm/boot/dts/exynos5260-xyref5260.dts b/arch/arm/boot/dts/exynos5260-xyref5260.dts
index 3daef94bee38..d0cc300cfb4b 100644
--- a/arch/arm/boot/dts/exynos5260-xyref5260.dts
+++ b/arch/arm/boot/dts/exynos5260-xyref5260.dts
@@ -16,7 +16,8 @@
model = "SAMSUNG XYREF5260 board based on EXYNOS5260";
compatible = "samsung,xyref5260", "samsung,exynos5260", "samsung,exynos5";
- memory {
+ memory@20000000 {
+ device_type = "memory";
reg = <0x20000000 0x80000000>;
};
@@ -42,9 +43,9 @@
&pinctrl_0 {
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS5260_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi
index 36da38e29000..a86a4898d077 100644
--- a/arch/arm/boot/dts/exynos5260.dtsi
+++ b/arch/arm/boot/dts/exynos5260.dtsi
@@ -9,13 +9,13 @@
* published by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
-
#include <dt-bindings/clock/exynos5260-clk.h>
/ {
compatible = "samsung,exynos5260", "samsung,exynos5";
interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
pinctrl0 = &pinctrl_0;
diff --git a/arch/arm/boot/dts/exynos5410-odroidxu.dts b/arch/arm/boot/dts/exynos5410-odroidxu.dts
index f6d135245a4b..3c271cb4b2be 100644
--- a/arch/arm/boot/dts/exynos5410-odroidxu.dts
+++ b/arch/arm/boot/dts/exynos5410-odroidxu.dts
@@ -21,12 +21,13 @@
model = "Hardkernel Odroid XU";
compatible = "hardkernel,odroid-xu", "samsung,exynos5410", "samsung,exynos5";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x7ea00000>;
};
chosen {
- linux,stdout-path = &serial_2;
+ stdout-path = "serial2:115200n8";
};
emmc_pwrseq: pwrseq {
@@ -473,38 +474,38 @@
&pinctrl_0 {
emmc_nrst_pin: emmc-nrst {
samsung,pins = "gpd1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_3: pmic-dvs-3 {
samsung,pins = "gpx0-0";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_2: pmic-dvs-2 {
samsung,pins = "gpx0-1";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_1: pmic-dvs-1 {
samsung,pins = "gpx0-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
samsung,pin-val = <1>;
};
max77802_irq: max77802-irq {
samsung,pins = "gpx0-4";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5410-pinctrl.dtsi b/arch/arm/boot/dts/exynos5410-pinctrl.dtsi
index b58a0f29f42c..a083d23fdee3 100644
--- a/arch/arm/boot/dts/exynos5410-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos5410-pinctrl.dtsi
@@ -9,6 +9,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
&pinctrl_0 {
gpa0: gpa0 {
gpio-controller;
@@ -280,212 +282,212 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c4_hs_bus: i2c4-hs-bus {
samsung,pins = "gpa2-0", "gpa2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c5_hs_bus: i2c5-hs-bus {
samsung,pins = "gpa2-2", "gpa2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c6_hs_bus: i2c6-hs-bus {
samsung,pins = "gpb1-3", "gpb1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpb2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpb2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpb2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpb2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c7_hs_bus: i2c7-hs-bus {
samsung,pins = "gpb2-2", "gpb2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpb3-0", "gpb3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpb3-2", "gpb3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
sd0_clk: sd0-clk {
samsung,pins = "gpc0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpc0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpc0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpc0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpc0-4", "gpc0-5", "gpc0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpc2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpc2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpc2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpc2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpc2-4", "gpc2-5", "gpc2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpc3-0", "gpc3-1", "gpc3-2", "gpc3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
};
diff --git a/arch/arm/boot/dts/exynos5410-smdk5410.dts b/arch/arm/boot/dts/exynos5410-smdk5410.dts
index 777fcf2edd79..6cc74d97daae 100644
--- a/arch/arm/boot/dts/exynos5410-smdk5410.dts
+++ b/arch/arm/boot/dts/exynos5410-smdk5410.dts
@@ -16,7 +16,8 @@
model = "Samsung SMDK5410 board based on EXYNOS5410";
compatible = "samsung,smdk5410", "samsung,exynos5410", "samsung,exynos5";
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x80000000>;
};
@@ -66,8 +67,8 @@
srom_ctl: srom-ctl {
samsung,pins = "gpy0-3", "gpy0-4", "gpy0-5",
"gpy1-0", "gpy1-1", "gpy1-2", "gpy1-3";
- samsung,pin-function = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
srom_ebi: srom-ebi {
@@ -77,9 +78,9 @@
"gpy5-4", "gpy5-5", "gpy5-6", "gpy5-7",
"gpy6-0", "gpy6-1", "gpy6-2", "gpy6-3",
"gpy6-4", "gpy6-5", "gpy6-6", "gpy6-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
index 39a3b81478fd..9cc83c51c925 100644
--- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -22,7 +22,8 @@
model = "Insignal Arndale Octa evaluation board based on EXYNOS5420";
compatible = "insignal,arndale-octa", "samsung,exynos5420", "samsung,exynos5";
- memory {
+ memory@20000000 {
+ device_type = "memory";
reg = <0x20000000 0x80000000>;
};
@@ -70,6 +71,15 @@
status = "disabled";
};
+&hdmi {
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ vdd_osc-supply = <&ldo7_reg>;
+ vdd_pll-supply = <&ldo6_reg>;
+ vdd-supply = <&ldo6_reg>;
+ ddc = <&i2c_2>;
+ status = "okay";
+};
+
&hsi2c_4 {
status = "okay";
@@ -347,6 +357,10 @@
};
};
+&i2c_2 {
+ status = "okay";
+};
+
&mmc_0 {
status = "okay";
broken-cd;
@@ -378,9 +392,9 @@
&pinctrl_0 {
s2mps11_irq: s2mps11-irq {
samsung,pins = "gpx3-2";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index fe4e0915c0c6..ec4a00f1ce01 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -79,7 +79,8 @@
};
};
- memory {
+ memory@20000000 {
+ device_type = "memory";
reg = <0x20000000 0x80000000>;
};
@@ -179,7 +180,7 @@
&hdmi {
status = "okay";
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
ddc = <&i2c_2>;
@@ -753,171 +754,171 @@
wifi_en: wifi-en {
samsung,pins = "gpx0-0";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
max98090_irq: max98090-irq {
samsung,pins = "gpx0-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
/* We need GPX0_6 to be low at sleep time; just keep it low always */
mask_tpm_reset: mask-tpm-reset {
samsung,pins = "gpx0-6";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
samsung,pin-val = <0>;
};
tpm_irq: tpm-irq {
samsung,pins = "gpx1-0";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
trackpad_irq: trackpad-irq {
samsung,pins = "gpx1-1";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
power_key_irq: power-key-irq {
samsung,pins = "gpx1-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
ec_irq: ec-irq {
samsung,pins = "gpx1-5";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
tps65090_irq: tps65090-irq {
samsung,pins = "gpx2-5";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
dp_hpd_gpio: dp_hpd_gpio {
samsung,pins = "gpx2-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
max77802_irq: max77802-irq {
samsung,pins = "gpx3-1";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
lid_irq: lid-irq {
samsung,pins = "gpx3-4";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_1: pmic-dvs-1 {
samsung,pins = "gpy7-6";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
&pinctrl_1 {
/* Adjust WiFi drive strengths lower for EMI */
sd1_clk: sd1-clk {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_cmd: sd1-cmd {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_bus1: sd1-bus-width1 {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_bus4: sd1-bus-width4 {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_bus8: sd1-bus-width8 {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
};
&pinctrl_2 {
pmic_dvs_2: pmic-dvs-2 {
samsung,pins = "gpj4-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_3: pmic-dvs-3 {
samsung,pins = "gpj4-3";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
&pinctrl_3 {
/* Drive SPI lines at x2 for better integrity */
spi2-bus {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
/* Drive SPI chip select at x2 for better integrity */
ec_spi_cs: ec-spi-cs {
samsung,pins = "gpb1-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
usb300_vbus_en: usb300-vbus-en {
samsung,pins = "gph0-0";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
usb301_vbus_en: usb301-vbus-en {
samsung,pins = "gph0-1";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_selb: pmic-selb {
samsung,pins = "gph0-2", "gph0-3", "gph0-4", "gph0-5",
"gph0-6";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
index 14beb7e07323..3924b4fafe72 100644
--- a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
@@ -12,6 +12,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
&pinctrl_0 {
gpy7: gpy7 {
gpio-controller;
@@ -61,9 +63,9 @@
dp_hpd: dp_hpd {
samsung,pins = "gpx0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
@@ -153,135 +155,135 @@
sd0_clk: sd0-clk {
samsung,pins = "gpc0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpc0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpc0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpc0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpc0-4", "gpc0-5", "gpc0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpc3-0", "gpc3-1", "gpc3-2", "gpc3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd0_rclk: sd0-rclk {
samsung,pins = "gpc0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpc1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpc1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpc1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd1_int: sd1-int {
samsung,pins = "gpd1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpc1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpc1-4", "gpc1-5", "gpc1-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd1_bus8: sd1-bus-width8 {
samsung,pins = "gpd1-4", "gpd1-5", "gpd1-6", "gpd1-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpc2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpc2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpc2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpc2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpc2-4", "gpc2-5", "gpc2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV4>;
};
};
@@ -354,52 +356,52 @@
samsung,pins = "gpe0-0", "gpe0-1", "gpe0-2", "gpe0-3",
"gpe0-4", "gpe0-5", "gpe0-6", "gpe0-7",
"gpe1-0", "gpe1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_gpio_b: cam-gpio-b {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3",
"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_i2c2_bus: cam-i2c2-bus {
samsung,pins = "gpf0-4", "gpf0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_spi1_bus: cam-spi1-bus {
samsung,pins = "gpe0-4", "gpe0-5", "gpf0-2", "gpf0-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_i2c1_bus: cam-i2c1-bus {
samsung,pins = "gpf0-2", "gpf0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_i2c0_bus: cam-i2c0-bus {
samsung,pins = "gpf0-0", "gpf0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_spi0_bus: cam-spi0-bus {
samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
cam_bayrgb_bus: cam-bayrgb-bus {
@@ -408,9 +410,9 @@
"gpg1-0", "gpg1-1", "gpg1-2", "gpg1-3",
"gpg1-4", "gpg1-5", "gpg1-6", "gpg1-7",
"gpg2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
@@ -489,216 +491,216 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c3_bus: i2c3-bus {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-4", "gpa1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpa2-0", "gpa2-1", "gpa2-2", "gpa2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpa2-4", "gpa2-6", "gpa2-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c4_hs_bus: i2c4-hs-bus {
samsung,pins = "gpa2-0", "gpa2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c5_hs_bus: i2c5-hs-bus {
samsung,pins = "gpa2-2", "gpa2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
"gpb0-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpb1-0", "gpb1-1", "gpb1-2", "gpb1-3",
"gpb1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpb1-0", "gpb1-1", "gpb1-2", "gpb1-3",
"gpb1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
spdif_bus: spdif-bus {
samsung,pins = "gpb1-0", "gpb1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpb1-1", "gpb1-3", "gpb1-4";
- samsung,pin-function = <5>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c6_hs_bus: i2c6-hs-bus {
samsung,pins = "gpb1-3", "gpb1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpb2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpb2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpb2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpb2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c7_hs_bus: i2c7-hs-bus {
samsung,pins = "gpb2-2", "gpb2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpb3-0", "gpb3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpb3-2", "gpb3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c8_hs_bus: i2c8-hs-bus {
samsung,pins = "gpb3-4", "gpb3-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c9_hs_bus: i2c9-hs-bus {
samsung,pins = "gpb3-6", "gpb3-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
i2c10_hs_bus: i2c10-hs-bus {
samsung,pins = "gpb4-0", "gpb4-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
@@ -714,8 +716,8 @@
i2s0_bus: i2s0-bus {
samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
"gpz-4", "gpz-5", "gpz-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index ed8f3426911b..aaccd0da41e5 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -19,7 +19,8 @@
model = "Samsung SMDK5420 board based on EXYNOS5420";
compatible = "samsung,smdk5420", "samsung,exynos5420", "samsung,exynos5";
- memory {
+ memory@20000000 {
+ device_type = "memory";
reg = <0x20000000 0x80000000>;
};
@@ -130,7 +131,7 @@
&hdmi {
status = "okay";
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
};
@@ -386,25 +387,25 @@
&pinctrl_0 {
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
&pinctrl_2 {
usb300_vbus_en: usb300-vbus-en {
samsung,pins = "gpg0-5";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
usb301_vbus_en: usb301-vbus-en {
samsung,pins = "gpg1-4";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
index d56253049ccb..246d298557f5 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
@@ -21,12 +21,13 @@
#include "exynos-mfc-reserved-memory.dtsi"
/ {
- memory {
+ memory@40000000 {
+ device_type = "memory";
reg = <0x40000000 0x7EA00000>;
};
chosen {
- linux,stdout-path = &serial_2;
+ stdout-path = "serial2:115200n8";
};
firmware@02073000 {
@@ -250,7 +251,7 @@
&hdmi {
status = "okay";
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
@@ -548,25 +549,25 @@
&pinctrl_0 {
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
s2mps11_irq: s2mps11-irq {
samsung,pins = "gpx0-4";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
&pinctrl_1 {
emmc_nrst_pin: emmc-nrst {
samsung,pins = "gpd1-0";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5440-sd5v1.dts b/arch/arm/boot/dts/exynos5440-sd5v1.dts
index a98501bab6fc..ad6f533b3f40 100644
--- a/arch/arm/boot/dts/exynos5440-sd5v1.dts
+++ b/arch/arm/boot/dts/exynos5440-sd5v1.dts
@@ -20,6 +20,12 @@
bootargs = "root=/dev/sda2 rw rootwait ignore_loglevel earlyprintk no_console_suspend mem=2048M@0x80000000 mem=6144M@0x100000000 console=ttySAC0,115200";
};
+ /* FIXME: set reg property with correct start address and size */
+ memory@0 {
+ device_type = "memory";
+ reg = <0 0>;
+ };
+
fixed-rate-clocks {
xtal {
compatible = "samsung,clock-xtal";
diff --git a/arch/arm/boot/dts/exynos5440-ssdk5440.dts b/arch/arm/boot/dts/exynos5440-ssdk5440.dts
index 6a0d802e87c8..92bd2c6f7631 100644
--- a/arch/arm/boot/dts/exynos5440-ssdk5440.dts
+++ b/arch/arm/boot/dts/exynos5440-ssdk5440.dts
@@ -21,6 +21,12 @@
bootargs = "root=/dev/sda2 rw rootwait ignore_loglevel earlyprintk no_console_suspend mem=2048M@0x80000000 mem=6144M@0x100000000 console=ttySAC0,115200";
};
+ /* FIXME: set reg property with correct start address and size */
+ memory@0 {
+ device_type = "memory";
+ reg = <0 0>;
+ };
+
fixed-rate-clocks {
xtal {
compatible = "samsung,clock-xtal";
diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
index fd176819b4bf..e6bffd13cedd 100644
--- a/arch/arm/boot/dts/exynos5440.dtsi
+++ b/arch/arm/boot/dts/exynos5440.dtsi
@@ -10,12 +10,13 @@
*/
#include <dt-bindings/clock/exynos5440.h>
-#include "skeleton.dtsi"
/ {
compatible = "samsung,exynos5440", "samsung,exynos5";
interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
serial0 = &serial_0;
diff --git a/arch/arm/boot/dts/exynos54xx.dtsi b/arch/arm/boot/dts/exynos54xx.dtsi
index 06a604911e87..9d31cdce1959 100644
--- a/arch/arm/boot/dts/exynos54xx.dtsi
+++ b/arch/arm/boot/dts/exynos54xx.dtsi
@@ -14,7 +14,6 @@
* published by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
#include "exynos5.dtsi"
/ {
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 5ec71e2400fd..01f466816fea 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -79,7 +79,8 @@
};
- memory {
+ memory@20000000 {
+ device_type = "memory";
reg = <0x20000000 0x80000000>;
};
@@ -179,7 +180,7 @@
&hdmi {
status = "okay";
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
ddc = <&i2c_2>;
@@ -722,171 +723,171 @@
wifi_en: wifi-en {
samsung,pins = "gpx0-0";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
max98091_irq: max98091-irq {
samsung,pins = "gpx0-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
/* We need GPX0_6 to be low at sleep time; just keep it low always */
mask_tpm_reset: mask-tpm-reset {
samsung,pins = "gpx0-6";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
samsung,pin-val = <0>;
};
tpm_irq: tpm-irq {
samsung,pins = "gpx1-0";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
trackpad_irq: trackpad-irq {
samsung,pins = "gpx1-1";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
power_key_irq: power-key-irq {
samsung,pins = "gpx1-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
ec_irq: ec-irq {
samsung,pins = "gpx1-5";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
tps65090_irq: tps65090-irq {
samsung,pins = "gpx2-5";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
dp_hpd_gpio: dp_hpd_gpio {
samsung,pins = "gpx2-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
max77802_irq: max77802-irq {
samsung,pins = "gpx3-1";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
lid_irq: lid-irq {
samsung,pins = "gpx3-4";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
hdmi_hpd_irq: hdmi-hpd-irq {
samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_1: pmic-dvs-1 {
samsung,pins = "gpy7-6";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
&pinctrl_1 {
/* Adjust WiFi drive strengths lower for EMI */
sd1_clk: sd1-clk {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_cmd: sd1-cmd {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_bus1: sd1-bus-width1 {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_bus4: sd1-bus-width4 {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
sd1_bus8: sd1-bus-width8 {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
};
&pinctrl_2 {
pmic_dvs_2: pmic-dvs-2 {
samsung,pins = "gpj4-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_dvs_3: pmic-dvs-3 {
samsung,pins = "gpj4-3";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
&pinctrl_3 {
/* Drive SPI lines at x2 for better integrity */
spi2-bus {
- samsung,pin-drv = <2>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
/* Drive SPI chip select at x2 for better integrity */
ec_spi_cs: ec-spi-cs {
samsung,pins = "gpb1-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV3>;
};
usb300_vbus_en: usb300-vbus-en {
samsung,pins = "gph0-0";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
usb301_vbus_en: usb301-vbus-en {
samsung,pins = "gph0-1";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
pmic_selb: pmic-selb {
samsung,pins = "gph0-2", "gph0-3", "gph0-4", "gph0-5",
"gph0-6";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi
index 490b7b44f1e7..f812d586c5ce 100644
--- a/arch/arm/boot/dts/imx35.dtsi
+++ b/arch/arm/boot/dts/imx35.dtsi
@@ -309,6 +309,13 @@
status = "disabled";
};
+ iim@53ff0000 {
+ compatible = "fsl,imx35-iim";
+ reg = <0x53ff0000 0x4000>;
+ interrupts = <19>;
+ clocks = <&clks 80>;
+ };
+
usbotg: usb@53ff4000 {
compatible = "fsl,imx35-usb", "fsl,imx27-usb";
reg = <0x53ff4000 0x0200>;
diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi
index e2457138311f..8fe8beeb68a4 100644
--- a/arch/arm/boot/dts/imx50.dtsi
+++ b/arch/arm/boot/dts/imx50.dtsi
@@ -227,6 +227,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 151 28>;
};
gpio2: gpio@53f88000 {
@@ -237,6 +238,10 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 75 8>, <&iomuxc 8 100 8>,
+ <&iomuxc 16 83 1>, <&iomuxc 17 85 1>,
+ <&iomuxc 18 87 1>, <&iomuxc 19 84 1>,
+ <&iomuxc 20 88 1>, <&iomuxc 21 86 1>;
};
gpio3: gpio@53f8c000 {
@@ -247,6 +252,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 108 32>;
};
gpio4: gpio@53f90000 {
@@ -257,6 +263,8 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 8 8>, <&iomuxc 8 45 12>,
+ <&iomuxc 20 140 11>;
};
wdog1: wdog@53f98000 {
@@ -346,6 +354,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 57 18>, <&iomuxc 18 89 11>;
};
gpio6: gpio@53fe0000 {
@@ -356,6 +365,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 27 18>, <&iomuxc 18 16 11>;
};
i2c3: i2c@53fec000 {
diff --git a/arch/arm/boot/dts/imx53-usbarmory.dts b/arch/arm/boot/dts/imx53-usbarmory.dts
new file mode 100644
index 000000000000..6782d7fc5961
--- /dev/null
+++ b/arch/arm/boot/dts/imx53-usbarmory.dts
@@ -0,0 +1,224 @@
+/*
+ * USB armory MkI device tree file
+ * https://inversepath.com/usbarmory
+ *
+ * Copyright (C) 2015, Inverse Path
+ * Andrej Rosano <andrej@inversepath.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "imx53.dtsi"
+
+/ {
+ model = "Inverse Path USB armory";
+ compatible = "inversepath,imx53-usbarmory", "fsl,imx53";
+};
+
+/ {
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory {
+ reg = <0x70000000 0x20000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_led>;
+
+ user {
+ label = "LED";
+ gpios = <&gpio4 27 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
+
+/*
+ * Not every i.MX53 P/N supports clock > 800MHz.
+ * As USB armory does not mount a specific P/N set a safe clock upper limit.
+ */
+&cpu0 {
+ operating-points = <
+ /* kHz */
+ 166666 850000
+ 400000 900000
+ 800000 1050000
+ >;
+};
+
+&esdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_esdhc1>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_esdhc1: esdhc1grp {
+ fsl,pins = <
+ MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5
+ MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5
+ MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5
+ MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5
+ MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5
+ MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5
+ >;
+ };
+
+ pinctrl_i2c1_pmic: i2c1grp {
+ fsl,pins = <
+ MX53_PAD_EIM_D21__I2C1_SCL 0x80
+ MX53_PAD_EIM_D28__I2C1_SDA 0x80
+ >;
+ };
+
+ pinctrl_led: ledgrp {
+ fsl,pins = <
+ MX53_PAD_DISP0_DAT6__GPIO4_27 0x1e4
+ >;
+ };
+
+ /*
+ * UART mode pin header configration
+ * 3 - GPIO5[26], pull-down 100K
+ * 4 - GPIO5[27], pull-down 100K
+ * 5 - TX, pull-up 100K
+ * 6 - RX, pull-up 100K
+ * 7 - GPIO5[30], pull-down 100K
+ */
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX53_PAD_CSI0_DAT8__GPIO5_26 0xc0
+ MX53_PAD_CSI0_DAT9__GPIO5_27 0xc0
+ MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4
+ MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4
+ MX53_PAD_CSI0_DAT12__GPIO5_30 0xc0
+ >;
+ };
+};
+
+&i2c1 {
+ pinctrl-0 = <&pinctrl_i2c1_pmic>;
+ status = "okay";
+
+ ltc3589: pmic@34 {
+ compatible = "lltc,ltc3589-2";
+ reg = <0x34>;
+
+ regulators {
+ sw1_reg: sw1 {
+ regulator-min-microvolt = <591930>;
+ regulator-max-microvolt = <1224671>;
+ lltc,fb-voltage-divider = <100000 158000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <704123>;
+ regulator-max-microvolt = <1456803>;
+ lltc,fb-voltage-divider = <180000 191000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3_reg: sw3 {
+ regulator-min-microvolt = <1341250>;
+ regulator-max-microvolt = <2775000>;
+ lltc,fb-voltage-divider = <270000 100000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ bb_out_reg: bb-out {
+ regulator-min-microvolt = <3387341>;
+ regulator-max-microvolt = <3387341>;
+ lltc,fb-voltage-divider = <511000 158000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: ldo1 {
+ regulator-min-microvolt = <1306329>;
+ regulator-max-microvolt = <1306329>;
+ lltc,fb-voltage-divider = <100000 158000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2_reg: ldo2 {
+ regulator-min-microvolt = <704123>;
+ regulator-max-microvolt = <1456806>;
+ lltc,fb-voltage-divider = <180000 191000>;
+ regulator-ramp-delay = <7000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo3_reg: ldo3 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-boot-on;
+ };
+
+ ldo4_reg: ldo4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3200000>;
+ };
+ };
+ };
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&usbotg {
+ dr_mode = "peripheral";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index cd170376eaca..0777b41cdfe8 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -136,6 +136,14 @@
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+ ipu_csi0: port@0 {
+ reg = <0>;
+ };
+
+ ipu_csi1: port@1 {
+ reg = <1>;
+ };
+
ipu_di0: port@2 {
#address-cells = <1>;
#size-cells = <0>;
@@ -217,6 +225,8 @@
clocks = <&clks IMX5_CLK_UART3_IPG_GATE>,
<&clks IMX5_CLK_UART3_PER_GATE>;
clock-names = "ipg", "per";
+ dmas = <&sdma 42 4 0>, <&sdma 43 4 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -498,6 +508,8 @@
clocks = <&clks IMX5_CLK_UART1_IPG_GATE>,
<&clks IMX5_CLK_UART1_PER_GATE>;
clock-names = "ipg", "per";
+ dmas = <&sdma 18 4 0>, <&sdma 19 4 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -508,6 +520,8 @@
clocks = <&clks IMX5_CLK_UART2_IPG_GATE>,
<&clks IMX5_CLK_UART2_PER_GATE>;
clock-names = "ipg", "per";
+ dmas = <&sdma 12 4 0>, <&sdma 13 4 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -591,6 +605,8 @@
clocks = <&clks IMX5_CLK_UART4_IPG_GATE>,
<&clks IMX5_CLK_UART4_PER_GATE>;
clock-names = "ipg", "per";
+ dmas = <&sdma 2 4 0>, <&sdma 3 4 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
};
@@ -621,6 +637,8 @@
clocks = <&clks IMX5_CLK_UART5_IPG_GATE>,
<&clks IMX5_CLK_UART5_PER_GATE>;
clock-names = "ipg", "per";
+ dmas = <&sdma 16 4 0>, <&sdma 17 4 0>;
+ dma-names = "rx", "tx";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx6dl-gw553x.dts b/arch/arm/boot/dts/imx6dl-gw553x.dts
new file mode 100644
index 000000000000..59b8afc36e66
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-gw553x.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 Gateworks Corporation
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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 file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "imx6dl.dtsi"
+#include "imx6qdl-gw553x.dtsi"
+
+/ {
+ model = "Gateworks Ventana i.MX6 DualLite/Solo GW553X";
+ compatible = "gw,imx6dl-gw553x", "gw,ventana", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl-riotboard.dts b/arch/arm/boot/dts/imx6dl-riotboard.dts
index 2becd7cd6544..75d73437adf7 100644
--- a/arch/arm/boot/dts/imx6dl-riotboard.dts
+++ b/arch/arm/boot/dts/imx6dl-riotboard.dts
@@ -376,18 +376,18 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */
- MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 /* AR8035 pin strapping: IO voltage: pull up */
- MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x130b0 /* AR8035 pin strapping: PHYADDR#0: pull down */
- MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x130b0 /* AR8035 pin strapping: PHYADDR#1: pull down */
- MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 /* AR8035 pin strapping: MODE#1: pull up */
- MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 /* AR8035 pin strapping: MODE#3: pull up */
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 /* AR8035 pin strapping: IO voltage: pull up */
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 /* AR8035 pin strapping: PHYADDR#0: pull down */
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 /* AR8035 pin strapping: PHYADDR#1: pull down */
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 /* AR8035 pin strapping: MODE#1: pull up */
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 /* AR8035 pin strapping: MODE#3: pull up */
MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0 /* AR8035 pin strapping: MODE#0: pull down */
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 /* GPIO16 -> AR8035 25MHz */
MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x130b0 /* RGMII_nRST */
diff --git a/arch/arm/boot/dts/imx6dl-ts4900.dts b/arch/arm/boot/dts/imx6dl-ts4900.dts
new file mode 100644
index 000000000000..85eddeb30e21
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-ts4900.dts
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Technologic Systems
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , 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.
+ */
+
+/dts-v1/;
+#include "imx6dl.dtsi"
+#include "imx6qdl-ts4900.dtsi"
+
+/ {
+ model = "Technologic Systems i.MX6 Solo/DualLite TS-4900 (Default Device Tree)";
+ compatible = "technologic,imx6dl-ts4900", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 9a4c22c2dade..1ade1951e620 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -111,6 +111,59 @@
};
};
+&gpio1 {
+ gpio-ranges = <&iomuxc 0 131 2>, <&iomuxc 2 137 8>, <&iomuxc 10 189 2>,
+ <&iomuxc 12 194 1>, <&iomuxc 13 193 1>, <&iomuxc 14 192 1>,
+ <&iomuxc 15 191 1>, <&iomuxc 16 185 2>, <&iomuxc 18 184 1>,
+ <&iomuxc 19 187 1>, <&iomuxc 20 183 1>, <&iomuxc 21 188 1>,
+ <&iomuxc 22 123 3>, <&iomuxc 25 121 1>, <&iomuxc 26 127 1>,
+ <&iomuxc 27 126 1>, <&iomuxc 28 128 1>, <&iomuxc 29 130 1>,
+ <&iomuxc 30 129 1>, <&iomuxc 31 122 1>;
+};
+
+&gpio2 {
+ gpio-ranges = <&iomuxc 0 161 8>, <&iomuxc 8 208 8>, <&iomuxc 16 74 1>,
+ <&iomuxc 17 73 1>, <&iomuxc 18 72 1>, <&iomuxc 19 71 1>,
+ <&iomuxc 20 70 1>, <&iomuxc 21 69 1>, <&iomuxc 22 68 1>,
+ <&iomuxc 23 79 2>, <&iomuxc 25 118 2>, <&iomuxc 27 117 1>,
+ <&iomuxc 28 113 4>;
+};
+
+&gpio3 {
+ gpio-ranges = <&iomuxc 0 97 2>, <&iomuxc 2 105 8>, <&iomuxc 10 99 6>,
+ <&iomuxc 16 81 16>;
+};
+
+&gpio4 {
+ gpio-ranges = <&iomuxc 5 136 1>, <&iomuxc 6 145 1>, <&iomuxc 7 150 1>,
+ <&iomuxc 8 146 1>, <&iomuxc 9 151 1>, <&iomuxc 10 147 1>,
+ <&iomuxc 11 151 1>, <&iomuxc 12 148 1>, <&iomuxc 13 153 1>,
+ <&iomuxc 14 149 1>, <&iomuxc 15 154 1>, <&iomuxc 16 39 7>,
+ <&iomuxc 23 56 1>, <&iomuxc 24 61 7>, <&iomuxc 31 46 1>;
+};
+
+&gpio5 {
+ gpio-ranges = <&iomuxc 0 120 1>, <&iomuxc 2 77 1>, <&iomuxc 4 76 1>,
+ <&iomuxc 5 47 9>, <&iomuxc 14 57 4>, <&iomuxc 18 37 1>,
+ <&iomuxc 19 36 1>, <&iomuxc 20 35 1>, <&iomuxc 21 38 1>,
+ <&iomuxc 22 29 6>, <&iomuxc 28 19 4>;
+};
+
+&gpio6 {
+ gpio-ranges = <&iomuxc 0 23 6>, <&iomuxc 6 75 1>, <&iomuxc 7 156 1>,
+ <&iomuxc 8 155 1>, <&iomuxc 9 170 1>, <&iomuxc 10 169 1>,
+ <&iomuxc 11 157 1>, <&iomuxc 14 158 3>, <&iomuxc 17 204 1>,
+ <&iomuxc 18 203 1>, <&iomuxc 19 182 1>, <&iomuxc 20 177 4>,
+ <&iomuxc 24 175 1>, <&iomuxc 25 171 1>, <&iomuxc 26 181 1>,
+ <&iomuxc 27 172 3>, <&iomuxc 30 176 1>, <&iomuxc 31 78 1>;
+};
+
+&gpio7 {
+ gpio-ranges = <&iomuxc 0 202 1>, <&iomuxc 1 201 1>, <&iomuxc 2 196 1>,
+ <&iomuxc 3 195 1>, <&iomuxc 4 197 4>, <&iomuxc 8 205 1>,
+ <&iomuxc 9 207 1>, <&iomuxc 10 206 1>, <&iomuxc 11 133 3>;
+};
+
&gpt {
compatible = "fsl,imx6dl-gpt";
};
diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts
index d8acf15611e4..4989d0bff10f 100644
--- a/arch/arm/boot/dts/imx6q-arm2.dts
+++ b/arch/arm/boot/dts/imx6q-arm2.dts
@@ -79,19 +79,19 @@
fsl,pins = <
MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0
MX6QDL_PAD_KEY_COL2__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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
>;
};
diff --git a/arch/arm/boot/dts/imx6q-b450v3.dts b/arch/arm/boot/dts/imx6q-b450v3.dts
index f0a2be5268e3..78bfc1a307d6 100644
--- a/arch/arm/boot/dts/imx6q-b450v3.dts
+++ b/arch/arm/boot/dts/imx6q-b450v3.dts
@@ -89,3 +89,19 @@
};
};
};
+
+&pca9539 {
+ P04 {
+ gpio-hog;
+ gpios = <4 0>;
+ output-low;
+ line-name = "PCA9539-P04";
+ };
+
+ P05 {
+ gpio-hog;
+ gpios = <5 0>;
+ output-low;
+ line-name = "PCA9539-P05";
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q-b650v3.dts b/arch/arm/boot/dts/imx6q-b650v3.dts
index 33cb71acadcc..d85388725426 100644
--- a/arch/arm/boot/dts/imx6q-b650v3.dts
+++ b/arch/arm/boot/dts/imx6q-b650v3.dts
@@ -89,3 +89,12 @@
};
};
};
+
+&pca9539 {
+ P05 {
+ gpio-hog;
+ gpios = <5 0>;
+ output-low;
+ line-name = "PCA9539-P05";
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q-ba16.dtsi b/arch/arm/boot/dts/imx6q-ba16.dtsi
index f2adc60723da..308e11cea1db 100644
--- a/arch/arm/boot/dts/imx6q-ba16.dtsi
+++ b/arch/arm/boot/dts/imx6q-ba16.dtsi
@@ -448,19 +448,19 @@
fsl,pins = <
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
- MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
- MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
- MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
- MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
- MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
- MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
- 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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
/* FEC Reset */
MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0
/* AR8033 Interrupt */
diff --git a/arch/arm/boot/dts/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/imx6q-bx50v3.dtsi
index cf3fd31e3406..e4a415fd899b 100644
--- a/arch/arm/boot/dts/imx6q-bx50v3.dtsi
+++ b/arch/arm/boot/dts/imx6q-bx50v3.dtsi
@@ -183,6 +183,76 @@
interrupt-controller;
interrupt-parent = <&gpio2>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ P06 {
+ gpio-hog;
+ gpios = <6 0>;
+ output-low;
+ line-name = "PCA9539-P06";
+ };
+
+ P07 {
+ gpio-hog;
+ gpios = <7 0>;
+ output-low;
+ line-name = "PCA9539-P07";
+ };
+
+ P10 {
+ gpio-hog;
+ gpios = <8 0>;
+ output-low;
+ line-name = "PCA9539-P10";
+ };
+
+ P11 {
+ gpio-hog;
+ gpios = <9 0>;
+ output-low;
+ line-name = "PCA9539-P11";
+ };
+
+ P12 {
+ gpio-hog;
+ gpios = <10 0>;
+ output-low;
+ line-name = "PCA9539-P12";
+ };
+
+ P13 {
+ gpio-hog;
+ gpios = <11 0>;
+ output-low;
+ line-name = "PCA9539-P13";
+ };
+
+ P14 {
+ gpio-hog;
+ gpios = <12 0>;
+ output-low;
+ line-name = "PCA9539-P14";
+ };
+
+ P15 {
+ gpio-hog;
+ gpios = <13 0>;
+ output-low;
+ line-name = "PCA9539-P15";
+ };
+
+ P16 {
+ gpio-hog;
+ gpios = <14 0>;
+ output-low;
+ line-name = "PCA9539-P16";
+ };
+
+ P17 {
+ gpio-hog;
+ gpios = <15 0>;
+ output-low;
+ line-name = "PCA9539-P17";
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6q-cm-fx6.dts b/arch/arm/boot/dts/imx6q-cm-fx6.dts
index b5de7e620905..59bc5a4dce17 100644
--- a/arch/arm/boot/dts/imx6q-cm-fx6.dts
+++ b/arch/arm/boot/dts/imx6q-cm-fx6.dts
@@ -168,18 +168,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
index 905907325f3b..908dab68bdca 100644
--- a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
+++ b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
@@ -324,18 +324,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
index 4fa56019225e..6de21ff47c3a 100644
--- a/arch/arm/boot/dts/imx6q-evi.dts
+++ b/arch/arm/boot/dts/imx6q-evi.dts
@@ -139,6 +139,9 @@
pinctrl-0 = <&pinctrl_enet>;
phy-mode = "rgmii";
phy-reset-gpios = <&gpio1 25 0>;
+ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
+ fsl,err006687-workaround-present;
status = "okay";
};
@@ -303,21 +306,22 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x4001b0a8
MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0
+ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
>;
};
diff --git a/arch/arm/boot/dts/imx6q-gw5400-a.dts b/arch/arm/boot/dts/imx6q-gw5400-a.dts
index 0511137d1e23..747bc104ad00 100644
--- a/arch/arm/boot/dts/imx6q-gw5400-a.dts
+++ b/arch/arm/boot/dts/imx6q-gw5400-a.dts
@@ -421,18 +421,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6q-gw553x.dts b/arch/arm/boot/dts/imx6q-gw553x.dts
new file mode 100644
index 000000000000..e9c224cea752
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-gw553x.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 Gateworks Corporation
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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 file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include "imx6qdl-gw553x.dtsi"
+
+/ {
+ model = "Gateworks Ventana i.MX6 Dual/Quad GW553X";
+ compatible = "gw,imx6q-gw553x", "gw,ventana", "fsl,imx6q";
+};
diff --git a/arch/arm/boot/dts/imx6q-marsboard.dts b/arch/arm/boot/dts/imx6q-marsboard.dts
index 3f8013c85fb9..f7995c513b67 100644
--- a/arch/arm/boot/dts/imx6q-marsboard.dts
+++ b/arch/arm/boot/dts/imx6q-marsboard.dts
@@ -252,26 +252,26 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
/* AR8035 CLK_25M --> ENET_REF_CLK (V22) */
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1
/* AR8035 pin strapping: IO voltage: pull up */
- MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030
/* AR8035 pin strapping: PHYADDR#0: pull down */
- MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x130b0
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030
/* AR8035 pin strapping: PHYADDR#1: pull down */
- MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x130b0
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030
/* AR8035 pin strapping: MODE#1: pull up */
- MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
/* AR8035 pin strapping: MODE#3: pull up */
- MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
/* AR8035 pin strapping: MODE#0: pull down */
- MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x13030
/* GPIO16 -> AR8035 25MHz */
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
/* RGMII_nRST */
diff --git a/arch/arm/boot/dts/imx6q-novena.dts b/arch/arm/boot/dts/imx6q-novena.dts
index 5acd0c63b33b..1723e89e3acc 100644
--- a/arch/arm/boot/dts/imx6q-novena.dts
+++ b/arch/arm/boot/dts/imx6q-novena.dts
@@ -549,12 +549,12 @@
MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b028
MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b028
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
/* Ethernet reset */
MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6q-sbc6x.dts b/arch/arm/boot/dts/imx6q-sbc6x.dts
index 86cf09364664..255733063ea4 100644
--- a/arch/arm/boot/dts/imx6q-sbc6x.dts
+++ b/arch/arm/boot/dts/imx6q-sbc6x.dts
@@ -31,19 +31,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
>;
};
diff --git a/arch/arm/boot/dts/imx6q-tbs2910.dts b/arch/arm/boot/dts/imx6q-tbs2910.dts
index d7c8ccb2da95..06f492e17ca7 100644
--- a/arch/arm/boot/dts/imx6q-tbs2910.dts
+++ b/arch/arm/boot/dts/imx6q-tbs2910.dts
@@ -284,19 +284,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b059
>;
diff --git a/arch/arm/boot/dts/imx6q-ts4900.dts b/arch/arm/boot/dts/imx6q-ts4900.dts
new file mode 100644
index 000000000000..9b81ebc8b0d4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-ts4900.dts
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Technologic Systems
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , 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.
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include "imx6qdl-ts4900.dtsi"
+
+/ {
+ model = "Technologic Systems i.MX6 Quad TS-4900 (Default Device Tree)";
+ compatible = "technologic,imx6q-ts4900", "fsl,imx6q";
+};
+
+&sata {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index c30c8368cae0..e9a5d0b8c7b0 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -209,6 +209,43 @@
};
};
+&gpio1 {
+ gpio-ranges = <&iomuxc 0 136 2>, <&iomuxc 2 141 1>, <&iomuxc 3 139 1>,
+ <&iomuxc 4 142 2>, <&iomuxc 6 140 1>, <&iomuxc 7 144 2>,
+ <&iomuxc 9 138 1>, <&iomuxc 10 213 3>, <&iomuxc 13 20 1>,
+ <&iomuxc 14 19 1>, <&iomuxc 15 21 1>, <&iomuxc 16 208 1>,
+ <&iomuxc 17 207 1>, <&iomuxc 18 210 3>, <&iomuxc 21 209 1>,
+ <&iomuxc 22 116 10>;
+};
+
+&gpio2 {
+ gpio-ranges = <&iomuxc 0 191 16>, <&iomuxc 16 55 14>, <&iomuxc 30 35 1>,
+ <&iomuxc 31 44 1>;
+};
+
+&gpio3 {
+ gpio-ranges = <&iomuxc 0 69 16>, <&iomuxc 16 36 8>, <&iomuxc 24 45 8>;
+};
+
+&gpio4 {
+ gpio-ranges = <&iomuxc 5 149 1>, <&iomuxc 6 126 10>, <&iomuxc 16 87 16>;
+};
+
+&gpio5 {
+ gpio-ranges = <&iomuxc 0 85 1>, <&iomuxc 2 34 1>, <&iomuxc 4 53 1>,
+ <&iomuxc 5 103 13>, <&iomuxc 18 150 14>;
+};
+
+&gpio6 {
+ gpio-ranges = <&iomuxc 0 164 6>, <&iomuxc 6 54 1>, <&iomuxc 7 181 5>,
+ <&iomuxc 14 186 3>, <&iomuxc 17 170 2>, <&iomuxc 19 22 12>,
+ <&iomuxc 31 86 1>;
+};
+
+&gpio7 {
+ gpio-ranges = <&iomuxc 0 172 9>, <&iomuxc 9 189 2>, <&iomuxc 11 146 3>;
+};
+
&hdmi {
compatible = "fsl,imx6q-hdmi";
diff --git a/arch/arm/boot/dts/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/imx6qdl-apalis.dtsi
index 315e033ff1d8..99e323b57261 100644
--- a/arch/arm/boot/dts/imx6qdl-apalis.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-apalis.dtsi
@@ -586,19 +586,19 @@
fsl,pins = <
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
- MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
- MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
- MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
- MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
- MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
- MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
- 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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
/* Ethernet PHY reset */
MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x000b0
/* Ethernet PHY interrupt */
diff --git a/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi b/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
index da1341d47b14..b2c083d57598 100644
--- a/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
@@ -67,18 +67,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
index 9d7ab6cdc9a6..afec2c7628ef 100644
--- a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
@@ -228,22 +228,28 @@
status = "okay";
};
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
&iomuxc {
imx6qdl-gw51xx {
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
@@ -364,5 +370,11 @@
MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 /* OTG_PWR_EN */
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
index 7191b84770b9..a7100f99123e 100644
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -315,6 +315,8 @@
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
+ uart-has-rtscts;
+ rts-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
status = "okay";
};
@@ -353,6 +355,12 @@
status = "okay";
};
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
&iomuxc {
imx6qdl-gw52xx {
pinctrl_audmux: audmuxgrp {
@@ -376,18 +384,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
@@ -487,6 +495,7 @@
fsl,pins = <
MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1
+ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x4001b0b1 /* TEN */
>;
};
@@ -549,5 +558,11 @@
MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x170f9
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
index 40d06b09deba..8953eba0573d 100644
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -312,6 +312,8 @@
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
+ uart-has-rtscts;
+ rts-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
status = "okay";
};
@@ -351,6 +353,12 @@
status = "okay";
};
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
&iomuxc {
imx6qdl-gw53xx {
pinctrl_audmux: audmuxgrp {
@@ -365,18 +373,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
@@ -476,6 +484,7 @@
fsl,pins = <
MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1
+ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x4001b0b1 /* TEN */
>;
};
@@ -539,5 +548,11 @@
MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x170f9
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index d6dbe2a88ee6..6ac41c7ed32e 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -414,6 +414,8 @@
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
+ uart-has-rtscts;
+ rts-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
status = "okay";
};
@@ -453,6 +455,17 @@
status = "okay";
};
+&wdog1 {
+ status = "disabled";
+};
+
+&wdog2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+ status = "okay";
+};
+
&iomuxc {
imx6qdl-gw54xx {
pinctrl_audmux: audmuxgrp {
@@ -467,18 +480,18 @@
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
@@ -592,6 +605,7 @@
fsl,pins = <
MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1
+ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x4001b0b1 /* TEN */
>;
};
@@ -654,5 +668,11 @@
MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x170f9
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT3__WDOG2_B 0x1b0b0
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
index 118bea524dab..4b9fef834822 100644
--- a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
@@ -239,6 +239,12 @@
status = "okay";
};
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
&iomuxc {
imx6qdl-gw51xx {
pinctrl_flexcan1: flexcan1grp {
@@ -333,5 +339,11 @@
MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
index f27f184558fb..805e23674a94 100644
--- a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
@@ -197,6 +197,12 @@
status = "okay";
};
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
&iomuxc {
imx6qdl-gw552x {
pinctrl_gpio_leds: gpioledsgrp {
@@ -286,5 +292,11 @@
MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0
+ >;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw553x.dtsi b/arch/arm/boot/dts/imx6qdl-gw553x.dtsi
new file mode 100644
index 000000000000..86cec0527f73
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-gw553x.dtsi
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2016 Gateworks Corporation
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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 file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ /* these are used by bootloader for disabling nodes */
+ aliases {
+ led0 = &led0;
+ led1 = &led1;
+ nand = &gpmi;
+ usb0 = &usbh1;
+ usb1 = &usbotg;
+ };
+
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ led0: user1 {
+ label = "user1";
+ gpios = <&gpio4 10 GPIO_ACTIVE_HIGH>; /* MX6_PANLEDG */
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+
+ led1: user2 {
+ label = "user2";
+ gpios = <&gpio4 11 GPIO_ACTIVE_HIGH>; /* MX6_PANLEDR */
+ default-state = "off";
+ };
+ };
+
+ memory {
+ reg = <0x10000000 0x20000000>;
+ };
+
+ pps {
+ compatible = "pps-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pps>;
+ gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P0V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_5p0v: regulator-5p0v {
+ compatible = "regulator-fixed";
+ regulator-name = "5P0V";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ reg_usb_otg_vbus: regulator-usb-otg-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ status = "okay";
+};
+
+&hdmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hdmi>;
+ ddc-i2c-bus = <&i2c3>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ gpio: pca9555@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ eeprom1: eeprom@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+
+ eeprom2: eeprom@51 {
+ compatible = "atmel,24c02";
+ reg = <0x51>;
+ pagesize = <16>;
+ };
+
+ eeprom3: eeprom@52 {
+ compatible = "atmel,24c02";
+ reg = <0x52>;
+ pagesize = <16>;
+ };
+
+ eeprom4: eeprom@53 {
+ compatible = "atmel,24c02";
+ reg = <0x53>;
+ pagesize = <16>;
+ };
+
+ rtc: ds1672@68 {
+ compatible = "dallas,ds1672";
+ reg = <0x68>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>; /* MX6_DIO1 */
+ status = "disabled";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>; /* MX6_DIO2 */
+ status = "disabled";
+};
+
+&pwm4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm4>; /* MX6_DIO3 */
+ status = "disabled";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&uart5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart5>;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+ cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&reg_3p3v>;
+ status = "okay";
+};
+
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
+&iomuxc {
+ 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_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
+ >;
+ };
+
+ pinctrl_hdmi: hdmigrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0
+ >;
+ };
+
+ 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
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0
+ MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x1b0b0
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x4001b0b0 /* PCIESKT_WDIS# */
+ >;
+ };
+
+ pinctrl_pps: ppsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm4: pwm4grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart5: uart5grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 /* OTG_PWR_EN */
+ >;
+ };
+
+ 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
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x17059 /* CD */
+ MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x17059
+ >;
+ };
+
+ pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x170b9 /* CD */
+ MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x170b9
+ >;
+ };
+
+ pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x170f9 /* CD */
+ MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x170f9
+ >;
+ };
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
index f8d945a56525..d5c3aa88adbe 100644
--- a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
@@ -254,19 +254,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0
>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
index cfd50ea1ed48..880bd782a5b7 100644
--- a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
@@ -361,12 +361,12 @@
MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
- 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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
/* Phy reset */
MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0
MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
index 9677bf323823..b0b3220a1fd9 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -484,19 +484,19 @@
fsl,pins = <
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
- MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
- MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
- MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
- MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
- MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
- MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
- 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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
/* Phy reset */
MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0
MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
index 97d9c333902b..db868bc42c0f 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
@@ -394,19 +394,19 @@
fsl,pins = <
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
- MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
- MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
- MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
- MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
- MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
- MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
- 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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
/* Phy reset */
MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x000b0
MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
index d6d98d426384..e0280cac2484 100644
--- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
@@ -231,19 +231,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0
>;
};
@@ -379,6 +379,18 @@
status = "disabled";
};
+&reg_arm {
+ vin-supply = <&vddcore_reg>;
+};
+
+&reg_pu {
+ vin-supply = <&vddsoc_reg>;
+};
+
+&reg_soc {
+ vin-supply = <&vddsoc_reg>;
+};
+
&uart3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart3>;
diff --git a/arch/arm/boot/dts/imx6qdl-rex.dtsi b/arch/arm/boot/dts/imx6qdl-rex.dtsi
index cacf5933707d..17704a5c1bcb 100644
--- a/arch/arm/boot/dts/imx6qdl-rex.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-rex.dtsi
@@ -196,19 +196,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
/* Phy reset */
MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x000b0
diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 6aa193fb283f..e000e6f12bf5 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -345,19 +345,19 @@
fsl,pins = <
MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0
MX6QDL_PAD_KEY_COL2__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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index f65fdfc2536d..81dd6cd1937d 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -359,19 +359,19 @@
fsl,pins = <
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
- MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
- MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
- MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
- MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
- MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
- MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
- 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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
/* Phy reset */
MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0
MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index d77ea9423bbc..8e9e0d98db2f 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -380,19 +380,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-ts4900.dtsi b/arch/arm/boot/dts/imx6qdl-ts4900.dtsi
new file mode 100644
index 000000000000..5c26b26e851a
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-ts4900.dtsi
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2015 Technologic Systems
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ aliases {
+ ethernet0 = &fec;
+ };
+
+ leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_leds1>;
+ compatible = "gpio-leds";
+
+ green-led {
+ label = "green-led";
+ gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ };
+
+ red-led {
+ label = "red-led";
+ gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3p3v";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_usb_otg_vbus: regulator-usb-otg-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
+};
+
+&ecspi1 {
+ fsl,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ n25q064: flash@0 {
+ compatible = "micron,n25q064", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ };
+};
+
+&ecspi2 {
+ fsl,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi2>;
+ status = "okay";
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+
+ isl12022: rtc@6f {
+ compatible = "isil,isl12022";
+ reg = <0x6f>;
+ };
+
+ gpio8: gpio@28 {
+ compatible = "technologic,ts4900-gpio";
+ reg = <0x28>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ ngpio = <32>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ pinctrl-1 = <&pinctrl_i2c2_gpio>;
+ scl-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hog>;
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x100b1 /* Onboard flash CS1# */
+ >;
+ };
+
+ pinctrl_ecspi2: ecspi2grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK 0x100b1
+ MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI 0x100b1
+ MX6QDL_PAD_CSI0_DAT10__ECSPI2_MISO 0x100b1
+ MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29 0x100b1 /* Offboard CS0# */
+ MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x100b1 /* FPGA CS1# */
+ MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x1b0b1 /* FPGA_RESET# */
+ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x1b0b1 /* FPGA_DONE */
+ MX6QDL_PAD_GPIO_3__XTALOSC_REF_CLK_24M 0x10 /* FPGA 24MHZ */
+ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b1 /* FPGA_IRQ */
+ >;
+ };
+
+ 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 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x4001b0a8
+ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b1
+ MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x1b0b1 /* ETH_PHY_RESET */
+ >;
+ };
+
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b1
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b1
+ >;
+ };
+
+ pinctrl_flexcan2: flexcan2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b1
+ MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_hog: hoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x1b0b1 /* OFF_BD_RESET# */
+ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x1b0b1 /* EN_USB_5V# */
+ MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x1b0b1 /* EN_LCD_3.3V */
+ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 /* Audio CLK */
+ MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b1 /* DIO_1 */
+ MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b1 /* DIO_2 */
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b1 /* DIO_3 */
+ MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x1b0b1 /* DIO_4 */
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b1 /* DIO_5 */
+ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b1 /* DIO_7 */
+ MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19 0x1b0b1 /* DIO_8 */
+ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x1b0b1 /* DIO_9 */
+ MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x1b0b1 /* DIO_0 */
+ MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x1b0b1 /* DIO_6 */
+ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x1b0b1 /* CPU_DIO_A */
+ MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b1 /* DIO_2 */
+ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x1b0b1 /* CPU_DIO_B */
+ MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b0b1 /* BUS_ALE# */
+ MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x1b0b1 /* DIO_15 */
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1b0b1 /* BUS_DIR */
+ MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x1b0b1 /* BUS_CS# */
+ MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x1b0b1 /* DIO_14 */
+ MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x1b0b1 /* DIO_16 */
+ MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x1b0b1 /* DIO_12 */
+ MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x1b0b1 /* DIO_18 */
+ MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x1b0b1 /* DIO_19 */
+ MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x1b0b1 /* DIO_20 */
+ MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x1b0b1 /* BUS_BHE# */
+ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x1b0b1 /* DIO_13 */
+ MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0x1b0b1 /* EIM_WAIT# */
+ MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x1b0b1 /* DIO_10 */
+ MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x1b0b1 /* MUX_AD_00 */
+ MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x1b0b1 /* MUX_AD_01 */
+ MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x1b0b1 /* MUX_AD_02 */
+ MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x1b0b1 /* MUX_AD_03 */
+ MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b0b1 /* MUX_AD_04 */
+ MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1 /* MUX_AD_05 */
+ MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x1b0b1 /* MUX_AD_06 */
+ MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x1b0b1 /* MUX_AD_07 */
+ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x1b0b1 /* MUX_AD_08 */
+ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x1b0b1 /* MUX_AD_09 */
+ MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x1b0b1 /* MUX_AD_10 */
+ MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x1b0b1 /* MUX_AD_11 */
+ MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x1b0b1 /* MUX_AD_12 */
+ MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x1b0b1 /* MUX_AD_13 */
+ MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x1b0b1 /* MUX_AD_14 */
+ MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x1b0b1 /* MUX_AD_15 */
+ MX6QDL_PAD_DI0_DISP_CLK__GPIO4_IO16 0x1b0b1 /* LCD_CLK */
+ MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x1b0b1 /* DE */
+ MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b1 /* Hsync */
+ MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b1 /* Vsync */
+ MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT1__GPIO4_IO22 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT2__GPIO4_IO23 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT7__GPIO4_IO28 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT8__GPIO4_IO29 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT10__GPIO4_IO31 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT12__GPIO5_IO06 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT14__GPIO5_IO08 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT15__GPIO5_IO09 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT16__GPIO5_IO10 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT17__GPIO5_IO11 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x1b0b1
+ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x1b0b1
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c1_gpio: i2c1gpiogrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x4001b8b1
+ >;
+ };
+
+ pinctrl_leds1: leds1grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b1 /* RED_LED# */
+ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x1b0b1 /* GREEN_LED# */
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_7__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_GPIO_8__UART2_RX_DATA 0x1b0b1
+ MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x1b0b1
+ MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart5: uart5grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
+ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
+ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x17059 /* WIFI IRQ */
+ >;
+ };
+
+ 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
+ MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x1b0b1 /* EN_SD_POWER# */
+ >;
+ };
+
+ 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
+ >;
+ };
+};
+
+&pcie {
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&uart5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart5>;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+/* SD */
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ vmmc-supply = <&reg_3p3v>;
+ bus-width = <4>;
+ fsl,wp-controller;
+ status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ vmmc-supply = <&reg_3p3v>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
index 3bee2f910067..c96c91d83678 100644
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
@@ -132,18 +132,18 @@
imx6q-udoo {
pinctrl_enet: enetgrp {
fsl,pins = <
- 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_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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
index 3ffe00c557f1..2b9c2be436f9 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
@@ -109,19 +109,19 @@
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_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
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_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
>;
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 542515089b1e..02378db3f5fc 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -375,6 +375,12 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 22 1>, <&iomuxc 1 20 2>,
+ <&iomuxc 3 23 1>, <&iomuxc 4 25 1>,
+ <&iomuxc 5 24 1>, <&iomuxc 6 19 1>,
+ <&iomuxc 7 36 2>, <&iomuxc 9 44 8>,
+ <&iomuxc 17 38 6>, <&iomuxc 23 68 4>,
+ <&iomuxc 27 64 4>, <&iomuxc 31 52 1>;
};
gpio2: gpio@020a0000 {
@@ -386,6 +392,13 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 53 3>, <&iomuxc 3 72 2>,
+ <&iomuxc 5 34 2>, <&iomuxc 7 57 4>,
+ <&iomuxc 11 56 1>, <&iomuxc 12 61 3>,
+ <&iomuxc 15 107 1>, <&iomuxc 16 132 2>,
+ <&iomuxc 18 135 1>, <&iomuxc 19 134 1>,
+ <&iomuxc 20 108 2>, <&iomuxc 22 120 1>,
+ <&iomuxc 23 125 7>, <&iomuxc 30 110 2>;
};
gpio3: gpio@020a4000 {
@@ -397,6 +410,14 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 112 8>, <&iomuxc 8 121 4>,
+ <&iomuxc 12 97 4>, <&iomuxc 16 166 3>,
+ <&iomuxc 19 85 2>, <&iomuxc 21 137 2>,
+ <&iomuxc 23 136 1>, <&iomuxc 24 91 1>,
+ <&iomuxc 25 99 1>, <&iomuxc 26 92 1>,
+ <&iomuxc 27 100 1>, <&iomuxc 28 93 1>,
+ <&iomuxc 29 101 1>, <&iomuxc 30 94 1>,
+ <&iomuxc 31 102 1>;
};
gpio4: gpio@020a8000 {
@@ -408,6 +429,21 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 95 1>, <&iomuxc 1 103 1>,
+ <&iomuxc 2 96 1>, <&iomuxc 3 104 1>,
+ <&iomuxc 4 97 1>, <&iomuxc 5 105 1>,
+ <&iomuxc 6 98 1>, <&iomuxc 7 106 1>,
+ <&iomuxc 8 28 1>, <&iomuxc 9 27 1>,
+ <&iomuxc 10 26 1>, <&iomuxc 11 29 1>,
+ <&iomuxc 12 32 1>, <&iomuxc 13 31 1>,
+ <&iomuxc 14 30 1>, <&iomuxc 15 33 1>,
+ <&iomuxc 16 84 1>, <&iomuxc 17 79 2>,
+ <&iomuxc 19 78 1>, <&iomuxc 20 76 1>,
+ <&iomuxc 21 81 2>, <&iomuxc 23 75 1>,
+ <&iomuxc 24 83 1>, <&iomuxc 25 74 1>,
+ <&iomuxc 26 77 1>, <&iomuxc 27 159 1>,
+ <&iomuxc 28 154 1>, <&iomuxc 29 157 1>,
+ <&iomuxc 30 152 1>, <&iomuxc 31 156 1>;
};
gpio5: gpio@020ac000 {
@@ -419,6 +455,17 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 158 1>, <&iomuxc 1 151 1>,
+ <&iomuxc 2 155 1>, <&iomuxc 3 153 1>,
+ <&iomuxc 4 150 1>, <&iomuxc 5 149 1>,
+ <&iomuxc 6 144 1>, <&iomuxc 7 147 1>,
+ <&iomuxc 8 142 1>, <&iomuxc 9 146 1>,
+ <&iomuxc 10 148 1>, <&iomuxc 11 141 1>,
+ <&iomuxc 12 145 1>, <&iomuxc 13 143 1>,
+ <&iomuxc 14 140 1>, <&iomuxc 15 139 1>,
+ <&iomuxc 16 164 2>, <&iomuxc 18 160 1>,
+ <&iomuxc 19 162 1>, <&iomuxc 20 163 1>,
+ <&iomuxc 21 161 1>;
};
kpp: kpp@020b8000 {
diff --git a/arch/arm/boot/dts/imx6sx-pinfunc.h b/arch/arm/boot/dts/imx6sx-pinfunc.h
index bb9c6b78cb97..42c4c800feea 100644
--- a/arch/arm/boot/dts/imx6sx-pinfunc.h
+++ b/arch/arm/boot/dts/imx6sx-pinfunc.h
@@ -308,6 +308,20 @@
#define MX6SX_PAD_ENET1_RX_CLK__VDEC_DEBUG_35 0x008C 0x03D4 0x0000 0x8 0x0
#define MX6SX_PAD_ENET1_RX_CLK__PCIE_CTRL_DEBUG_29 0x008C 0x03D4 0x0000 0x9 0x0
#define MX6SX_PAD_ENET1_TX_CLK__ENET1_TX_CLK 0x0090 0x03D8 0x0000 0x0 0x0
+/*
+ * SION bit is necessary for ENET1_REF_CLK1 (ENET2_REF_CLK2 untested) if it is
+ * used as clock output of IMX6SX_CLK_ENET_REF (ENET1_TX_CLK) to e.g. supply a
+ * PHY in RMII mode. This configuration is valid if:
+ * - bit 1 in field IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK is set
+ * - bit 1 in field IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK unset
+ * It seems to be a silicon bug that in this configuration ENET1_TX reference
+ * clock isn't provided automatically. According to i.MX6SX reference manual
+ * (IOMUXC_GPR_GPR1 field descriptions: ENET1_CLK_SEL, Rev. 0 from 2/2015) it
+ * should be the case.
+ * So this might have unwanted side effects for other hardware units that are
+ * also connected to that pin and using respective function as input (e.g.
+ * UART1's DTR handling on MX6SX_PAD_ENET1_TX_CLK__UART1_DTR_B).
+ */
#define MX6SX_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x0090 0x03D8 0x0760 0x1 0x1
#define MX6SX_PAD_ENET1_TX_CLK__AUDMUX_AUD4_RXD 0x0090 0x03D8 0x0644 0x2 0x1
#define MX6SX_PAD_ENET1_TX_CLK__UART1_DTR_B 0x0090 0x03D8 0x0000 0x3 0x0
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 2863c52be6f5..1a473e83efbf 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -159,6 +159,16 @@
arm,data-latency = <4 2 3>;
};
+ gpu: gpu@01800000 {
+ compatible = "vivante,gc";
+ reg = <0x01800000 0x4000>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6SX_CLK_GPU>,
+ <&clks IMX6SX_CLK_GPU>,
+ <&clks IMX6SX_CLK_GPU>;
+ clock-names = "bus", "core", "shader";
+ };
+
dma_apbh: dma-apbh@01804000 {
compatible = "fsl,imx6sx-dma-apbh", "fsl,imx28-dma-apbh";
reg = <0x01804000 0x2000>;
@@ -438,6 +448,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 5 26>;
};
gpio2: gpio@020a0000 {
@@ -449,6 +460,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 31 20>;
};
gpio3: gpio@020a4000 {
@@ -460,6 +472,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 51 29>;
};
gpio4: gpio@020a8000 {
@@ -471,6 +484,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 80 32>;
};
gpio5: gpio@020ac000 {
@@ -482,6 +496,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 112 24>;
};
gpio6: gpio@020b0000 {
@@ -493,6 +508,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 136 12>, <&iomuxc 12 158 11>;
};
gpio7: gpio@020b4000 {
@@ -504,6 +520,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 148 10>, <&iomuxc 10 169 2>;
};
kpp: kpp@020b8000 {
@@ -1273,4 +1290,9 @@
status = "disabled";
};
};
+
+ gpu-subsystem {
+ compatible = "fsl,imx-gpu-subsystem";
+ cores = <&gpu>;
+ };
};
diff --git a/arch/arm/boot/dts/imx6ul-geam-kit.dts b/arch/arm/boot/dts/imx6ul-geam-kit.dts
new file mode 100644
index 000000000000..4c4af76143e3
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-geam-kit.dts
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 Amarula Solutions B.V.
+ * Copyright (C) 2016 Engicam S.r.l.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , 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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx6ul-geam.dtsi"
+
+/ {
+ model = "Engicam GEAM6UL";
+ compatible = "engicam,imx6ul-geam", "fsl,imx6ul";
+};
+
+&can1 {
+ status = "okay";
+};
+
+&can2 {
+ status = "okay";
+};
+
+&lcdif {
+ display = <&display0>;
+ status = "okay";
+
+ display0: display {
+ bits-per-pixel = <16>;
+ bus-width = <18>;
+ status = "okay";
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: timing0 {
+ clock-frequency = <28000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hfront-porch = <30>;
+ hback-porch = <30>;
+ hsync-len = <64>;
+ vback-porch = <5>;
+ vfront-porch = <5>;
+ vsync-len = <20>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
+ };
+ };
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ status = "okay";
+};
+
+&tsc {
+ measure-delay-time = <0x1ffff>;
+ pre-charge-time = <0x1fff>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ul-geam.dtsi b/arch/arm/boot/dts/imx6ul-geam.dtsi
new file mode 100644
index 000000000000..64eb9ed59b9c
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-geam.dtsi
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2016 Amarula Solutions B.V.
+ * Copyright (C) 2016 Engicam S.r.l.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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 file is distributed in 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include "imx6ul.dtsi"
+
+/ {
+ memory {
+ reg = <0x80000000 0x08000000>;
+ };
+
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ reg_1p8v: regulator-1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "1P8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ xceiver-supply = <&reg_3p3v>;
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ xceiver-supply = <&reg_3p3v>;
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1>;
+ phy-mode = "rmii";
+ phy-handle = <&ethphy0>;
+ status = "okay";
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2>;
+ phy-mode = "rmii";
+ phy-handle = <&ethphy1>;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+ };
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ nand-on-flash-bbt;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock_frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&lcdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcdif_dat
+ &pinctrl_lcdif_ctrl>;
+ display = <&display0>;
+};
+
+&tsc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tsc>;
+ xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&usbotg1 {
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usbotg2 {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usdhc1 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+ bus-width = <4>;
+ cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_enet1: enet1grp {
+ fsl,pins = <
+ MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
+ >;
+ };
+
+ pinctrl_enet2: enet2grp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
+ MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
+ MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15 0x1b0b0 /* ENET_nRST */
+ MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
+ MX6UL_PAD_GPIO1_IO05__ENET2_REF_CLK2 0x4001b031
+ >;
+ };
+
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <
+ MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
+ MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
+ >;
+ };
+
+ pinctrl_flexcan2: flexcan2grp {
+ fsl,pins = <
+ MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020
+ MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020
+ >;
+ };
+
+ pinctrl_gpmi_nand: gpmi-nand {
+ fsl,pins = <
+ MX6UL_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1
+ MX6UL_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1
+ MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1
+ MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000
+ MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1
+ MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1
+ MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1
+ MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1
+ MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1
+ MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1
+ MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1
+ MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1
+ MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1
+ MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1
+ MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
+ MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
+ MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
+ >;
+ };
+
+ pinctrl_lcdif_ctrl: lcdifctrlgrp {
+ fsl,pins = <
+ MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79
+ MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79
+ MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79
+ MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79
+ >;
+ };
+
+ pinctrl_lcdif_dat: lcdifdatgrp {
+ fsl,pins = <
+ MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79
+ MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79
+ MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79
+ MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79
+ MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79
+ MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79
+ MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79
+ MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79
+ MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79
+ MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79
+ MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79
+ MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79
+ MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79
+ MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79
+ MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79
+ MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79
+ MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79
+ MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79
+ >;
+ };
+
+ pinctrl_tsc: tscgrp {
+ fsl,pin = <
+ MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
+ MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0
+ MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0
+ MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1
+ MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1
+ MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
+ >;
+ };
+
+ pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
+ >;
+ };
+
+ pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_VSYNC__USDHC2_CLK 0x17070
+ MX6UL_PAD_CSI_HSYNC__USDHC2_CMD 0x10070
+ MX6UL_PAD_CSI_DATA00__USDHC2_DATA0 0x17070
+ MX6UL_PAD_CSI_DATA01__USDHC2_DATA1 0x17070
+ MX6UL_PAD_CSI_DATA02__USDHC2_DATA2 0x17070
+ MX6UL_PAD_CSI_DATA03__USDHC2_DATA3 0x17070
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6ul-pico-hobbit.dts b/arch/arm/boot/dts/imx6ul-pico-hobbit.dts
index 86f68faded0e..827d9e8fc74e 100644
--- a/arch/arm/boot/dts/imx6ul-pico-hobbit.dts
+++ b/arch/arm/boot/dts/imx6ul-pico-hobbit.dts
@@ -100,6 +100,18 @@
gpio = <&gpio1 6 0>;
};
+ reg_brcm: regulator-brcm {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio4 8 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_brcm_reg>;
+ regulator-name = "brcm_reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <200000>;
+ };
+
sound {
compatible = "fsl,imx-audio-sgtl5000";
model = "imx6ul-sgtl5000";
@@ -325,12 +337,27 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc2>;
no-1-8-v;
+ non-removable;
keep-power-in-suspend;
wakeup-source;
+ vmmc-supply = <&reg_brcm>;
status = "okay";
};
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
&iomuxc {
+ pinctrl_brcm_reg: brcmreggrp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_DATA06__GPIO4_IO08 0x10b0 /* WL_REG_ON */
+ MX6UL_PAD_NAND_DATA04__GPIO4_IO06 0x10b0 /* WL_HOST_WAKE */
+ >;
+ };
+
pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_ENET1_TX_DATA1__ENET2_MDIO 0x1b0b0
@@ -513,4 +540,10 @@
MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
>;
};
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0
+ >;
+ };
};
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 33b95d78831a..c5c05fdccc78 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -411,6 +411,8 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 23 10>, <&iomuxc 10 17 6>,
+ <&iomuxc 16 33 16>;
};
gpio2: gpio@020a0000 {
@@ -422,6 +424,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 49 16>, <&iomuxc 16 111 6>;
};
gpio3: gpio@020a4000 {
@@ -433,6 +436,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 65 29>;
};
gpio4: gpio@020a8000 {
@@ -444,6 +448,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 94 17>, <&iomuxc 17 117 12>;
};
gpio5: gpio@020ac000 {
@@ -455,6 +460,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 7 10>, <&iomuxc 10 5 2>;
};
fec2: ethernet@020b4000 {
@@ -644,7 +650,8 @@
};
gpr: iomuxc-gpr@020e4000 {
- compatible = "fsl,imx6ul-iomuxc-gpr", "syscon";
+ compatible = "fsl,imx6ul-iomuxc-gpr",
+ "fsl,imx6q-iomuxc-gpr", "syscon";
reg = <0x020e4000 0x4000>;
};
diff --git a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
index 1545661df583..373ee19196a6 100644
--- a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
@@ -138,10 +138,6 @@
};
&usdhc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_cd_usdhc1>;
- no-1-8-v;
- cd-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
keep-power-in-suspend;
wakeup-source;
status = "okay";
diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi
index 0a9d3a822fc0..a9cc65725f19 100644
--- a/arch/arm/boot/dts/imx7-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri.dtsi
@@ -46,12 +46,18 @@
pwms = <&pwm1 0 5000000>;
};
- reg_3p3v: regulator-3p3v {
+ reg_module_3v3: regulator-module-3v3 {
compatible = "regulator-fixed";
- regulator-name = "3P3V";
+ regulator-name = "+V3.3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_module_3v3_avdd: regulator-module-3v3-avdd {
+ compatible = "regulator-fixed";
+ regulator-name = "+V3.3_AVDD_AUDIO";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- regulator-always-on;
};
reg_vref_1v8: regulator-vref-1v8 {
@@ -60,6 +66,22 @@
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "imx7-sgtl5000";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&dailink_master>;
+ simple-audio-card,frame-master = <&dailink_master>;
+ simple-audio-card,cpu {
+ sound-dai = <&sai1>;
+ };
+
+ dailink_master: simple-audio-card,codec {
+ sound-dai = <&codec>;
+ clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+ };
+ };
};
&adc1 {
@@ -97,6 +119,18 @@
pinctrl-0 = <&pinctrl_i2c1 &pinctrl_i2c1_int>;
status = "okay";
+ codec: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ #sound-dai-cells = <0>;
+ reg = <0x0a>;
+ clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai1_mclk>;
+ VDDA-supply = <&reg_module_3v3_avdd>;
+ VDDIO-supply = <&reg_module_3v3>;
+ VDDD-supply = <&reg_DCDC3>;
+ };
+
ad7879@2c {
compatible = "adi,ad7879-1";
reg = <0x2c>;
@@ -217,6 +251,12 @@
vin-supply = <&reg_DCDC3>;
};
+&sai1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai1>;
+ status = "okay";
+};
+
&snvs_pwrkey {
status = "disabled";
};
@@ -251,6 +291,14 @@
dr_mode = "host";
};
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_cd_usdhc1>;
+ no-1-8-v;
+ cd-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ disable-wp;
+};
+
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4>;
@@ -528,13 +576,18 @@
pinctrl_sai1: sai1-grp {
fsl,pins = <
- MX7D_PAD_SAI1_MCLK__SAI1_MCLK 0x1f
MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK 0x1f
MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC 0x1f
MX7D_PAD_ENET1_COL__SAI1_TX_DATA0 0x30
MX7D_PAD_ENET1_TX_CLK__SAI1_RX_DATA0 0x1f
>;
};
+
+ pinctrl_sai1_mclk: sai1grp_mclk {
+ fsl,pins = <
+ MX7D_PAD_SAI1_MCLK__SAI1_MCLK 0x1f
+ >;
+ };
};
&iomuxc_lpsr {
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index 51c13cbdffb7..f6dee41a05d9 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -45,30 +45,42 @@
/ {
cpus {
+ cpu0: cpu@0 {
+ operating-points = <
+ /* KHz uV */
+ 996000 1075000
+ 792000 975000
+ >;
+ clock-frequency = <996000000>;
+ };
+
cpu1: cpu@1 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <1>;
+ clock-frequency = <996000000>;
};
};
- etm@3007d000 {
- compatible = "arm,coresight-etm3x", "arm,primecell";
- reg = <0x3007d000 0x1000>;
+ soc {
+ etm@3007d000 {
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x3007d000 0x1000>;
- /*
- * System will hang if added nosmp in kernel command line
- * without arm,primecell-periphid because amba bus try to
- * read id and core1 power off at this time.
- */
- arm,primecell-periphid = <0xbb956>;
- cpu = <&cpu1>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
+ /*
+ * System will hang if added nosmp in kernel command line
+ * without arm,primecell-periphid because amba bus try to
+ * read id and core1 power off at this time.
+ */
+ arm,primecell-periphid = <0xbb956>;
+ cpu = <&cpu1>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- port {
- etm1_out_port: endpoint {
- remote-endpoint = <&ca_funnel_in_port1>;
+ port {
+ etm1_out_port: endpoint {
+ remote-endpoint = <&ca_funnel_in_port1>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-warp.dts
new file mode 100644
index 000000000000..0345267f3390
--- /dev/null
+++ b/arch/arm/boot/dts/imx7s-warp.dts
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2016 NXP Semiconductors.
+ * Author: Fabio Estevam <fabio.estevam@nxp.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "imx7s.dtsi"
+
+/ {
+ model = "Warp i.MX7 Board";
+ compatible = "warp,imx7s-warp", "fsl,imx7s";
+
+ memory {
+ reg = <0x80000000 0x20000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&pinctrl_gpio>;
+ autorepeat;
+
+ back {
+ label = "Back";
+ gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
+ linux,code = <KEY_BACK>;
+ wakeup-source;
+ };
+ };
+
+ reg_brcm: regulator-brcm {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_brcm_reg>;
+ regulator-name = "brcm_reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <200000>;
+ };
+
+ reg_bt: regulator-bt {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_bt_reg>;
+ enable-active-high;
+ gpio = <&gpio5 17 GPIO_ACTIVE_HIGH>;
+ regulator-name = "bt_reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "imx7-sgtl5000";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&dailink_master>;
+ simple-audio-card,frame-master = <&dailink_master>;
+ simple-audio-card,cpu {
+ sound-dai = <&sai1>;
+ };
+
+ dailink_master: simple-audio-card,codec {
+ sound-dai = <&codec>;
+ clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+ };
+ };
+};
+
+&clks {
+ assigned-clocks = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+ assigned-clock-rates = <884736000>;
+};
+
+&cpu0 {
+ arm-supply = <&sw1a_reg>;
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ pmic: pfuze3000@08 {
+ compatible = "fsl,pfuze3000";
+ reg = <0x08>;
+
+ regulators {
+ sw1a_reg: sw1a {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1475000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ /* use sw1c_reg to align with pfuze100/pfuze200 */
+ sw1c_reg: sw1b {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1475000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1850000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3a_reg: sw3 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1650000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ swbst_reg: swbst {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5150000>;
+ };
+
+ snvs_reg: vsnvs {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vref_reg: vrefddr {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vgen1_reg: vldo1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen2_reg: vldo2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen3_reg: vccsd {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen4_reg: v33 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen5_reg: vldo3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen6_reg: vldo4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c4 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ status = "okay";
+
+ codec: sgtl5000@0a {
+ #sound-dai-cells = <0>;
+ reg = <0x0a>;
+ compatible = "fsl,sgtl5000";
+ clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai1_mclk>;
+ VDDA-supply = <&vgen4_reg>;
+ VDDIO-supply = <&vgen4_reg>;
+ VDDD-supply = <&vgen2_reg>;
+ };
+
+ mpl3115@60 {
+ compatible = "fsl,mpl3115";
+ reg = <0x60>;
+ };
+};
+
+&sai1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai1>;
+ assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>,
+ <&clks IMX7D_SAI1_ROOT_CLK>;
+ assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+ assigned-clock-rates = <0>, <36864000>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>;
+ assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
+ assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
+&usbotg1 {
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ bus-width = <4>;
+ keep-power-in-suspend;
+ no-1-8-v;
+ non-removable;
+ vmmc-supply = <&reg_brcm>;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+ assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
+ assigned-clock-rates = <400000000>;
+ bus-width = <8>;
+ fsl,tuning-step = <2>;
+ non-removable;
+ status = "okay";
+};
+
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_brcm_reg: brcmreggrp {
+ fsl,pins = <
+ MX7D_PAD_SD2_WP__GPIO5_IO10 0x14 /* WL_REG_ON */
+ >;
+ };
+
+ pinctrl_bt_reg: btreggrp {
+ fsl,pins = <
+ MX7D_PAD_SD2_DATA3__GPIO5_IO17 0x14 /* BT_REG_ON */
+ >;
+ };
+
+ pinctrl_gpio: gpiogrp {
+ fsl,pins = <
+ MX7D_PAD_ENET1_RGMII_RD1__GPIO7_IO1 0x14
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f
+ MX7D_PAD_I2C1_SCL__I2C1_SCL 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX7D_PAD_I2C2_SDA__I2C2_SDA 0x4000007f
+ MX7D_PAD_I2C2_SCL__I2C2_SCL 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c4: i2c4grp {
+ fsl,pins = <
+ MX7D_PAD_I2C4_SCL__I2C4_SCL 0x4000007f
+ MX7D_PAD_I2C4_SDA__I2C4_SDA 0x4000007f
+ >;
+ };
+
+ pinctrl_sai1: sai1grp {
+ fsl,pins = <
+ MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0 0x1f
+ MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK 0x1f
+ MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC 0x1f
+ MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0 0x30
+ >;
+ };
+
+ pinctrl_sai1_mclk: sai1mclkgrp {
+ fsl,pins = <
+ MX7D_PAD_SAI1_MCLK__SAI1_MCLK 0x1f
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79
+ MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x79
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX 0x79
+ MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX 0x79
+ MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS 0x79
+ MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS 0x79
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX7D_PAD_SD1_CMD__SD1_CMD 0x59
+ MX7D_PAD_SD1_CLK__SD1_CLK 0x19
+ MX7D_PAD_SD1_DATA0__SD1_DATA0 0x59
+ MX7D_PAD_SD1_DATA1__SD1_DATA1 0x59
+ MX7D_PAD_SD1_DATA2__SD1_DATA2 0x59
+ MX7D_PAD_SD1_DATA3__SD1_DATA3 0x59
+ MX7D_PAD_SD2_RESET_B__GPIO5_IO11 0x14 /* WL_HOST_WAKE */
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX7D_PAD_SD3_CMD__SD3_CMD 0x59
+ MX7D_PAD_SD3_CLK__SD3_CLK 0x19
+ MX7D_PAD_SD3_DATA0__SD3_DATA0 0x59
+ MX7D_PAD_SD3_DATA1__SD3_DATA1 0x59
+ MX7D_PAD_SD3_DATA2__SD3_DATA2 0x59
+ MX7D_PAD_SD3_DATA3__SD3_DATA3 0x59
+ MX7D_PAD_SD3_DATA4__SD3_DATA4 0x59
+ MX7D_PAD_SD3_DATA5__SD3_DATA5 0x59
+ MX7D_PAD_SD3_DATA6__SD3_DATA6 0x59
+ MX7D_PAD_SD3_DATA7__SD3_DATA7 0x59
+ MX7D_PAD_SD3_RESET_B__SD3_RESET_B 0x19
+ >;
+ };
+
+ pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
+ fsl,pins = <
+ MX7D_PAD_SD3_CMD__SD3_CMD 0x5a
+ MX7D_PAD_SD3_CLK__SD3_CLK 0x1a
+ MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5a
+ MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5a
+ MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5a
+ MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5a
+ MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5a
+ MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5a
+ MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5a
+ MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5a
+ MX7D_PAD_SD3_RESET_B__SD3_RESET_B 0x1a
+ >;
+ };
+
+ pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
+ fsl,pins = <
+ MX7D_PAD_SD3_CMD__SD3_CMD 0x5b
+ MX7D_PAD_SD3_CLK__SD3_CLK 0x1b
+ MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5b
+ MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5b
+ MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5b
+ MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5b
+ MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5b
+ MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5b
+ MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5b
+ MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5b
+ MX7D_PAD_SD3_RESET_B__SD3_RESET_B 0x1b
+ >;
+ };
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX7D_PAD_GPIO1_IO00__WDOD1_WDOG_B 0x74
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 1e90bdbe3a6e..0d7d5ac6257b 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -85,26 +85,12 @@
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
- operating-points = <
- /* KHz uV */
- 996000 1075000
- 792000 975000
- >;
+ clock-frequency = <792000000>;
clock-latency = <61036>; /* two CLK32 periods */
clocks = <&clks IMX7D_CLK_ARM>;
};
};
- intc: interrupt-controller@31001000 {
- compatible = "arm,cortex-a7-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x31001000 0x1000>,
- <0x31002000 0x1000>,
- <0x31004000 0x2000>,
- <0x31006000 0x2000>;
- };
-
ckil: clock-cki {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -119,195 +105,205 @@
clock-output-names = "osc";
};
- timer {
- compatible = "arm,armv7-timer";
- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
interrupt-parent = <&intc>;
- };
+ ranges;
+
+ funnel@30041000 {
+ compatible = "arm,coresight-funnel", "arm,primecell";
+ reg = <0x30041000 0x1000>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- etr@30086000 {
- compatible = "arm,coresight-tmc", "arm,primecell";
- reg = <0x30086000 0x1000>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
+ ca_funnel_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- port {
- etr_in_port: endpoint {
- slave-mode;
- remote-endpoint = <&replicator_out_port1>;
+ /* funnel input ports */
+ port@0 {
+ reg = <0>;
+ ca_funnel_in_port0: endpoint {
+ slave-mode;
+ remote-endpoint = <&etm0_out_port>;
+ };
+ };
+
+ /* funnel output port */
+ port@2 {
+ reg = <0>;
+ ca_funnel_out_port0: endpoint {
+ remote-endpoint = <&hugo_funnel_in_port0>;
+ };
+ };
+
+ /* the other input ports are not connect to anything */
};
};
- };
- tpiu@30087000 {
- compatible = "arm,coresight-tpiu", "arm,primecell";
- reg = <0x30087000 0x1000>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
+ etm@3007c000 {
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x3007c000 0x1000>;
+ cpu = <&cpu0>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- port {
- tpiu_in_port: endpoint {
- slave-mode;
- remote-endpoint = <&replicator_out_port1>;
+ port {
+ etm0_out_port: endpoint {
+ remote-endpoint = <&ca_funnel_in_port0>;
+ };
};
};
- };
- replicator {
- /*
- * non-configurable replicators don't show up on the
- * AMBA bus. As such no need to add "arm,primecell"
- */
- compatible = "arm,coresight-replicator";
+ funnel@30083000 {
+ compatible = "arm,coresight-funnel", "arm,primecell";
+ reg = <0x30083000 0x1000>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- /* replicator output ports */
- port@0 {
- reg = <0>;
- replicator_out_port0: endpoint {
- remote-endpoint = <&tpiu_in_port>;
+ /* funnel input ports */
+ port@0 {
+ reg = <0>;
+ hugo_funnel_in_port0: endpoint {
+ slave-mode;
+ remote-endpoint = <&ca_funnel_out_port0>;
+ };
};
- };
- port@1 {
- reg = <1>;
- replicator_out_port1: endpoint {
- remote-endpoint = <&etr_in_port>;
+ port@1 {
+ reg = <1>;
+ hugo_funnel_in_port1: endpoint {
+ slave-mode; /* M4 input */
+ };
};
- };
- /* replicator input port */
- port@2 {
- reg = <0>;
- replicator_in_port0: endpoint {
- slave-mode;
- remote-endpoint = <&etf_out_port>;
+ port@2 {
+ reg = <0>;
+ hugo_funnel_out_port0: endpoint {
+ remote-endpoint = <&etf_in_port>;
+ };
};
+
+ /* the other input ports are not connect to anything */
};
};
- };
- etf@30084000 {
- compatible = "arm,coresight-tmc", "arm,primecell";
- reg = <0x30084000 0x1000>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
+ etf@30084000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0x30084000 0x1000>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- port@0 {
- reg = <0>;
- etf_in_port: endpoint {
- slave-mode;
- remote-endpoint = <&hugo_funnel_out_port0>;
+ port@0 {
+ reg = <0>;
+ etf_in_port: endpoint {
+ slave-mode;
+ remote-endpoint = <&hugo_funnel_out_port0>;
+ };
};
- };
- port@1 {
- reg = <0>;
- etf_out_port: endpoint {
- remote-endpoint = <&replicator_in_port0>;
+ port@1 {
+ reg = <0>;
+ etf_out_port: endpoint {
+ remote-endpoint = <&replicator_in_port0>;
+ };
};
};
};
- };
-
- funnel@30083000 {
- compatible = "arm,coresight-funnel", "arm,primecell";
- reg = <0x30083000 0x1000>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
+ etr@30086000 {
+ compatible = "arm,coresight-tmc", "arm,primecell";
+ reg = <0x30086000 0x1000>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- /* funnel input ports */
- port@0 {
- reg = <0>;
- hugo_funnel_in_port0: endpoint {
+ port {
+ etr_in_port: endpoint {
slave-mode;
- remote-endpoint = <&ca_funnel_out_port0>;
+ remote-endpoint = <&replicator_out_port1>;
};
};
+ };
- port@1 {
- reg = <1>;
- hugo_funnel_in_port1: endpoint {
- slave-mode; /* M4 input */
- };
- };
+ tpiu@30087000 {
+ compatible = "arm,coresight-tpiu", "arm,primecell";
+ reg = <0x30087000 0x1000>;
+ clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
+ clock-names = "apb_pclk";
- port@2 {
- reg = <0>;
- hugo_funnel_out_port0: endpoint {
- remote-endpoint = <&etf_in_port>;
+ port {
+ tpiu_in_port: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_port1>;
};
};
-
- /* the other input ports are not connect to anything */
};
- };
- funnel@30041000 {
- compatible = "arm,coresight-funnel", "arm,primecell";
- reg = <0x30041000 0x1000>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
+ replicator {
+ /*
+ * non-configurable replicators don't show up on the
+ * AMBA bus. As such no need to add "arm,primecell"
+ */
+ compatible = "arm,coresight-replicator";
- ca_funnel_ports: ports {
- #address-cells = <1>;
- #size-cells = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- /* funnel input ports */
- port@0 {
- reg = <0>;
- ca_funnel_in_port0: endpoint {
- slave-mode;
- remote-endpoint = <&etm0_out_port>;
+ /* replicator output ports */
+ port@0 {
+ reg = <0>;
+ replicator_out_port0: endpoint {
+ remote-endpoint = <&tpiu_in_port>;
+ };
};
- };
- /* funnel output port */
- port@2 {
- reg = <0>;
- ca_funnel_out_port0: endpoint {
- remote-endpoint = <&hugo_funnel_in_port0>;
+ port@1 {
+ reg = <1>;
+ replicator_out_port1: endpoint {
+ remote-endpoint = <&etr_in_port>;
+ };
};
- };
- /* the other input ports are not connect to anything */
+ /* replicator input port */
+ port@2 {
+ reg = <0>;
+ replicator_in_port0: endpoint {
+ slave-mode;
+ remote-endpoint = <&etf_out_port>;
+ };
+ };
+ };
};
- };
- etm@3007c000 {
- compatible = "arm,coresight-etm3x", "arm,primecell";
- reg = <0x3007c000 0x1000>;
- cpu = <&cpu0>;
- clocks = <&clks IMX7D_MAIN_AXI_ROOT_CLK>;
- clock-names = "apb_pclk";
-
- port {
- etm0_out_port: endpoint {
- remote-endpoint = <&ca_funnel_in_port0>;
- };
+ intc: interrupt-controller@31001000 {
+ compatible = "arm,cortex-a7-gic";
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x31001000 0x1000>,
+ <0x31002000 0x2000>,
+ <0x31004000 0x2000>,
+ <0x31006000 0x2000>;
};
- };
- soc {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "simple-bus";
- interrupt-parent = <&intc>;
- ranges;
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
aips1: aips-bus@30000000 {
compatible = "fsl,aips-bus", "simple-bus";
@@ -325,6 +321,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc_lpsr 0 0 8>, <&iomuxc 8 5 8>;
};
gpio2: gpio@30210000 {
@@ -336,6 +333,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 13 32>;
};
gpio3: gpio@30220000 {
@@ -347,6 +345,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 45 29>;
};
gpio4: gpio@30230000 {
@@ -358,6 +357,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 74 24>;
};
gpio5: gpio@30240000 {
@@ -369,6 +369,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 98 18>;
};
gpio6: gpio@30250000 {
@@ -380,6 +381,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 116 23>;
};
gpio7: gpio@30260000 {
@@ -391,6 +393,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 139 16>;
};
wdog1: wdog@30280000 {
@@ -723,6 +726,51 @@
status = "disabled";
};
+ sai1: sai@308a0000 {
+ #sound-dai-cells = <0>;
+ compatible = "fsl,imx7d-sai", "fsl,imx6sx-sai";
+ reg = <0x308a0000 0x10000>;
+ interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_SAI1_IPG_CLK>,
+ <&clks IMX7D_SAI1_ROOT_CLK>,
+ <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CLK_DUMMY>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
+ dma-names = "rx", "tx";
+ dmas = <&sdma 8 24 0>, <&sdma 9 24 0>;
+ status = "disabled";
+ };
+
+ sai2: sai@308b0000 {
+ #sound-dai-cells = <0>;
+ compatible = "fsl,imx7d-sai", "fsl,imx6sx-sai";
+ reg = <0x308b0000 0x10000>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_SAI2_IPG_CLK>,
+ <&clks IMX7D_SAI2_ROOT_CLK>,
+ <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CLK_DUMMY>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
+ dma-names = "rx", "tx";
+ dmas = <&sdma 10 24 0>, <&sdma 11 24 0>;
+ status = "disabled";
+ };
+
+ sai3: sai@308c0000 {
+ #sound-dai-cells = <0>;
+ compatible = "fsl,imx7d-sai", "fsl,imx6sx-sai";
+ reg = <0x308c0000 0x10000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_SAI3_IPG_CLK>,
+ <&clks IMX7D_SAI3_ROOT_CLK>,
+ <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CLK_DUMMY>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
+ dma-names = "rx", "tx";
+ dmas = <&sdma 12 24 0>, <&sdma 13 24 0>;
+ status = "disabled";
+ };
+
flexcan1: can@30a00000 {
compatible = "fsl,imx7d-flexcan", "fsl,imx6q-flexcan";
reg = <0x30a00000 0x10000>;
@@ -911,6 +959,17 @@
status = "disabled";
};
+ sdma: sdma@30bd0000 {
+ compatible = "fsl,imx7d-sdma", "fsl,imx35-sdma";
+ reg = <0x30bd0000 0x10000>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_SDMA_CORE_CLK>,
+ <&clks IMX7D_AHB_CHANNEL_ROOT_CLK>;
+ clock-names = "ipg", "ahb";
+ #dma-cells = <3>;
+ fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+ };
+
fec1: ethernet@30be0000 {
compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec";
reg = <0x30be0000 0x10000>;
diff --git a/arch/arm/boot/dts/integratorap.dts b/arch/arm/boot/dts/integratorap.dts
index 4b34b54e09a1..6f16d09dc5a4 100644
--- a/arch/arm/boot/dts/integratorap.dts
+++ b/arch/arm/boot/dts/integratorap.dts
@@ -19,7 +19,7 @@
bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk";
};
- /* 24 MHz chrystal on the core module */
+ /* 24 MHz chrystal on the Integrator/AP development board */
xtal24mhz: xtal24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -39,6 +39,34 @@
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <14745600>;
+ clocks = <&xtal24mhz>;
+ };
+
+ core-module@10000000 {
+ /* 24 MHz chrystal on the core module */
+ cm24mhz: cm24mhz@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ };
+
+ /* Oscillator on the core module, clocks the CPU core */
+ cmosc: cmosc@24M {
+ compatible = "arm,syscon-icst525-integratorap-cm";
+ #clock-cells = <0>;
+ lock-offset = <0x14>;
+ vco-offset = <0x08>;
+ clocks = <&cm24mhz>;
+ };
+
+ /* Auxilary oscillator on the core module, 32.369MHz at boot */
+ auxosc: auxosc@24M {
+ compatible = "arm,syscon-icst525";
+ #clock-cells = <0>;
+ lock-offset = <0x14>;
+ vco-offset = <0x1c>;
+ clocks = <&cm24mhz>;
+ };
};
syscon {
@@ -47,6 +75,27 @@
interrupt-parent = <&pic>;
/* These are the logical module IRQs */
interrupts = <9>, <10>, <11>, <12>;
+
+ /*
+ * SYSCLK clocks PCIv3 bridge, system controller and the
+ * logic modules.
+ */
+ sysclk: apsys@24M {
+ compatible = "arm,syscon-icst525-integratorap-sys";
+ #clock-cells = <0>;
+ lock-offset = <0x1c>;
+ vco-offset = <0x04>;
+ clocks = <&xtal24mhz>;
+ };
+
+ /* One-bit control for the PCI bus clock (33 or 25 MHz) */
+ pciclk: pciclk@24M {
+ compatible = "arm,syscon-icst525-integratorap-pci";
+ #clock-cells = <0>;
+ lock-offset = <0x1c>;
+ vco-offset = <0x04>;
+ clocks = <&xtal24mhz>;
+ };
};
timer0: timer@13000000 {
diff --git a/arch/arm/boot/dts/integratorcp.dts b/arch/arm/boot/dts/integratorcp.dts
index 79430fbfec3b..1b5e4b006b72 100644
--- a/arch/arm/boot/dts/integratorcp.dts
+++ b/arch/arm/boot/dts/integratorcp.dts
@@ -58,20 +58,37 @@
core-module@10000000 {
/* 24 MHz chrystal on the core module */
- xtal24mhz: xtal24mhz@24M {
+ cm24mhz: cm24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
- /*
- * External oscillator on the core module, usually used
- * to drive video circuitry. Driven from the 24MHz clock.
- */
- auxosc: cm_aux_osc@25M {
+ /* Oscillator on the core module, clocks the CPU core */
+ cmcore: cmosc@24M {
+ compatible = "arm,syscon-icst525-integratorcp-cm-core";
+ #clock-cells = <0>;
+ lock-offset = <0x14>;
+ vco-offset = <0x08>;
+ clocks = <&cm24mhz>;
+ };
+
+ /* Oscillator on the core module, clocks the memory bus */
+ cmmem: cmosc@24M {
+ compatible = "arm,syscon-icst525-integratorcp-cm-mem";
+ #clock-cells = <0>;
+ lock-offset = <0x14>;
+ vco-offset = <0x08>;
+ clocks = <&cm24mhz>;
+ };
+
+ /* Auxilary oscillator on the core module, clocks the CLCD */
+ auxosc: auxosc@24M {
+ compatible = "arm,syscon-icst525";
#clock-cells = <0>;
- compatible = "arm,integrator-cm-auxosc";
- clocks = <&xtal24mhz>;
+ lock-offset = <0x14>;
+ vco-offset = <0x1c>;
+ clocks = <&cm24mhz>;
};
/* The KMI clock is the 24 MHz oscillator divided to 8MHz */
@@ -80,7 +97,7 @@
compatible = "fixed-factor-clock";
clock-div = <3>;
clock-mult = <1>;
- clocks = <&xtal24mhz>;
+ clocks = <&cm24mhz>;
};
/* The timer clock is the 24 MHz oscillator divided to 1MHz */
@@ -89,7 +106,7 @@
compatible = "fixed-factor-clock";
clock-div = <24>;
clock-mult = <1>;
- clocks = <&xtal24mhz>;
+ clocks = <&cm24mhz>;
};
};
@@ -209,7 +226,42 @@
reg = <0xC0000000 0x1000>;
interrupts = <22>;
clocks = <&auxosc>, <&pclk>;
- clock-names = "clcd", "apb_pclk";
+ clock-names = "clcdclk", "apb_pclk";
+
+ port {
+ /*
+ * The VGA connected is implemented with a
+ * THS8134A triple DAC that can be run in 24bit
+ * or 16bit RGB mode.
+ */
+ clcd_pads: endpoint {
+ remote-endpoint = <&clcd_panel>;
+ arm,pl11x,tft-r0g0b0-pads = <1 7 13>;
+ };
+ };
+
+ panel {
+ compatible = "panel-dpi";
+
+ port {
+ clcd_panel: endpoint {
+ remote-endpoint = <&clcd_pads>;
+ };
+ };
+
+ /* Standard 640x480 VGA timings */
+ panel-timing {
+ clock-frequency = <25175000>;
+ hactive = <640>;
+ hback-porch = <48>;
+ hfront-porch = <16>;
+ hsync-len = <96>;
+ vactive = <480>;
+ vback-porch = <33>;
+ vfront-porch = <10>;
+ vsync-len = <2>;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/keystone-k2e-evm.dts b/arch/arm/boot/dts/keystone-k2e-evm.dts
index 4c32ebc1425a..ae1ebe7ee021 100644
--- a/arch/arm/boot/dts/keystone-k2e-evm.dts
+++ b/arch/arm/boot/dts/keystone-k2e-evm.dts
@@ -47,18 +47,26 @@
status = "okay";
};
-&usb {
+&keystone_usb0 {
status = "okay";
};
+&usb0 {
+ dr_mode = "host";
+};
+
&usb1_phy {
status = "okay";
};
-&usb1 {
+&keystone_usb1 {
status = "okay";
};
+&usb1 {
+ dr_mode = "peripheral";
+};
+
&i2c0 {
dtt@50 {
compatible = "at,24c1024";
diff --git a/arch/arm/boot/dts/keystone-k2e.dtsi b/arch/arm/boot/dts/keystone-k2e.dtsi
index 9a51b8c88581..497c417db5b6 100644
--- a/arch/arm/boot/dts/keystone-k2e.dtsi
+++ b/arch/arm/boot/dts/keystone-k2e.dtsi
@@ -61,7 +61,7 @@
status = "disabled";
};
- usb1: usb@25000000 {
+ keystone_usb1: usb@25000000 {
compatible = "ti,keystone-dwc3";
#address-cells = <1>;
#size-cells = <1>;
@@ -74,7 +74,7 @@
dma-ranges;
status = "disabled";
- dwc3@25010000 {
+ usb1: dwc3@25010000 {
compatible = "synopsys,dwc3";
reg = <0x25010000 0x70000>;
interrupts = <GIC_SPI 414 IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm/boot/dts/keystone-k2g.dtsi b/arch/arm/boot/dts/keystone-k2g.dtsi
index 3372615b885c..2919c5190653 100644
--- a/arch/arm/boot/dts/keystone-k2g.dtsi
+++ b/arch/arm/boot/dts/keystone-k2g.dtsi
@@ -83,6 +83,11 @@
pinctrl-single,function-mask = <0x001b0007>;
};
+ devctrl: device-state-control@02620000 {
+ compatible = "ti,keystone-devctrl", "syscon";
+ reg = <0x02620000 0x1000>;
+ };
+
uart0: serial@02530c00 {
compatible = "ns16550a";
current-speed = <115200>;
@@ -93,5 +98,32 @@
clock-frequency = <200000000>;
status = "disabled";
};
+
+ kirq0: keystone_irq@026202a0 {
+ compatible = "ti,keystone-irq";
+ interrupts = <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ ti,syscon-dev = <&devctrl 0x2a0>;
+ };
+
+ dspgpio0: keystone_dsp_gpio@02620240 {
+ compatible = "ti,keystone-dsp-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio,syscon-dev = <&devctrl 0x240>;
+ };
+
+ msgmgr: msgmgr@02a00000 {
+ compatible = "ti,k2g-message-manager";
+ #mbox-cells = <2>;
+ reg-names = "queue_proxy_region",
+ "queue_state_debug_region";
+ reg = <0x02a00000 0x400000>, <0x028c3400 0x400>;
+ interrupt-names = "rx_005",
+ "rx_057";
+ interrupts = <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+ };
};
};
diff --git a/arch/arm/boot/dts/keystone-k2hk-evm.dts b/arch/arm/boot/dts/keystone-k2hk-evm.dts
index b38b3441818b..2156ff92d08f 100644
--- a/arch/arm/boot/dts/keystone-k2hk-evm.dts
+++ b/arch/arm/boot/dts/keystone-k2hk-evm.dts
@@ -83,10 +83,14 @@
status = "okay";
};
-&usb {
+&keystone_usb0 {
status = "okay";
};
+&usb0 {
+ dr_mode = "host";
+};
+
&aemif {
cs0 {
#address-cells = <2>;
diff --git a/arch/arm/boot/dts/keystone-k2l-evm.dts b/arch/arm/boot/dts/keystone-k2l-evm.dts
index 7f9c2e94d605..056b42f99d7a 100644
--- a/arch/arm/boot/dts/keystone-k2l-evm.dts
+++ b/arch/arm/boot/dts/keystone-k2l-evm.dts
@@ -32,10 +32,14 @@
status = "okay";
};
-&usb {
+&keystone_usb0 {
status = "okay";
};
+&usb0 {
+ dr_mode = "host";
+};
+
&i2c0 {
dtt@50 {
compatible = "at,24c1024";
diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
index e23f46d15c80..02708ba2d4f4 100644
--- a/arch/arm/boot/dts/keystone.dtsi
+++ b/arch/arm/boot/dts/keystone.dtsi
@@ -188,7 +188,7 @@
status = "disabled";
};
- usb: usb@2680000 {
+ keystone_usb0: usb@2680000 {
compatible = "ti,keystone-dwc3";
#address-cells = <1>;
#size-cells = <1>;
@@ -201,7 +201,7 @@
dma-ranges;
status = "disabled";
- dwc3@2690000 {
+ usb0: dwc3@2690000 {
compatible = "synopsys,dwc3";
reg = <0x2690000 0x70000>;
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a6.dts b/arch/arm/boot/dts/kirkwood-openblocks_a6.dts
index 0db0e3edc88f..94e49f32d5f9 100644
--- a/arch/arm/boot/dts/kirkwood-openblocks_a6.dts
+++ b/arch/arm/boot/dts/kirkwood-openblocks_a6.dts
@@ -41,7 +41,7 @@
};
pinctrl: pin-controller@10000 {
- pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>;
+ pinctrl-0 = <&pmx_dip_switches>;
pinctrl-names = "default";
pmx_uart0: pmx-uart0 {
@@ -174,3 +174,10 @@
phy-handle = <&ethphy0>;
};
};
+
+&gpio0 {
+ status = "okay";
+
+ pinctrl-0 = <&pmx_gpio_header>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
index 1c2c74655416..731ec37aed5b 100644
--- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
+++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
@@ -13,6 +13,11 @@
};
};
+ memory@0 {
+ device_type = "memory";
+ reg = <0 0>;
+ };
+
leds {
compatible = "gpio-leds";
user0 {
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index fdb736c82045..7cae9c5e27db 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -20,6 +20,9 @@
#define LPC_GPIO(port, pin) (port * 32 + pin)
/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -186,6 +189,10 @@
clock-names = "stmmaceth";
resets = <&rgu 22>;
reset-names = "stmmaceth";
+ rx-fifo-depth = <256>;
+ tx-fifo-depth = <256>;
+ snps,pbl = <4>; /* 32 (8x mode) */
+ snps,force_thresh_dma_mode;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi
index e295e1ec82a5..b5841fab51c1 100644
--- a/arch/arm/boot/dts/lpc32xx.dtsi
+++ b/arch/arm/boot/dts/lpc32xx.dtsi
@@ -51,9 +51,19 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
- ranges = <0x20000000 0x20000000 0x30000000>,
+ ranges = <0x00000000 0x00000000 0x10000000>,
+ <0x20000000 0x20000000 0x30000000>,
<0xe0000000 0xe0000000 0x04000000>;
+ iram: sram@08000000 {
+ compatible = "mmio-sram";
+ reg = <0x08000000 0x20000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x00000000 0x08000000 0x20000>;
+ };
+
/*
* Enable either SLC or MLC
*/
diff --git a/arch/arm/boot/dts/lpc4337-ciaa.dts b/arch/arm/boot/dts/lpc4337-ciaa.dts
index 5cfadb06c8df..7c16d639a1b4 100644
--- a/arch/arm/boot/dts/lpc4337-ciaa.dts
+++ b/arch/arm/boot/dts/lpc4337-ciaa.dts
@@ -30,7 +30,7 @@
stdout-path = &uart2;
};
- memory {
+ memory@28000000 {
device_type = "memory";
reg = <0x28000000 0x0800000>; /* 8 MB */
};
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
index 6c9048d4d03c..874c75d44013 100644
--- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -33,7 +33,7 @@
stdout-path = &uart0;
};
- memory {
+ memory@28000000 {
device_type = "memory";
reg = <0x28000000 0x800000>; /* 8 MB */
};
@@ -424,7 +424,7 @@
/* NXP SE97BTP with temperature sensor + eeprom */
sensor@18 {
- compatible = "nxp,jc42";
+ compatible = "nxp,se97", "jedec,jc-42.4-temp";
reg = <0x18>;
};
diff --git a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
index 1919be4dab2b..9b5fad622522 100644
--- a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
+++ b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
@@ -33,7 +33,7 @@
stdout-path = &uart0;
};
- memory {
+ memory@28000000 {
device_type = "memory";
reg = <0x28000000 0x2000000>; /* 32 MB */
};
diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts
index 75ecaed32ae5..a8b148ad1dd2 100644
--- a/arch/arm/boot/dts/ls1021a-twr.dts
+++ b/arch/arm/boot/dts/ls1021a-twr.dts
@@ -108,12 +108,23 @@
panel: panel {
compatible = "nec,nl4827hc19-05b";
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dcu_out>;
+ };
+ };
};
};
&dcu {
- fsl,panel = <&panel>;
status = "okay";
+
+ port {
+ dcu_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
};
&dspi1 {
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index fc4080de4b7b..41fd53671859 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -162,6 +162,27 @@
reg = <0xc1108000 0x4>, <0xc1104000 0x460>;
};
+ pwm_ab: pwm@8550 {
+ compatible = "amlogic,meson8b-pwm";
+ reg = <0xc1108550 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_cd: pwm@8650 {
+ compatible = "amlogic,meson8b-pwm";
+ reg = <0xc1108650 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ef: pwm@86c0 {
+ compatible = "amlogic,meson8b-pwm";
+ reg = <0xc11086c0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
pinctrl_cbus: pinctrl@c1109880 {
compatible = "amlogic,meson8b-cbus-pinctrl";
reg = <0xc1109880 0x10>;
diff --git a/arch/arm/boot/dts/mps2.dtsi b/arch/arm/boot/dts/mps2.dtsi
index e3fed8d34558..efb8a03cb970 100644
--- a/arch/arm/boot/dts/mps2.dtsi
+++ b/arch/arm/boot/dts/mps2.dtsi
@@ -42,6 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "skeleton.dtsi"
#include "armv7-m.dtsi"
/ {
diff --git a/arch/arm/boot/dts/ntc-gr8-evb.dts b/arch/arm/boot/dts/ntc-gr8-evb.dts
new file mode 100644
index 000000000000..4b622f3b5220
--- /dev/null
+++ b/arch/arm/boot/dts/ntc-gr8-evb.dts
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2016 Free Electrons
+ * Copyright 2016 NextThing Co
+ *
+ * Mylène Josserand <mylene.josserand@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "ntc-gr8.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "NextThing GR8-EVB";
+ compatible = "nextthing,gr8-evb", "nextthing,gr8";
+
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ serial0 = &uart1;
+ serial1 = &uart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 10000 0>;
+ enable-gpios = <&axp_gpio 1 GPIO_ACTIVE_HIGH>;
+
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ };
+};
+
+&be0 {
+ status = "okay";
+};
+
+&codec {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+
+ /*
+ * The interrupt is routed through the "External Fast
+ * Interrupt Request" pin (ball G13 of the module)
+ * directly to the main interrupt controller, without
+ * any other controller interfering.
+ */
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ wm8978: codec@1a {
+ #sound-dai-cells = <0>;
+ compatible = "wlf,wm8978";
+ reg = <0x1a>;
+ };
+
+ pcf8563: rtc@51 {
+ compatible = "phg,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&i2s0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_mclk_pins_a>, <&i2s0_data_pins_a>;
+ status = "okay";
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@190 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <190000>;
+ };
+
+ button@390 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <390000>;
+ };
+
+ button@600 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+
+ button@800 {
+ label = "Search";
+ linux,code = <KEY_SEARCH>;
+ channel = <0>;
+ voltage = <800000>;
+ };
+
+ button@980 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <980000>;
+ };
+
+ button@1180 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1180000>;
+ };
+
+ button@1400 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <1400000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_gr8_evb>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+
+ /* MLC Support sucks for now */
+ status = "disabled";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_gr8_evb: mmc0-cd-pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb0_id_pin_gr8_evb: usb0-id-pin@0 {
+ allwinner,pins = "PG2";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb0_vbus_det_pin_gr8_evb: usb0-vbus-det-pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_gr8_evb: usb1-vbus-pin@0 {
+ allwinner,pins = "PG13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>;
+ status = "okay";
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+ regulator-always-on;
+};
+
+&reg_dcdc3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-name = "vdd-sys";
+ regulator-always-on;
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
+ regulator-always-on;
+};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_gr8_evb>;
+ gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&rtp {
+ allwinner,ts-attached;
+};
+
+&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdif_tx_pins_a>;
+ status = "okay";
+};
+
+&tve0 {
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_a>, <&uart1_cts_rts_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ /*
+ * The GR8-EVB has a somewhat interesting design. There's a
+ * pin supposed to control VBUS, an ID pin, a VBUS detect pin,
+ * so everything should work just fine.
+ *
+ * Except that the pin supposed to control VBUS is not
+ * connected to any controllable output, neither to the SoC
+ * through a GPIO or to the PMIC, and it is pulled down,
+ * meaning that we will never be able to enable VBUS on this
+ * board.
+ */
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_pin_gr8_evb>, <&usb0_vbus_det_pin_gr8_evb>;
+ usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+ usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/ntc-gr8.dtsi b/arch/arm/boot/dts/ntc-gr8.dtsi
new file mode 100644
index 000000000000..ca54e03ef366
--- /dev/null
+++ b/arch/arm/boot/dts/ntc-gr8.dtsi
@@ -0,0 +1,1087 @@
+/*
+ * Copyright 2016 Mylène Josserand
+ *
+ * Mylène Josserand <mylene.josserand@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/clock/sun4i-a10-pll2.h>
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a8";
+ reg = <0x0>;
+ clocks = <&cpu>;
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ /*
+ * This is a dummy clock, to be used as placeholder on
+ * other mux clocks when a specific parent clock is not
+ * yet implemented. It should be dropped when the driver
+ * is complete.
+ */
+ dummy: dummy {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc3M: osc3M-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <8>;
+ clock-mult = <1>;
+ clocks = <&osc24M>;
+ clock-output-names = "osc3M";
+ };
+
+ osc32k: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+ };
+
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a13-pll2-clk";
+ reg = <0x01c20008 0x8>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2-1x", "pll2-2x",
+ "pll2-4x", "pll2-8x";
+ };
+
+ pll3: clk@01c20010 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll3-clk";
+ reg = <0x01c20010 0x4>;
+ clocks = <&osc3M>;
+ clock-output-names = "pll3";
+ };
+
+ pll3x2: pll3x2-clk {
+ compatible = "allwinner,sun4i-a10-pll3-2x-clk";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <2>;
+ clocks = <&pll3>;
+ clock-output-names = "pll3-2x";
+ };
+
+ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+ };
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6_sata", "pll6_other", "pll6";
+ };
+
+ pll7: clk@01c20030 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll3-clk";
+ reg = <0x01c20030 0x4>;
+ clocks = <&osc3M>;
+ clock-output-names = "pll7";
+ };
+
+ pll7x2: pll7x2-clk {
+ compatible = "allwinner,sun4i-a10-pll3-2x-clk";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <2>;
+ clocks = <&pll7>;
+ clock-output-names = "pll7-2x";
+ };
+
+ /* dummy is 200M */
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+ };
+
+ ahb: ahb@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun5i-a13-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>, <&cpu>, <&pll6 1>;
+ clock-output-names = "ahb";
+ /*
+ * Use PLL6 as parent, instead of CPU/AXI
+ * which has rate changes due to cpufreq
+ */
+ assigned-clocks = <&ahb>;
+ assigned-clock-parents = <&pll6 1>;
+ };
+
+ apb0: apb0@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+ };
+
+ apb1: clk@01c20058 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+ clock-output-names = "apb1";
+ };
+
+ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-gates-clk";
+ reg = <0x01c2005c 0x4>;
+ clocks = <&axi>;
+ clock-indices = <0>;
+ clock-output-names = "axi_dram";
+ };
+
+ ahb_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a13-ahb-gates-clk";
+ reg = <0x01c20060 0x8>;
+ clocks = <&ahb>;
+ clock-indices = <0>, <1>,
+ <2>, <5>, <6>,
+ <7>, <8>, <9>,
+ <10>, <13>,
+ <14>, <17>, <20>,
+ <21>, <22>,
+ <28>, <32>, <34>,
+ <36>, <40>, <44>,
+ <46>, <51>,
+ <52>;
+ clock-output-names = "ahb_usbotg", "ahb_ehci",
+ "ahb_ohci", "ahb_ss", "ahb_dma",
+ "ahb_bist", "ahb_mmc0", "ahb_mmc1",
+ "ahb_mmc2", "ahb_nand",
+ "ahb_sdram", "ahb_emac", "ahb_spi0",
+ "ahb_spi1", "ahb_spi2",
+ "ahb_hstimer", "ahb_ve", "ahb_tve",
+ "ahb_lcd", "ahb_csi", "ahb_de_be",
+ "ahb_de_fe", "ahb_iep",
+ "ahb_mali400";
+ };
+
+ apb0_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-gates-clk";
+ reg = <0x01c20068 0x4>;
+ clocks = <&apb0>;
+ clock-indices = <0>, <3>,
+ <5>, <6>;
+ clock-output-names = "apb0_codec", "apb0_i2s0",
+ "apb0_pio", "apb0_ir";
+ };
+
+ apb1_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-gates-clk";
+ reg = <0x01c2006c 0x4>;
+ clocks = <&apb1>;
+ clock-indices = <0>, <1>,
+ <2>, <17>,
+ <18>, <19>;
+ clock-output-names = "apb1_i2c0", "apb1_i2c1",
+ "apb1_i2c2", "apb1_uart1",
+ "apb1_uart2", "apb1_uart3";
+ };
+
+ nand_clk: clk@01c20080 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20080 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "nand";
+ };
+
+ ms_clk: clk@01c20084 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20084 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ms";
+ };
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc0",
+ "mmc0_output",
+ "mmc0_sample";
+ };
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc1",
+ "mmc1_output",
+ "mmc1_sample";
+ };
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
+ };
+
+ ts_clk: clk@01c20098 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20098 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ts";
+ };
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ss";
+ };
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi0";
+ };
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi1";
+ };
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi2";
+ };
+
+ ir0_clk: clk@01c200b0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir0";
+ };
+
+ i2s0_clk: clk@01c200b8 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200b8 0x4>;
+ clocks = <&pll2 SUN4I_A10_PLL2_8X>,
+ <&pll2 SUN4I_A10_PLL2_4X>,
+ <&pll2 SUN4I_A10_PLL2_2X>,
+ <&pll2 SUN4I_A10_PLL2_1X>;
+ clock-output-names = "i2s0";
+ };
+
+ spdif_clk: clk@01c200c0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200c0 0x4>;
+ clocks = <&pll2 SUN4I_A10_PLL2_8X>,
+ <&pll2 SUN4I_A10_PLL2_4X>,
+ <&pll2 SUN4I_A10_PLL2_2X>,
+ <&pll2 SUN4I_A10_PLL2_1X>;
+ clock-output-names = "spdif";
+ };
+
+ usb_clk: clk@01c200cc {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun5i-a13-usb-clk";
+ reg = <0x01c200cc 0x4>;
+ clocks = <&pll6 1>;
+ clock-output-names = "usb_ohci0", "usb_phy";
+ };
+
+ dram_gates: clk@01c20100 {
+ #clock-cells = <1>;
+ compatible = "nextthing,gr8-dram-gates-clk",
+ "allwinner,sun4i-a10-gates-clk";
+ reg = <0x01c20100 0x4>;
+ clocks = <&pll5 0>;
+ clock-indices = <0>,
+ <1>,
+ <25>,
+ <26>,
+ <29>,
+ <31>;
+ clock-output-names = "dram_ve",
+ "dram_csi",
+ "dram_de_fe",
+ "dram_de_be",
+ "dram_ace",
+ "dram_iep";
+ };
+
+ de_be_clk: clk@01c20104 {
+ #clock-cells = <0>;
+ #reset-cells = <0>;
+ compatible = "allwinner,sun4i-a10-display-clk";
+ reg = <0x01c20104 0x4>;
+ clocks = <&pll3>, <&pll7>, <&pll5 1>;
+ clock-output-names = "de-be";
+ };
+
+ de_fe_clk: clk@01c2010c {
+ #clock-cells = <0>;
+ #reset-cells = <0>;
+ compatible = "allwinner,sun4i-a10-display-clk";
+ reg = <0x01c2010c 0x4>;
+ clocks = <&pll3>, <&pll7>, <&pll5 1>;
+ clock-output-names = "de-fe";
+ };
+
+ tcon_ch0_clk: clk@01c20118 {
+ #clock-cells = <0>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun4i-a10-tcon-ch0-clk";
+ reg = <0x01c20118 0x4>;
+ clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
+ clock-output-names = "tcon-ch0-sclk";
+ };
+
+ tcon_ch1_clk: clk@01c2012c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-tcon-ch1-clk";
+ reg = <0x01c2012c 0x4>;
+ clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
+ clock-output-names = "tcon-ch1-sclk";
+ };
+
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 SUN4I_A10_PLL2_1X>;
+ clock-output-names = "codec";
+ };
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun5i-a13-mbus-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mbus";
+ };
+ };
+
+ display-engine {
+ compatible = "allwinner,sun5i-a13-display-engine";
+ allwinner,pipelines = <&fe0>;
+ };
+
+ soc@01c00000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram-controller@01c00000 {
+ compatible = "allwinner,sun4i-a10-sram-controller";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a: sram@00000000 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0xc000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00000000 0xc000>;
+ };
+
+ sram_d: sram@00010000 {
+ compatible = "mmio-sram";
+ reg = <0x00010000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00010000 0x1000>;
+
+ otg_sram: sram-section@0000 {
+ compatible = "allwinner,sun4i-a10-sram-d";
+ reg = <0x0000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun4i-a10-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <27>;
+ clocks = <&ahb_gates 6>;
+ #dma-cells = <2>;
+ };
+
+ nfc: nand@01c03000 {
+ compatible = "allwinner,sun4i-a10-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <37>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 3>;
+ dma-names = "rxtx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi0: spi@01c05000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c05000 0x1000>;
+ interrupts = <10>;
+ clocks = <&ahb_gates 20>, <&spi0_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+ <&dma SUN4I_DMA_DEDICATED 26>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi1: spi@01c06000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c06000 0x1000>;
+ interrupts = <11>;
+ clocks = <&ahb_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+ <&dma SUN4I_DMA_DEDICATED 8>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ tve0: tv-encoder@01c0a000 {
+ compatible = "allwinner,sun4i-a10-tv-encoder";
+ reg = <0x01c0a000 0x1000>;
+ clocks = <&ahb_gates 34>;
+ resets = <&tcon_ch0_clk 0>;
+ status = "disabled";
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tve0_in_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_out_tve0>;
+ };
+ };
+ };
+
+ tcon0: lcd-controller@01c0c000 {
+ compatible = "allwinner,sun5i-a13-tcon";
+ reg = <0x01c0c000 0x1000>;
+ interrupts = <44>;
+ resets = <&tcon_ch0_clk 1>;
+ reset-names = "lcd";
+ clocks = <&ahb_gates 36>,
+ <&tcon_ch0_clk>,
+ <&tcon_ch1_clk>;
+ clock-names = "ahb",
+ "tcon-ch0",
+ "tcon-ch1";
+ clock-output-names = "tcon-pixel-clock";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tcon0_in_be0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&be0_out_tcon0>;
+ };
+ };
+
+ tcon0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tcon0_out_tve0: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&tve0_in_tcon0>;
+ };
+ };
+ };
+ };
+
+ mmc0: mmc@01c0f000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c0f000 0x1000>;
+ clocks = <&ahb_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ interrupts = <32>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc1: mmc@01c10000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c10000 0x1000>;
+ clocks = <&ahb_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ interrupts = <33>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc2: mmc@01c11000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c11000 0x1000>;
+ clocks = <&ahb_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ interrupts = <34>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ usb_otg: usb@01c13000 {
+ compatible = "allwinner,sun4i-a10-musb";
+ reg = <0x01c13000 0x0400>;
+ clocks = <&ahb_gates 0>;
+ interrupts = <38>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ allwinner,sram = <&otg_sram 1>;
+ status = "disabled";
+
+ dr_mode = "otg";
+ };
+
+ usbphy: phy@01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun5i-a13-usb-phy";
+ reg = <0x01c13400 0x10 0x01c14800 0x4>;
+ reg-names = "phy_ctrl", "pmu1";
+ clocks = <&usb_clk 8>;
+ clock-names = "usb_phy";
+ resets = <&usb_clk 0>, <&usb_clk 1>;
+ reset-names = "usb0_reset", "usb1_reset";
+ status = "disabled";
+ };
+
+ ehci0: usb@01c14000 {
+ compatible = "allwinner,sun5i-a13-ehci", "generic-ehci";
+ reg = <0x01c14000 0x100>;
+ interrupts = <39>;
+ clocks = <&ahb_gates 1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@01c14400 {
+ compatible = "allwinner,sun5i-a13-ohci", "generic-ohci";
+ reg = <0x01c14400 0x100>;
+ interrupts = <40>;
+ clocks = <&usb_clk 6>, <&ahb_gates 2>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ spi2: spi@01c17000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c17000 0x1000>;
+ interrupts = <12>;
+ clocks = <&ahb_gates 22>, <&spi2_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+ <&dma SUN4I_DMA_DEDICATED 28>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ intc: interrupt-controller@01c20400 {
+ compatible = "allwinner,sun4i-a10-ic";
+ reg = <0x01c20400 0x400>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pio: pinctrl@01c20800 {
+ compatible = "nextthing,gr8-pinctrl";
+ reg = <0x01c20800 0x400>;
+ interrupts = <28>;
+ clocks = <&apb0_gates 5>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #gpio-cells = <3>;
+
+ i2c0_pins_a: i2c0@0 {
+ allwinner,pins = "PB0", "PB1";
+ allwinner,function = "i2c0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c1_pins_a: i2c1@0 {
+ allwinner,pins = "PB15", "PB16";
+ allwinner,function = "i2c1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c2_pins_a: i2c2@0 {
+ allwinner,pins = "PB17", "PB18";
+ allwinner,function = "i2c2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2s0_data_pins_a: i2s0-data@0 {
+ allwinner,pins = "PB6", "PB7", "PB8", "PB9";
+ allwinner,function = "i2s0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2s0_mclk_pins_a: i2s0-mclk@0 {
+ allwinner,pins = "PB6", "PB7", "PB8", "PB9";
+ allwinner,function = "i2s0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ir0_rx_pins_a: ir0@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "ir0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ lcd_rgb666_pins: lcd-rgb666@0 {
+ allwinner,pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
+ "PD10", "PD11", "PD12", "PD13", "PD14", "PD15",
+ "PD18", "PD19", "PD20", "PD21", "PD22", "PD23",
+ "PD24", "PD25", "PD26", "PD27";
+ allwinner,function = "lcd0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_pins_a: mmc0@0 {
+ allwinner,pins = "PF0", "PF1", "PF2", "PF3",
+ "PF4", "PF5";
+ allwinner,function = "mmc0";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ nand_pins_a: nand-base0@0 {
+ allwinner,pins = "PC0", "PC1", "PC2",
+ "PC5", "PC8", "PC9", "PC10",
+ "PC11", "PC12", "PC13", "PC14",
+ "PC15";
+ allwinner,function = "nand0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ nand_cs0_pins_a: nand-cs@0 {
+ allwinner,pins = "PC4";
+ allwinner,function = "nand0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ nand_rb0_pins_a: nand-rb@0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ pwm0_pins_a: pwm0@0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "pwm0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spdif_tx_pins_a: spdif@0 {
+ allwinner,pins = "PB10";
+ allwinner,function = "spdif";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ uart1_pins_a: uart1@1 {
+ allwinner,pins = "PG3", "PG4";
+ allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ uart1_cts_rts_pins_a: uart1-cts-rts@0 {
+ allwinner,pins = "PG5", "PG6";
+ allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+ };
+
+ pwm: pwm@01c20e00 {
+ compatible = "allwinner,sun5i-a10s-pwm";
+ reg = <0x01c20e00 0xc>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ timer@01c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0x90>;
+ interrupts = <22>;
+ clocks = <&osc24M>;
+ };
+
+ wdt: watchdog@01c20c90 {
+ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+ spdif: spdif@01c21000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun4i-a10-spdif";
+ reg = <0x01c21000 0x400>;
+ interrupts = <13>;
+ clocks = <&apb0_gates 1>, <&spdif_clk>;
+ clock-names = "apb", "spdif";
+ dmas = <&dma SUN4I_DMA_NORMAL 2>,
+ <&dma SUN4I_DMA_NORMAL 2>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ ir0: ir@01c21800 {
+ compatible = "allwinner,sun4i-a10-ir";
+ clocks = <&apb0_gates 6>, <&ir0_clk>;
+ clock-names = "apb", "ir";
+ interrupts = <5>;
+ reg = <0x01c21800 0x40>;
+ status = "disabled";
+ };
+
+ i2s0: i2s@01c22400 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun4i-a10-i2s";
+ reg = <0x01c22400 0x400>;
+ interrupts = <16>;
+ clocks = <&apb0_gates 3>, <&i2s0_clk>;
+ clock-names = "apb", "mod";
+ dmas = <&dma SUN4I_DMA_NORMAL 3>,
+ <&dma SUN4I_DMA_NORMAL 3>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ status = "disabled";
+ };
+
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec";
+ reg = <0x01c22c00 0x40>;
+ interrupts = <30>;
+ clocks = <&apb0_gates 0>, <&codec_clk>;
+ clock-names = "apb", "codec";
+ dmas = <&dma SUN4I_DMA_NORMAL 19>,
+ <&dma SUN4I_DMA_NORMAL 19>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ rtp: rtp@01c25000 {
+ compatible = "allwinner,sun5i-a13-ts";
+ reg = <0x01c25000 0x100>;
+ interrupts = <29>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ uart1: serial@01c28400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28400 0x400>;
+ interrupts = <2>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 17>;
+ status = "disabled";
+ };
+
+ uart2: serial@01c28800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28800 0x400>;
+ interrupts = <3>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 18>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2ac00 0x400>;
+ interrupts = <7>;
+ clocks = <&apb1_gates 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <8>;
+ clocks = <&apb1_gates 1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2b400 0x400>;
+ interrupts = <9>;
+ clocks = <&apb1_gates 2>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ timer@01c60000 {
+ compatible = "allwinner,sun5i-a13-hstimer";
+ reg = <0x01c60000 0x1000>;
+ interrupts = <82>, <83>;
+ clocks = <&ahb_gates 28>;
+ };
+
+ fe0: display-frontend@01e00000 {
+ compatible = "allwinner,sun5i-a13-display-frontend";
+ reg = <0x01e00000 0x20000>;
+ interrupts = <47>;
+ clocks = <&ahb_gates 46>, <&de_fe_clk>,
+ <&dram_gates 25>;
+ clock-names = "ahb", "mod",
+ "ram";
+ resets = <&de_fe_clk>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fe0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ fe0_out_be0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&be0_in_fe0>;
+ };
+ };
+ };
+ };
+
+ be0: display-backend@01e60000 {
+ compatible = "allwinner,sun5i-a13-display-backend";
+ reg = <0x01e60000 0x10000>;
+ clocks = <&ahb_gates 44>, <&de_be_clk>,
+ <&dram_gates 26>;
+ clock-names = "ahb", "mod",
+ "ram";
+ resets = <&de_be_clk>;
+ status = "disabled";
+
+ assigned-clocks = <&de_be_clk>;
+ assigned-clock-rates = <300000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ be0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ be0_in_fe0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&fe0_out_be0>;
+ };
+ };
+
+ be0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ be0_out_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_in_be0>;
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi
index 578fa2a54dce..4f793a025a72 100644
--- a/arch/arm/boot/dts/omap2.dtsi
+++ b/arch/arm/boot/dts/omap2.dtsi
@@ -12,11 +12,11 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/omap.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,omap2430", "ti,omap2420", "ti,omap2";
interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
serial0 = &uart1;
diff --git a/arch/arm/boot/dts/omap2420-h4.dts b/arch/arm/boot/dts/omap2420-h4.dts
index 34cdecb4fdda..9265c0b9c3f3 100644
--- a/arch/arm/boot/dts/omap2420-h4.dts
+++ b/arch/arm/boot/dts/omap2420-h4.dts
@@ -13,7 +13,7 @@
model = "TI OMAP2420 H4 board";
compatible = "ti,omap2420-h4", "ti,omap2420", "ti,omap2";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x4000000>; /* 64 MB */
};
diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
index db95aadcca70..7e5ffc583c90 100644
--- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
+++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
@@ -1,7 +1,7 @@
#include "omap2420.dtsi"
/ {
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x8000000>; /* 128 MB */
};
diff --git a/arch/arm/boot/dts/omap2430-sdp.dts b/arch/arm/boot/dts/omap2430-sdp.dts
index 6b36ede58488..4f7d9d7c00c7 100644
--- a/arch/arm/boot/dts/omap2430-sdp.dts
+++ b/arch/arm/boot/dts/omap2430-sdp.dts
@@ -13,7 +13,7 @@
model = "TI OMAP2430 SDP";
compatible = "ti,omap2430-sdp", "ti,omap2430", "ti,omap2";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x8000000>; /* 128 MB */
};
diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
index 8ffde06281ad..85e297ed0ea1 100644
--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
+++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
@@ -19,7 +19,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index a19d907d4850..4be85ce59dd1 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -19,7 +19,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
index 6a0df13fa0f3..57b9a028a49a 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
@@ -4,7 +4,7 @@
/ {
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-devkit8000-common.dtsi b/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
index 586010179752..f330c69cc683 100644
--- a/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
+++ b/arch/arm/boot/dts/omap3-devkit8000-common.dtsi
@@ -10,7 +10,7 @@
#include "omap34xx.dtsi"
/ {
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts
index ed449827c3d3..4f9a76544602 100644
--- a/arch/arm/boot/dts/omap3-evm-37xx.dts
+++ b/arch/arm/boot/dts/omap3-evm-37xx.dts
@@ -15,7 +15,7 @@
model = "TI OMAP37XX EVM (TMDSEVM3730)";
compatible = "ti,omap3-evm-37xx", "ti,omap3630", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-evm.dts b/arch/arm/boot/dts/omap3-evm.dts
index e10dcd0fa539..99b2bfcd1059 100644
--- a/arch/arm/boot/dts/omap3-evm.dts
+++ b/arch/arm/boot/dts/omap3-evm.dts
@@ -14,7 +14,7 @@
model = "TI OMAP35XX EVM (TMDSEVM3530)";
compatible = "ti,omap3-evm", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index c09a0574af90..b3a8b1f24499 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -21,7 +21,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
@@ -102,7 +102,7 @@
backlight {
compatible = "pwm-backlight";
- pwms = <&pwm11 0 2000000 0>;
+ pwms = <&pwm11 0 12000000 0>;
pwm-names = "backlight";
brightness-levels = <0 11 20 30 40 50 60 70 80 90 100>;
default-brightness-level = <9>; /* => 90 */
diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi
index f4f2ce46d681..54c4c07bbe4a 100644
--- a/arch/arm/boot/dts/omap3-igep.dtsi
+++ b/arch/arm/boot/dts/omap3-igep.dtsi
@@ -13,7 +13,7 @@
#include "omap36xx.dtsi"
/ {
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index 2f353dadfa40..e28fe13cb007 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -15,7 +15,7 @@
model = "TI OMAP3430 LDP (Zoom1 Labrador)";
compatible = "ti,omap3-ldp", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x8000000>; /* 128 MB */
};
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index eff816e0bc0a..fa611a5e4850 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -17,7 +17,7 @@
bootargs = "console=ttyO0,115200n8 vt.global_cursor_default=0 consoleblank=0";
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x8000000>; /* 128 MB */
};
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 2a6078a8422c..87ca50b53002 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -54,7 +54,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 927b17fc4ed8..5d8c4b4a4205 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -24,12 +24,12 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
- vemmc: fixedregulator@0 {
+ vemmc: fixedregulator0 {
compatible = "regulator-fixed";
regulator-name = "VEMMC";
regulator-min-microvolt = <2900000>;
@@ -39,7 +39,7 @@
enable-active-high;
};
- vwlan_fixed: fixedregulator@2 {
+ vwlan_fixed: fixedregulator2 {
compatible = "regulator-fixed";
regulator-name = "VWLAN";
gpio = <&gpio2 3 GPIO_ACTIVE_HIGH>; /* gpio 35 */
diff --git a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
index 3b3a75997f81..99a7eee6e61f 100644
--- a/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-alto35-common.dtsi
@@ -44,7 +44,7 @@
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&button_pins>;
- button0@10 {
+ button0 {
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* gpio_10 */
diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi
index 3e946cac55f3..401fae838fe9 100644
--- a/arch/arm/boot/dts/omap3-overo-base.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-base.dtsi
@@ -11,6 +11,12 @@
*/
/ {
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0 0>;
+ };
+
pwmleds {
compatible = "pwm-leds";
diff --git a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
index 4f4c6efbd518..56dbd113430e 100644
--- a/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
@@ -37,13 +37,13 @@
pinctrl-0 = <&button_pins>;
#address-cells = <1>;
#size-cells = <0>;
- button0@23 {
+ button0 {
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
wakeup-source;
};
- button1@14 {
+ button1 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
index ca86da68220c..854117dc0b77 100644
--- a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
@@ -119,7 +119,7 @@
pinctrl-names = "default";
pinctrl-0 = <&mcspi1_pins>;
- lcd0: display {
+ lcd0: display@1 {
compatible = "lgphilips,lb035q02";
label = "lcd35";
diff --git a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
index 250cc7fe5d5e..286f5baddf07 100644
--- a/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-gallop43-common.dtsi
@@ -37,13 +37,13 @@
pinctrl-0 = <&button_pins>;
#address-cells = <1>;
#size-cells = <0>;
- button0@23 {
+ button0 {
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
wakeup-source;
};
- button1@14 {
+ button1 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
diff --git a/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
index 8df7ec35d17d..a8020fb42464 100644
--- a/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-palo35-common.dtsi
@@ -37,13 +37,13 @@
pinctrl-0 = <&button_pins>;
#address-cells = <1>;
#size-cells = <0>;
- button0@23 {
+ button0 {
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
wakeup-source;
};
- button1@14 {
+ button1 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
diff --git a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
index 0ea2c451c809..11965737e2c9 100644
--- a/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-palo43-common.dtsi
@@ -37,13 +37,13 @@
pinctrl-0 = <&button_pins>;
#address-cells = <1>;
#size-cells = <0>;
- button0@23 {
+ button0 {
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; /* gpio_23 */
wakeup-source;
};
- button1@14 {
+ button1 {
label = "button1";
linux,code = <BTN_1>;
gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; /* gpio_14 */
diff --git a/arch/arm/boot/dts/omap3-pandora-common.dtsi b/arch/arm/boot/dts/omap3-pandora-common.dtsi
index dbc4dc721cc2..53e007abdc71 100644
--- a/arch/arm/boot/dts/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/omap3-pandora-common.dtsi
@@ -18,7 +18,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
@@ -45,28 +45,28 @@
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
- led@1 {
+ led1 {
label = "pandora::sd1";
gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>; /* GPIO_128 */
linux,default-trigger = "mmc0";
default-state = "off";
};
- led@2 {
+ led2 {
label = "pandora::sd2";
gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; /* GPIO_129 */
linux,default-trigger = "mmc1";
default-state = "off";
};
- led@3 {
+ led3 {
label = "pandora::bluetooth";
gpios = <&gpio5 30 GPIO_ACTIVE_HIGH>; /* GPIO_158 */
linux,default-trigger = "heartbeat";
default-state = "off";
};
- led@4 {
+ led4 {
label = "pandora::wifi";
gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>; /* GPIO_159 */
linux,default-trigger = "mmc2";
diff --git a/arch/arm/boot/dts/omap3-sniper.dts b/arch/arm/boot/dts/omap3-sniper.dts
index 78a1184cb312..bc4498e77bc9 100644
--- a/arch/arm/boot/dts/omap3-sniper.dts
+++ b/arch/arm/boot/dts/omap3-sniper.dts
@@ -20,7 +20,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/omap3-tao3530.dtsi b/arch/arm/boot/dts/omap3-tao3530.dtsi
index 644d3c8ea66a..dc80886b5329 100644
--- a/arch/arm/boot/dts/omap3-tao3530.dtsi
+++ b/arch/arm/boot/dts/omap3-tao3530.dtsi
@@ -26,7 +26,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap3-zoom3.dts b/arch/arm/boot/dts/omap3-zoom3.dts
index c29b41dc7b95..45e2ce0803de 100644
--- a/arch/arm/boot/dts/omap3-zoom3.dts
+++ b/arch/arm/boot/dts/omap3-zoom3.dts
@@ -20,7 +20,7 @@
};
};
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 4c3c471d2a83..353d818ce5a6 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -12,11 +12,11 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/omap.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,omap3430", "ti,omap3";
interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
i2c0 = &i2c1;
@@ -78,7 +78,7 @@
* the moment, just use a fake OCP bus entry to represent the whole bus
* hierarchy.
*/
- ocp {
+ ocp@68000000 {
compatible = "ti,omap3-l3-smx", "simple-bus";
reg = <0x68000000 0x10000>;
interrupts = <9 10>;
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index a0dc8d854142..abd6921143be 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -13,7 +13,7 @@
model = "TI OMAP3430 SDP";
compatible = "ti,omap3430-sdp", "ti,omap3";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi
index e44656258225..e41c52d3b113 100644
--- a/arch/arm/boot/dts/omap34xx.dtsi
+++ b/arch/arm/boot/dts/omap34xx.dtsi
@@ -28,7 +28,7 @@
};
};
- ocp {
+ ocp@68000000 {
omap3_pmx_core2: pinmux@480025d8 {
compatible = "ti,omap3-padconf", "pinctrl-single";
reg = <0x480025d8 0x24>;
diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi
index 8b7979153008..718fa88407cd 100644
--- a/arch/arm/boot/dts/omap36xx.dtsi
+++ b/arch/arm/boot/dts/omap36xx.dtsi
@@ -30,7 +30,7 @@
};
};
- ocp {
+ ocp@68000000 {
uart4: serial@49042000 {
compatible = "ti,omap3-uart";
reg = <0x49042000 0x400>;
diff --git a/arch/arm/boot/dts/omap4-duovero-parlor.dts b/arch/arm/boot/dts/omap4-duovero-parlor.dts
index 6b39808b8313..1b825128a7b9 100644
--- a/arch/arm/boot/dts/omap4-duovero-parlor.dts
+++ b/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -32,7 +32,7 @@
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
- button0@121 {
+ button0 {
label = "button0";
linux,code = <BTN_0>;
gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; /* gpio_121 */
diff --git a/arch/arm/boot/dts/omap4-duovero.dtsi b/arch/arm/boot/dts/omap4-duovero.dtsi
index a90b582e4c3f..ec0bd9779e1a 100644
--- a/arch/arm/boot/dts/omap4-duovero.dtsi
+++ b/arch/arm/boot/dts/omap4-duovero.dtsi
@@ -12,7 +12,7 @@
model = "Gumstix Duovero";
compatible = "gumstix,omap4-duovero", "ti,omap4430", "ti,omap4";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
diff --git a/arch/arm/boot/dts/omap4-kc1.dts b/arch/arm/boot/dts/omap4-kc1.dts
index 2251bd54e4e6..e3763ac75719 100644
--- a/arch/arm/boot/dts/omap4-kc1.dts
+++ b/arch/arm/boot/dts/omap4-kc1.dts
@@ -13,7 +13,7 @@
model = "Amazon Kindle Fire (first generation)";
compatible = "amazon,omap4-kc1", "ti,omap4430", "ti,omap4";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
index f8f13952cfeb..1673689e6705 100644
--- a/arch/arm/boot/dts/omap4-panda-common.dtsi
+++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
@@ -8,7 +8,7 @@
#include "elpida_ecb240abacn.dtsi"
/ {
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
@@ -446,6 +446,8 @@
pinctrl-names = "default";
pinctrl-0 = <&wl12xx_pins>;
vmmc-supply = <&wl12xx_vmmc>;
+ interrupts-extended = <&wakeupgen GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH
+ &omap4_pmx_core 0x10e>;
non-removable;
bus-width = <4>;
cap-power-off-card;
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index 10d73a784050..d728ec963111 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -14,7 +14,7 @@
model = "TI OMAP4 SDP board";
compatible = "ti,omap4-sdp", "ti,omap4430", "ti,omap4";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
diff --git a/arch/arm/boot/dts/omap4-var-som-om44.dtsi b/arch/arm/boot/dts/omap4-var-som-om44.dtsi
index 873cfc87260c..758b6eb7ae43 100644
--- a/arch/arm/boot/dts/omap4-var-som-om44.dtsi
+++ b/arch/arm/boot/dts/omap4-var-som-om44.dtsi
@@ -12,7 +12,7 @@
model = "Variscite VAR-SOM-OM44";
compatible = "variscite,var-som-om44", "ti,omap4460", "ti,omap4";
- memory {
+ memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 3fdc51cd0fad..0ced079b7ae3 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -10,11 +10,11 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/omap.h>
-#include "skeleton.dtsi"
-
/ {
compatible = "ti,omap4430", "ti,omap4";
interrupt-parent = <&wakeupgen>;
+ #address-cells = <1>;
+ #size-cells = <1>;
aliases {
i2c0 = &i2c1;
diff --git a/arch/arm/boot/dts/omap5-board-common.dtsi b/arch/arm/boot/dts/omap5-board-common.dtsi
index 5196113202a2..6365635fea5c 100644
--- a/arch/arm/boot/dts/omap5-board-common.dtsi
+++ b/arch/arm/boot/dts/omap5-board-common.dtsi
@@ -77,16 +77,6 @@
reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; /* gpio3_79 ETH_NRESET */
};
- leds {
- compatible = "gpio-leds";
- led@1 {
- label = "omap5:blue:usr1";
- gpios = <&gpio5 25 GPIO_ACTIVE_HIGH>; /* gpio5_153 D1 LED */
- linux,default-trigger = "heartbeat";
- default-state = "off";
- };
- };
-
tpd12s015: encoder {
compatible = "ti,tpd12s015";
@@ -332,7 +322,7 @@
wlcore_irq_pin: pinmux_wlcore_irq_pin {
pinctrl-single,pins = <
- OMAP5_IOPAD(0x40, PIN_INPUT_PULLUP | MUX_MODE6) /* llia_wakereqin.gpio1_wk14 */
+ OMAP5_IOPAD(0x40, PIN_INPUT | MUX_MODE6) /* llia_wakereqin.gpio1_wk14 */
>;
};
};
@@ -355,15 +345,17 @@
non-removable;
cap-power-off-card;
pinctrl-names = "default";
- pinctrl-0 = <&mmc3_pins &wlcore_irq_pin>;
- interrupts-extended = <&gic GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH
- &omap5_pmx_core 0x168>;
+ pinctrl-0 = <&mmc3_pins>;
+ interrupts-extended = <&wakeupgen GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH
+ &omap5_pmx_core 0x16a>;
#address-cells = <1>;
#size-cells = <0>;
wlcore: wlcore@2 {
compatible = "ti,wl1271";
reg = <2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlcore_irq_pin>;
interrupt-parent = <&gpio1>;
interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; /* gpio 14 */
ref-clock-frequency = <26000000>;
@@ -391,14 +383,23 @@
interrupt-controller;
#interrupt-cells = <2>;
ti,system-power-controller;
+ ti,mux-pad1 = <0xa1>;
+ ti,mux-pad2 = <0x1b>;
pinctrl-names = "default";
pinctrl-0 = <&palmas_sys_nirq_pins &palmas_msecure_pins>;
+ palmas_gpio: gpio {
+ compatible = "ti,palmas-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
extcon_usb3: palmas_usb {
compatible = "ti,palmas-usb-vid";
ti,enable-vbus-detection;
ti,enable-id-detection;
ti,wakeup;
+ id-gpios = <&palmas_gpio 0 GPIO_ACTIVE_HIGH>;
};
clk32kgaudio: palmas_clk32k@1 {
diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts
index a9765605d53b..b153f604932a 100644
--- a/arch/arm/boot/dts/omap5-cm-t54.dts
+++ b/arch/arm/boot/dts/omap5-cm-t54.dts
@@ -11,9 +11,9 @@
model = "CompuLab CM-T54";
compatible = "compulab,omap5-cm-t54", "ti,omap5";
- memory {
+ memory@80000000 {
device_type = "memory";
- reg = <0x80000000 0x7F000000>; /* 2048 MB */
+ reg = <0 0x80000000 0 0x7f000000>; /* 2048 MB */
};
aliases {
@@ -72,7 +72,7 @@
leds {
compatible = "gpio-leds";
- led@1 {
+ led1 {
label = "Heartbeat";
gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; /* gpio3_80 ACT_LED */
linux,default-trigger = "heartbeat";
diff --git a/arch/arm/boot/dts/omap5-igep0050.dts b/arch/arm/boot/dts/omap5-igep0050.dts
index f75ce02fb398..8fc19218057e 100644
--- a/arch/arm/boot/dts/omap5-igep0050.dts
+++ b/arch/arm/boot/dts/omap5-igep0050.dts
@@ -7,15 +7,47 @@
*/
/dts-v1/;
+#include <dt-bindings/input/input.h>
#include "omap5-board-common.dtsi"
/ {
model = "IGEPv5";
compatible = "isee,omap5-igep0050", "ti,omap5";
- memory {
+ memory@80000000 {
device_type = "memory";
- reg = <0x80000000 0x7f000000>; /* 2032 MB */
+ reg = <0x0 0x80000000 0 0x7f000000>; /* 2032 MB */
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&power_button_pin>;
+ pinctrl-names = "default";
+
+ power-button {
+ label = "Power Button";
+ linux,code = <KEY_POWER>;
+ gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ led@1 {
+ label = "board:green:usr0";
+ gpios = <&tca6416 1 0>;
+ default-state = "off";
+ };
+ led@2 {
+ label = "board:red:usr1";
+ gpios = <&tca6416 2 0>;
+ default-state = "off";
+ };
+ led@3 {
+ label = "board:blue:usr1";
+ gpios = <&tca6416 3 0>;
+ default-state = "off";
+ };
};
};
@@ -58,6 +90,12 @@
OMAP5_IOPAD(0x0fa, PIN_INPUT | MUX_MODE0) /* i2c4_sda */
>;
};
+
+ power_button_pin: pinctrl_power_button_pin {
+ pinctrl-single,pins = <
+ OMAP5_IOPAD(0x086, PIN_INPUT | MUX_MODE6) /* gpio4_118 */
+ >;
+ };
};
&tpd12s015 {
diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts
index a51e60518eb6..53d31a87b44b 100644
--- a/arch/arm/boot/dts/omap5-uevm.dts
+++ b/arch/arm/boot/dts/omap5-uevm.dts
@@ -13,9 +13,19 @@
model = "TI OMAP5 uEVM board";
compatible = "ti,omap5-uevm", "ti,omap5";
- memory {
+ memory@80000000 {
device_type = "memory";
- reg = <0x80000000 0x7F000000>; /* 2032 MB */
+ reg = <0 0x80000000 0 0x7f000000>; /* 2032 MB */
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ led1 {
+ label = "omap5:blue:usr1";
+ gpios = <&gpio5 25 GPIO_ACTIVE_HIGH>; /* gpio5_153 D1 LED */
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
};
};
@@ -61,3 +71,7 @@
OMAP5_IOPAD(0x1be, PIN_OUTPUT | MUX_MODE6) /* mcspi1_somi.gpio5_141 */
>;
};
+
+&wlcore {
+ compatible = "ti,wl1837";
+};
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 84c10195e79b..25262118ec3d 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -11,11 +11,9 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/omap.h>
-#include "skeleton.dtsi"
-
/ {
- #address-cells = <1>;
- #size-cells = <1>;
+ #address-cells = <2>;
+ #size-cells = <2>;
compatible = "ti,omap5";
interrupt-parent = <&wakeupgen>;
@@ -92,10 +90,10 @@
compatible = "arm,cortex-a15-gic";
interrupt-controller;
#interrupt-cells = <3>;
- reg = <0x48211000 0x1000>,
- <0x48212000 0x1000>,
- <0x48214000 0x2000>,
- <0x48216000 0x2000>;
+ reg = <0 0x48211000 0 0x1000>,
+ <0 0x48212000 0 0x1000>,
+ <0 0x48214000 0 0x2000>,
+ <0 0x48216000 0 0x2000>;
interrupt-parent = <&gic>;
};
@@ -103,7 +101,7 @@
compatible = "ti,omap5-wugen-mpu", "ti,omap4-wugen-mpu";
interrupt-controller;
#interrupt-cells = <3>;
- reg = <0x48281000 0x1000>;
+ reg = <0 0x48281000 0 0x1000>;
interrupt-parent = <&gic>;
};
@@ -131,11 +129,11 @@
compatible = "ti,omap5-l3-noc", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
- ranges;
+ ranges = <0 0 0 0xc0000000>;
ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3";
- reg = <0x44000000 0x2000>,
- <0x44800000 0x3000>,
- <0x45000000 0x4000>;
+ reg = <0 0x44000000 0 0x2000>,
+ <0 0x44800000 0 0x3000>,
+ <0 0x45000000 0 0x4000>;
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
@@ -865,7 +863,7 @@
#size-cells = <1>;
utmi-mode = <2>;
ranges;
- dwc3@4a030000 {
+ dwc3: dwc3@4a030000 {
compatible = "snps,dwc3";
reg = <0x4a030000 0x10000>;
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/arch/arm/boot/dts/orion5x-mv88f5181.dtsi b/arch/arm/boot/dts/orion5x-mv88f5181.dtsi
new file mode 100644
index 000000000000..f667012b26ca
--- /dev/null
+++ b/arch/arm/boot/dts/orion5x-mv88f5181.dtsi
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 Jamie Lentin <jm@lentin.co.uk>
+ *
+ * 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-88f5181", "marvell,orion5x";
+
+ soc {
+ compatible = "marvell,orion5x-88f5181-mbus", "simple-bus";
+
+ internal-regs {
+ pinctrl: pinctrl@10000 {
+ compatible = "marvell,88f5181-pinctrl";
+ reg = <0x10000 0x8>, <0x10050 0x4>;
+ };
+
+ core_clk: core-clocks@10030 {
+ compatible = "marvell,mv88f5181-core-clock";
+ reg = <0x10010 0x4>;
+ #clock-cells = <1>;
+ };
+
+ mbusc: mbus-controller@20000 {
+ compatible = "marvell,mbus-controller";
+ reg = <0x20000 0x100>, <0x1500 0x20>;
+ };
+ };
+ };
+};
+
+&pinctrl {
+ pmx_ge: pmx-ge {
+ marvell,pins = "mpp8", "mpp9", "mpp10", "mpp11",
+ "mpp12", "mpp13", "mpp14", "mpp15",
+ "mpp16", "mpp17", "mpp18", "mpp19";
+ marvell,function = "ge";
+ };
+};
+
+&eth {
+ pinctrl-0 = <&pmx_ge>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts b/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts
new file mode 100644
index 000000000000..9f6ae4e1de06
--- /dev/null
+++ b/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 Jamie Lentin <jm@lentin.co.uk>
+ *
+ * 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 "orion5x-mv88f5181.dtsi"
+
+/ {
+ model = "Netgear WNR854-t";
+ compatible = "netgear,wnr854t", "marvell,orion5x-88f5181",
+ "marvell,orion5x";
+ aliases {
+ serial0 = &uart0;
+ };
+
+ memory {
+ reg = <0x00000000 0x2000000>; /* 32 MB */
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000>,
+ <MBUS_ID(0x09, 0x00) 0 0xf2200000 0x800>,
+ <MBUS_ID(0x01, 0x0f) 0 0xf4000000 0x800000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&pmx_reset_button>;
+ pinctrl-names = "default";
+
+ reset {
+ label = "Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&pmx_power_led &pmx_power_led_blink &pmx_wan_led>;
+ pinctrl-names = "default";
+
+ led@0 {
+ label = "wnr854t:green:power";
+ gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+ };
+
+ led@1 {
+ label = "wnr854t:blink:power";
+ gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+ };
+
+ led@2 {
+ label = "wnr854t:green:wan";
+ gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&devbus_bootcs {
+ status = "okay";
+
+ devbus,keep-config;
+
+ flash@0 {
+ compatible = "cfi-flash";
+ reg = <0 0x800000>;
+ bank-width = <2>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "kernel";
+ reg = <0x0 0x100000>;
+ };
+
+ partition@100000 {
+ label = "rootfs";
+ reg = <0x100000 0x660000>;
+ };
+
+ partition@760000 {
+ label = "uboot_env";
+ reg = <0x760000 0x20000>;
+ };
+
+ partition@780000 {
+ label = "uboot";
+ reg = <0x780000 0x80000>;
+ read-only;
+ };
+ };
+ };
+};
+
+&mdio {
+ status = "okay";
+
+ switch: switch@0 {
+ compatible = "marvell,mv88e6085";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ dsa,member = <0 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "lan3";
+ phy-handle = <&lan3phy>;
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan4";
+ phy-handle = <&lan4phy>;
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "wan";
+ phy-handle = <&wanphy>;
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "cpu";
+ ethernet = <&ethport>;
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "lan1";
+ phy-handle = <&lan1phy>;
+ };
+
+ port@7 {
+ reg = <7>;
+ label = "lan2";
+ phy-handle = <&lan2phy>;
+ };
+ };
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ lan3phy: ethernet-phy@0 {
+ /* Marvell 88E1121R (port 1) */
+ compatible = "ethernet-phy-id0141.0cb0",
+ "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ marvell,reg-init = <3 16 0 0x1777 3 17 0 0x15>;
+ };
+
+ lan4phy: ethernet-phy@1 {
+ /* Marvell 88E1121R (port 2) */
+ compatible = "ethernet-phy-id0141.0cb0",
+ "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ marvell,reg-init = <3 16 0 0x1777 3 17 0 0x15>;
+ };
+
+ wanphy: ethernet-phy@2 {
+ /* Marvell 88E1121R (port 1) */
+ compatible = "ethernet-phy-id0141.0cb0",
+ "ethernet-phy-ieee802.3-c22";
+ reg = <2>;
+ marvell,reg-init = <3 16 0 0x1777 3 17 0 0x15>;
+ };
+
+ lan1phy: ethernet-phy@5 {
+ /* Marvell 88E1112 */
+ compatible = "ethernet-phy-id0141.0cb0",
+ "ethernet-phy-ieee802.3-c22";
+ reg = <5>;
+ marvell,reg-init = <3 16 0 0x1777 3 17 0 0x15>;
+ };
+
+ lan2phy: ethernet-phy@7 {
+ /* Marvell 88E1112 */
+ compatible = "ethernet-phy-id0141.0cb0",
+ "ethernet-phy-ieee802.3-c22";
+ reg = <7>;
+ marvell,reg-init = <3 16 0 0x1777 3 17 0 0x15>;
+ };
+ };
+ };
+};
+
+&eth {
+ status = "okay";
+
+ ethernet-port@0 {
+ /* Hardwired to DSA switch */
+ speed = <1000>;
+ duplex = <1>;
+ };
+};
+
+&pinctrl {
+ pinctrl-0 = <&pmx_pci_gpios>;
+ pinctrl-names = "default";
+
+ pmx_power_led: pmx-power-led {
+ marvell,pins = "mpp0";
+ marvell,function = "gpio";
+ };
+
+ pmx_reset_button: pmx-reset-button {
+ marvell,pins = "mpp1";
+ marvell,function = "gpio";
+ };
+
+ pmx_power_led_blink: pmx-power-led-blink {
+ marvell,pins = "mpp2";
+ marvell,function = "gpio";
+ };
+
+ pmx_wan_led: pmx-wan-led {
+ marvell,pins = "mpp3";
+ marvell,function = "gpio";
+ };
+
+ pmx_pci_gpios: pmx-pci-gpios {
+ marvell,pins = "mpp4";
+ marvell,function = "gpio";
+ };
+};
+
+&uart0 {
+ /* Pin 1: Tx, Pin 7: Rx, Pin 8: Gnd */
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi
index e1b6d2a2ac49..fbccfbbab223 100644
--- a/arch/arm/boot/dts/orion5x.dtsi
+++ b/arch/arm/boot/dts/orion5x.dtsi
@@ -144,9 +144,10 @@
wdt: wdt@20300 {
compatible = "marvell,orion-wdt";
- reg = <0x20300 0x28>;
+ reg = <0x20300 0x28>, <0x20108 0x4>;
interrupt-parent = <&bridge_intc>;
interrupts = <3>;
+ clocks = <&core_clk 0>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
index 0abc93e5bb00..6c0038398ef2 100644
--- a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
+++ b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
@@ -239,6 +239,45 @@
};
};
};
+
+ led@48 {
+ /*
+ * The keypad LED @0x48 is routed to
+ * the sensor board where it is
+ * connected to an infrared LED
+ * SFH4650 (60mW, @850nm) next to the
+ * ambient light and proximity sensor
+ * Capella Microsystems CM3605.
+ */
+ compatible = "qcom,pm8058-keypad-led";
+ reg = <0x48>;
+ label = "pm8058:infrared:proximitysensor";
+ default-state = "off";
+ };
+ led@131 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x131>;
+ label = "pm8058:red";
+ default-state = "off";
+ };
+ led@132 {
+ /*
+ * This is actually green too on my
+ * board, but documented as yellow.
+ */
+ compatible = "qcom,pm8058-led";
+ reg = <0x132>;
+ label = "pm8058:yellow";
+ default-state = "off";
+ linux,default-trigger = "mmc0";
+ };
+ led@133 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x133>;
+ label = "pm8058:green";
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
index 7b05f072bfc2..b72e09506448 100644
--- a/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
@@ -253,6 +253,7 @@
vddcx-supply = <&pm8921_s3>;
v3p3-supply = <&pm8921_l3>;
v1p8-supply = <&pm8921_l4>;
+ dr_mode = "otg";
};
gadget@12500000 {
@@ -272,5 +273,19 @@
vqmmc-supply = <&pm8921_s4>;
};
};
+
+ imem@2a03f000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x2a03f000 0x1000>;
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x65c>;
+
+ mode-normal = <0x77665501>;
+ mode-bootloader = <0x77665500>;
+ mode-recovery = <0x77665502>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 74a9b6c394f5..1dbe697b2e90 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -5,6 +5,7 @@
#include <dt-bindings/reset/qcom,gcc-msm8960.h>
#include <dt-bindings/clock/qcom,mmcc-msm8960.h>
#include <dt-bindings/soc/qcom,gsbi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
model = "Qualcomm APQ8064";
@@ -86,6 +87,92 @@
};
};
+ thermal-zones {
+ cpu-thermal0 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&gcc 7>;
+ coefficients = <1199 0>;
+
+ trips {
+ cpu_alert0: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit0: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal1 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&gcc 8>;
+ coefficients = <1132 0>;
+
+ trips {
+ cpu_alert1: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit1: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal2 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&gcc 9>;
+ coefficients = <1199 0>;
+
+ trips {
+ cpu_alert2: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit2: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal3 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&gcc 10>;
+ coefficients = <1132 0>;
+
+ trips {
+ cpu_alert3: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit3: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
cpu-pmu {
compatible = "qcom,krait-pmu";
interrupts = <1 10 0x304>;
@@ -559,22 +646,50 @@
compatible = "qcom,pm8921-gpio",
"qcom,ssbi-gpio";
reg = <0x150>;
- interrupts = <192 1>, <193 1>, <194 1>,
- <195 1>, <196 1>, <197 1>,
- <198 1>, <199 1>, <200 1>,
- <201 1>, <202 1>, <203 1>,
- <204 1>, <205 1>, <206 1>,
- <207 1>, <208 1>, <209 1>,
- <210 1>, <211 1>, <212 1>,
- <213 1>, <214 1>, <215 1>,
- <216 1>, <217 1>, <218 1>,
- <219 1>, <220 1>, <221 1>,
- <222 1>, <223 1>, <224 1>,
- <225 1>, <226 1>, <227 1>,
- <228 1>, <229 1>, <230 1>,
- <231 1>, <232 1>, <233 1>,
- <234 1>, <235 1>;
-
+ interrupts = <192 IRQ_TYPE_NONE>,
+ <193 IRQ_TYPE_NONE>,
+ <194 IRQ_TYPE_NONE>,
+ <195 IRQ_TYPE_NONE>,
+ <196 IRQ_TYPE_NONE>,
+ <197 IRQ_TYPE_NONE>,
+ <198 IRQ_TYPE_NONE>,
+ <199 IRQ_TYPE_NONE>,
+ <200 IRQ_TYPE_NONE>,
+ <201 IRQ_TYPE_NONE>,
+ <202 IRQ_TYPE_NONE>,
+ <203 IRQ_TYPE_NONE>,
+ <204 IRQ_TYPE_NONE>,
+ <205 IRQ_TYPE_NONE>,
+ <206 IRQ_TYPE_NONE>,
+ <207 IRQ_TYPE_NONE>,
+ <208 IRQ_TYPE_NONE>,
+ <209 IRQ_TYPE_NONE>,
+ <210 IRQ_TYPE_NONE>,
+ <211 IRQ_TYPE_NONE>,
+ <212 IRQ_TYPE_NONE>,
+ <213 IRQ_TYPE_NONE>,
+ <214 IRQ_TYPE_NONE>,
+ <215 IRQ_TYPE_NONE>,
+ <216 IRQ_TYPE_NONE>,
+ <217 IRQ_TYPE_NONE>,
+ <218 IRQ_TYPE_NONE>,
+ <219 IRQ_TYPE_NONE>,
+ <220 IRQ_TYPE_NONE>,
+ <221 IRQ_TYPE_NONE>,
+ <222 IRQ_TYPE_NONE>,
+ <223 IRQ_TYPE_NONE>,
+ <224 IRQ_TYPE_NONE>,
+ <225 IRQ_TYPE_NONE>,
+ <226 IRQ_TYPE_NONE>,
+ <227 IRQ_TYPE_NONE>,
+ <228 IRQ_TYPE_NONE>,
+ <229 IRQ_TYPE_NONE>,
+ <230 IRQ_TYPE_NONE>,
+ <231 IRQ_TYPE_NONE>,
+ <232 IRQ_TYPE_NONE>,
+ <233 IRQ_TYPE_NONE>,
+ <234 IRQ_TYPE_NONE>,
+ <235 IRQ_TYPE_NONE>;
gpio-controller;
#gpio-cells = <2>;
@@ -587,9 +702,18 @@
gpio-controller;
#gpio-cells = <2>;
interrupts =
- <128 1>, <129 1>, <130 1>, <131 1>,
- <132 1>, <133 1>, <134 1>, <135 1>,
- <136 1>, <137 1>, <138 1>, <139 1>;
+ <128 IRQ_TYPE_NONE>,
+ <129 IRQ_TYPE_NONE>,
+ <130 IRQ_TYPE_NONE>,
+ <131 IRQ_TYPE_NONE>,
+ <132 IRQ_TYPE_NONE>,
+ <133 IRQ_TYPE_NONE>,
+ <134 IRQ_TYPE_NONE>,
+ <135 IRQ_TYPE_NONE>,
+ <136 IRQ_TYPE_NONE>,
+ <137 IRQ_TYPE_NONE>,
+ <138 IRQ_TYPE_NONE>,
+ <139 IRQ_TYPE_NONE>;
};
rtc@11d {
@@ -611,11 +735,28 @@
};
};
+ qfprom: qfprom@700000 {
+ compatible = "qcom,qfprom";
+ reg = <0x00700000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ tsens_calib: calib {
+ reg = <0x404 0x10>;
+ };
+ tsens_backup: backup_calib {
+ reg = <0x414 0x10>;
+ };
+ };
+
gcc: clock-controller@900000 {
compatible = "qcom,gcc-apq8064";
reg = <0x00900000 0x4000>;
+ nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
#clock-cells = <1>;
#reset-cells = <1>;
+ #thermal-sensor-cells = <1>;
};
lcc: clock-controller@28000000 {
@@ -712,7 +853,6 @@
reg = <0x12500000 0x400>;
interrupts = <GIC_SPI 100 IRQ_TYPE_NONE>;
status = "disabled";
- dr_mode = "host";
clocks = <&gcc USB_HS1_XCVR_CLK>,
<&gcc USB_HS1_H_CLK>;
diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi
index 7c2df062a025..39eb7a4ed16a 100644
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -94,6 +94,88 @@
};
};
+ thermal-zones {
+ cpu-thermal0 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 5>;
+
+ trips {
+ cpu_alert0: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit0: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal1 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 6>;
+
+ trips {
+ cpu_alert1: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit1: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal2 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 7>;
+
+ trips {
+ cpu_alert2: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit2: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal3 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 8>;
+
+ trips {
+ cpu_alert3: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit3: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
cpu-pmu {
compatible = "qcom,krait-pmu";
interrupts = <1 7 0xf04>;
@@ -150,6 +232,27 @@
reg = <0xf9011000 0x1000>;
};
+ qfprom: qfprom@fc4bc000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qfprom";
+ reg = <0xfc4bc000 0x1000>;
+ tsens_calib: calib@d0 {
+ reg = <0xd0 0x18>;
+ };
+ tsens_backup: backup@440 {
+ reg = <0x440 0x10>;
+ };
+ };
+
+ tsens: thermal-sensor@fc4a8000 {
+ compatible = "qcom,msm8974-tsens";
+ reg = <0xfc4a8000 0x2000>;
+ nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ #thermal-sensor-cells = <1>;
+ };
+
timer@f9020000 {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
index d501382493e3..348503d1a1c1 100644
--- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
@@ -95,6 +95,7 @@
};
sata@29000000 {
+ ports-implemented = <0x1>;
status = "ok";
};
};
diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi
index acbe71febe13..8c65e0d82559 100644
--- a/arch/arm/boot/dts/qcom-msm8660.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8660.dtsi
@@ -2,6 +2,7 @@
/include/ "skeleton.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8660.h>
#include <dt-bindings/soc/qcom,gsbi.h>
@@ -159,21 +160,50 @@
"qcom,ssbi-gpio";
reg = <0x150>;
interrupt-parent = <&pmicintc>;
- interrupts = <192 1>, <193 1>, <194 1>,
- <195 1>, <196 1>, <197 1>,
- <198 1>, <199 1>, <200 1>,
- <201 1>, <202 1>, <203 1>,
- <204 1>, <205 1>, <206 1>,
- <207 1>, <208 1>, <209 1>,
- <210 1>, <211 1>, <212 1>,
- <213 1>, <214 1>, <215 1>,
- <216 1>, <217 1>, <218 1>,
- <219 1>, <220 1>, <221 1>,
- <222 1>, <223 1>, <224 1>,
- <225 1>, <226 1>, <227 1>,
- <228 1>, <229 1>, <230 1>,
- <231 1>, <232 1>, <233 1>,
- <234 1>, <235 1>;
+ interrupts = <192 IRQ_TYPE_NONE>,
+ <193 IRQ_TYPE_NONE>,
+ <194 IRQ_TYPE_NONE>,
+ <195 IRQ_TYPE_NONE>,
+ <196 IRQ_TYPE_NONE>,
+ <197 IRQ_TYPE_NONE>,
+ <198 IRQ_TYPE_NONE>,
+ <199 IRQ_TYPE_NONE>,
+ <200 IRQ_TYPE_NONE>,
+ <201 IRQ_TYPE_NONE>,
+ <202 IRQ_TYPE_NONE>,
+ <203 IRQ_TYPE_NONE>,
+ <204 IRQ_TYPE_NONE>,
+ <205 IRQ_TYPE_NONE>,
+ <206 IRQ_TYPE_NONE>,
+ <207 IRQ_TYPE_NONE>,
+ <208 IRQ_TYPE_NONE>,
+ <209 IRQ_TYPE_NONE>,
+ <210 IRQ_TYPE_NONE>,
+ <211 IRQ_TYPE_NONE>,
+ <212 IRQ_TYPE_NONE>,
+ <213 IRQ_TYPE_NONE>,
+ <214 IRQ_TYPE_NONE>,
+ <215 IRQ_TYPE_NONE>,
+ <216 IRQ_TYPE_NONE>,
+ <217 IRQ_TYPE_NONE>,
+ <218 IRQ_TYPE_NONE>,
+ <219 IRQ_TYPE_NONE>,
+ <220 IRQ_TYPE_NONE>,
+ <221 IRQ_TYPE_NONE>,
+ <222 IRQ_TYPE_NONE>,
+ <223 IRQ_TYPE_NONE>,
+ <224 IRQ_TYPE_NONE>,
+ <225 IRQ_TYPE_NONE>,
+ <226 IRQ_TYPE_NONE>,
+ <227 IRQ_TYPE_NONE>,
+ <228 IRQ_TYPE_NONE>,
+ <229 IRQ_TYPE_NONE>,
+ <230 IRQ_TYPE_NONE>,
+ <231 IRQ_TYPE_NONE>,
+ <232 IRQ_TYPE_NONE>,
+ <233 IRQ_TYPE_NONE>,
+ <234 IRQ_TYPE_NONE>,
+ <235 IRQ_TYPE_NONE>;
gpio-controller;
#gpio-cells = <2>;
@@ -187,9 +217,18 @@
#gpio-cells = <2>;
interrupt-parent = <&pmicintc>;
interrupts =
- <128 1>, <129 1>, <130 1>, <131 1>,
- <132 1>, <133 1>, <134 1>, <135 1>,
- <136 1>, <137 1>, <138 1>, <139 1>;
+ <128 IRQ_TYPE_NONE>,
+ <129 IRQ_TYPE_NONE>,
+ <130 IRQ_TYPE_NONE>,
+ <131 IRQ_TYPE_NONE>,
+ <132 IRQ_TYPE_NONE>,
+ <133 IRQ_TYPE_NONE>,
+ <134 IRQ_TYPE_NONE>,
+ <135 IRQ_TYPE_NONE>,
+ <136 IRQ_TYPE_NONE>,
+ <137 IRQ_TYPE_NONE>,
+ <138 IRQ_TYPE_NONE>,
+ <139 IRQ_TYPE_NONE>;
};
pwrkey@1c {
diff --git a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
new file mode 100644
index 000000000000..c0fb4a698c56
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
@@ -0,0 +1,262 @@
+#include "qcom-msm8974.dtsi"
+#include "qcom-pm8841.dtsi"
+#include "qcom-pm8941.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+/ {
+ model = "LGE MSM 8974 HAMMERHEAD";
+ compatible = "lge,hammerhead", "qcom,msm8974";
+
+ aliases {
+ serial0 = &blsp1_uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ smd {
+ rpm {
+ rpm_requests {
+ pm8841-regulators {
+ s1 {
+ regulator-min-microvolt = <675000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ s2 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ s3 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ s4 {
+ regulator-min-microvolt = <815000>;
+ regulator-max-microvolt = <900000>;
+ };
+ };
+
+ pm8941-regulators {
+ vdd_l1_l3-supply = <&pm8941_s1>;
+ vdd_l2_lvs1_2_3-supply = <&pm8941_s3>;
+ vdd_l4_l11-supply = <&pm8941_s1>;
+ vdd_l5_l7-supply = <&pm8941_s2>;
+ vdd_l6_l12_l14_l15-supply = <&pm8941_s2>;
+ vdd_l8_l16_l18_l19-supply = <&vreg_vph_pwr>;
+ vdd_l9_l10_l17_l22-supply = <&vreg_boost>;
+ vdd_l13_l20_l23_l24-supply = <&vreg_boost>;
+ vdd_l21-supply = <&vreg_boost>;
+
+ s1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ s2 {
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+
+ regulator-boot-on;
+ };
+
+ s3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ l3 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ l4 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-boot-on;
+ };
+
+ l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-boot-on;
+ };
+
+ l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ l11 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ l15 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ l16 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ l18 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ l19 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ l20 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ l21 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+
+ regulator-boot-on;
+ };
+
+ l22 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ l23 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ l24 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+
+ regulator-boot-on;
+ };
+ };
+ };
+ };
+ };
+};
+
+&soc {
+ serial@f991d000 {
+ status = "ok";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_keys_pin_a>;
+
+ volume-up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEUP>;
+ };
+
+ volume-down {
+ label = "volume_down";
+ gpios = <&pm8941_gpios 3 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ };
+ };
+};
+
+&spmi_bus {
+ pm8941@0 {
+ gpios@c000 {
+ gpio_keys_pin_a: gpio-keys-active {
+ pins = "gpio2", "gpio3";
+ function = "normal";
+
+ bias-pull-up;
+ power-source = <PM8941_GPIO_S3>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts
index 3fb4dada6b0d..e7c1577d56f4 100644
--- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts
@@ -257,23 +257,6 @@
};
};
};
-
- vreg_boost: vreg-boost {
- compatible = "regulator-fixed";
-
- regulator-name = "vreg-boost";
- regulator-min-microvolt = <3150000>;
- regulator-max-microvolt = <3150000>;
-
- regulator-always-on;
- regulator-boot-on;
-
- gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>;
- enable-active-high;
-
- pinctrl-names = "default";
- pinctrl-0 = <&boost_bypass_n_pin>;
- };
};
&soc {
@@ -311,6 +294,45 @@
pinctrl-0 = <&blsp1_uart2_pin_a>;
};
+ i2c@f9924000 {
+ status = "ok";
+
+ clock-frequency = <355000>;
+ qcom,src-freq = <50000000>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+
+ synaptics@2c {
+ compatible = "syna,rmi4-i2c";
+ reg = <0x2c>;
+
+ interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vdd-supply = <&pm8941_l22>;
+ vio-supply = <&pm8941_lvs3>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_int_pin>;
+
+ syna,startup-delay-ms = <10>;
+
+ rmi4-f01@1 {
+ reg = <0x1>;
+ syna,nosleep-mode = <1>;
+ };
+
+ rmi4-f11@11 {
+ reg = <0x11>;
+ touchscreen-inverted-x;
+ syna,sensor-type = <1>;
+ };
+ };
+ };
+
pinctrl@fd510000 {
blsp1_uart2_pin_a: blsp1-uart2-pin-active {
rx {
@@ -330,6 +352,16 @@
};
};
+ i2c2_pins: i2c2 {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c2";
+
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
sdhc1_pin_a: sdhc1-pin-active {
clk {
pins = "sdc1_clk";
@@ -366,6 +398,16 @@
};
};
+ ts_int_pin: touch-int {
+ pin {
+ pins = "gpio61";
+ function = "gpio";
+
+ drive-strength = <2>;
+ bias-disable;
+ input-enable;
+ };
+ };
};
dma-controller@f9944000 {
@@ -387,11 +429,6 @@
};
gpios@c000 {
- boost_bypass_n_pin: boost-bypass {
- pins = "gpio21";
- function = "normal";
- };
-
gpio_keys_pin_a: gpio-keys-active {
pins = "gpio2", "gpio3", "gpio4", "gpio5";
function = "normal";
diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 561d4d136762..d2109475bdfd 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -2,6 +2,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8974.h>
+#include <dt-bindings/gpio/gpio.h>
#include "skeleton.dtsi"
/ {
@@ -131,6 +132,88 @@
};
};
+ thermal-zones {
+ cpu-thermal0 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 5>;
+
+ trips {
+ cpu_alert0: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit0: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal1 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 6>;
+
+ trips {
+ cpu_alert1: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit1: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal2 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 7>;
+
+ trips {
+ cpu_alert2: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit2: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal3 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 8>;
+
+ trips {
+ cpu_alert3: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit3: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
cpu-pmu {
compatible = "qcom,krait-pmu";
interrupts = <1 7 0xf04>;
@@ -287,6 +370,27 @@
reg = <0xf9011000 0x1000>;
};
+ qfprom: qfprom@fc4bc000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qfprom";
+ reg = <0xfc4bc000 0x1000>;
+ tsens_calib: calib@d0 {
+ reg = <0xd0 0x18>;
+ };
+ tsens_backup: backup@440 {
+ reg = <0x440 0x10>;
+ };
+ };
+
+ tsens: thermal-sensor@fc4a8000 {
+ compatible = "qcom,msm8974-tsens";
+ reg = <0xfc4a8000 0x2000>;
+ nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ #thermal-sensor-cells = <1>;
+ };
+
timer@f9020000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -430,6 +534,15 @@
reg = <0xfc428000 0x4000>;
};
+ blsp1_uart1: serial@f991d000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0xf991d000 0x1000>;
+ interrupts = <0 107 0x0>;
+ clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
blsp1_uart2: serial@f991e000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xf991e000 0x1000>;
@@ -615,4 +728,30 @@
};
};
};
+
+ vreg_boost: vreg-boost {
+ compatible = "regulator-fixed";
+
+ regulator-name = "vreg-boost";
+ regulator-min-microvolt = <3150000>;
+ regulator-max-microvolt = <3150000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+
+ gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&boost_bypass_n_pin>;
+ };
+ vreg_vph_pwr: vreg-vph-pwr {
+ compatible = "regulator-fixed";
+ regulator-name = "vph-pwr";
+
+ regulator-min-microvolt = <3600000>;
+ regulator-max-microvolt = <3600000>;
+
+ regulator-always-on;
+ };
};
diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi
index d95edb6f6265..f8eb5e31c920 100644
--- a/arch/arm/boot/dts/qcom-pm8941.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8941.dtsi
@@ -88,6 +88,11 @@
<0 0xe1 0 IRQ_TYPE_NONE>,
<0 0xe2 0 IRQ_TYPE_NONE>,
<0 0xe3 0 IRQ_TYPE_NONE>;
+
+ boost_bypass_n_pin: boost-bypass {
+ pins = "gpio21";
+ function = "normal";
+ };
};
pm8941_mpps: mpps@a000 {
diff --git a/arch/arm/boot/dts/r7s72100-rskrza1.dts b/arch/arm/boot/dts/r7s72100-rskrza1.dts
new file mode 100644
index 000000000000..e5dea5bb4032
--- /dev/null
+++ b/arch/arm/boot/dts/r7s72100-rskrza1.dts
@@ -0,0 +1,61 @@
+/*
+ * Device Tree Source for the RZ/A1H RSK board
+ *
+ * Copyright (C) 2016 Renesas Electronics
+ *
+ * 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 "r7s72100.dtsi"
+
+/ {
+ model = "RSKRZA1";
+ compatible = "renesas,rskrza1", "renesas,r7s72100";
+
+ aliases {
+ serial0 = &scif2;
+ };
+
+ chosen {
+ bootargs = "ignore_loglevel";
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@8000000 {
+ device_type = "memory";
+ reg = <0x08000000 0x02000000>;
+ };
+
+ lbsc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+};
+
+&extal_clk {
+ clock-frequency = <13330000>;
+};
+
+&usb_x1_clk {
+ clock-frequency = <48000000>;
+};
+
+&mtu2 {
+ status = "okay";
+};
+
+&ether {
+ status = "okay";
+ renesas,no-ether-link;
+ phy-handle = <&phy0>;
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+};
+
+&scif2 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
index e8e2a5d71976..fb9ef9ca120e 100644
--- a/arch/arm/boot/dts/r7s72100.dtsi
+++ b/arch/arm/boot/dts/r7s72100.dtsi
@@ -108,6 +108,15 @@
clock-output-names = "scif0", "scif1", "scif2", "scif3", "scif4", "scif5", "scif6", "scif7";
};
+ mstp7_clks: mstp7_clks@fcfe0430 {
+ #clock-cells = <1>;
+ compatible = "renesas,r7s72100-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0xfcfe0430 4>;
+ clocks = <&p0_clk>;
+ clock-indices = <R7S72100_CLK_ETHER>;
+ clock-output-names = "ether";
+ };
+
mstp9_clks: mstp9_clks@fcfe0438 {
#clock-cells = <1>;
compatible = "renesas,r7s72100-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -419,4 +428,17 @@
power-domains = <&cpg_clocks>;
status = "disabled";
};
+
+ ether: ethernet@e8203000 {
+ compatible = "renesas,ether-r7s72100";
+ reg = <0xe8203000 0x800>,
+ <0xe8204800 0x200>;
+ interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R7S72100_CLK_ETHER>;
+ power-domains = <&cpg_clocks>;
+ phy-mode = "mii";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index d18558f21102..351fcc2f87df 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -944,11 +944,6 @@
interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_VSP1_R>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-
- renesas,has-sru;
- renesas,#rpf = <5>;
- renesas,#uds = <1>;
- renesas,#wpf = <4>;
};
vsp1@fe928000 {
@@ -957,12 +952,6 @@
interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-
- renesas,has-lut;
- renesas,has-sru;
- renesas,#rpf = <5>;
- renesas,#uds = <3>;
- renesas,#wpf = <4>;
};
vsp1@fe930000 {
@@ -971,12 +960,6 @@
interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU0>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-
- renesas,has-lif;
- renesas,has-lut;
- renesas,#rpf = <4>;
- renesas,#uds = <1>;
- renesas,#wpf = <4>;
};
vsp1@fe938000 {
@@ -985,12 +968,6 @@
interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU1>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-
- renesas,has-lif;
- renesas,has-lut;
- renesas,#rpf = <4>;
- renesas,#uds = <1>;
- renesas,#wpf = <4>;
};
du: display@feb00000 {
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 8f0086bbd96b..162b55c665a3 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -983,12 +983,6 @@
interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7791_CLK_VSP1_S>;
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-
- renesas,has-lut;
- renesas,has-sru;
- renesas,#rpf = <5>;
- renesas,#uds = <3>;
- renesas,#wpf = <4>;
};
vsp1@fe930000 {
@@ -997,12 +991,6 @@
interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU0>;
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-
- renesas,has-lif;
- renesas,has-lut;
- renesas,#rpf = <4>;
- renesas,#uds = <1>;
- renesas,#wpf = <4>;
};
vsp1@fe938000 {
@@ -1011,12 +999,6 @@
interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU1>;
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-
- renesas,has-lif;
- renesas,has-lut;
- renesas,#rpf = <4>;
- renesas,#uds = <1>;
- renesas,#wpf = <4>;
};
du: display@feb00000 {
diff --git a/arch/arm/boot/dts/r8a7792-blanche.dts b/arch/arm/boot/dts/r8a7792-blanche.dts
index e7b40f0e7da6..f3ea43b7b724 100644
--- a/arch/arm/boot/dts/r8a7792-blanche.dts
+++ b/arch/arm/boot/dts/r8a7792-blanche.dts
@@ -11,6 +11,8 @@
/dts-v1/;
#include "r8a7792.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
/ {
model = "Blanche";
@@ -50,6 +52,139 @@
reg-io-width = <4>;
vddvario-supply = <&d3_3v>;
vdd33a-supply = <&d3_3v>;
+
+ pinctrl-0 = <&lan89218_pins>;
+ pinctrl-names = "default";
+ };
+
+ vga-encoder {
+ compatible = "adi,adv7123";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7123_in: endpoint {
+ remote-endpoint = <&du_out_rgb1>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ adv7123_out: endpoint {
+ remote-endpoint = <&vga_in>;
+ };
+ };
+ };
+ };
+
+ hdmi-out {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con: endpoint {
+ remote-endpoint = <&adv7511_out>;
+ };
+ };
+ };
+
+ vga {
+ compatible = "vga-connector";
+
+ port {
+ vga_in: endpoint {
+ remote-endpoint = <&adv7123_out>;
+ };
+ };
+ };
+
+ x1_clk: x1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <74250000>;
+ };
+
+ x2_clk: x2 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <65000000>;
+ };
+
+ keyboard {
+ compatible = "gpio-keys";
+
+ key-1 {
+ linux,code = <KEY_1>;
+ label = "SW2-1";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
+ };
+ key-2 {
+ linux,code = <KEY_2>;
+ label = "SW2-2";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio3 11 GPIO_ACTIVE_LOW>;
+ };
+ key-3 {
+ linux,code = <KEY_3>;
+ label = "SW2-3";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
+ };
+ key-4 {
+ linux,code = <KEY_4>;
+ label = "SW2-4";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
+ };
+ key-a {
+ linux,code = <KEY_A>;
+ label = "SW24";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+ };
+ key-b {
+ linux,code = <KEY_B>;
+ label = "SW25";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio11 2 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led17 {
+ gpios = <&gpio10 10 GPIO_ACTIVE_HIGH>;
+ };
+ led18 {
+ gpios = <&gpio10 11 GPIO_ACTIVE_HIGH>;
+ };
+ led19 {
+ gpios = <&gpio10 12 GPIO_ACTIVE_HIGH>;
+ };
+ led20 {
+ gpios = <&gpio10 23 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ vcc_sdhi0: regulator-vcc-sdhi0 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI0 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&gpio11 12 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
};
};
@@ -57,10 +192,139 @@
clock-frequency = <20000000>;
};
+&can_clk {
+ clock-frequency = <48000000>;
+};
+
+&pfc {
+ scif0_pins: scif0 {
+ groups = "scif0_data";
+ function = "scif0";
+ };
+
+ scif3_pins: scif3 {
+ groups = "scif3_data";
+ function = "scif3";
+ };
+
+ lan89218_pins: lan89218 {
+ intc {
+ groups = "intc_irq0";
+ function = "intc";
+ };
+ lbsc {
+ groups = "lbsc_ex_cs0";
+ function = "lbsc";
+ };
+ };
+
+ can0_pins: can0 {
+ groups = "can0_data", "can_clk";
+ function = "can0";
+ };
+
+ sdhi0_pins: sdhi0 {
+ groups = "sdhi0_data4", "sdhi0_ctrl";
+ function = "sdhi0";
+ };
+
+ du0_pins: du0 {
+ groups = "du0_rgb888", "du0_sync", "du0_disp";
+ function = "du0";
+ };
+
+ du1_pins: du1 {
+ groups = "du1_rgb666", "du1_sync", "du1_disp";
+ function = "du1";
+ };
+};
+
&scif0 {
+ pinctrl-0 = <&scif0_pins>;
+ pinctrl-names = "default";
+
status = "okay";
};
&scif3 {
+ pinctrl-0 = <&scif3_pins>;
+ pinctrl-names = "default";
+
status = "okay";
};
+
+&can0 {
+ pinctrl-0 = <&can0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&sdhi0 {
+ pinctrl-0 = <&sdhi0_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi0>;
+ cd-gpios = <&gpio11 11 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ hdmi@39 {
+ compatible = "adi,adv7511w";
+ reg = <0x39>;
+ interrupt-parent = <&irqc>;
+ interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+
+ adi,input-depth = <8>;
+ adi,input-colorspace = "rgb";
+ adi,input-clock = "1x";
+ adi,input-style = <1>;
+ adi,input-justification = "evenly";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7511_in: endpoint {
+ remote-endpoint = <&du_out_rgb0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ adv7511_out: endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+};
+
+&du {
+ pinctrl-0 = <&du0_pins &du1_pins>;
+ pinctrl-names = "default";
+
+ clocks = <&mstp7_clks R8A7792_CLK_DU0>, <&mstp7_clks R8A7792_CLK_DU1>,
+ <&x1_clk>, <&x2_clk>;
+ clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1";
+ status = "okay";
+
+ ports {
+ port@0 {
+ endpoint {
+ remote-endpoint = <&adv7511_in>;
+ };
+ };
+ port@1 {
+ endpoint {
+ remote-endpoint = <&adv7123_in>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/r8a7792-wheat.dts b/arch/arm/boot/dts/r8a7792-wheat.dts
new file mode 100644
index 000000000000..6dbb94114a93
--- /dev/null
+++ b/arch/arm/boot/dts/r8a7792-wheat.dts
@@ -0,0 +1,199 @@
+/*
+ * Device Tree Source for the Wheat board
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016 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 "r8a7792.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Wheat";
+ compatible = "renesas,wheat", "renesas,r8a7792";
+
+ aliases {
+ serial0 = &scif0;
+ };
+
+ chosen {
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@40000000 {
+ device_type = "memory";
+ reg = <0 0x40000000 0 0x40000000>;
+ };
+
+ d3_3v: regulator-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "D3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ethernet@18000000 {
+ compatible = "smsc,lan89218", "smsc,lan9115";
+ reg = <0 0x18000000 0 0x100>;
+ phy-mode = "mii";
+ interrupt-parent = <&irqc>;
+ interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+ smsc,irq-push-pull;
+ smsc,save-mac-address;
+ reg-io-width = <4>;
+ vddvario-supply = <&d3_3v>;
+ vdd33a-supply = <&d3_3v>;
+
+ pinctrl-0 = <&lan89218_pins>;
+ pinctrl-names = "default";
+ };
+
+ keyboard {
+ compatible = "gpio-keys";
+
+ key-a {
+ linux,code = <KEY_A>;
+ label = "SW2";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+ };
+ key-b {
+ linux,code = <KEY_B>;
+ label = "SW3";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio11 2 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ vcc_sdhi0: regulator-vcc-sdhi0 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI0 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&gpio11 12 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&extal_clk {
+ clock-frequency = <20000000>;
+};
+
+&pfc {
+ scif0_pins: scif0 {
+ groups = "scif0_data";
+ function = "scif0";
+ };
+
+ lan89218_pins: lan89218 {
+ intc {
+ groups = "intc_irq0";
+ function = "intc";
+ };
+ lbsc {
+ groups = "lbsc_ex_cs0";
+ function = "lbsc";
+ };
+ };
+
+ can0_pins: can0 {
+ groups = "can0_data";
+ function = "can0";
+ };
+
+ can1_pins: can1 {
+ groups = "can1_data";
+ function = "can1";
+ };
+
+ sdhi0_pins: sdhi0 {
+ groups = "sdhi0_data4", "sdhi0_ctrl";
+ function = "sdhi0";
+ };
+
+ qspi_pins: qspi {
+ groups = "qspi_ctrl", "qspi_data4";
+ function = "qspi";
+ };
+};
+
+&scif0 {
+ pinctrl-0 = <&scif0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&can0 {
+ pinctrl-0 = <&can0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&can1 {
+ pinctrl-0 = <&can1_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&sdhi0 {
+ pinctrl-0 = <&sdhi0_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi0>;
+ cd-gpios = <&gpio11 11 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&qspi {
+ pinctrl-0 = <&qspi_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ flash@0 {
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <30000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ spi-cpol;
+ spi-cpha;
+ m25p,fast-read;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "loader";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash";
+ reg = <0x00440000 0x03bc0000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi
index 3fd61d7ab906..713141d38b3e 100644
--- a/arch/arm/boot/dts/r8a7792.dtsi
+++ b/arch/arm/boot/dts/r8a7792.dtsi
@@ -18,6 +18,22 @@
#address-cells = <2>;
#size-cells = <2>;
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ spi0 = &qspi;
+ vin0 = &vin0;
+ vin1 = &vin1;
+ vin2 = &vin2;
+ vin3 = &vin3;
+ vin4 = &vin4;
+ vin5 = &vin5;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -108,6 +124,179 @@
#power-domain-cells = <1>;
};
+ pfc: pin-controller@e6060000 {
+ compatible = "renesas,pfc-r8a7792";
+ reg = <0 0xe6060000 0 0x144>;
+ };
+
+ gpio0: gpio@e6050000 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6050000 0 0x50>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 0 29>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO0>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio1: gpio@e6051000 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6051000 0 0x50>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 32 23>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO1>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio2: gpio@e6052000 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6052000 0 0x50>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 64 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO2>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio3: gpio@e6053000 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6053000 0 0x50>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 96 28>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO3>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio4: gpio@e6054000 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6054000 0 0x50>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 128 17>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO4>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio5: gpio@e6055000 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055000 0 0x50>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 160 17>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO5>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio6: gpio@e6055100 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055100 0 0x50>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 192 17>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO6>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio7: gpio@e6055200 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055200 0 0x50>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 224 17>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO7>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio8: gpio@e6055300 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055300 0 0x50>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 256 17>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO8>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio9: gpio@e6055400 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055400 0 0x50>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 288 17>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO9>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio10: gpio@e6055500 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055500 0 0x50>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 320 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO10>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ gpio11: gpio@e6055600 {
+ compatible = "renesas,gpio-r8a7792",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055600 0 0x50>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 352 30>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7792_CLK_GPIO11>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
dmac0: dma-controller@e6700000 {
compatible = "renesas,dmac-r8a7792",
"renesas,rcar-dmac";
@@ -262,6 +451,18 @@
status = "disabled";
};
+ sdhi0: sd@ee100000 {
+ compatible = "renesas,sdhi-r8a7792";
+ reg = <0 0xee100000 0 0x328>;
+ interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+ <&dmac1 0xcd>, <&dmac1 0xce>;
+ dma-names = "tx", "rx", "tx", "rx";
+ clocks = <&mstp3_clks R8A7792_CLK_SDHI0>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
jpu: jpeg-codec@fe980000 {
compatible = "renesas,jpu-r8a7792",
"renesas,rcar-gen2-jpu";
@@ -271,6 +472,242 @@
power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
};
+ avb: ethernet@e6800000 {
+ compatible = "renesas,etheravb-r8a7792",
+ "renesas,etheravb-rcar-gen2";
+ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+ interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_ETHERAVB>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ /* I2C doesn't need pinmux */
+ i2c0: i2c@e6508000 {
+ compatible = "renesas,i2c-r8a7792";
+ reg = <0 0xe6508000 0 0x40>;
+ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_I2C0>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ i2c-scl-internal-delay-ns = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@e6518000 {
+ compatible = "renesas,i2c-r8a7792";
+ reg = <0 0xe6518000 0 0x40>;
+ interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_I2C1>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ i2c-scl-internal-delay-ns = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@e6530000 {
+ compatible = "renesas,i2c-r8a7792";
+ reg = <0 0xe6530000 0 0x40>;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_I2C2>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ i2c-scl-internal-delay-ns = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@e6540000 {
+ compatible = "renesas,i2c-r8a7792";
+ reg = <0 0xe6540000 0 0x40>;
+ interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_I2C3>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ i2c-scl-internal-delay-ns = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@e6520000 {
+ compatible = "renesas,i2c-r8a7792";
+ reg = <0 0xe6520000 0 0x40>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_I2C4>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ i2c-scl-internal-delay-ns = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@e6528000 {
+ compatible = "renesas,i2c-r8a7792";
+ reg = <0 0xe6528000 0 0x40>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_I2C5>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ i2c-scl-internal-delay-ns = <110>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ qspi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7792", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_QSPI_MOD>;
+ dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+ <&dmac1 0x17>, <&dmac1 0x18>;
+ dma-names = "tx", "rx", "tx", "rx";
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ du: display@feb00000 {
+ compatible = "renesas,du-r8a7792";
+ reg = <0 0xfeb00000 0 0x40000>;
+ reg-names = "du";
+ interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7792_CLK_DU0>,
+ <&mstp7_clks R8A7792_CLK_DU1>;
+ clock-names = "du.0", "du.1";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb0: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_rgb1: endpoint {
+ };
+ };
+ };
+ };
+
+ can0: can@e6e80000 {
+ compatible = "renesas,can-r8a7792",
+ "renesas,rcar-gen2-can";
+ reg = <0 0xe6e80000 0 0x1000>;
+ interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_CAN0>,
+ <&rcan_clk>, <&can_clk>;
+ clock-names = "clkp1", "clkp2", "can_clk";
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ can1: can@e6e88000 {
+ compatible = "renesas,can-r8a7792",
+ "renesas,rcar-gen2-can";
+ reg = <0 0xe6e88000 0 0x1000>;
+ interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7792_CLK_CAN1>,
+ <&rcan_clk>, <&can_clk>;
+ clock-names = "clkp1", "clkp2", "can_clk";
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vin0: video@e6ef0000 {
+ compatible = "renesas,vin-r8a7792",
+ "renesas,rcar-gen2-vin";
+ reg = <0 0xe6ef0000 0 0x1000>;
+ interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_VIN0>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vin1: video@e6ef1000 {
+ compatible = "renesas,vin-r8a7792",
+ "renesas,rcar-gen2-vin";
+ reg = <0 0xe6ef1000 0 0x1000>;
+ interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_VIN1>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vin2: video@e6ef2000 {
+ compatible = "renesas,vin-r8a7792",
+ "renesas,rcar-gen2-vin";
+ reg = <0 0xe6ef2000 0 0x1000>;
+ interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_VIN2>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vin3: video@e6ef3000 {
+ compatible = "renesas,vin-r8a7792",
+ "renesas,rcar-gen2-vin";
+ reg = <0 0xe6ef3000 0 0x1000>;
+ interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_VIN3>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vin4: video@e6ef4000 {
+ compatible = "renesas,vin-r8a7792",
+ "renesas,rcar-gen2-vin";
+ reg = <0 0xe6ef4000 0 0x1000>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_VIN4>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vin5: video@e6ef5000 {
+ compatible = "renesas,vin-r8a7792",
+ "renesas,rcar-gen2-vin";
+ reg = <0 0xe6ef5000 0 0x1000>;
+ interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7792_CLK_VIN5>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
+ vsp1@fe928000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe928000 0 0x8000>;
+ interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7792_CLK_VSP1_SY>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ vsp1@fe930000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe930000 0 0x8000>;
+ interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7792_CLK_VSP1DU0>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
+ vsp1@fe938000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe938000 0 0x8000>;
+ interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7792_CLK_VSP1DU1>;
+ power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+ };
+
/* Special CPG clocks */
cpg_clocks: cpg_clocks@e6150000 {
compatible = "renesas,r8a7792-cpg-clocks",
@@ -291,6 +728,13 @@
clock-div = <2>;
clock-mult = <1>;
};
+ zx_clk: zx {
+ compatible = "fixed-factor-clock";
+ clocks = <&cpg_clocks R8A7792_CLK_PLL1>;
+ #clock-cells = <0>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
zs_clk: zs {
compatible = "fixed-factor-clock";
clocks = <&cpg_clocks R8A7792_CLK_PLL1>;
@@ -298,6 +742,13 @@
clock-div = <6>;
clock-mult = <1>;
};
+ hp_clk: hp {
+ compatible = "fixed-factor-clock";
+ clocks = <&cpg_clocks R8A7792_CLK_PLL1>;
+ #clock-cells = <0>;
+ clock-div = <12>;
+ clock-mult = <1>;
+ };
p_clk: p {
compatible = "fixed-factor-clock";
clocks = <&cpg_clocks R8A7792_CLK_PLL1>;
@@ -319,16 +770,42 @@
clock-div = <8>;
clock-mult = <1>;
};
+ sd_clk: sd {
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_div2_clk>;
+ #clock-cells = <0>;
+ clock-div = <8>;
+ clock-mult = <1>;
+ };
+ rcan_clk: rcan {
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_div2_clk>;
+ #clock-cells = <0>;
+ clock-div = <49>;
+ clock-mult = <1>;
+ };
+ zg_clk: zg {
+ compatible = "fixed-factor-clock";
+ clocks = <&cpg_clocks R8A7792_CLK_PLL1>;
+ #clock-cells = <0>;
+ clock-div = <5>;
+ clock-mult = <1>;
+ };
/* Gate clocks */
mstp1_clks: mstp1_clks@e6150134 {
compatible = "renesas,r8a7792-mstp-clocks",
"renesas,cpg-mstp-clocks";
reg = <0 0xe6150134 0 4>, <0 0xe6150038 0 4>;
- clocks = <&m2_clk>;
+ clocks = <&m2_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>;
#clock-cells = <1>;
- clock-indices = <R8A7792_CLK_JPU>;
- clock-output-names = "jpu";
+ clock-indices = <
+ R8A7792_CLK_JPU
+ R8A7792_CLK_VSP1DU1 R8A7792_CLK_VSP1DU0
+ R8A7792_CLK_VSP1_SY
+ >;
+ clock-output-names = "jpu", "vsp1du1", "vsp1du0",
+ "vsp1-sy";
};
mstp2_clks: mstp2_clks@e6150138 {
compatible = "renesas,r8a7792-mstp-clocks",
@@ -341,6 +818,15 @@
>;
clock-output-names = "sys-dmac1", "sys-dmac0";
};
+ mstp3_clks: mstp3_clks@e615013c {
+ compatible = "renesas,r8a7792-mstp-clocks",
+ "renesas,cpg-mstp-clocks";
+ reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
+ clocks = <&sd_clk>;
+ #clock-cells = <1>;
+ renesas,clock-indices = <R8A7792_CLK_SDHI0>;
+ clock-output-names = "sdhi0";
+ };
mstp4_clks: mstp4_clks@e6150140 {
compatible = "renesas,r8a7792-mstp-clocks",
"renesas,cpg-mstp-clocks";
@@ -355,15 +841,65 @@
"renesas,cpg-mstp-clocks";
reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
clocks = <&zs_clk>, <&zs_clk>, <&p_clk>, <&p_clk>,
- <&p_clk>, <&p_clk>;
+ <&p_clk>, <&p_clk>, <&zx_clk>, <&zx_clk>;
#clock-cells = <1>;
clock-indices = <
R8A7792_CLK_HSCIF1 R8A7792_CLK_HSCIF0
R8A7792_CLK_SCIF3 R8A7792_CLK_SCIF2
R8A7792_CLK_SCIF1 R8A7792_CLK_SCIF0
+ R8A7792_CLK_DU1 R8A7792_CLK_DU0
>;
clock-output-names = "hscif1", "hscif0", "scif3",
- "scif2", "scif1", "scif0";
+ "scif2", "scif1", "scif0",
+ "du1", "du0";
+ };
+ mstp8_clks: mstp8_clks@e6150990 {
+ compatible = "renesas,r8a7792-mstp-clocks",
+ "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>;
+ clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&zg_clk>,
+ <&zg_clk>, <&zg_clk>, <&hp_clk>;
+ #clock-cells = <1>;
+ clock-indices = <
+ R8A7792_CLK_VIN5 R8A7792_CLK_VIN4
+ R8A7792_CLK_VIN3 R8A7792_CLK_VIN2
+ R8A7792_CLK_VIN1 R8A7792_CLK_VIN0
+ R8A7792_CLK_ETHERAVB
+ >;
+ clock-output-names = "vin5", "vin4", "vin3", "vin2",
+ "vin1", "vin0", "etheravb";
+ };
+ mstp9_clks: mstp9_clks@e6150994 {
+ compatible = "renesas,r8a7792-mstp-clocks",
+ "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>;
+ clocks = <&cp_clk>, <&cp_clk>, <&cp_clk>, <&cp_clk>,
+ <&cp_clk>, <&cp_clk>, <&cp_clk>, <&cp_clk>,
+ <&cp_clk>, <&cp_clk>, <&p_clk>, <&p_clk>,
+ <&cpg_clocks R8A7792_CLK_QSPI>,
+ <&cp_clk>, <&cp_clk>, <&hp_clk>, <&hp_clk>,
+ <&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>;
+ #clock-cells = <1>;
+ clock-indices = <
+ R8A7792_CLK_GPIO7 R8A7792_CLK_GPIO6
+ R8A7792_CLK_GPIO5 R8A7792_CLK_GPIO4
+ R8A7792_CLK_GPIO3 R8A7792_CLK_GPIO2
+ R8A7792_CLK_GPIO1 R8A7792_CLK_GPIO0
+ R8A7792_CLK_GPIO11 R8A7792_CLK_GPIO10
+ R8A7792_CLK_CAN1 R8A7792_CLK_CAN0
+ R8A7792_CLK_QSPI_MOD
+ R8A7792_CLK_GPIO9 R8A7792_CLK_GPIO8
+ R8A7792_CLK_I2C5 R8A7792_CLK_I2C4
+ R8A7792_CLK_I2C3 R8A7792_CLK_I2C2
+ R8A7792_CLK_I2C1 R8A7792_CLK_I2C0
+ >;
+ clock-output-names =
+ "gpio7", "gpio6", "gpio5", "gpio4",
+ "gpio3", "gpio2", "gpio1", "gpio0",
+ "gpio11", "gpio10", "can1", "can0",
+ "qspi_mod", "gpio9", "gpio8",
+ "i2c5", "i2c4", "i2c3", "i2c2",
+ "i2c1", "i2c0";
};
};
@@ -382,4 +918,12 @@
/* This value must be overridden by the board. */
clock-frequency = <0>;
};
+
+ /* External CAN clock */
+ can_clk: can {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ /* This value must be overridden by the board. */
+ clock-frequency = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index 1ad37d431a2a..8d1b35afaf82 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "r8a7794.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Alt";
@@ -29,6 +30,63 @@
reg = <0 0x40000000 0 0x40000000>;
};
+ d3_3v: regulator-d3-3v {
+ compatible = "regulator-fixed";
+ regulator-name = "D3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vcc_sdhi0: regulator-vcc-sdhi0 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI0 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&gpio2 26 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vccq_sdhi0: regulator-vccq-sdhi0 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI0 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
+
+ vcc_sdhi1: regulator-vcc-sdhi1 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI1 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&gpio4 26 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vccq_sdhi1: regulator-vccq-sdhi1 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI1 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
+
lbsc {
#address-cells = <1>;
#size-cells = <1>;
@@ -140,6 +198,21 @@
groups = "vin0_data8", "vin0_clk";
function = "vin0";
};
+
+ mmcif0_pins: mmcif0 {
+ groups = "mmc_data8", "mmc_ctrl";
+ function = "mmc";
+ };
+
+ sdhi0_pins: sd0 {
+ groups = "sdhi0_data4", "sdhi0_ctrl";
+ function = "sdhi0";
+ };
+
+ sdhi1_pins: sd1 {
+ groups = "sdhi1_data4", "sdhi1_ctrl";
+ function = "sdhi1";
+ };
};
&cmt0 {
@@ -169,6 +242,39 @@
};
};
+&mmcif0 {
+ pinctrl-0 = <&mmcif0_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&d3_3v>;
+ vqmmc-supply = <&d3_3v>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+};
+
+&sdhi0 {
+ pinctrl-0 = <&sdhi0_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi0>;
+ vqmmc-supply = <&vccq_sdhi0>;
+ cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&sdhi1 {
+ pinctrl-0 = <&sdhi1_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi1>;
+ vqmmc-supply = <&vccq_sdhi1>;
+ cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
&i2c1 {
pinctrl-0 = <&i2c1_pins>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts
index cf24f45fff22..cf880ac06f4b 100644
--- a/arch/arm/boot/dts/r8a7794-silk.dts
+++ b/arch/arm/boot/dts/r8a7794-silk.dts
@@ -10,6 +10,17 @@
* kind, whether express or implied.
*/
+/*
+ * SSI-AK4643
+ *
+ * SW1: 2-1: AK4643
+ * 2-3: ADV7511
+ *
+ * This command is required before playback/capture:
+ *
+ * amixer set "LINEOUT Mixer DACL" on
+ */
+
/dts-v1/;
#include "r8a7794.dtsi"
#include <dt-bindings/gpio/gpio.h>
@@ -119,6 +130,29 @@
#clock-cells = <0>;
clock-frequency = <74250000>;
};
+
+ x9_clk: audio_clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12288000>;
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&soundcodec>;
+ simple-audio-card,frame-master = <&soundcodec>;
+
+ simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ soundcodec: simple-audio-card,codec {
+ sound-dai = <&ak4643>;
+ clocks = <&x9_clk>;
+ };
+ };
};
&extal_clk {
@@ -193,6 +227,16 @@
groups = "du1_rgb666", "du1_sync", "du1_disp", "du1_clk0_out";
function = "du1";
};
+
+ ssi_pins: sound {
+ groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data";
+ function = "ssi";
+ };
+
+ audio_clk_pins: audio_clk {
+ groups = "audio_clkc";
+ function = "audio_clk";
+ };
};
&scif2 {
@@ -230,6 +274,12 @@
status = "okay";
clock-frequency = <400000>;
+ ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
+
composite-in@20 {
compatible = "adi,adv7180";
reg = <0x20>;
@@ -392,3 +442,23 @@
};
};
};
+
+&rcar_sound {
+ pinctrl-0 = <&ssi_pins &audio_clk_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ /* Single DAI */
+ #sound-dai-cells = <0>;
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0>;
+ capture = <&ssi1>;
+ };
+ };
+};
+
+&ssi1 {
+ shared-pin;
+};
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index 685f986cf962..9365580a194f 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -296,6 +296,34 @@
dma-channels = <15>;
};
+ audma0: dma-controller@ec700000 {
+ compatible = "renesas,dmac-r8a7794", "renesas,rcar-dmac";
+ reg = <0 0xec700000 0 0x10000>;
+ interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+ GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3", "ch4", "ch5",
+ "ch6", "ch7", "ch8", "ch9", "ch10", "ch11",
+ "ch12";
+ clocks = <&mstp5_clks R8A7794_CLK_AUDIO_DMAC0>;
+ clock-names = "fck";
+ power-domains = <&cpg_clocks>;
+ #dma-cells = <1>;
+ dma-channels = <13>;
+ };
+
scifa0: serial@e6c40000 {
compatible = "renesas,scifa-r8a7794",
"renesas,rcar-gen2-scifa", "renesas,scifa";
@@ -697,7 +725,7 @@
sdhi0: sd@ee100000 {
compatible = "renesas,sdhi-r8a7794";
- reg = <0 0xee100000 0 0x200>;
+ reg = <0 0xee100000 0 0x328>;
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7794_CLK_SDHI0>;
dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
@@ -866,6 +894,22 @@
};
};
+ vsp1@fe928000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe928000 0 0x8000>;
+ interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7794_CLK_VSP1_S>;
+ power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+ };
+
+ vsp1@fe930000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe930000 0 0x8000>;
+ interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7794_CLK_VSP1_DU0>;
+ power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+ };
+
du: display@feb00000 {
compatible = "renesas,du-r8a7794";
reg = <0 0xfeb00000 0 0x40000>;
@@ -952,6 +996,27 @@
clock-frequency = <0>;
};
+ /*
+ * The external audio clocks are configured as 0 Hz fixed
+ * frequency clocks by default. Boards that provide audio
+ * clocks should override them.
+ */
+ audio_clka: audio_clka {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ };
+ audio_clkb: audio_clkb {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ };
+ audio_clkc: audio_clkc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ };
+
/* Special CPG clocks */
cpg_clocks: cpg_clocks@e6150000 {
compatible = "renesas,r8a7794-cpg-clocks",
@@ -1183,6 +1248,15 @@
clock-indices = <R8A7794_CLK_IRQC>;
clock-output-names = "irqc";
};
+ mstp5_clks: mstp5_clks@e6150144 {
+ compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
+ clocks = <&hp_clk>, <&p_clk>;
+ #clock-cells = <1>;
+ clock-indices = <R8A7794_CLK_AUDIO_DMAC0
+ R8A7794_CLK_PWM>;
+ clock-output-names = "audmac0", "pwm";
+ };
mstp7_clks: mstp7_clks@e615014c {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
@@ -1237,6 +1311,58 @@
"gpio1", "gpio0", "rcan1", "rcan0", "qspi_mod",
"i2c5", "i2c4", "i2c3", "i2c2", "i2c1", "i2c0";
};
+ mstp10_clks: mstp10_clks@e6150998 {
+ compatible = "renesas,r8a7794-mstp-clocks",
+ "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>;
+ clocks = <&p_clk>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&p_clk>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>,
+ <&mstp10_clks R8A7794_CLK_SCU_ALL>;
+ #clock-cells = <1>;
+ clock-indices = <R8A7794_CLK_SSI_ALL
+ R8A7794_CLK_SSI9 R8A7794_CLK_SSI8
+ R8A7794_CLK_SSI7 R8A7794_CLK_SSI6
+ R8A7794_CLK_SSI5 R8A7794_CLK_SSI4
+ R8A7794_CLK_SSI3 R8A7794_CLK_SSI2
+ R8A7794_CLK_SSI1 R8A7794_CLK_SSI0
+ R8A7794_CLK_SCU_ALL
+ R8A7794_CLK_SCU_DVC1
+ R8A7794_CLK_SCU_DVC0
+ R8A7794_CLK_SCU_CTU1_MIX1
+ R8A7794_CLK_SCU_CTU0_MIX0
+ R8A7794_CLK_SCU_SRC6
+ R8A7794_CLK_SCU_SRC5
+ R8A7794_CLK_SCU_SRC4
+ R8A7794_CLK_SCU_SRC3
+ R8A7794_CLK_SCU_SRC2
+ R8A7794_CLK_SCU_SRC1>;
+ clock-output-names = "ssi-all", "ssi9", "ssi8", "ssi7",
+ "ssi6", "ssi5", "ssi4", "ssi3",
+ "ssi2", "ssi1", "ssi0",
+ "scu-all", "scu-dvc1", "scu-dvc0",
+ "scu-ctu1-mix1", "scu-ctu0-mix0",
+ "scu-src6", "scu-src5", "scu-src4",
+ "scu-src3", "scu-src2", "scu-src1";
+ };
mstp11_clks: mstp11_clks@e615099c {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe615099c 0 4>, <0 0xe61509ac 0 4>;
@@ -1306,4 +1432,185 @@
#iommu-cells = <1>;
status = "disabled";
};
+
+ rcar_sound: sound@ec500000 {
+ /*
+ * #sound-dai-cells is required
+ *
+ * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
+ * Multi DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
+ */
+ compatible = "renesas,rcar_sound-r8a7794",
+ "renesas,rcar_sound-gen2";
+ reg = <0 0xec500000 0 0x1000>, /* SCU */
+ <0 0xec5a0000 0 0x100>, /* ADG */
+ <0 0xec540000 0 0x1000>, /* SSIU */
+ <0 0xec541000 0 0x280>, /* SSI */
+ <0 0xec740000 0 0x200>; /* Audio DMAC peri peri */
+ reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+ clocks = <&mstp10_clks R8A7794_CLK_SSI_ALL>,
+ <&mstp10_clks R8A7794_CLK_SSI9>,
+ <&mstp10_clks R8A7794_CLK_SSI8>,
+ <&mstp10_clks R8A7794_CLK_SSI7>,
+ <&mstp10_clks R8A7794_CLK_SSI6>,
+ <&mstp10_clks R8A7794_CLK_SSI5>,
+ <&mstp10_clks R8A7794_CLK_SSI4>,
+ <&mstp10_clks R8A7794_CLK_SSI3>,
+ <&mstp10_clks R8A7794_CLK_SSI2>,
+ <&mstp10_clks R8A7794_CLK_SSI1>,
+ <&mstp10_clks R8A7794_CLK_SSI0>,
+ <&mstp10_clks R8A7794_CLK_SCU_SRC6>,
+ <&mstp10_clks R8A7794_CLK_SCU_SRC5>,
+ <&mstp10_clks R8A7794_CLK_SCU_SRC4>,
+ <&mstp10_clks R8A7794_CLK_SCU_SRC3>,
+ <&mstp10_clks R8A7794_CLK_SCU_SRC2>,
+ <&mstp10_clks R8A7794_CLK_SCU_SRC1>,
+ <&mstp10_clks R8A7794_CLK_SCU_CTU0_MIX0>,
+ <&mstp10_clks R8A7794_CLK_SCU_CTU1_MIX1>,
+ <&mstp10_clks R8A7794_CLK_SCU_CTU0_MIX0>,
+ <&mstp10_clks R8A7794_CLK_SCU_CTU1_MIX1>,
+ <&mstp10_clks R8A7794_CLK_SCU_DVC0>,
+ <&mstp10_clks R8A7794_CLK_SCU_DVC1>,
+ <&audio_clka>, <&audio_clkb>, <&audio_clkc>,
+ <&m2_clk>;
+ clock-names = "ssi-all",
+ "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
+ "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
+ "src.6", "src.5", "src.4", "src.3", "src.2",
+ "src.1",
+ "ctu.0", "ctu.1",
+ "mix.0", "mix.1",
+ "dvc.0", "dvc.1",
+ "clk_a", "clk_b", "clk_c", "clk_i";
+ power-domains = <&cpg_clocks>;
+
+ status = "disabled";
+
+ rcar_sound,dvc {
+ dvc0: dvc@0 {
+ dmas = <&audma0 0xbc>;
+ dma-names = "tx";
+ };
+ dvc1: dvc@1 {
+ dmas = <&audma0 0xbe>;
+ dma-names = "tx";
+ };
+ };
+
+ rcar_sound,mix {
+ mix0: mix@0 { };
+ mix1: mix@1 { };
+ };
+
+ rcar_sound,ctu {
+ ctu00: ctu@0 { };
+ ctu01: ctu@1 { };
+ ctu02: ctu@2 { };
+ ctu03: ctu@3 { };
+ ctu10: ctu@4 { };
+ ctu11: ctu@5 { };
+ ctu12: ctu@6 { };
+ ctu13: ctu@7 { };
+ };
+
+ rcar_sound,src {
+ src@0 {
+ status = "disabled";
+ };
+ src1: src@1 {
+ interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x87>, <&audma0 0x9c>;
+ dma-names = "rx", "tx";
+ };
+ src2: src@2 {
+ interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x89>, <&audma0 0x9e>;
+ dma-names = "rx", "tx";
+ };
+ src3: src@3 {
+ interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x8b>, <&audma0 0xa0>;
+ dma-names = "rx", "tx";
+ };
+ src4: src@4 {
+ interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x8d>, <&audma0 0xb0>;
+ dma-names = "rx", "tx";
+ };
+ src5: src@5 {
+ interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x8f>, <&audma0 0xb2>;
+ dma-names = "rx", "tx";
+ };
+ src6: src@6 {
+ interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x91>, <&audma0 0xb4>;
+ dma-names = "rx", "tx";
+ };
+ };
+
+ rcar_sound,ssi {
+ ssi0: ssi@0 {
+ interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x01>, <&audma0 0x02>,
+ <&audma0 0x15>, <&audma0 0x16>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi1: ssi@1 {
+ interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x03>, <&audma0 0x04>,
+ <&audma0 0x49>, <&audma0 0x4a>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi2: ssi@2 {
+ interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x05>, <&audma0 0x06>,
+ <&audma0 0x63>, <&audma0 0x64>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi3: ssi@3 {
+ interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x07>, <&audma0 0x08>,
+ <&audma0 0x6f>, <&audma0 0x70>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi4: ssi@4 {
+ interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x09>, <&audma0 0x0a>,
+ <&audma0 0x71>, <&audma0 0x72>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi5: ssi@5 {
+ interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x0b>, <&audma0 0x0c>,
+ <&audma0 0x73>, <&audma0 0x74>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi6: ssi@6 {
+ interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x0d>, <&audma0 0x0e>,
+ <&audma0 0x75>, <&audma0 0x76>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi7: ssi@7 {
+ interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x0f>, <&audma0 0x10>,
+ <&audma0 0x79>, <&audma0 0x7a>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi8: ssi@8 {
+ interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x11>, <&audma0 0x12>,
+ <&audma0 0x7b>, <&audma0 0x7c>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ ssi9: ssi@9 {
+ interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&audma0 0x13>, <&audma0 0x14>,
+ <&audma0 0x7d>, <&audma0 0x7e>;
+ dma-names = "rx", "tx", "rxu", "txu";
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index 843d2be2e4e9..a935523a1eb8 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -43,6 +43,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/clock/rk3036-cru.h>
+#include <dt-bindings/soc/rockchip,boot-mode.h>
#include "skeleton.dtsi"
/ {
@@ -313,8 +314,17 @@
};
grf: syscon@20008000 {
- compatible = "rockchip,rk3036-grf", "syscon";
+ compatible = "rockchip,rk3036-grf", "syscon", "simple-mfd";
reg = <0x20008000 0x1000>;
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x1d8>;
+ mode-normal = <BOOT_NORMAL>;
+ mode-recovery = <BOOT_RECOVERY>;
+ mode-bootloader = <BOOT_FASTBOOT>;
+ mode-loader = <BOOT_BL_DOWNLOAD>;
+ };
};
acodec: acodec-ana@20030000 {
diff --git a/arch/arm/boot/dts/rk3288-evb-act8846.dts b/arch/arm/boot/dts/rk3288-evb-act8846.dts
index 452ca2441e84..041dd5d2d18c 100644
--- a/arch/arm/boot/dts/rk3288-evb-act8846.dts
+++ b/arch/arm/boot/dts/rk3288-evb-act8846.dts
@@ -206,6 +206,10 @@
};
};
+&panel {
+ power-supply = <&vcc_lcd>;
+};
+
&pinctrl {
lcd {
lcd_en: lcd-en {
diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
index 736b08b0bfdd..44ebc6e59b3a 100644
--- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
+++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
@@ -233,3 +233,7 @@
};
};
};
+
+&panel {
+ power-supply = <&vcc_lcd>;
+};
diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index 963365d12208..d59208b5eb6c 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -48,7 +48,7 @@
reg = <0x0 0x80000000>;
};
- backlight {
+ backlight: backlight {
compatible = "pwm-backlight";
brightness-levels = <
0 1 2 3 4 5 6 7
@@ -97,6 +97,21 @@
#clock-cells = <0>;
};
+ panel: panel {
+ compatible ="lg,lp079qx1-sp0v", "simple-panel";
+ backlight = <&backlight>;
+ enable-gpios = <&gpio7 4 GPIO_ACTIVE_HIGH>;
+ pinctrl-0 = <&lcd_cs>;
+
+ ports {
+ panel_in: port {
+ panel_in_edp: endpoint {
+ remote-endpoint = <&edp_out_panel>;
+ };
+ };
+ };
+ };
+
gpio-keys {
compatible = "gpio-keys";
autorepeat;
@@ -170,6 +185,28 @@
cpu0-supply = <&vdd_cpu>;
};
+&edp {
+ force-hpd;
+ status = "okay";
+
+ ports {
+ edp_out: port@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ edp_out_panel: endpoint {
+ reg = <0>;
+ remote-endpoint = <&panel_in_edp>;
+ };
+ };
+ };
+};
+
+&edp_phy {
+ status = "okay";
+};
+
&emmc {
bus-width = <8>;
cap-mmc-highspeed;
@@ -280,6 +317,12 @@
};
};
+ lcd {
+ lcd_cs: lcd-cs {
+ rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
pmic {
pmic_int: pmic-int {
rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
diff --git a/arch/arm/boot/dts/rk3288-fennec.dts b/arch/arm/boot/dts/rk3288-fennec.dts
new file mode 100644
index 000000000000..2e3c34135ed8
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-fennec.dts
@@ -0,0 +1,382 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+
+#include "rk3288.dtsi"
+
+/ {
+ model = "Rockchip RK3288 Fennec Board";
+ compatible = "rockchip,rk3288-fennec", "rockchip,rk3288";
+
+ memory {
+ reg = <0x0 0x80000000>;
+ device_type = "memory";
+ };
+
+ ext_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <125000000>;
+ clock-output-names = "ext_gmac";
+ };
+
+ vcc_sys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&emmc {
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>;
+ status = "okay";
+};
+
+&gmac {
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&ext_gmac>;
+ clock_in_out = "input";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>;
+ phy-supply = <&vcc_lan>;
+ phy-mode = "rgmii";
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 1000000>;
+ snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_LOW>;
+ tx_delay = <0x30>;
+ rx_delay = <0x10>;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ rk808: pmic@1b {
+ compatible = "rockchip,rk808";
+ reg = <0x1b>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+ #clock-cells = <1>;
+ clock-output-names = "xin32k", "rk808-clkout2";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int &global_pwroff>;
+ rockchip,system-power-controller;
+ wakeup-source;
+
+ vcc1-supply = <&vcc_sys>;
+ vcc2-supply = <&vcc_sys>;
+ vcc3-supply = <&vcc_sys>;
+ vcc4-supply = <&vcc_sys>;
+ vcc6-supply = <&vcc_sys>;
+ vcc7-supply = <&vcc_sys>;
+ vcc8-supply = <&vcc_io>;
+ vcc9-supply = <&vcc_io>;
+ vcc10-supply = <&vcc_io>;
+ vcc11-supply = <&vcc_io>;
+ vcc12-supply = <&vcc_io>;
+ vddio-supply = <&vcc_io>;
+
+ regulators {
+ vdd_cpu: DCDC_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-name = "vdd_arm";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_gpu: DCDC_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd_gpu";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_ddr";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_io: DCDC_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_io";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vccio_pmu: LDO_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vccio_pmu";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcca_33: LDO_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcca_33";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_10: LDO_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd_10";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_wl: LDO_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc_wl";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vccio_sd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vdd10_lcd: LDO_REG6 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd10_lcd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_18: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc_18";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc18_lcd: LDO_REG8 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc18_lcd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcc_sd: SWITCH_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_sd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_lan: SWITCH_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_lan";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+ };
+ };
+};
+
+&pinctrl {
+ pcfg_output_high: pcfg-output-high {
+ output-high;
+ };
+
+ pcfg_output_low: pcfg-output-low {
+ output-low;
+ };
+
+ pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
+ drive-strength = <8>;
+ };
+
+ pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma {
+ bias-pull-up;
+ drive-strength = <8>;
+ };
+
+ gmac {
+ phy_int: phy-int {
+ rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ phy_pmeb: phy-pmeb {
+ rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ phy_rst: phy-rst {
+ rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+ };
+
+ pmic {
+ pmic_int: pmic-int {
+ rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ usbphy {
+ host_drv: host-drv {
+ rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&host_drv>;
+ vbus_drv-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host1 {
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&usb_hsic {
+ status = "okay";
+};
+
+&vopb {
+ status = "okay";
+};
+
+&vopb_mmu {
+ status = "okay";
+};
+
+&vopl {
+ status = "okay";
+};
+
+&vopl_mmu {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi b/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi
new file mode 100644
index 000000000000..ec418c99de95
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi
@@ -0,0 +1,310 @@
+/*
+ * Device tree file for Firefly Rockchip RK3288 Core board
+ * Copyright (c) 2016 Randy Li <ayaka@soulik.info>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/input/input.h>
+#include "rk3288.dtsi"
+
+/ {
+ memory {
+ device_type = "memory";
+ reg = <0 0x80000000>;
+ };
+
+ ext_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <125000000>;
+ clock-output-names = "ext_gmac";
+ };
+
+
+ vcc_flash: flash-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_flash";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc_io>;
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&emmc {
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_pwr>, <&emmc_bus8>;
+ vmmc-supply = <&vcc_io>;
+ vqmmc-supply = <&vcc_flash>;
+ status = "okay";
+};
+
+&gmac {
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&ext_gmac>;
+ clock_in_out = "input";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>;
+ phy-supply = <&vcc_lan>;
+ phy-mode = "rgmii";
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 1000000>;
+ snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_LOW>;
+ tx_delay = <0x30>;
+ rx_delay = <0x10>;
+ status = "ok";
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ vdd_cpu: syr827@40 {
+ compatible = "silergy,syr827";
+ fcs,suspend-voltage-selector = <1>;
+ reg = <0x40>;
+ regulator-name = "vdd_cpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-enable-ramp-delay = <300>;
+ regulator-ramp-delay = <8000>;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vdd_gpu: syr828@41 {
+ compatible = "silergy,syr828";
+ fcs,suspend-voltage-selector = <1>;
+ reg = <0x41>;
+ regulator-name = "vdd_gpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ act8846: act8846@5a {
+ compatible = "active-semi,act8846";
+ reg = <0x5a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_vsel>, <&pwr_hold>;
+ system-power-controller;
+
+ vp1-supply = <&vcc_sys>;
+ vp2-supply = <&vcc_sys>;
+ vp3-supply = <&vcc_sys>;
+ vp4-supply = <&vcc_sys>;
+ inl1-supply = <&vcc_sys>;
+ inl2-supply = <&vcc_sys>;
+ inl3-supply = <&vcc_20>;
+
+ regulators {
+ vcc_ddr: REG1 {
+ regulator-name = "vcc_ddr";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vcc_io: REG2 {
+ regulator-name = "vcc_io";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_log: REG3 {
+ regulator-name = "vdd_log";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ vcc_20: REG4 {
+ regulator-name = "vcc_20";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ vccio_sd: REG5 {
+ regulator-name = "vccio_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vdd10_lcd: REG6 {
+ regulator-name = "vdd10_lcd";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ vcca_18: REG7 {
+ regulator-name = "vcca_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vcca_33: REG8 {
+ regulator-name = "vcca_33";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vcc_lan: REG9 {
+ regulator-name = "vcca_lan";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vdd_10: REG10 {
+ regulator-name = "vdd_10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vccio_wl: vcc_18: REG11 {
+ regulator-name = "vcc_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vcc18_lcd: REG12 {
+ regulator-name = "vcc18_lcd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+ };
+};
+
+&io_domains {
+ status = "okay";
+
+ audio-supply = <&vccio_wl>;
+ bb-supply = <&vcc_io>;
+ dvp-supply = <&dovdd_1v8>;
+ flash0-supply = <&vcc_flash>;
+ flash1-supply = <&vcc_lan>;
+ gpio30-supply = <&vcc_io>;
+ gpio1830-supply = <&vcc_io>;
+ lcdc-supply = <&vcc_io>;
+ sdcard-supply = <&vccio_sd>;
+ wifi-supply = <&vccio_wl>;
+};
+
+&pinctrl {
+ pcfg_output_high: pcfg-output-high {
+ output-high;
+ };
+
+ pcfg_output_low: pcfg-output-low {
+ output-low;
+ };
+
+ pcfg_pull_up_drv_12ma: pcfg-pull-up-drv-12ma {
+ bias-pull-up;
+ drive-strength = <12>;
+ };
+
+ act8846 {
+ pwr_hold: pwr-hold {
+ rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+
+ pmic_vsel: pmic-vsel {
+ rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_output_low>;
+ };
+ };
+
+ gmac {
+ phy_int: phy-int {
+ rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ phy_pmeb: phy-pmeb {
+ rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ phy_rst: phy-rst {
+ rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+ };
+};
+
+&tsadc {
+ rockchip,hw-tshut-mode = <0>;
+ rockchip,hw-tshut-polarity = <0>;
+ status = "okay";
+};
+
+&vopb {
+ status = "okay";
+};
+
+&vopb_mmu {
+ status = "okay";
+};
+
+&vopl {
+ status = "okay";
+};
+
+&vopl_mmu {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-firefly-reload.dts b/arch/arm/boot/dts/rk3288-firefly-reload.dts
new file mode 100644
index 000000000000..751bee81128e
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-firefly-reload.dts
@@ -0,0 +1,403 @@
+/*
+ * Device tree file for Firefly Rockchip RK3288 Core board
+ * Copyright (c) 2016 Randy Li <ayaka@soulik.info>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "rk3288-firefly-reload-core.dtsi"
+
+/ {
+ model = "Firefly-RK3288-reload";
+ compatible = "firefly,firefly-rk3288-reload", "rockchip,rk3288";
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ power {
+ wakeup-source;
+ gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
+ label = "GPIO Power";
+ linux,code = <KEY_POWER>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_key>;
+ };
+ };
+
+ ir-receiver {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power {
+ gpios = <&gpio8 2 GPIO_ACTIVE_LOW>;
+ label = "firefly:blue:power";
+ pinctrl-names = "default";
+ pinctrl-0 = <&power_led>;
+ panic-indicator;
+ };
+
+ work {
+ gpios = <&gpio8 1 GPIO_ACTIVE_LOW>;
+ label = "firefly:blue:user";
+ linux,default-trigger = "rc-feedback";
+ pinctrl-names = "default";
+ pinctrl-0 = <&work_led>;
+ };
+ };
+
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&hym8563>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable>;
+ reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "SPDIF";
+ simple-audio-card,dai-link@1 { /* S/PDIF - S/PDIF */
+ cpu { sound-dai = <&spdif>; };
+ codec { sound-dai = <&spdif_out>; };
+ };
+ };
+
+ spdif_out: spdif-out {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ };
+
+ vcc_host_5v: usb-host-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&host_vbus_drv>;
+ regulator-name = "vcc_host_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ vin-supply = <&vcc_5v>;
+ };
+
+ vcc_5v: vcc_sys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vcc_sd: sdmmc-regulator {
+ compatible = "regulator-fixed";
+ gpio = <&gpio7 11 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_pwr>;
+ regulator-name = "vcc_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_otg_5v: usb-otg-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&otg_vbus_drv>;
+ regulator-name = "vcc_otg_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ vin-supply = <&vcc_5v>;
+ };
+
+ dovdd_1v8: dovdd-1v8-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dvp_pwr>;
+ regulator-name = "dovdd_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc28_dvp: vcc28-dvp-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dvp_pwr>;
+ regulator-name = "vcc28_dvp";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ af_28: af_28-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dvp_pwr>;
+ regulator-name = "af_28";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ dvdd_1v2: af_28-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cif_pwr>;
+ regulator-name = "dvdd_1v2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ vbat_wl: wifi-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vbat_wl";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc_io>;
+ };
+};
+
+&i2c0 {
+ hym8563: hym8563@51 {
+ compatible = "haoyu,hym8563";
+ reg = <0x51>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "xin32k";
+ interrupt-parent = <&gpio7>;
+ interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rtc_int>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ codec: es8328@10 {
+ compatible = "everest,es8328";
+ DVDD-supply = <&vcca_33>;
+ AVDD-supply = <&vcca_33>;
+ PVDD-supply = <&vcca_33>;
+ HPVDD-supply = <&vcca_33>;
+ clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+ clock-names = "i2s_hclk", "i2s_clk";
+ reg = <0x10>;
+ };
+};
+
+&i2s {
+ status = "okay";
+};
+
+&sdmmc {
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ card-detect-delay = <200>;
+ disable-wp;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+&sdio0 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ disable-wp;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio0_bus4>, <&sdio0_cmd>, <&sdio0_clk>, <&sdio0_int>;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-ddr50;
+ vmmc-supply = <&vbat_wl>;
+ vqmmc-supply = <&vccio_wl>;
+ status = "okay";
+};
+
+&spdif {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>;
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+&usb_host1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usbhub_rst>;
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&pinctrl {
+ ir {
+ ir_int: ir-int {
+ rockchip,pins = <7 0 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ dvp {
+ dvp_pwr: dvp-pwr {
+ rockchip,pins = <0 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ cif_pwr: cif-pwr {
+ rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ hym8563 {
+ rtc_int: rtc-int {
+ rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ keys {
+ pwr_key: pwr-key {
+ rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ leds {
+ power_led: power-led {
+ rockchip,pins = <8 2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ work_led: work-led {
+ rockchip,pins = <8 1 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ sdmmc {
+ /*
+ * Default drive strength isn't enough to achieve even
+ * high-speed mode on firefly board so bump up to 12ma.
+ */
+ sdmmc_bus4: sdmmc-bus4 {
+ rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
+ <6 17 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
+ <6 18 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
+ <6 19 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+ };
+
+ sdmmc_clk: sdmmc-clk {
+ rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_12ma>;
+ };
+
+ sdmmc_cmd: sdmmc-cmd {
+ rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+ };
+
+ sdmmc_pwr: sdmmc-pwr {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ sdio {
+ wifi_enable: wifi-enable {
+ rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb_host {
+ host_vbus_drv: host-vbus-drv {
+ rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ usbhub_rst: usbhub-rst {
+ rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+ };
+
+ usb_otg {
+ otg_vbus_drv: otg-vbus-drv {
+ rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3288-popmetal.dts b/arch/arm/boot/dts/rk3288-popmetal.dts
index dda8d259bb6d..56dd377d5658 100644
--- a/arch/arm/boot/dts/rk3288-popmetal.dts
+++ b/arch/arm/boot/dts/rk3288-popmetal.dts
@@ -387,12 +387,16 @@
interrupts = <1 IRQ_TYPE_EDGE_RISING>;
pinctrl-names = "default";
pinctrl-0 = <&comp_int>;
+ vdd-supply = <&vcc_io>;
+ vid-supply = <&vcc_io>;
};
- l3g4200d: l3g4200d@68 {
+ l3g4200d: l3g4200d@69 {
compatible = "st,l3g4200d-gyro";
st,drdy-int-pin = <2>;
- reg = <0x6b>;
+ reg = <0x69>;
+ vdd-supply = <&vcc_io>;
+ vddio-supply = <&vcc_io>;
};
mma8452: mma8452@1d {
@@ -525,3 +529,7 @@
&usbphy {
status = "okay";
};
+
+&usb_otg {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 91c4b3c7a8d5..17ec2e2d7a60 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -45,6 +45,7 @@
#include <dt-bindings/clock/rk3288-cru.h>
#include <dt-bindings/thermal/thermal.h>
#include <dt-bindings/power/rk3288-power.h>
+#include <dt-bindings/soc/rockchip,boot-mode.h>
#include "skeleton.dtsi"
/ {
@@ -793,6 +794,15 @@
clocks = <&cru ACLK_GPU>;
};
};
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x94>;
+ mode-normal = <BOOT_NORMAL>;
+ mode-recovery = <BOOT_RECOVERY>;
+ mode-bootloader = <BOOT_FASTBOOT>;
+ mode-loader = <BOOT_BL_DOWNLOAD>;
+ };
};
sgrf: syscon@ff740000 {
@@ -834,6 +844,37 @@
compatible = "rockchip,rk3288-io-voltage-domain";
status = "disabled";
};
+
+ usbphy: usbphy {
+ compatible = "rockchip,rk3288-usb-phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ usbphy0: usb-phy@320 {
+ #phy-cells = <0>;
+ reg = <0x320>;
+ clocks = <&cru SCLK_OTGPHY0>;
+ clock-names = "phyclk";
+ #clock-cells = <0>;
+ };
+
+ usbphy1: usb-phy@334 {
+ #phy-cells = <0>;
+ reg = <0x334>;
+ clocks = <&cru SCLK_OTGPHY1>;
+ clock-names = "phyclk";
+ #clock-cells = <0>;
+ };
+
+ usbphy2: usb-phy@348 {
+ #phy-cells = <0>;
+ reg = <0x348>;
+ clocks = <&cru SCLK_OTGPHY2>;
+ clock-names = "phyclk";
+ #clock-cells = <0>;
+ };
+ };
};
wdt: watchdog@ff800000 {
@@ -1087,38 +1128,6 @@
};
};
- usbphy: phy {
- compatible = "rockchip,rk3288-usb-phy";
- rockchip,grf = <&grf>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
-
- usbphy0: usb-phy@320 {
- #phy-cells = <0>;
- reg = <0x320>;
- clocks = <&cru SCLK_OTGPHY0>;
- clock-names = "phyclk";
- #clock-cells = <0>;
- };
-
- usbphy1: usb-phy@334 {
- #phy-cells = <0>;
- reg = <0x334>;
- clocks = <&cru SCLK_OTGPHY1>;
- clock-names = "phyclk";
- #clock-cells = <0>;
- };
-
- usbphy2: usb-phy@348 {
- #phy-cells = <0>;
- reg = <0x348>;
- clocks = <&cru SCLK_OTGPHY2>;
- clock-names = "phyclk";
- #clock-cells = <0>;
- };
- };
-
pinctrl: pinctrl {
compatible = "rockchip,rk3288-pinctrl";
rockchip,grf = <&grf>;
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index e2cd683b4e4b..e15beb3c671e 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -43,6 +43,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/rockchip,boot-mode.h>
#include "skeleton.dtsi"
/ {
@@ -246,8 +247,17 @@
};
pmu: pmu@20004000 {
- compatible = "rockchip,rk3066-pmu", "syscon";
+ compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd";
reg = <0x20004000 0x100>;
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x40>;
+ mode-normal = <BOOT_NORMAL>;
+ mode-recovery = <BOOT_RECOVERY>;
+ mode-bootloader = <BOOT_FASTBOOT>;
+ mode-loader = <BOOT_BL_DOWNLOAD>;
+ };
};
grf: grf@20008000 {
diff --git a/arch/arm/boot/dts/s3c2416-pinctrl.dtsi b/arch/arm/boot/dts/s3c2416-pinctrl.dtsi
index 527e3193817f..6274359fb323 100644
--- a/arch/arm/boot/dts/s3c2416-pinctrl.dtsi
+++ b/arch/arm/boot/dts/s3c2416-pinctrl.dtsi
@@ -8,6 +8,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
&pinctrl_0 {
/*
* Pin banks
@@ -83,91 +85,91 @@
uart0_data: uart0-data {
samsung,pins = "gph-0", "gph-1";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gph-8", "gph-9";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
uart1_data: uart1-data {
samsung,pins = "gph-2", "gph-3";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gph-10", "gph-11";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
uart2_data: uart2-data {
samsung,pins = "gph-4", "gph-5";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gph-6", "gph-7";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
uart3_data: uart3-data {
samsung,pins = "gph-6", "gph-7";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
extuart_clk: extuart-clk {
samsung,pins = "gph-12";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpe-14", "gpe-15";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpe-11", "gpe-12", "gpe-13";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd0_clk: sd0-clk {
samsung,pins = "gpe-5";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpe-6";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd0_bus1: sd0-bus1 {
samsung,pins = "gpe-7";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd0_bus4: sd0-bus4 {
samsung,pins = "gpe-8", "gpe-9", "gpe-10";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpl-8";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpl-9";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd1_bus1: sd1-bus1 {
samsung,pins = "gpl-0";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
sd1_bus4: sd1-bus4 {
samsung,pins = "gpl-1", "gpl-2", "gpl-3";
- samsung,pin-function = <2>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
};
};
diff --git a/arch/arm/boot/dts/s3c6410-mini6410.dts b/arch/arm/boot/dts/s3c6410-mini6410.dts
index a25debb50401..f4afda3594f8 100644
--- a/arch/arm/boot/dts/s3c6410-mini6410.dts
+++ b/arch/arm/boot/dts/s3c6410-mini6410.dts
@@ -201,13 +201,13 @@
&pinctrl0 {
gpio_leds: gpio-leds {
samsung,pins = "gpk-4", "gpk-5", "gpk-6", "gpk-7";
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
gpio_keys: gpio-keys {
samsung,pins = "gpn-0", "gpn-1", "gpn-2", "gpn-3",
"gpn-4", "gpn-5", "gpl-11", "gpl-12";
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
};
diff --git a/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi b/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi
index b1197d8b04de..4e8e802b4ee1 100644
--- a/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi
+++ b/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi
@@ -12,9 +12,7 @@
* published by the Free Software Foundation.
*/
-#define PIN_PULL_NONE 0
-#define PIN_PULL_DOWN 1
-#define PIN_PULL_UP 2
+#include <dt-bindings/pinctrl/samsung.h>
&pinctrl0 {
/*
@@ -138,514 +136,514 @@
uart0_data: uart0-data {
samsung,pins = "gpa-0", "gpa-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa-2", "gpa-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
uart1_data: uart1-data {
samsung,pins = "gpa-4", "gpa-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa-6", "gpa-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
uart2_data: uart2-data {
samsung,pins = "gpb-0", "gpb-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
uart3_data: uart3-data {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
ext_dma_0: ext-dma-0 {
samsung,pins = "gpb-0", "gpb-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
ext_dma_1: ext-dma-1 {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
irda_data_0: irda-data-0 {
samsung,pins = "gpb-0", "gpb-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
irda_data_1: irda-data-1 {
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
irda_sdbw: irda-sdbw {
samsung,pins = "gpb-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpb-5", "gpb-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
};
i2c1_bus: i2c1-bus {
/* S3C6410-only */
samsung,pins = "gpb-2", "gpb-3";
- samsung,pin-function = <6>;
- samsung,pin-pud = <PIN_PULL_UP>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_6>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpc-0", "gpc-1", "gpc-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
};
spi0_cs: spi0-cs {
samsung,pins = "gpc-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpc-4", "gpc-5", "gpc-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
};
spi1_cs: spi1-cs {
samsung,pins = "gpc-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpg-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd0_clk: sd0-clk {
samsung,pins = "gpg-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd0_bus1: sd0-bus1 {
samsung,pins = "gpg-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd0_bus4: sd0-bus4 {
samsung,pins = "gpg-2", "gpg-3", "gpg-4", "gpg-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpg-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_UP>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gph-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd1_clk: sd1-clk {
samsung,pins = "gph-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd1_bus1: sd1-bus1 {
samsung,pins = "gph-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd1_bus4: sd1-bus4 {
samsung,pins = "gph-2", "gph-3", "gph-4", "gph-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd1_bus8: sd1-bus8 {
samsung,pins = "gph-2", "gph-3", "gph-4", "gph-5",
"gph-6", "gph-7", "gph-8", "gph-9";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpg-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_UP>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpc-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpc-5";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd2_bus1: sd2-bus1 {
samsung,pins = "gph-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
sd2_bus4: sd2-bus4 {
samsung,pins = "gph-6", "gph-7", "gph-8", "gph-9";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2s0_bus: i2s0-bus {
samsung,pins = "gpd-0", "gpd-2", "gpd-3", "gpd-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2s0_cdclk: i2s0-cdclk {
samsung,pins = "gpd-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpe-0", "gpe-2", "gpe-3", "gpe-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2s1_cdclk: i2s1-cdclk {
samsung,pins = "gpe-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2s2_bus: i2s2-bus {
/* S3C6410-only */
samsung,pins = "gpc-4", "gpc-5", "gpc-6", "gph-6",
"gph-8", "gph-9";
- samsung,pin-function = <5>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
i2s2_cdclk: i2s2-cdclk {
/* S3C6410-only */
samsung,pins = "gph-7";
- samsung,pin-function = <5>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pcm0_bus: pcm0-bus {
samsung,pins = "gpd-0", "gpd-2", "gpd-3", "gpd-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pcm0_extclk: pcm0-extclk {
samsung,pins = "gpd-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpe-0", "gpe-2", "gpe-3", "gpe-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pcm1_extclk: pcm1-extclk {
samsung,pins = "gpe-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
ac97_bus_0: ac97-bus-0 {
samsung,pins = "gpd-0", "gpd-1", "gpd-2", "gpd-3", "gpd-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
ac97_bus_1: ac97-bus-1 {
samsung,pins = "gpe-0", "gpe-1", "gpe-2", "gpe-3", "gpe-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
cam_port: cam-port {
samsung,pins = "gpf-0", "gpf-1", "gpf-2", "gpf-4",
"gpf-5", "gpf-6", "gpf-7", "gpf-8",
"gpf-9", "gpf-10", "gpf-11", "gpf-12";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
cam_rst: cam-rst {
samsung,pins = "gpf-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
cam_field: cam-field {
/* S3C6410-only */
samsung,pins = "gpb-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pwm_extclk: pwm-extclk {
samsung,pins = "gpf-13";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpf-14";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpf-15";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
clkout0: clkout-0 {
samsung,pins = "gpf-14";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col0_0: keypad-col0-0 {
samsung,pins = "gph-0";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col1_0: keypad-col1-0 {
samsung,pins = "gph-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col2_0: keypad-col2-0 {
samsung,pins = "gph-2";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col3_0: keypad-col3-0 {
samsung,pins = "gph-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col4_0: keypad-col4-0 {
samsung,pins = "gph-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col5_0: keypad-col5-0 {
samsung,pins = "gph-5";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col6_0: keypad-col6-0 {
samsung,pins = "gph-6";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col7_0: keypad-col7-0 {
samsung,pins = "gph-7";
- samsung,pin-function = <4>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col0_1: keypad-col0-1 {
samsung,pins = "gpl-0";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col1_1: keypad-col1-1 {
samsung,pins = "gpl-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col2_1: keypad-col2-1 {
samsung,pins = "gpl-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col3_1: keypad-col3-1 {
samsung,pins = "gpl-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col4_1: keypad-col4-1 {
samsung,pins = "gpl-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col5_1: keypad-col5-1 {
samsung,pins = "gpl-5";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col6_1: keypad-col6-1 {
samsung,pins = "gpl-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_col7_1: keypad-col7-1 {
samsung,pins = "gpl-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row0_0: keypad-row0-0 {
samsung,pins = "gpk-8";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row1_0: keypad-row1-0 {
samsung,pins = "gpk-9";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row2_0: keypad-row2-0 {
samsung,pins = "gpk-10";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row3_0: keypad-row3-0 {
samsung,pins = "gpk-11";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row4_0: keypad-row4-0 {
samsung,pins = "gpk-12";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row5_0: keypad-row5-0 {
samsung,pins = "gpk-13";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row6_0: keypad-row6-0 {
samsung,pins = "gpk-14";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row7_0: keypad-row7-0 {
samsung,pins = "gpk-15";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row0_1: keypad-row0-1 {
samsung,pins = "gpn-0";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row1_1: keypad-row1-1 {
samsung,pins = "gpn-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row2_1: keypad-row2-1 {
samsung,pins = "gpn-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row3_1: keypad-row3-1 {
samsung,pins = "gpn-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row4_1: keypad-row4-1 {
samsung,pins = "gpn-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row5_1: keypad-row5-1 {
samsung,pins = "gpn-5";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row6_1: keypad-row6-1 {
samsung,pins = "gpn-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
keypad_row7_1: keypad-row7-1 {
samsung,pins = "gpn-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
lcd_ctrl: lcd-ctrl {
samsung,pins = "gpj-8", "gpj-9", "gpj-10", "gpj-11";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
lcd_data16: lcd-data-width16 {
@@ -653,8 +651,8 @@
"gpi-7", "gpi-10", "gpi-11", "gpi-12",
"gpi-13", "gpi-14", "gpi-15", "gpj-3",
"gpj-4", "gpj-5", "gpj-6", "gpj-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
lcd_data18: lcd-data-width18 {
@@ -663,8 +661,8 @@
"gpi-12", "gpi-13", "gpi-14", "gpi-15",
"gpj-2", "gpj-3", "gpj-4", "gpj-5",
"gpj-6", "gpj-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
lcd_data24: lcd-data-width24 {
@@ -674,14 +672,14 @@
"gpi-12", "gpi-13", "gpi-14", "gpi-15",
"gpj-0", "gpj-1", "gpj-2", "gpj-3",
"gpj-4", "gpj-5", "gpj-6", "gpj-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
hsi_bus: hsi-bus {
samsung,pins = "gpk-0", "gpk-1", "gpk-2", "gpk-3",
"gpk-4", "gpk-5", "gpk-6", "gpk-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <PIN_PULL_NONE>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
};
diff --git a/arch/arm/boot/dts/s5pv210-aquila.dts b/arch/arm/boot/dts/s5pv210-aquila.dts
index da24ab570b0e..40139923eef0 100644
--- a/arch/arm/boot/dts/s5pv210-aquila.dts
+++ b/arch/arm/boot/dts/s5pv210-aquila.dts
@@ -29,7 +29,7 @@
bootargs = "console=ttySAC2,115200n8 root=/dev/mmcblk1p5 rw rootwait ignore_loglevel earlyprintk";
};
- memory {
+ memory@30000000 {
device_type = "memory";
reg = <0x30000000 0x05000000
0x40000000 0x18000000>;
@@ -387,7 +387,7 @@
&pinctrl0 {
t_flash_detect: t-flash-detect {
samsung,pins = "gph3-4";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
};
};
diff --git a/arch/arm/boot/dts/s5pv210-goni.dts b/arch/arm/boot/dts/s5pv210-goni.dts
index 0a33d402138e..c56f51ee7897 100644
--- a/arch/arm/boot/dts/s5pv210-goni.dts
+++ b/arch/arm/boot/dts/s5pv210-goni.dts
@@ -29,7 +29,7 @@
bootargs = "console=ttySAC0,115200n8 root=/dev/mmcblk0p5 rw rootwait ignore_loglevel earlyprintk";
};
- memory {
+ memory@30000000 {
device_type = "memory";
reg = <0x30000000 0x05000000
0x40000000 0x10000000
diff --git a/arch/arm/boot/dts/s5pv210-pinctrl.dtsi b/arch/arm/boot/dts/s5pv210-pinctrl.dtsi
index 8c714088e3c6..9a3e851e2e22 100644
--- a/arch/arm/boot/dts/s5pv210-pinctrl.dtsi
+++ b/arch/arm/boot/dts/s5pv210-pinctrl.dtsi
@@ -19,6 +19,8 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/pinctrl/samsung.h>
+
&pinctrl0 {
gpa0: gpa0 {
gpio-controller;
@@ -270,559 +272,559 @@
uart0_data: uart0-data {
samsung,pins = "gpa0-0", "gpa0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart0_fctl: uart0-fctl {
samsung,pins = "gpa0-2", "gpa0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_data: uart1-data {
samsung,pins = "gpa0-4", "gpa0-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart1_fctl: uart1-fctl {
samsung,pins = "gpa0-6", "gpa0-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_data: uart2-data {
samsung,pins = "gpa1-0", "gpa1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart2_fctl: uart2-fctl {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart3_data: uart3-data {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
uart_audio: uart-audio {
samsung,pins = "gpa1-2", "gpa1-3";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi0_bus: spi0-bus {
samsung,pins = "gpb-0", "gpb-2", "gpb-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi1_bus: spi1-bus {
samsung,pins = "gpb-4", "gpb-6", "gpb-7";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s0_bus: i2s0-bus {
samsung,pins = "gpi-0", "gpi-1", "gpi-2", "gpi-3",
"gpi-4", "gpi-5", "gpi-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s1_bus: i2s1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm1_bus: pcm1-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
ac97_bus: ac97-bus {
samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
"gpc0-4";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2s2_bus: i2s2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pcm2_bus: pcm2-bus {
samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
"gpc1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spdif_bus: spdif-bus {
samsung,pins = "gpc1-0", "gpc1-1";
- samsung,pin-function = <4>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
spi2_bus: spi2-bus {
samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4";
- samsung,pin-function = <5>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c0_bus: i2c0-bus {
samsung,pins = "gpd1-0", "gpd1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c1_bus: i2c1-bus {
samsung,pins = "gpd1-2", "gpd1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
i2c2_bus: i2c2-bus {
samsung,pins = "gpd1-4", "gpd1-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm0_out: pwm0-out {
samsung,pins = "gpd0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm1_out: pwm1-out {
samsung,pins = "gpd0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm2_out: pwm2-out {
samsung,pins = "gpd0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
pwm3_out: pwm3-out {
samsung,pins = "gpd0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row0: keypad-row-0 {
samsung,pins = "gph3-0";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row1: keypad-row-1 {
samsung,pins = "gph3-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row2: keypad-row-2 {
samsung,pins = "gph3-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row3: keypad-row-3 {
samsung,pins = "gph3-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row4: keypad-row-4 {
samsung,pins = "gph3-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row5: keypad-row-5 {
samsung,pins = "gph3-5";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row6: keypad-row-6 {
samsung,pins = "gph3-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_row7: keypad-row-7 {
samsung,pins = "gph3-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col0: keypad-col-0 {
samsung,pins = "gph2-0";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col1: keypad-col-1 {
samsung,pins = "gph2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col2: keypad-col-2 {
samsung,pins = "gph2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col3: keypad-col-3 {
samsung,pins = "gph2-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col4: keypad-col-4 {
samsung,pins = "gph2-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col5: keypad-col-5 {
samsung,pins = "gph2-5";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col6: keypad-col-6 {
samsung,pins = "gph2-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
keypad_col7: keypad-col-7 {
samsung,pins = "gph2-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
sd0_clk: sd0-clk {
samsung,pins = "gpg0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cmd: sd0-cmd {
samsung,pins = "gpg0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_cd: sd0-cd {
samsung,pins = "gpg0-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus1: sd0-bus-width1 {
samsung,pins = "gpg0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus4: sd0-bus-width4 {
samsung,pins = "gpg0-3", "gpg0-4", "gpg0-5", "gpg0-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd0_bus8: sd0-bus-width8 {
samsung,pins = "gpg1-3", "gpg1-4", "gpg1-5", "gpg1-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_clk: sd1-clk {
samsung,pins = "gpg1-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cmd: sd1-cmd {
samsung,pins = "gpg1-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_cd: sd1-cd {
samsung,pins = "gpg1-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus1: sd1-bus-width1 {
samsung,pins = "gpg1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd1_bus4: sd1-bus-width4 {
samsung,pins = "gpg1-3", "gpg1-4", "gpg1-5", "gpg1-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_clk: sd2-clk {
samsung,pins = "gpg2-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cmd: sd2-cmd {
samsung,pins = "gpg2-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_cd: sd2-cd {
samsung,pins = "gpg2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus1: sd2-bus-width1 {
samsung,pins = "gpg2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus4: sd2-bus-width4 {
samsung,pins = "gpg2-3", "gpg2-4", "gpg2-5", "gpg2-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd2_bus8: sd2-bus-width8 {
samsung,pins = "gpg3-3", "gpg3-4", "gpg3-5", "gpg3-6";
- samsung,pin-function = <3>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_clk: sd3-clk {
samsung,pins = "gpg3-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cmd: sd3-cmd {
samsung,pins = "gpg3-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_cd: sd3-cd {
samsung,pins = "gpg3-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus1: sd3-bus-width1 {
samsung,pins = "gpg3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
sd3_bus4: sd3-bus-width4 {
samsung,pins = "gpg3-3", "gpg3-4", "gpg3-5", "gpg3-6";
- samsung,pin-function = <2>;
- samsung,pin-pud = <2>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
eint0: ext-int0 {
samsung,pins = "gph0-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint8: ext-int8 {
samsung,pins = "gph1-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint15: ext-int15 {
samsung,pins = "gph1-7";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint16: ext-int16 {
samsung,pins = "gph2-0";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
eint31: ext-int31 {
samsung,pins = "gph3-7";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a_io: cam-port-a-io {
samsung,pins = "gpe0-0", "gpe0-1", "gpe0-2", "gpe0-3",
"gpe0-4", "gpe0-5", "gpe0-6", "gpe0-7",
"gpe1-0", "gpe1-1", "gpe1-2", "gpe1-4";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_a_clk_active: cam-port-a-clk-active {
samsung,pins = "gpe1-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_a_clk_idle: cam-port-a-clk-idle {
samsung,pins = "gpe1-3";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_b_io: cam-port-b-io {
samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
cam_port_b_clk_active: cam-port-b-clk-active {
samsung,pins = "gpj1-3";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <3>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
};
cam_port_b_clk_idle: cam-port-b-clk-idle {
samsung,pins = "gpj1-3";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_ctrl: lcd-ctrl {
samsung,pins = "gpd0-0", "gpd0-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_sync: lcd-sync {
samsung,pins = "gpf0-0", "gpf0-1";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_clk: lcd-clk {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
lcd_data24: lcd-data-width24 {
@@ -832,8 +834,8 @@
"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+ samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+ samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
diff --git a/arch/arm/boot/dts/s5pv210-smdkc110.dts b/arch/arm/boot/dts/s5pv210-smdkc110.dts
index 1eedab7ffe94..5d14da911aa5 100644
--- a/arch/arm/boot/dts/s5pv210-smdkc110.dts
+++ b/arch/arm/boot/dts/s5pv210-smdkc110.dts
@@ -29,7 +29,7 @@
bootargs = "console=ttySAC0,115200n8 root=/dev/mmcblk0p1 rw rootwait ignore_loglevel earlyprintk";
};
- memory {
+ memory@20000000 {
device_type = "memory";
reg = <0x20000000 0x20000000>;
};
diff --git a/arch/arm/boot/dts/s5pv210-smdkv210.dts b/arch/arm/boot/dts/s5pv210-smdkv210.dts
index 9eb6aff3e38f..75398318ed57 100644
--- a/arch/arm/boot/dts/s5pv210-smdkv210.dts
+++ b/arch/arm/boot/dts/s5pv210-smdkv210.dts
@@ -29,7 +29,7 @@
bootargs = "console=ttySAC0,115200n8 root=/dev/mmcblk0p1 rw rootwait ignore_loglevel earlyprintk";
};
- memory {
+ memory@20000000 {
device_type = "memory";
reg = <0x20000000 0x40000000>;
};
diff --git a/arch/arm/boot/dts/s5pv210-torbreck.dts b/arch/arm/boot/dts/s5pv210-torbreck.dts
index 622599fd2cfa..7cb50bcee888 100644
--- a/arch/arm/boot/dts/s5pv210-torbreck.dts
+++ b/arch/arm/boot/dts/s5pv210-torbreck.dts
@@ -29,7 +29,7 @@
bootargs = "console=ttySAC0,115200n8 root=/dev/mmcblk0p1 rw rootwait ignore_loglevel earlyprintk";
};
- memory {
+ memory@20000000 {
device_type = "memory";
reg = <0x20000000 0x20000000>;
};
diff --git a/arch/arm/boot/dts/s5pv210.dtsi b/arch/arm/boot/dts/s5pv210.dtsi
index ffc36bd24d2f..a853918be43f 100644
--- a/arch/arm/boot/dts/s5pv210.dtsi
+++ b/arch/arm/boot/dts/s5pv210.dtsi
@@ -19,11 +19,13 @@
* published by the Free Software Foundation.
*/
-#include "skeleton.dtsi"
#include <dt-bindings/clock/s5pv210.h>
#include <dt-bindings/clock/s5pv210-audss.h>
/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
aliases {
csis0 = &csis0;
fimc0 = &fimc0;
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 353d0e5ec83b..7173ec9059a1 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -77,6 +77,35 @@
interrupts = <2 IRQ_TYPE_LEVEL_HIGH 0>;
};
+ etb {
+ compatible = "arm,coresight-etb10", "arm,primecell";
+ reg = <0x740000 0x1000>;
+
+ clocks = <&mck>;
+ clock-names = "apb_pclk";
+
+ port {
+ etb_in: endpoint {
+ slave-mode;
+ remote-endpoint = <&etm_out>;
+ };
+ };
+ };
+
+ etm {
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x73C000 0x1000>;
+
+ clocks = <&mck>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm_out: endpoint {
+ remote-endpoint = <&etb_in>;
+ };
+ };
+ };
+
memory {
reg = <0x20000000 0x20000000>;
};
diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi
index b41d241de2cd..28b81d60b407 100644
--- a/arch/arm/boot/dts/skeleton.dtsi
+++ b/arch/arm/boot/dts/skeleton.dtsi
@@ -1,4 +1,8 @@
/*
+ * This file is deprecated, and will be removed once existing users have been
+ * updated. New dts{,i} files should *not* include skeleton.dtsi, and should
+ * instead explicitly provide the below nodes only as required.
+ *
* Skeleton device tree; the bare minimum needed to boot; just include and
* add a compatible value. The bootloader will typically populate the memory
* node.
diff --git a/arch/arm/boot/dts/ste-nomadik-nhk15.dts b/arch/arm/boot/dts/ste-nomadik-nhk15.dts
index d35aa88791ad..1ec46a794a4d 100644
--- a/arch/arm/boot/dts/ste-nomadik-nhk15.dts
+++ b/arch/arm/boot/dts/ste-nomadik-nhk15.dts
@@ -140,6 +140,10 @@
0x03020067 // Up
0x0303006c>; // Down
};
+ stmpe0_pwm: stmpe_pwm {
+ compatible = "st,stmpe-pwm";
+ #pwm-cells = <2>;
+ };
};
stmpe1: stmpe2401@44 {
compatible = "st,stmpe2401";
@@ -172,6 +176,50 @@
};
amba {
+ clcd@10120000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&clcd_24bit_mux>;
+ port {
+ nomadik_clcd_pads: endpoint {
+ remote-endpoint = <&nomadik_clcd_panel>;
+ arm,pl11x,tft-r0g0b0-pads = <16 8 0>;
+ };
+ };
+
+ /*
+ * WVGA connector 21
+ * WVGA (800x480): 4.3" TPG110 TDO43MTEA2 24-bit RGB
+ * with TPO touch screen.
+ */
+ panel {
+ compatible = "tpo,tpg110", "panel-dpi";
+ grestb-gpios = <&stmpe_gpio44 5 GPIO_ACTIVE_LOW>;
+ scen-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+ scl-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+ backlight = <&bl>;
+
+ port {
+ nomadik_clcd_panel: endpoint {
+ remote-endpoint = <&nomadik_clcd_pads>;
+ };
+ };
+
+ panel-timing {
+ clock-frequency = <33200000>;
+ hactive = <800>;
+ hback-porch = <216>;
+ hfront-porch = <40>;
+ hsync-len = <1>;
+ vactive = <480>;
+ vback-porch = <35>;
+ vfront-porch = <10>;
+ vsync-len = <1>;
+ };
+ };
+ };
+
/* Activate RX/TX and CTS/RTS on UART 0 */
uart0: uart@101fd000 {
pinctrl-names = "default";
@@ -183,4 +231,24 @@
wp-gpios = <&stmpe_gpio44 18 GPIO_ACTIVE_HIGH>;
};
};
+
+ bl: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&stmpe0_pwm 0 500000>;
+ pwm-names = "backlight";
+ brightness-levels = <
+ 0 1 2 3 4 5 6 7 8 9
+ 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29
+ 30 31 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47 48 49
+ 50 51 52 53 54 55 56 57 58 59
+ 60 61 62 63 64 65 66 67 68 69
+ 70 71 72 73 74 75 76 77 78 79
+ 80 81 82 83 84 85 86 87 88 89
+ 90 91 92 93 94 95 96 97 98 99
+ 100
+ >;
+ default-brightness-level = <100>;
+ };
};
diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
index d2d532a9d783..adb1c0998b81 100644
--- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -166,6 +166,24 @@
};
};
};
+ clcd {
+ /*
+ * This should be activated to use the additional
+ * 8 lines for bits 16 thru 23 from the CLCD block.
+ */
+ clcd_24bit_mux: clcd_mux {
+ clcd_24bit_mux {
+ function = "clcd";
+ groups = "clcd_16_23_b_1";
+ };
+ };
+ };
+ };
+
+ /* Power Management Unit */
+ pmu: pmu@101e9000 {
+ compatible = "stericsson,nomadik-pmu", "syscon";
+ reg = <0x101e0000 0x1000>;
};
src: src@101e0000 {
@@ -726,6 +744,16 @@
#size-cells = <1>;
ranges;
+ clcd@10120000 {
+ compatible = "arm,pl110", "arm,primecell";
+ reg = <0x10120000 0x1000>;
+ interrupt-names = "combined";
+ interrupts = <14>;
+ clocks = <&clcdclk>, <&hclkclcd>;
+ clock-names = "clcdclk", "apb_pclk";
+ status = "disabled";
+ };
+
vica: intc@10140000 {
compatible = "arm,versatile-vic";
interrupt-controller;
diff --git a/arch/arm/boot/dts/stih407-clock.dtsi b/arch/arm/boot/dts/stih407-clock.dtsi
index ad45f5e8fac7..13029c03d7c6 100644
--- a/arch/arm/boot/dts/stih407-clock.dtsi
+++ b/arch/arm/boot/dts/stih407-clock.dtsi
@@ -42,7 +42,7 @@
clockgen_a9_pll: clockgen-a9-pll {
#clock-cells = <1>;
- compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32";
+ compatible = "st,stih407-clkgen-plla9";
clocks = <&clk_sysin>;
@@ -55,7 +55,7 @@
*/
clk_m_a9: clk-m-a9@92b0000 {
#clock-cells = <0>;
- compatible = "st,stih407-clkgen-a9-mux", "st,clkgen-mux";
+ compatible = "st,stih407-clkgen-a9-mux";
reg = <0x92b0000 0x10000>;
clocks = <&clockgen_a9_pll 0>,
@@ -96,7 +96,7 @@
clk_s_a0_pll: clk-s-a0-pll {
#clock-cells = <1>;
- compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll0";
clocks = <&clk_sysin>;
@@ -117,7 +117,7 @@
clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-C", "st,quadfs";
+ compatible = "st,quadfs-pll";
reg = <0x9103000 0x1000>;
clocks = <&clk_sysin>;
@@ -134,7 +134,7 @@
clk_s_c0_pll0: clk-s-c0-pll0 {
#clock-cells = <1>;
- compatible = "st,plls-c32-cx_0", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll0";
clocks = <&clk_sysin>;
@@ -143,7 +143,7 @@
clk_s_c0_pll1: clk-s-c0-pll1 {
#clock-cells = <1>;
- compatible = "st,plls-c32-cx_1", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll1";
clocks = <&clk_sysin>;
@@ -199,7 +199,7 @@
clk_s_d0_quadfs: clk-s-d0-quadfs@9104000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9104000 0x1000>;
clocks = <&clk_sysin>;
@@ -216,7 +216,7 @@
clk_s_d0_flexgen: clk-s-d0-flexgen {
#clock-cells = <1>;
- compatible = "st,flexgen";
+ compatible = "st,flexgen-audio", "st,flexgen";
clocks = <&clk_s_d0_quadfs 0>,
<&clk_s_d0_quadfs 1>,
@@ -233,7 +233,7 @@
clk_s_d2_quadfs: clk-s-d2-quadfs@9106000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9106000 0x1000>;
clocks = <&clk_sysin>;
@@ -256,7 +256,7 @@
clk_s_d2_flexgen: clk-s-d2-flexgen {
#clock-cells = <1>;
- compatible = "st,flexgen";
+ compatible = "st,flexgen-video", "st,flexgen";
clocks = <&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
@@ -287,7 +287,7 @@
clk_s_d3_quadfs: clk-s-d3-quadfs@9107000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9107000 0x1000>;
clocks = <&clk_sysin>;
diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
index 8b063ab10c19..5430747c6b73 100644
--- a/arch/arm/boot/dts/stih407-family.dtsi
+++ b/arch/arm/boot/dts/stih407-family.dtsi
@@ -554,7 +554,6 @@
clocks = <&clk_s_c0_flexgen CLK_MMC_0>,
<&clk_s_c0_flexgen CLK_RX_ICN_HVA>;
bus-width = <8>;
- non-removable;
};
mmc1: sdhci@09080000 {
@@ -610,6 +609,8 @@
clock-names = "ahci_clk";
clocks = <&clk_s_c0_flexgen CLK_ICN_REG>;
+ ports-implemented = <0x1>;
+
status = "disabled";
};
@@ -633,6 +634,8 @@
clock-names = "ahci_clk";
clocks = <&clk_s_c0_flexgen CLK_ICN_REG>;
+ ports-implemented = <0x1>;
+
status = "disabled";
};
@@ -669,6 +672,7 @@
compatible = "st,sti-pwm";
#pwm-cells = <2>;
reg = <0x9810000 0x68>;
+ interrupts = <GIC_SPI 128 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm0_chan0_default>;
clock-names = "pwm";
@@ -823,5 +827,172 @@
clock-frequency = <600000000>;
st,syscfg = <&syscfg_core 0x224>;
};
+
+ /* fdma audio */
+ fdma0: dma-controller@8e20000 {
+ compatible = "st,stih407-fdma-mpe31-11", "st,slim-rproc";
+ reg = <0x8e20000 0x8000>,
+ <0x8e30000 0x3000>,
+ <0x8e37000 0x1000>,
+ <0x8e38000 0x8000>;
+ reg-names = "slimcore", "dmem", "peripherals", "imem";
+ clocks = <&clk_s_c0_flexgen CLK_FDMA>,
+ <&clk_s_c0_flexgen CLK_EXT2F_A9>,
+ <&clk_s_c0_flexgen CLK_EXT2F_A9>,
+ <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_NONE>;
+ dma-channels = <16>;
+ #dma-cells = <3>;
+ };
+
+ /* fdma app */
+ fdma1: dma-controller@8e40000 {
+ compatible = "st,stih407-fdma-mpe31-12", "st,slim-rproc";
+ reg = <0x8e40000 0x8000>,
+ <0x8e50000 0x3000>,
+ <0x8e57000 0x1000>,
+ <0x8e58000 0x8000>;
+ reg-names = "slimcore", "dmem", "peripherals", "imem";
+ clocks = <&clk_s_c0_flexgen CLK_FDMA>,
+ <&clk_s_c0_flexgen CLK_TX_ICN_DMU>,
+ <&clk_s_c0_flexgen CLK_TX_ICN_DMU>,
+ <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+
+ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>;
+ dma-channels = <16>;
+ #dma-cells = <3>;
+ };
+
+ /* fdma free running */
+ fdma2: dma-controller@8e60000 {
+ compatible = "st,stih407-fdma-mpe31-13", "st,slim-rproc";
+ reg = <0x8e60000 0x8000>,
+ <0x8e70000 0x3000>,
+ <0x8e77000 0x1000>,
+ <0x8e78000 0x8000>;
+ reg-names = "slimcore", "dmem", "peripherals", "imem";
+ interrupts = <GIC_SPI 9 IRQ_TYPE_NONE>;
+ dma-channels = <16>;
+ #dma-cells = <3>;
+ clocks = <&clk_s_c0_flexgen CLK_FDMA>,
+ <&clk_s_c0_flexgen CLK_EXT2F_A9>,
+ <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+ <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ };
+
+ sti_sasg_codec: sti-sasg-codec {
+ compatible = "st,stih407-sas-codec";
+ #sound-dai-cells = <1>;
+ status = "disabled";
+ st,syscfg = <&syscfg_core>;
+ };
+
+ sti_uni_player0: sti-uni-player@8d80000 {
+ compatible = "st,sti-uni-player";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ clocks = <&clk_s_d0_flexgen CLK_PCM_0>;
+ assigned-clocks = <&clk_s_d0_quadfs 0>, <&clk_s_d0_flexgen CLK_PCM_0>;
+ assigned-clock-parents = <0>, <&clk_s_d0_quadfs 0>;
+ assigned-clock-rates = <50000000>;
+ reg = <0x8d80000 0x158>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 2 0 1>;
+ dai-name = "Uni Player #0 (HDMI)";
+ dma-names = "tx";
+ st,uniperiph-id = <0>;
+ st,version = <5>;
+ st,mode = "HDMI";
+
+ status = "disabled";
+ };
+
+ sti_uni_player1: sti-uni-player@8d81000 {
+ compatible = "st,sti-uni-player";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ clocks = <&clk_s_d0_flexgen CLK_PCM_1>;
+ assigned-clocks = <&clk_s_d0_quadfs 1>, <&clk_s_d0_flexgen CLK_PCM_1>;
+ assigned-clock-parents = <0>, <&clk_s_d0_quadfs 1>;
+ assigned-clock-rates = <50000000>;
+ reg = <0x8d81000 0x158>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 3 0 1>;
+ dai-name = "Uni Player #1 (PIO)";
+ dma-names = "tx";
+ st,uniperiph-id = <1>;
+ st,version = <5>;
+ st,mode = "PCM";
+
+ status = "disabled";
+ };
+
+ sti_uni_player2: sti-uni-player@8d82000 {
+ compatible = "st,sti-uni-player";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
+ assigned-clocks = <&clk_s_d0_quadfs 2>, <&clk_s_d0_flexgen CLK_PCM_2>;
+ assigned-clock-parents = <0>, <&clk_s_d0_quadfs 2>;
+ assigned-clock-rates = <50000000>;
+ reg = <0x8d82000 0x158>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 4 0 1>;
+ dai-name = "Uni Player #1 (DAC)";
+ dma-names = "tx";
+ st,uniperiph-id = <2>;
+ st,version = <5>;
+ st,mode = "PCM";
+
+ status = "disabled";
+ };
+
+ sti_uni_player3: sti-uni-player@8d85000 {
+ compatible = "st,sti-uni-player";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ clocks = <&clk_s_d0_flexgen CLK_SPDIFF>;
+ assigned-clocks = <&clk_s_d0_quadfs 3>, <&clk_s_d0_flexgen CLK_SPDIFF>;
+ assigned-clock-parents = <0>, <&clk_s_d0_quadfs 3>;
+ assigned-clock-rates = <50000000>;
+ reg = <0x8d85000 0x158>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 7 0 1>;
+ dma-names = "tx";
+ dai-name = "Uni Player #1 (PIO)";
+ st,uniperiph-id = <3>;
+ st,version = <5>;
+ st,mode = "SPDIF";
+
+ status = "disabled";
+ };
+
+ sti_uni_reader0: sti-uni-reader@8d83000 {
+ compatible = "st,sti-uni-reader";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ reg = <0x8d83000 0x158>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 5 0 1>;
+ dma-names = "rx";
+ dai-name = "Uni Reader #0 (PCM IN)";
+ st,version = <3>;
+
+ status = "disabled";
+ };
+
+ sti_uni_reader1: sti-uni-reader@8d84000 {
+ compatible = "st,sti-uni-reader";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ reg = <0x8d84000 0x158>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 6 0 1>;
+ dma-names = "rx";
+ dai-name = "Uni Reader #1 (HDMI RX)";
+ st,version = <3>;
+
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi
index a538ae52d32b..c325cc059ae4 100644
--- a/arch/arm/boot/dts/stih407-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi
@@ -58,7 +58,7 @@
pio0: gpio@09610000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x0 0x100>;
@@ -66,7 +66,7 @@
};
pio1: gpio@09611000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -74,7 +74,7 @@
};
pio2: gpio@09612000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -82,7 +82,7 @@
};
pio3: gpio@09613000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -90,7 +90,7 @@
};
pio4: gpio@09614000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -99,7 +99,7 @@
pio5: gpio@09615000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -230,6 +230,13 @@
};
};
+ pinctrl_rgmii1_mdio_1: rgmii1-mdio-1 {
+ st,pins {
+ mdio = <&pio1 0 ALT1 OUT BYPASS 0>;
+ mdc = <&pio1 1 ALT1 OUT NICLK 0 CLK_A>;
+ };
+ };
+
pinctrl_mii1: mii1 {
st,pins {
txd0 = <&pio0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
@@ -289,10 +296,12 @@
pinctrl_pwm1_chan0_default: pwm1-0-default {
st,pins {
pwm-out = <&pio3 0 ALT1 OUT>;
+ pwm-capturein = <&pio3 2 ALT1 IN>;
};
};
pinctrl_pwm1_chan1_default: pwm1-1-default {
st,pins {
+ pwm-capturein = <&pio4 3 ALT1 IN>;
pwm-out = <&pio4 4 ALT1 OUT>;
};
};
@@ -373,7 +382,7 @@
pio10: pio@09200000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x0 0x100>;
@@ -381,7 +390,7 @@
};
pio11: pio@09201000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -389,7 +398,7 @@
};
pio12: pio@09202000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -397,7 +406,7 @@
};
pio13: pio@09203000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -405,7 +414,7 @@
};
pio14: pio@09204000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -413,7 +422,7 @@
};
pio15: pio@09205000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -421,7 +430,7 @@
};
pio16: pio@09206000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x6000 0x100>;
@@ -429,7 +438,7 @@
};
pio17: pio@09207000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x7000 0x100>;
@@ -437,7 +446,7 @@
};
pio18: pio@09208000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x8000 0x100>;
@@ -445,7 +454,7 @@
};
pio19: pio@09209000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x9000 0x100>;
@@ -523,6 +532,13 @@
scl = <&pio15 5 ALT2 BIDIR>;
};
};
+
+ pinctrl_i2c2_alt2_1: i2c2-alt2-1 {
+ st,pins {
+ sda = <&pio12 6 ALT2 BIDIR>;
+ scl = <&pio12 5 ALT2 BIDIR>;
+ };
+ };
};
i2c3 {
@@ -916,6 +932,15 @@
interrupt-names = "irqmux";
ranges = <0 0x09210000 0x10000>;
+ pio20: pio@09210000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x0 0x100>;
+ st,bank-name = "PIO20";
+ };
+
tsin4 {
pinctrl_tsin4_serial_alt1: tsin4_serial_alt1 {
st,pins {
@@ -927,15 +952,6 @@
};
};
};
-
- pio20: pio@09210000 {
- gpio-controller;
- #gpio-cells = <1>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x0 0x100>;
- st,bank-name = "PIO20";
- };
};
pin-controller-rear {
@@ -951,7 +967,7 @@
pio30: gpio@09220000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x0 0x100>;
@@ -959,7 +975,7 @@
};
pio31: gpio@09221000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -967,7 +983,7 @@
};
pio32: gpio@09222000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -975,7 +991,7 @@
};
pio33: gpio@09223000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -983,7 +999,7 @@
};
pio34: gpio@09224000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -991,7 +1007,7 @@
};
pio35: gpio@09225000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -1030,6 +1046,7 @@
pwm0 {
pinctrl_pwm0_chan0_default: pwm0-0-default {
st,pins {
+ pwm-capturein = <&pio31 0 ALT1 IN>;
pwm-out = <&pio31 1 ALT1 OUT>;
};
};
@@ -1067,6 +1084,61 @@
};
};
+ i2s_out {
+ pinctrl_i2s_8ch_out: i2s_8ch_out{
+ st,pins {
+ mclk = <&pio33 5 ALT1 OUT>;
+ lrclk = <&pio33 7 ALT1 OUT>;
+ sclk = <&pio33 6 ALT1 OUT>;
+ data0 = <&pio33 4 ALT1 OUT>;
+ data1 = <&pio34 0 ALT1 OUT>;
+ data2 = <&pio34 1 ALT1 OUT>;
+ data3 = <&pio34 2 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_i2s_2ch_out: i2s_2ch_out{
+ st,pins {
+ mclk = <&pio33 5 ALT1 OUT>;
+ lrclk = <&pio33 7 ALT1 OUT>;
+ sclk = <&pio33 6 ALT1 OUT>;
+ data0 = <&pio33 4 ALT1 OUT>;
+ };
+ };
+ };
+
+ i2s_in {
+ pinctrl_i2s_8ch_in: i2s_8ch_in{
+ st,pins {
+ mclk = <&pio32 5 ALT1 IN>;
+ lrclk = <&pio32 7 ALT1 IN>;
+ sclk = <&pio32 6 ALT1 IN>;
+ data0 = <&pio32 4 ALT1 IN>;
+ data1 = <&pio33 0 ALT1 IN>;
+ data2 = <&pio33 1 ALT1 IN>;
+ data3 = <&pio33 2 ALT1 IN>;
+ data4 = <&pio33 3 ALT1 IN>;
+ };
+ };
+
+ pinctrl_i2s_2ch_in: i2s_2ch_in{
+ st,pins {
+ mclk = <&pio32 5 ALT1 IN>;
+ lrclk = <&pio32 7 ALT1 IN>;
+ sclk = <&pio32 6 ALT1 IN>;
+ data0 = <&pio32 4 ALT1 IN>;
+ };
+ };
+ };
+
+ spdif_out {
+ pinctrl_spdif_out: spdif_out{
+ st,pins {
+ spdif_out = <&pio34 7 ALT1 OUT>;
+ };
+ };
+ };
+
serial3 {
pinctrl_serial3: serial3-0 {
st,pins {
@@ -1090,7 +1162,7 @@
pio40: gpio@09230000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -1098,7 +1170,7 @@
};
pio41: gpio@09231000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -1106,7 +1178,7 @@
};
pio42: gpio@09232000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi
index d60f0d8add26..291ffacbd2e0 100644
--- a/arch/arm/boot/dts/stih407.dtsi
+++ b/arch/arm/boot/dts/stih407.dtsi
@@ -16,7 +16,10 @@
#size-cells = <1>;
assigned-clocks = <&clk_s_d2_quadfs 0>,
- <&clk_s_d2_quadfs 0>,
+ <&clk_s_d2_quadfs 1>,
+ <&clk_s_c0_pll1 0>,
+ <&clk_s_c0_flexgen CLK_COMPO_DVP>,
+ <&clk_s_c0_flexgen CLK_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
<&clk_s_d2_flexgen CLK_PIX_GDP1>,
@@ -26,14 +29,21 @@
assigned-clock-parents = <0>,
<0>,
+ <0>,
+ <&clk_s_c0_pll1 0>,
+ <&clk_s_c0_pll1 0>,
<&clk_s_d2_quadfs 0>,
- <&clk_s_d2_quadfs 0>,
+ <&clk_s_d2_quadfs 1>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>;
- assigned-clock-rates = <297000000>, <297000000>;
+ assigned-clock-rates = <297000000>,
+ <108000000>,
+ <0>,
+ <400000000>,
+ <400000000>;
ranges;
diff --git a/arch/arm/boot/dts/stih410-b2260.dts b/arch/arm/boot/dts/stih410-b2260.dts
new file mode 100644
index 000000000000..ef2ff2f518f6
--- /dev/null
+++ b/arch/arm/boot/dts/stih410-b2260.dts
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 STMicroelectronics (R&D) Limited.
+ * Author: Patrice Chotard <patrice.chotard@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih410.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "STiH410 B2260";
+ compatible = "st,stih410-b2260", "st,stih410";
+
+ chosen {
+ bootargs = "console=ttyAS1,115200 clk_ignore_unused";
+ linux,stdout-path = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x40000000>;
+ };
+
+ aliases {
+ ttyAS1 = &uart1;
+ ethernet0 = &ethernet0;
+ };
+
+ soc {
+
+ leds {
+ compatible = "gpio-leds";
+ user_green_1 {
+ label = "User_green_1";
+ gpios = <&pio1 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ user_green_2 {
+ label = "User_green_2";
+ gpios = <&pio4 1 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ user_green_3 {
+ label = "User_green_3";
+ gpios = <&pio2 1 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ user_green_4 {
+ label = "User_green_4";
+ gpios = <&pio2 5 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+
+ /* Low speed expansion connector */
+ uart0: serial@9830000 {
+ label = "LS-UART0";
+ status = "okay";
+ };
+
+ /* Low speed expansion connector */
+ uart1: serial@9831000 {
+ label = "LS-UART1";
+ status = "okay";
+ };
+
+ /* Low speed expansion connector */
+ spi0: spi@9844000 {
+ label = "LS-SPI0";
+ cs-gpio = <&pio30 3 0>;
+ status = "okay";
+ };
+
+ /* Low speed expansion connector */
+ i2c0: i2c@9840000 {
+ label = "LS-I2C0";
+ status = "okay";
+ };
+
+ /* Low speed expansion connector */
+ i2c1: i2c@9841000 {
+ label = "LS-I2C1";
+ status = "okay";
+ };
+
+ /* high speed expansion connector */
+ i2c2: i2c@9842000 {
+ label = "HS-I2C2";
+ pinctrl-0 = <&pinctrl_i2c2_alt2_1>;
+ status = "okay";
+ };
+
+ /* high speed expansion connector */
+ i2c3: i2c@9843000 {
+ label = "HS-I2C3";
+ pinctrl-0 = <&pinctrl_i2c3_alt3_0>;
+ status = "okay";
+ };
+
+ mmc0: sdhci@09060000 {
+ pinctrl-0 = <&pinctrl_sd0>;
+ bus-width = <4>;
+ status = "okay";
+ };
+
+ /* high speed expansion connector */
+ mmc1: sdhci@09080000 {
+ status = "okay";
+ };
+
+ pwm0: pwm@9810000 {
+ status = "okay";
+ };
+
+ pwm1: pwm@9510000 {
+ status = "okay";
+ };
+
+ usb2_picophy1: phy2 {
+ status = "okay";
+ };
+
+ usb2_picophy2: phy3 {
+ status = "okay";
+ };
+
+ ohci0: usb@9a03c00 {
+ status = "okay";
+ };
+
+ ehci0: usb@9a03e00 {
+ status = "okay";
+ };
+
+ ohci1: usb@9a83c00 {
+ status = "okay";
+ };
+
+ ehci1: usb@9a83e00 {
+ status = "okay";
+ };
+
+ st_dwc3: dwc3@8f94000 {
+ status = "okay";
+ };
+
+ ethernet0: dwmac@9630000 {
+ phy-mode = "rgmii";
+ pinctrl-0 = <&pinctrl_rgmii1 &pinctrl_rgmii1_mdio_1>;
+
+ snps,phy-bus-name = "stmmac";
+ snps,phy-bus-id = <0>;
+ snps,phy-addr = <0>;
+ snps,reset-gpio = <&pio0 7 0>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 1000000>;
+
+ status = "okay";
+ };
+
+ /* SSC11 to HDMI */
+ hdmiddc: i2c@9541000 {
+ /* HDMI V1.3a supports Standard mode only */
+ clock-frequency = <100000>;
+ st,i2c-min-scl-pulse-width-us = <0>;
+ st,i2c-min-sda-pulse-width-us = <5>;
+ status = "okay";
+ };
+
+ sti-display-subsystem {
+ sti_hdmi: sti-hdmi@8d04000 {
+ status = "okay";
+ };
+ };
+
+ miphy28lp_phy: miphy28lp@9b22000 {
+
+ phy_port1: port@9b2a000 {
+ st,osc-force-ext;
+ };
+ };
+
+ sata1: sata@9b28000 {
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih410-clock.dtsi b/arch/arm/boot/dts/stih410-clock.dtsi
index fd5049682181..8598effd6c01 100644
--- a/arch/arm/boot/dts/stih410-clock.dtsi
+++ b/arch/arm/boot/dts/stih410-clock.dtsi
@@ -44,7 +44,7 @@
clockgen_a9_pll: clockgen-a9-pll {
#clock-cells = <1>;
- compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32";
+ compatible = "st,stih407-clkgen-plla9";
clocks = <&clk_sysin>;
@@ -98,7 +98,7 @@
clk_s_a0_pll: clk-s-a0-pll {
#clock-cells = <1>;
- compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll0";
clocks = <&clk_sysin>;
@@ -122,7 +122,7 @@
clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-C", "st,quadfs";
+ compatible = "st,quadfs-pll";
reg = <0x9103000 0x1000>;
clocks = <&clk_sysin>;
@@ -140,7 +140,7 @@
clk_s_c0_pll0: clk-s-c0-pll0 {
#clock-cells = <1>;
- compatible = "st,plls-c32-cx_0", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll0";
clocks = <&clk_sysin>;
@@ -150,7 +150,7 @@
clk_s_c0_pll1: clk-s-c0-pll1 {
#clock-cells = <1>;
- compatible = "st,plls-c32-cx_1", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll1";
clocks = <&clk_sysin>;
@@ -218,7 +218,7 @@
clk_s_d0_quadfs: clk-s-d0-quadfs@9104000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9104000 0x1000>;
clocks = <&clk_sysin>;
@@ -235,7 +235,7 @@
clk_s_d0_flexgen: clk-s-d0-flexgen {
#clock-cells = <1>;
- compatible = "st,flexgen";
+ compatible = "st,flexgen-audio", "st,flexgen";
clocks = <&clk_s_d0_quadfs 0>,
<&clk_s_d0_quadfs 1>,
@@ -254,7 +254,7 @@
clk_s_d2_quadfs: clk-s-d2-quadfs@9106000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9106000 0x1000>;
clocks = <&clk_sysin>;
@@ -277,7 +277,7 @@
clk_s_d2_flexgen: clk-s-d2-flexgen {
#clock-cells = <1>;
- compatible = "st,flexgen";
+ compatible = "st,flexgen-video", "st,flexgen";
clocks = <&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
@@ -308,7 +308,7 @@
clk_s_d3_quadfs: clk-s-d3-quadfs@9107000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9107000 0x1000>;
clocks = <&clk_sysin>;
diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi
index 40318869c733..a3ef7341c051 100644
--- a/arch/arm/boot/dts/stih410.dtsi
+++ b/arch/arm/boot/dts/stih410.dtsi
@@ -107,7 +107,10 @@
#size-cells = <1>;
assigned-clocks = <&clk_s_d2_quadfs 0>,
- <&clk_s_d2_quadfs 0>,
+ <&clk_s_d2_quadfs 1>,
+ <&clk_s_c0_pll1 0>,
+ <&clk_s_c0_flexgen CLK_COMPO_DVP>,
+ <&clk_s_c0_flexgen CLK_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
<&clk_s_d2_flexgen CLK_PIX_GDP1>,
@@ -117,14 +120,21 @@
assigned-clock-parents = <0>,
<0>,
+ <0>,
+ <&clk_s_c0_pll1 0>,
+ <&clk_s_c0_pll1 0>,
<&clk_s_d2_quadfs 0>,
- <&clk_s_d2_quadfs 0>,
+ <&clk_s_d2_quadfs 1>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>;
- assigned-clock-rates = <297000000>, <297000000>;
+ assigned-clock-rates = <297000000>,
+ <108000000>,
+ <0>,
+ <400000000>,
+ <400000000>;
ranges;
@@ -231,5 +241,23 @@
clock-names = "bdisp";
clocks = <&clk_s_c0_flexgen CLK_IC_BDISP_0>;
};
+
+ hva@8c85000 {
+ compatible = "st,st-hva";
+ reg = <0x8c85000 0x400>, <0x6000000 0x40000>;
+ reg-names = "hva_registers", "hva_esram";
+ interrupts = <GIC_SPI 58 IRQ_TYPE_NONE>,
+ <GIC_SPI 59 IRQ_TYPE_NONE>;
+ clock-names = "clk_hva";
+ clocks = <&clk_s_c0_flexgen CLK_HVA>;
+ };
+
+ thermal@91a0000 {
+ compatible = "st,stih407-thermal";
+ reg = <0x91a0000 0x28>;
+ clock-names = "thermal";
+ clocks = <&clk_sysin>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi
index 3791ad95dbaf..bd028ce98b61 100644
--- a/arch/arm/boot/dts/stih415-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi
@@ -54,7 +54,7 @@
pio0: gpio@fe610000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -62,7 +62,7 @@
};
pio1: gpio@fe611000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -70,7 +70,7 @@
};
pio2: gpio@fe612000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -78,7 +78,7 @@
};
pio3: gpio@fe613000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -86,7 +86,7 @@
};
pio4: gpio@fe614000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -208,7 +208,7 @@
pio5: gpio@fee00000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -216,7 +216,7 @@
};
pio6: gpio@fee01000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -224,7 +224,7 @@
};
pio7: gpio@fee02000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -232,7 +232,7 @@
};
pio8: gpio@fee03000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -240,7 +240,7 @@
};
pio9: gpio@fee04000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -248,7 +248,7 @@
};
pio10: gpio@fee05000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -256,7 +256,7 @@
};
pio11: gpio@fee06000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x6000 0x100>;
@@ -264,7 +264,7 @@
};
pio12: gpio@fee07000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x7000 0x100>;
@@ -303,7 +303,7 @@
pio13: gpio@fe820000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -311,7 +311,7 @@
};
pio14: gpio@fe821000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -319,7 +319,7 @@
};
pio15: gpio@fe822000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -327,7 +327,7 @@
};
pio16: gpio@fe823000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -335,7 +335,7 @@
};
pio17: gpio@fe824000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -343,7 +343,7 @@
};
pio18: gpio@fe825000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -465,7 +465,7 @@
pio100: gpio@fd6b0000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -473,7 +473,7 @@
};
pio101: gpio@fd6b1000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -481,7 +481,7 @@
};
pio102: gpio@fd6b2000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -502,7 +502,7 @@
pio103: gpio@fd330000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -510,7 +510,7 @@
};
pio104: gpio@fd331000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -518,7 +518,7 @@
};
pio105: gpio@fd332000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -526,7 +526,7 @@
};
pio106: gpio@fd333000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -534,7 +534,7 @@
};
pio107: gpio@fd334000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
diff --git a/arch/arm/boot/dts/stih416-b2020e.dts b/arch/arm/boot/dts/stih416-b2020e.dts
index f1ceee192a0e..de320cd067de 100644
--- a/arch/arm/boot/dts/stih416-b2020e.dts
+++ b/arch/arm/boot/dts/stih416-b2020e.dts
@@ -9,6 +9,7 @@
/dts-v1/;
#include "stih416.dtsi"
#include "stih41x-b2020.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "STiH416 B2020 REV-E";
compatible = "st,stih416-b2020", "st,stih416";
@@ -17,13 +18,12 @@
leds {
compatible = "gpio-leds";
red {
- #gpio-cells = <1>;
label = "Front Panel LED";
- gpios = <&pio4 1>;
+ gpios = <&pio4 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
green {
- gpios = <&pio1 3>;
+ gpios = <&pio1 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi
index 051fc16f3706..9c97f7e651a0 100644
--- a/arch/arm/boot/dts/stih416-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi
@@ -58,7 +58,7 @@
pio0: gpio@fe610000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -66,7 +66,7 @@
};
pio1: gpio@fe611000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -74,7 +74,7 @@
};
pio2: gpio@fe612000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -82,7 +82,7 @@
};
pio3: gpio@fe613000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -90,7 +90,7 @@
};
pio4: gpio@fe614000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -98,7 +98,7 @@
};
pio40: gpio@fe615000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -221,11 +221,14 @@
pinctrl_pwm1_chan0_default: pwm1-0-default {
st,pins {
pwm-out = <&pio3 0 ALT1 OUT>;
+ pwm-capturein = <&pio3 2 ALT1 IN>;
+
};
};
pinctrl_pwm1_chan1_default: pwm1-1-default {
st,pins {
pwm-out = <&pio4 4 ALT1 OUT>;
+ pwm-capturein = <&pio4 3 ALT1 IN>;
};
};
pinctrl_pwm1_chan2_default: pwm1-2-default {
@@ -254,7 +257,7 @@
pio5: gpio@fee00000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -262,7 +265,7 @@
};
pio6: gpio@fee01000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -270,7 +273,7 @@
};
pio7: gpio@fee02000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -278,7 +281,7 @@
};
pio8: gpio@fee03000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -286,7 +289,7 @@
};
pio9: gpio@fee04000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -294,7 +297,7 @@
};
pio10: gpio@fee05000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -302,7 +305,7 @@
};
pio11: gpio@fee06000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x6000 0x100>;
@@ -310,7 +313,7 @@
};
pio12: gpio@fee07000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x7000 0x100>;
@@ -318,7 +321,7 @@
};
pio30: gpio@fee08000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x8000 0x100>;
@@ -326,7 +329,7 @@
};
pio31: gpio@fee09000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x9000 0x100>;
@@ -337,6 +340,7 @@
pinctrl_pwm0_chan0_default: pwm0-0-default {
st,pins {
pwm-out = <&pio9 7 ALT2 OUT>;
+ pwm-capturein = <&pio9 6 ALT2 IN>;
};
};
};
@@ -404,7 +408,7 @@
pio13: gpio@fe820000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -412,7 +416,7 @@
};
pio14: gpio@fe821000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -420,7 +424,7 @@
};
pio15: gpio@fe822000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -428,7 +432,7 @@
};
pio16: gpio@fe823000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -436,7 +440,7 @@
};
pio17: gpio@fe824000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
@@ -444,7 +448,7 @@
};
pio18: gpio@fe825000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
@@ -576,6 +580,7 @@
pinctrl_pwm0_chan1_default: pwm0-1-default {
st,pins {
pwm-out = <&pio13 2 ALT2 OUT>;
+ pwm-capturein = <&pio13 1 ALT2 IN>;
};
};
pinctrl_pwm0_chan2_default: pwm0-2-default {
@@ -605,7 +610,7 @@
pio100: gpio@fd6b0000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -613,7 +618,7 @@
};
pio101: gpio@fd6b1000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -621,7 +626,7 @@
};
pio102: gpio@fd6b2000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -642,7 +647,7 @@
pio103: gpio@fd330000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0 0x100>;
@@ -650,7 +655,7 @@
};
pio104: gpio@fd331000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x1000 0x100>;
@@ -658,7 +663,7 @@
};
pio105: gpio@fd332000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2000 0x100>;
@@ -666,7 +671,7 @@
};
pio106: gpio@fd333000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x3000 0x100>;
@@ -675,7 +680,7 @@
pio107: gpio@fd334000 {
gpio-controller;
- #gpio-cells = <1>;
+ #gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x4000 0x100>;
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index 9e3170ccd18c..fe1f9cf770e4 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -474,6 +474,7 @@
status = "disabled";
#pwm-cells = <2>;
reg = <0xfed10000 0x68>;
+ interrupts = <GIC_SPI 200 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm0_chan0_default
@@ -481,9 +482,11 @@
&pinctrl_pwm0_chan2_default
&pinctrl_pwm0_chan3_default>;
- clock-names = "pwm";
- clocks = <&clk_sysin>;
+ clock-names = "pwm", "capture";
+ clocks = <&clk_sysin>, <&clk_s_a0_ls CLK_ICN_REG>;
+
st,pwm-num-chan = <4>;
+ st,capture-num-chan = <2>;
};
/* SBC PWM Module */
@@ -492,6 +495,7 @@
status = "disabled";
#pwm-cells = <2>;
reg = <0xfe510000 0x68>;
+ interrupts = <GIC_SPI 202 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm1_chan0_default
diff --git a/arch/arm/boot/dts/stih418-b2199.dts b/arch/arm/boot/dts/stih418-b2199.dts
index 772d2bb07e5f..438e54c585b1 100644
--- a/arch/arm/boot/dts/stih418-b2199.dts
+++ b/arch/arm/boot/dts/stih418-b2199.dts
@@ -8,6 +8,7 @@
*/
/dts-v1/;
#include "stih418.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "STiH418 B2199";
compatible = "st,stih418-b2199", "st,stih418";
@@ -35,14 +36,12 @@
leds {
compatible = "gpio-leds";
red {
- #gpio-cells = <2>;
label = "Front Panel LED";
- gpios = <&pio4 1 0>;
+ gpios = <&pio4 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
green {
- #gpio-cells = <2>;
- gpios = <&pio1 3 0>;
+ gpios = <&pio1 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
@@ -86,6 +85,7 @@
sd-uhs-sdr50;
sd-uhs-sdr104;
sd-uhs-ddr50;
+ non-removable;
};
miphy28lp_phy: miphy28lp@9b22000 {
diff --git a/arch/arm/boot/dts/stih418-clock.dtsi b/arch/arm/boot/dts/stih418-clock.dtsi
index ae6d9978ea19..ee6614b79f7d 100644
--- a/arch/arm/boot/dts/stih418-clock.dtsi
+++ b/arch/arm/boot/dts/stih418-clock.dtsi
@@ -44,7 +44,7 @@
clockgen_a9_pll: clockgen-a9-pll {
#clock-cells = <1>;
- compatible = "st,stih418-plls-c28-a9", "st,clkgen-plls-c32";
+ compatible = "st,stih418-clkgen-plla9";
clocks = <&clk_sysin>;
@@ -98,7 +98,7 @@
clk_s_a0_pll: clk-s-a0-pll {
#clock-cells = <1>;
- compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll0";
clocks = <&clk_sysin>;
@@ -120,7 +120,7 @@
clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-C", "st,quadfs";
+ compatible = "st,quadfs-pll";
reg = <0x9103000 0x1000>;
clocks = <&clk_sysin>;
@@ -137,7 +137,7 @@
clk_s_c0_pll0: clk-s-c0-pll0 {
#clock-cells = <1>;
- compatible = "st,plls-c32-cx_0", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll0";
clocks = <&clk_sysin>;
@@ -146,7 +146,7 @@
clk_s_c0_pll1: clk-s-c0-pll1 {
#clock-cells = <1>;
- compatible = "st,plls-c32-cx_1", "st,clkgen-plls-c32";
+ compatible = "st,clkgen-pll1";
clocks = <&clk_sysin>;
@@ -212,7 +212,7 @@
clk_s_d0_quadfs: clk-s-d0-quadfs@9104000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9104000 0x1000>;
clocks = <&clk_sysin>;
@@ -229,7 +229,7 @@
clk_s_d0_flexgen: clk-s-d0-flexgen {
#clock-cells = <1>;
- compatible = "st,flexgen";
+ compatible = "st,flexgen-audio", "st,flexgen";
clocks = <&clk_s_d0_quadfs 0>,
<&clk_s_d0_quadfs 1>,
@@ -248,7 +248,7 @@
clk_s_d2_quadfs: clk-s-d2-quadfs@9106000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9106000 0x1000>;
clocks = <&clk_sysin>;
@@ -271,7 +271,7 @@
clk_s_d2_flexgen: clk-s-d2-flexgen {
#clock-cells = <1>;
- compatible = "st,flexgen";
+ compatible = "st,flexgen-video", "st,flexgen";
clocks = <&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
@@ -309,7 +309,7 @@
clk_s_d3_quadfs: clk-s-d3-quadfs@9107000 {
#clock-cells = <1>;
- compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ compatible = "st,quadfs";
reg = <0x9107000 0x1000>;
clocks = <&clk_sysin>;
diff --git a/arch/arm/boot/dts/stih41x-b2000.dtsi b/arch/arm/boot/dts/stih41x-b2000.dtsi
index 5f91f455f05b..9bfa0674b452 100644
--- a/arch/arm/boot/dts/stih41x-b2000.dtsi
+++ b/arch/arm/boot/dts/stih41x-b2000.dtsi
@@ -7,6 +7,8 @@
* publishhed by the Free Software Foundation.
*/
#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
/ {
memory{
@@ -33,9 +35,8 @@
leds {
compatible = "gpio-leds";
fp_led {
- #gpio-cells = <1>;
label = "Front Panel LED";
- gpios = <&pio105 7>;
+ gpios = <&pio105 7 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
};
diff --git a/arch/arm/boot/dts/stih41x-b2020.dtsi b/arch/arm/boot/dts/stih41x-b2020.dtsi
index 487d7d87dbef..322e0e95176c 100644
--- a/arch/arm/boot/dts/stih41x-b2020.dtsi
+++ b/arch/arm/boot/dts/stih41x-b2020.dtsi
@@ -7,6 +7,7 @@
* publishhed by the Free Software Foundation.
*/
#include "stih41x-b2020x.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
memory{
device_type = "memory";
@@ -30,13 +31,12 @@
leds {
compatible = "gpio-leds";
red {
- #gpio-cells = <1>;
label = "Front Panel LED";
- gpios = <&pio4 1>;
+ gpios = <&pio4 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
green {
- gpios = <&pio4 7>;
+ gpios = <&pio4 7 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
index 133375bc8aa5..ed2b7a99ecff 100644
--- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -18,14 +18,12 @@
leds {
compatible = "gpio-leds";
red {
- #gpio-cells = <2>;
label = "Front Panel LED";
- gpios = <&pio4 1 0>;
+ gpios = <&pio4 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
green {
- #gpio-cells = <2>;
- gpios = <&pio1 3 0>;
+ gpios = <&pio1 3 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
@@ -65,6 +63,7 @@
};
mmc0: sdhci@09060000 {
+ non-removable;
status = "okay";
};
@@ -135,5 +134,50 @@
dvb-card = <STV0367_TDA18212_NIMA_1>;
};
};
+
+ sti_uni_player2: sti-uni-player@8d82000 {
+ status = "okay";
+ };
+
+ sti_uni_player3: sti-uni-player@8d85000 {
+ status = "okay";
+ };
+
+ sti_sasg_codec: sti-sasg-codec {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spdif_out>;
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "sti audio card";
+ status = "okay";
+
+ simple-audio-card,dai-link@0 {
+ /* DAC */
+ format = "i2s";
+ mclk-fs = <256>;
+ cpu {
+ sound-dai = <&sti_uni_player2>;
+ };
+
+ codec {
+ sound-dai = <&sti_sasg_codec 1>;
+ };
+ };
+ simple-audio-card,dai-link@1 {
+ /* SPDIF */
+ format = "left_j";
+ mclk-fs = <128>;
+ cpu {
+ sound-dai = <&sti_uni_player3>;
+ };
+
+ codec {
+ sound-dai = <&sti_sasg_codec 0>;
+ };
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 1a189d44ad38..336ee4fb587d 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -45,6 +45,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "skeleton.dtsi"
#include "armv7-m.dtsi"
#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
@@ -334,6 +335,7 @@
};
rcc: rcc@40023810 {
+ #reset-cells = <1>;
#clock-cells = <2>;
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
diff --git a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
index f3cb297fd1db..5f98582232d6 100644
--- a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
+++ b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
@@ -121,10 +121,6 @@
status = "okay";
};
-&ohci1 {
- status = "okay";
-};
-
&otg_sram {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun5i-a13-empire-electronix-m712.dts b/arch/arm/boot/dts/sun5i-a13-empire-electronix-m712.dts
new file mode 100644
index 000000000000..b1e2afd9de52
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-empire-electronix-m712.dts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "sun5i-a13.dtsi"
+#include "sun5i-reference-design-tablet.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "Empire Electronix M712 tablet";
+ compatible = "empire-electronix,m712", "allwinner,sun5i-a13";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts b/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts
index 1b11ec95ae53..439ae3b537df 100644
--- a/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts
+++ b/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts
@@ -42,171 +42,9 @@
/dts-v1/;
#include "sun5i-a13.dtsi"
-#include "sunxi-common-regulators.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include "sun5i-reference-design-tablet.dtsi"
/ {
model = "INet-98V Rev 02";
compatible = "primux,inet98v-rev2", "allwinner,sun5i-a13";
-
- aliases {
- serial0 = &uart1;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-
-};
-
-&cpu0 {
- cpu-supply = <&reg_dcdc2>;
-};
-
-&ehci0 {
- status = "okay";
-};
-
-&i2c0 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- reg = <0x34>;
- interrupts = <0>;
- };
-};
-
-#include "axp209.dtsi"
-
-&i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
-
- pcf8563: rtc@51 {
- compatible = "nxp,pcf8563";
- reg = <0x51>;
- };
-};
-
-&lradc {
- vref-supply = <&reg_ldo2>;
- status = "okay";
-
- button@200 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <200000>;
- };
-
- button@400 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <400000>;
- };
-};
-
-&mmc0 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_inet98fv2>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
- cd-inverted;
- status = "okay";
-};
-
-&otg_sram {
- status = "okay";
-};
-
-&pio {
- mmc0_cd_pin_inet98fv2: mmc0_cd_pin@0 {
- allwinner,pins = "PG0";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
- allwinner,pins = "PG1";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
- };
-
- usb0_id_detect_pin: usb0_id_detect_pin@0 {
- allwinner,pins = "PG2";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-};
-
-&reg_dcdc2 {
- regulator-always-on;
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1400000>;
- regulator-name = "vdd-cpu";
-};
-
-&reg_dcdc3 {
- regulator-always-on;
- regulator-min-microvolt = <1250000>;
- regulator-max-microvolt = <1250000>;
- regulator-name = "vdd-int-pll";
-};
-
-&reg_ldo1 {
- regulator-name = "vdd-rtc";
-};
-
-&reg_ldo2 {
- regulator-always-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-name = "avcc";
-};
-
-&reg_ldo3 {
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "vcc-wifi";
-};
-
-&reg_usb0_vbus {
- gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
- status = "okay";
-};
-
-&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins_b>;
- status = "okay";
-};
-
-&usb_otg {
- dr_mode = "otg";
- status = "okay";
-};
-
-&usb0_vbus_pin_a {
- allwinner,pins = "PG12";
-};
-
-&usbphy {
- pinctrl-names = "default";
- pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
- usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
- usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
- usb0_vbus-supply = <&reg_usb0_vbus>;
- usb1_vbus-supply = <&reg_ldo3>;
- status = "okay";
};
diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts
index f694482bdeb6..b68a12374b35 100644
--- a/arch/arm/boot/dts/sun5i-r8-chip.dts
+++ b/arch/arm/boot/dts/sun5i-r8-chip.dts
@@ -64,6 +64,16 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "chip:white:status";
+ gpios = <&axp_gpio 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+ };
};
&be0 {
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 0d24f107ede0..ce1960453a0b 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -47,7 +47,9 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/clock/sun6i-a31-ccu.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/reset/sun6i-a31-ccu.h>
/ {
interrupt-parent = <&gic>;
@@ -65,7 +67,10 @@
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
- clocks = <&pll6 0>;
+ clocks = <&ccu CLK_AHB1_BE0>, <&ccu CLK_AHB1_LCD0>,
+ <&ccu CLK_AHB1_HDMI>, <&ccu CLK_DRAM_BE0>,
+ <&ccu CLK_IEP_DRC0>, <&ccu CLK_BE0>,
+ <&ccu CLK_LCD0_CH1>, <&ccu CLK_HDMI>;
status = "disabled";
};
@@ -73,7 +78,9 @@
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
- clocks = <&pll6 0>;
+ clocks = <&ccu CLK_AHB1_BE0>, <&ccu CLK_AHB1_LCD0>,
+ <&ccu CLK_DRAM_BE0>, <&ccu CLK_IEP_DRC0>,
+ <&ccu CLK_BE0>, <&ccu CLK_LCD0_CH0>;
status = "disabled";
};
};
@@ -97,7 +104,7 @@
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
- clocks = <&cpu>;
+ clocks = <&ccu CLK_CPU>;
clock-latency = <244144>; /* 8 32k periods */
operating-points = <
/* kHz uV */
@@ -192,235 +199,6 @@
clock-output-names = "osc32k";
};
- pll1: clk@01c20000 {
- #clock-cells = <0>;
- compatible = "allwinner,sun6i-a31-pll1-clk";
- reg = <0x01c20000 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll1";
- };
-
- pll6: clk@01c20028 {
- #clock-cells = <1>;
- compatible = "allwinner,sun6i-a31-pll6-clk";
- reg = <0x01c20028 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll6", "pll6x2";
- };
-
- cpu: cpu@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-cpu-clk";
- reg = <0x01c20050 0x4>;
-
- /*
- * PLL1 is listed twice here.
- * While it looks suspicious, it's actually documented
- * that way both in the datasheet and in the code from
- * Allwinner.
- */
- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
- clock-output-names = "cpu";
- };
-
- axi: axi@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-axi-clk";
- reg = <0x01c20050 0x4>;
- clocks = <&cpu>;
- clock-output-names = "axi";
- };
-
- ahb1: ahb1@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun6i-a31-ahb1-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
- clock-output-names = "ahb1";
-
- /*
- * Clock AHB1 from PLL6, instead of CPU/AXI which
- * has rate changes due to cpufreq. Also the DMA
- * controller requires AHB1 clocked from PLL6.
- */
- assigned-clocks = <&ahb1>;
- assigned-clock-parents = <&pll6 0>;
- };
-
- ahb1_gates: clk@01c20060 {
- #clock-cells = <1>;
- compatible = "allwinner,sun6i-a31-ahb1-gates-clk";
- reg = <0x01c20060 0x8>;
- clocks = <&ahb1>;
- clock-indices = <1>, <5>,
- <6>, <8>, <9>,
- <10>, <11>, <12>,
- <13>, <14>,
- <17>, <18>, <19>,
- <20>, <21>, <22>,
- <23>, <24>, <26>,
- <27>, <29>,
- <30>, <31>, <32>,
- <36>, <37>, <40>,
- <43>, <44>, <45>,
- <46>, <47>, <50>,
- <52>, <55>, <56>,
- <57>, <58>;
- clock-output-names = "ahb1_mipidsi", "ahb1_ss",
- "ahb1_dma", "ahb1_mmc0", "ahb1_mmc1",
- "ahb1_mmc2", "ahb1_mmc3", "ahb1_nand1",
- "ahb1_nand0", "ahb1_sdram",
- "ahb1_gmac", "ahb1_ts", "ahb1_hstimer",
- "ahb1_spi0", "ahb1_spi1", "ahb1_spi2",
- "ahb1_spi3", "ahb1_otg", "ahb1_ehci0",
- "ahb1_ehci1", "ahb1_ohci0",
- "ahb1_ohci1", "ahb1_ohci2", "ahb1_ve",
- "ahb1_lcd0", "ahb1_lcd1", "ahb1_csi",
- "ahb1_hdmi", "ahb1_de0", "ahb1_de1",
- "ahb1_fe0", "ahb1_fe1", "ahb1_mp",
- "ahb1_gpu", "ahb1_deu0", "ahb1_deu1",
- "ahb1_drc0", "ahb1_drc1";
- };
-
- apb1: apb1@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb0-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&ahb1>;
- clock-output-names = "apb1";
- };
-
- apb1_gates: clk@01c20068 {
- #clock-cells = <1>;
- compatible = "allwinner,sun6i-a31-apb1-gates-clk";
- reg = <0x01c20068 0x4>;
- clocks = <&apb1>;
- clock-indices = <0>, <4>,
- <5>, <12>,
- <13>;
- clock-output-names = "apb1_codec", "apb1_digital_mic",
- "apb1_pio", "apb1_daudio0",
- "apb1_daudio1";
- };
-
- apb2: clk@01c20058 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb1-clk";
- reg = <0x01c20058 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
- clock-output-names = "apb2";
- };
-
- apb2_gates: clk@01c2006c {
- #clock-cells = <1>;
- compatible = "allwinner,sun6i-a31-apb2-gates-clk";
- reg = <0x01c2006c 0x4>;
- clocks = <&apb2>;
- clock-indices = <0>, <1>,
- <2>, <3>, <16>,
- <17>, <18>, <19>,
- <20>, <21>;
- clock-output-names = "apb2_i2c0", "apb2_i2c1",
- "apb2_i2c2", "apb2_i2c3",
- "apb2_uart0", "apb2_uart1",
- "apb2_uart2", "apb2_uart3",
- "apb2_uart4", "apb2_uart5";
- };
-
- mmc0_clk: clk@01c20088 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc0",
- "mmc0_output",
- "mmc0_sample";
- };
-
- mmc1_clk: clk@01c2008c {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c2008c 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc1",
- "mmc1_output",
- "mmc1_sample";
- };
-
- mmc2_clk: clk@01c20090 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20090 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc2",
- "mmc2_output",
- "mmc2_sample";
- };
-
- mmc3_clk: clk@01c20094 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20094 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc3",
- "mmc3_output",
- "mmc3_sample";
- };
-
- ss_clk: clk@01c2009c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c2009c 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "ss";
- };
-
- spi0_clk: clk@01c200a0 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a0 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "spi0";
- };
-
- spi1_clk: clk@01c200a4 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a4 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "spi1";
- };
-
- spi2_clk: clk@01c200a8 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a8 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "spi2";
- };
-
- spi3_clk: clk@01c200ac {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200ac 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "spi3";
- };
-
- usb_clk: clk@01c200cc {
- #clock-cells = <1>;
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-usb-clk";
- reg = <0x01c200cc 0x4>;
- clocks = <&osc24M>;
- clock-indices = <8>, <9>, <10>,
- <16>, <17>,
- <18>;
- clock-output-names = "usb_phy0", "usb_phy1", "usb_phy2",
- "usb_ohci0", "usb_ohci1",
- "usb_ohci2";
- };
-
/*
* The following two are dummy clocks, placeholders
* used in the gmac_tx clock. The gmac driver will
@@ -463,23 +241,23 @@
compatible = "allwinner,sun6i-a31-dma";
reg = <0x01c02000 0x1000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 6>;
- resets = <&ahb1_rst 6>;
+ clocks = <&ccu CLK_AHB1_DMA>;
+ resets = <&ccu RST_AHB1_DMA>;
#dma-cells = <1>;
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb1_gates 8>,
- <&mmc0_clk 0>,
- <&mmc0_clk 1>,
- <&mmc0_clk 2>;
+ clocks = <&ccu CLK_AHB1_MMC0>,
+ <&ccu CLK_MMC0>,
+ <&ccu CLK_MMC0_OUTPUT>,
+ <&ccu CLK_MMC0_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 8>;
+ resets = <&ccu RST_AHB1_MMC0>;
reset-names = "ahb";
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -490,15 +268,15 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb1_gates 9>,
- <&mmc1_clk 0>,
- <&mmc1_clk 1>,
- <&mmc1_clk 2>;
+ clocks = <&ccu CLK_AHB1_MMC1>,
+ <&ccu CLK_MMC1>,
+ <&ccu CLK_MMC1_OUTPUT>,
+ <&ccu CLK_MMC1_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 9>;
+ resets = <&ccu RST_AHB1_MMC1>;
reset-names = "ahb";
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -509,15 +287,15 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb1_gates 10>,
- <&mmc2_clk 0>,
- <&mmc2_clk 1>,
- <&mmc2_clk 2>;
+ clocks = <&ccu CLK_AHB1_MMC2>,
+ <&ccu CLK_MMC2>,
+ <&ccu CLK_MMC2_OUTPUT>,
+ <&ccu CLK_MMC2_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 10>;
+ resets = <&ccu RST_AHB1_MMC2>;
reset-names = "ahb";
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -528,15 +306,15 @@
mmc3: mmc@01c12000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c12000 0x1000>;
- clocks = <&ahb1_gates 11>,
- <&mmc3_clk 0>,
- <&mmc3_clk 1>,
- <&mmc3_clk 2>;
+ clocks = <&ccu CLK_AHB1_MMC3>,
+ <&ccu CLK_MMC3>,
+ <&ccu CLK_MMC3_OUTPUT>,
+ <&ccu CLK_MMC3_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 11>;
+ resets = <&ccu RST_AHB1_MMC3>;
reset-names = "ahb";
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -547,8 +325,8 @@
usb_otg: usb@01c19000 {
compatible = "allwinner,sun6i-a31-musb";
reg = <0x01c19000 0x0400>;
- clocks = <&ahb1_gates 24>;
- resets = <&ahb1_rst 24>;
+ clocks = <&ccu CLK_AHB1_OTG>;
+ resets = <&ccu RST_AHB1_OTG>;
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "mc";
phys = <&usbphy 0>;
@@ -565,15 +343,15 @@
reg-names = "phy_ctrl",
"pmu1",
"pmu2";
- clocks = <&usb_clk 8>,
- <&usb_clk 9>,
- <&usb_clk 10>;
+ clocks = <&ccu CLK_USB_PHY0>,
+ <&ccu CLK_USB_PHY1>,
+ <&ccu CLK_USB_PHY2>;
clock-names = "usb0_phy",
"usb1_phy",
"usb2_phy";
- resets = <&usb_clk 0>,
- <&usb_clk 1>,
- <&usb_clk 2>;
+ resets = <&ccu RST_USB_PHY0>,
+ <&ccu RST_USB_PHY1>,
+ <&ccu RST_USB_PHY2>;
reset-names = "usb0_reset",
"usb1_reset",
"usb2_reset";
@@ -585,8 +363,8 @@
compatible = "allwinner,sun6i-a31-ehci", "generic-ehci";
reg = <0x01c1a000 0x100>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 26>;
- resets = <&ahb1_rst 26>;
+ clocks = <&ccu CLK_AHB1_EHCI0>;
+ resets = <&ccu RST_AHB1_EHCI0>;
phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled";
@@ -596,8 +374,8 @@
compatible = "allwinner,sun6i-a31-ohci", "generic-ohci";
reg = <0x01c1a400 0x100>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 29>, <&usb_clk 16>;
- resets = <&ahb1_rst 29>;
+ clocks = <&ccu CLK_AHB1_OHCI0>, <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_AHB1_OHCI0>;
phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled";
@@ -607,8 +385,8 @@
compatible = "allwinner,sun6i-a31-ehci", "generic-ehci";
reg = <0x01c1b000 0x100>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 27>;
- resets = <&ahb1_rst 27>;
+ clocks = <&ccu CLK_AHB1_EHCI1>;
+ resets = <&ccu RST_AHB1_EHCI1>;
phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled";
@@ -618,8 +396,8 @@
compatible = "allwinner,sun6i-a31-ohci", "generic-ohci";
reg = <0x01c1b400 0x100>;
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 30>, <&usb_clk 17>;
- resets = <&ahb1_rst 30>;
+ clocks = <&ccu CLK_AHB1_OHCI1>, <&ccu CLK_USB_OHCI1>;
+ resets = <&ccu RST_AHB1_OHCI1>;
phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled";
@@ -629,11 +407,20 @@
compatible = "allwinner,sun6i-a31-ohci", "generic-ohci";
reg = <0x01c1c400 0x100>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 31>, <&usb_clk 18>;
- resets = <&ahb1_rst 31>;
+ clocks = <&ccu CLK_AHB1_OHCI2>, <&ccu CLK_USB_OHCI2>;
+ resets = <&ccu RST_AHB1_OHCI2>;
status = "disabled";
};
+ ccu: clock@01c20000 {
+ compatible = "allwinner,sun6i-a31-ccu";
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&osc32k>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
pio: pinctrl@01c20800 {
compatible = "allwinner,sun6i-a31-pinctrl";
reg = <0x01c20800 0x400>;
@@ -641,7 +428,7 @@
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb1_gates 5>;
+ clocks = <&ccu CLK_APB1_PIO>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
@@ -762,24 +549,6 @@
};
};
- ahb1_rst: reset@01c202c0 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-ahb1-reset";
- reg = <0x01c202c0 0xc>;
- };
-
- apb1_rst: reset@01c202d0 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-clock-reset";
- reg = <0x01c202d0 0x4>;
- };
-
- apb2_rst: reset@01c202d8 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-clock-reset";
- reg = <0x01c202d8 0x4>;
- };
-
timer@01c20c00 {
compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0xa0>;
@@ -816,8 +585,8 @@
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 16>;
- resets = <&apb2_rst 16>;
+ clocks = <&ccu CLK_APB2_UART0>;
+ resets = <&ccu RST_APB2_UART0>;
dmas = <&dma 6>, <&dma 6>;
dma-names = "rx", "tx";
status = "disabled";
@@ -829,8 +598,8 @@
interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 17>;
- resets = <&apb2_rst 17>;
+ clocks = <&ccu CLK_APB2_UART1>;
+ resets = <&ccu RST_APB2_UART1>;
dmas = <&dma 7>, <&dma 7>;
dma-names = "rx", "tx";
status = "disabled";
@@ -842,8 +611,8 @@
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 18>;
- resets = <&apb2_rst 18>;
+ clocks = <&ccu CLK_APB2_UART2>;
+ resets = <&ccu RST_APB2_UART2>;
dmas = <&dma 8>, <&dma 8>;
dma-names = "rx", "tx";
status = "disabled";
@@ -855,8 +624,8 @@
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 19>;
- resets = <&apb2_rst 19>;
+ clocks = <&ccu CLK_APB2_UART3>;
+ resets = <&ccu RST_APB2_UART3>;
dmas = <&dma 9>, <&dma 9>;
dma-names = "rx", "tx";
status = "disabled";
@@ -868,8 +637,8 @@
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 20>;
- resets = <&apb2_rst 20>;
+ clocks = <&ccu CLK_APB2_UART4>;
+ resets = <&ccu RST_APB2_UART4>;
dmas = <&dma 10>, <&dma 10>;
dma-names = "rx", "tx";
status = "disabled";
@@ -881,8 +650,8 @@
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 21>;
- resets = <&apb2_rst 21>;
+ clocks = <&ccu CLK_APB2_UART5>;
+ resets = <&ccu RST_APB2_UART5>;
dmas = <&dma 22>, <&dma 22>;
dma-names = "rx", "tx";
status = "disabled";
@@ -892,8 +661,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2ac00 0x400>;
interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 0>;
- resets = <&apb2_rst 0>;
+ clocks = <&ccu CLK_APB2_I2C0>;
+ resets = <&ccu RST_APB2_I2C0>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -903,8 +672,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2b000 0x400>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 1>;
- resets = <&apb2_rst 1>;
+ clocks = <&ccu CLK_APB2_I2C1>;
+ resets = <&ccu RST_APB2_I2C1>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -914,8 +683,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2b400 0x400>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 2>;
- resets = <&apb2_rst 2>;
+ clocks = <&ccu CLK_APB2_I2C2>;
+ resets = <&ccu RST_APB2_I2C2>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -925,8 +694,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2b800 0x400>;
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 3>;
- resets = <&apb2_rst 3>;
+ clocks = <&ccu CLK_APB2_I2C3>;
+ resets = <&ccu RST_APB2_I2C3>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -937,9 +706,9 @@
reg = <0x01c30000 0x1054>;
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
- clocks = <&ahb1_gates 17>, <&gmac_tx_clk>;
+ clocks = <&ccu CLK_AHB1_EMAC>, <&gmac_tx_clk>;
clock-names = "stmmaceth", "allwinner_gmac_tx";
- resets = <&ahb1_rst 17>;
+ resets = <&ccu RST_AHB1_EMAC>;
reset-names = "stmmaceth";
snps,pbl = <2>;
snps,fixed-burst;
@@ -953,9 +722,9 @@
compatible = "allwinner,sun4i-a10-crypto";
reg = <0x01c15000 0x1000>;
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 5>, <&ss_clk>;
+ clocks = <&ccu CLK_AHB1_SS>, <&ccu CLK_SS>;
clock-names = "ahb", "mod";
- resets = <&ahb1_rst 5>;
+ resets = <&ccu RST_AHB1_SS>;
reset-names = "ahb";
};
@@ -967,19 +736,19 @@
<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 19>;
- resets = <&ahb1_rst 19>;
+ clocks = <&ccu CLK_AHB1_HSTIMER>;
+ resets = <&ccu RST_AHB1_HSTIMER>;
};
spi0: spi@01c68000 {
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c68000 0x1000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 20>, <&spi0_clk>;
+ clocks = <&ccu CLK_AHB1_SPI0>, <&ccu CLK_SPI0>;
clock-names = "ahb", "mod";
dmas = <&dma 23>, <&dma 23>;
dma-names = "rx", "tx";
- resets = <&ahb1_rst 20>;
+ resets = <&ccu RST_AHB1_SPI0>;
status = "disabled";
};
@@ -987,11 +756,11 @@
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c69000 0x1000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clocks = <&ccu CLK_AHB1_SPI1>, <&ccu CLK_SPI1>;
clock-names = "ahb", "mod";
dmas = <&dma 24>, <&dma 24>;
dma-names = "rx", "tx";
- resets = <&ahb1_rst 21>;
+ resets = <&ccu RST_AHB1_SPI1>;
status = "disabled";
};
@@ -999,11 +768,11 @@
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c6a000 0x1000>;
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 22>, <&spi2_clk>;
+ clocks = <&ccu CLK_AHB1_SPI2>, <&ccu CLK_SPI2>;
clock-names = "ahb", "mod";
dmas = <&dma 25>, <&dma 25>;
dma-names = "rx", "tx";
- resets = <&ahb1_rst 22>;
+ resets = <&ccu RST_AHB1_SPI2>;
status = "disabled";
};
@@ -1011,11 +780,11 @@
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c6b000 0x1000>;
interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 23>, <&spi3_clk>;
+ clocks = <&ccu CLK_AHB1_SPI3>, <&ccu CLK_SPI3>;
clock-names = "ahb", "mod";
dmas = <&dma 26>, <&dma 26>;
dma-names = "rx", "tx";
- resets = <&ahb1_rst 23>;
+ resets = <&ccu RST_AHB1_SPI3>;
status = "disabled";
};
@@ -1052,8 +821,9 @@
ar100: ar100_clk {
compatible = "allwinner,sun6i-a31-ar100-clk";
#clock-cells = <0>;
- clocks = <&osc32k>, <&osc24M>, <&pll6 0>,
- <&pll6 0>;
+ clocks = <&osc32k>, <&osc24M>,
+ <&ccu CLK_PLL_PERIPH>,
+ <&ccu CLK_PLL_PERIPH>;
clock-output-names = "ar100";
};
diff --git a/arch/arm/boot/dts/sun6i-a31s-colorfly-e708-q1.dts b/arch/arm/boot/dts/sun6i-a31s-colorfly-e708-q1.dts
index e182eec6d878..882a4d89fa22 100644
--- a/arch/arm/boot/dts/sun6i-a31s-colorfly-e708-q1.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-colorfly-e708-q1.dts
@@ -42,32 +42,11 @@
/dts-v1/;
#include "sun6i-a31s.dtsi"
-#include "sunxi-common-regulators.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include "sun6i-reference-design-tablet.dtsi"
/ {
model = "Colorfly E708 Q1 tablet";
compatible = "colorfly,e708-q1", "allwinner,sun6i-a31s";
-
- aliases {
- serial0 = &uart0;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-};
-
-&cpu0 {
- cpu-supply = <&reg_dcdc3>;
-};
-
-&ehci0 {
- /* rtl8188etv wifi is connected here */
- status = "okay";
};
&lradc {
@@ -82,103 +61,6 @@
};
};
-&mmc0 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_e708_q1>;
- vmmc-supply = <&reg_dcdc1>;
- bus-width = <4>;
- cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
- cd-inverted;
- status = "okay";
-};
-
-&pio {
- mma8452_int_e708_q1: mma8452_int_pin@0 {
- allwinner,pins = "PA9";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- mmc0_cd_pin_e708_q1: mmc0_cd_pin@0 {
- allwinner,pins = "PA8";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-};
-
-&p2wi {
- status = "okay";
-
- axp22x: pmic@68 {
- compatible = "x-powers,axp221";
- reg = <0x68>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- };
-};
-
-#include "axp22x.dtsi"
-
-&reg_aldo3 {
- regulator-always-on;
- regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "avcc";
-};
-
-&reg_dc1sw {
- regulator-name = "vcc-lcd";
-};
-
-&reg_dc5ldo {
- regulator-always-on;
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <1320000>;
- regulator-name = "vdd-cpus"; /* This is an educated guess */
-};
-
-&reg_dcdc1 {
- regulator-always-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-name = "vcc-3v0";
-};
-
-&reg_dcdc2 {
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <1320000>;
- regulator-name = "vdd-gpu";
-};
-
-&reg_dcdc3 {
- regulator-always-on;
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <1320000>;
- regulator-name = "vdd-cpu";
-};
-
-&reg_dcdc4 {
- regulator-always-on;
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <1320000>;
- regulator-name = "vdd-sys-dll";
-};
-
-&reg_dcdc5 {
- regulator-always-on;
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
- regulator-name = "vcc-dram";
-};
-
-&reg_dldo1 {
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "vcc-wifi";
-};
-
&reg_dldo2 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -186,23 +68,5 @@
};
&simplefb_lcd {
- vcc-lcd-supply = <&reg_dc1sw>;
vcc-pg-supply = <&reg_dldo2>;
};
-
-/*
- * FIXME for now we only support host mode and rely on u-boot to have
- * turned on Vbus which is controlled by the axp221 pmic on the board.
- *
- * Once we have axp221 power-supply and vbus-usb support we should switch
- * to fully supporting otg.
- */
-&usb_otg {
- dr_mode = "host";
- status = "okay";
-};
-
-&usbphy {
- usb1_vbus-supply = <&reg_dldo1>;
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/sun6i-a31s-inet-q972.dts b/arch/arm/boot/dts/sun6i-a31s-inet-q972.dts
new file mode 100644
index 000000000000..e584e6b186a7
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-inet-q972.dts
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "sun6i-a31s.dtsi"
+#include "sun6i-reference-design-tablet.dtsi"
+
+/ {
+ model = "iNet Q972 tablet";
+ compatible = "inet-tek,inet-q972", "allwinner,sun6i-a31s";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ ft5406ee8: touchscreen@38 {
+ compatible = "edt,edt-ft5406";
+ reg = <0x38>;
+ interrupt-parent = <&pio>;
+ interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>; /* PA3 */
+ touchscreen-size-x = <768>;
+ touchscreen-size-y = <1024>;
+ touchscreen-swapped-x-y;
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_aldo3>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@900 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <900000>;
+ };
+
+ button@1200 {
+ label = "Back";
+ linux,code = <KEY_BACK>;
+ channel = <0>;
+ voltage = <1200000>;
+ };
+};
+
+&ohci1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
new file mode 100644
index 000000000000..0c434304e040
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc3>;
+};
+
+&ehci0 {
+ /* Wifi is connected here */
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_e708_q1>;
+ vmmc-supply = <&reg_dcdc1>;
+ bus-width = <4>;
+ cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_e708_q1: mmc0_cd_pin@0 {
+ allwinner,pins = "PA8";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PA15";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&p2wi {
+ status = "okay";
+
+ axp22x: pmic@68 {
+ compatible = "x-powers,axp221";
+ reg = <0x68>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ drivevbus-supply = <&reg_vcc5v0>;
+ x-powers,drive-vbus-en;
+ };
+};
+
+#include "axp22x.dtsi"
+
+&reg_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
+};
+
+&reg_dc1sw {
+ regulator-name = "vcc-lcd";
+};
+
+&reg_dc5ldo {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpus"; /* This is an educated guess */
+};
+
+&reg_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc4 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-sys-dll";
+};
+
+&reg_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+&reg_dldo1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&reg_drivevbus {
+ regulator-name = "usb0-vbus";
+ status = "okay";
+};
+
+&simplefb_lcd {
+ vcc-lcd-supply = <&reg_dc1sw>;
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_drivevbus>;
+ usb1_vbus-supply = <&reg_dldo1>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index e3b196e08ccf..48fc24f36fcb 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -46,7 +46,9 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun8i-a23-a33-ccu.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/reset/sun8i-a23-a33-ccu.h>
/ {
interrupt-parent = <&gic>;
@@ -60,7 +62,9 @@
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
- clocks = <&pll6 0>;
+ clocks = <&ccu CLK_BUS_LCD>, <&ccu CLK_BUS_DE_BE>,
+ <&ccu CLK_LCD_CH0>, <&ccu CLK_DE_BE>,
+ <&ccu CLK_DRAM_DE_BE>, <&ccu CLK_DRC>;
status = "disabled";
};
};
@@ -111,143 +115,6 @@
clock-frequency = <32768>;
clock-output-names = "osc32k";
};
-
- pll1: clk@01c20000 {
- #clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-pll1-clk";
- reg = <0x01c20000 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll1";
- };
-
- /* dummy clock until actually implemented */
- pll5: pll5_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
- clock-output-names = "pll5";
- };
-
- pll6: clk@01c20028 {
- #clock-cells = <1>;
- compatible = "allwinner,sun6i-a31-pll6-clk";
- reg = <0x01c20028 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll6", "pll6x2";
- };
-
- cpu: cpu_clk@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-cpu-clk";
- reg = <0x01c20050 0x4>;
-
- /*
- * PLL1 is listed twice here.
- * While it looks suspicious, it's actually documented
- * that way both in the datasheet and in the code from
- * Allwinner.
- */
- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
- clock-output-names = "cpu";
- };
-
- axi: axi_clk@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-axi-clk";
- reg = <0x01c20050 0x4>;
- clocks = <&cpu>;
- clock-output-names = "axi";
- };
-
- ahb1: ahb1_clk@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun6i-a31-ahb1-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
- clock-output-names = "ahb1";
- };
-
- apb1: apb1_clk@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb0-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&ahb1>;
- clock-output-names = "apb1";
- };
-
- apb1_gates: clk@01c20068 {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-apb1-gates-clk";
- reg = <0x01c20068 0x4>;
- clocks = <&apb1>;
- clock-indices = <0>, <5>,
- <12>, <13>;
- clock-output-names = "apb1_codec", "apb1_pio",
- "apb1_daudio0", "apb1_daudio1";
- };
-
- apb2: clk@01c20058 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb1-clk";
- reg = <0x01c20058 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
- clock-output-names = "apb2";
- };
-
- apb2_gates: clk@01c2006c {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-apb2-gates-clk";
- reg = <0x01c2006c 0x4>;
- clocks = <&apb2>;
- clock-indices = <0>, <1>,
- <2>, <16>,
- <17>, <18>,
- <19>, <20>;
- clock-output-names = "apb2_i2c0", "apb2_i2c1",
- "apb2_i2c2", "apb2_uart0",
- "apb2_uart1", "apb2_uart2",
- "apb2_uart3", "apb2_uart4";
- };
-
- mmc0_clk: clk@01c20088 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc0",
- "mmc0_output",
- "mmc0_sample";
- };
-
- mmc1_clk: clk@01c2008c {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c2008c 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc1",
- "mmc1_output",
- "mmc1_sample";
- };
-
- mmc2_clk: clk@01c20090 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20090 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "mmc2",
- "mmc2_output",
- "mmc2_sample";
- };
-
- usb_clk: clk@01c200cc {
- #clock-cells = <1>;
- #reset-cells = <1>;
- compatible = "allwinner,sun8i-a23-usb-clk";
- reg = <0x01c200cc 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "usb_phy0", "usb_phy1", "usb_hsic",
- "usb_hsic_12M", "usb_ohci0";
- };
};
soc@01c00000 {
@@ -260,23 +127,23 @@
compatible = "allwinner,sun8i-a23-dma";
reg = <0x01c02000 0x1000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 6>;
- resets = <&ahb1_rst 6>;
+ clocks = <&ccu CLK_BUS_DMA>;
+ resets = <&ccu RST_BUS_DMA>;
#dma-cells = <1>;
};
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
- clocks = <&ahb1_gates 8>,
- <&mmc0_clk 0>,
- <&mmc0_clk 1>,
- <&mmc0_clk 2>;
+ clocks = <&ccu CLK_BUS_MMC0>,
+ <&ccu CLK_MMC0>,
+ <&ccu CLK_MMC0_OUTPUT>,
+ <&ccu CLK_MMC0_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 8>;
+ resets = <&ccu RST_BUS_MMC0>;
reset-names = "ahb";
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -287,15 +154,15 @@
mmc1: mmc@01c10000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c10000 0x1000>;
- clocks = <&ahb1_gates 9>,
- <&mmc1_clk 0>,
- <&mmc1_clk 1>,
- <&mmc1_clk 2>;
+ clocks = <&ccu CLK_BUS_MMC1>,
+ <&ccu CLK_MMC1>,
+ <&ccu CLK_MMC1_OUTPUT>,
+ <&ccu CLK_MMC1_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 9>;
+ resets = <&ccu RST_BUS_MMC1>;
reset-names = "ahb";
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -306,15 +173,15 @@
mmc2: mmc@01c11000 {
compatible = "allwinner,sun7i-a20-mmc";
reg = <0x01c11000 0x1000>;
- clocks = <&ahb1_gates 10>,
- <&mmc2_clk 0>,
- <&mmc2_clk 1>,
- <&mmc2_clk 2>;
+ clocks = <&ccu CLK_BUS_MMC2>,
+ <&ccu CLK_MMC2>,
+ <&ccu CLK_MMC2_OUTPUT>,
+ <&ccu CLK_MMC2_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
- resets = <&ahb1_rst 10>;
+ resets = <&ccu RST_BUS_MMC2>;
reset-names = "ahb";
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -322,12 +189,55 @@
#size-cells = <0>;
};
+ nfc: nand@01c03000 {
+ compatible = "allwinner,sun4i-a10-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_NAND>, <&ccu CLK_NAND>;
+ clock-names = "ahb", "mod";
+ resets = <&ccu RST_BUS_NAND>;
+ reset-names = "ahb";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ usb_otg: usb@01c19000 {
+ /* compatible gets set in SoC specific dtsi file */
+ reg = <0x01c19000 0x0400>;
+ clocks = <&ccu CLK_BUS_OTG>;
+ resets = <&ccu RST_BUS_OTG>;
+ interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ status = "disabled";
+ };
+
+ usbphy: phy@01c19400 {
+ /*
+ * compatible and address regions get set in
+ * SoC specific dtsi file
+ */
+ clocks = <&ccu CLK_USB_PHY0>,
+ <&ccu CLK_USB_PHY1>;
+ clock-names = "usb0_phy",
+ "usb1_phy";
+ resets = <&ccu RST_USB_PHY0>,
+ <&ccu RST_USB_PHY1>;
+ reset-names = "usb0_reset",
+ "usb1_reset";
+ status = "disabled";
+ #phy-cells = <1>;
+ };
+
ehci0: usb@01c1a000 {
compatible = "allwinner,sun8i-a23-ehci", "generic-ehci";
reg = <0x01c1a000 0x100>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 26>;
- resets = <&ahb1_rst 26>;
+ clocks = <&ccu CLK_BUS_EHCI>;
+ resets = <&ccu RST_BUS_EHCI>;
phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled";
@@ -337,18 +247,26 @@
compatible = "allwinner,sun8i-a23-ohci", "generic-ohci";
reg = <0x01c1a400 0x100>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 29>, <&usb_clk 16>;
- resets = <&ahb1_rst 29>;
+ clocks = <&ccu CLK_BUS_OHCI>, <&ccu CLK_USB_OHCI>;
+ resets = <&ccu RST_BUS_OHCI>;
phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled";
};
+ ccu: clock@01c20000 {
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&osc32k>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
pio: pinctrl@01c20800 {
/* compatible gets set in SoC specific dtsi file */
reg = <0x01c20800 0x400>;
/* interrupts get set in SoC specific dtsi file */
- clocks = <&apb1_gates 5>;
+ clocks = <&ccu CLK_BUS_PIO>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
@@ -361,6 +279,16 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ uart1_pins_a: uart1@0 {
+ allwinner,pins = "PG6", "PG7";
+ allwinner,function = "uart1";
+ };
+
+ uart1_pins_cts_rts_a: uart1-cts-rts@0 {
+ allwinner,pins = "PG8", "PG9";
+ allwinner,function = "uart1";
+ };
+
mmc0_pins_a: mmc0@0 {
allwinner,pins = "PF0", "PF1", "PF2",
"PF3", "PF4", "PF5";
@@ -414,24 +342,16 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- };
- ahb1_rst: reset@01c202c0 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-clock-reset";
- reg = <0x01c202c0 0xc>;
- };
-
- apb1_rst: reset@01c202d0 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-clock-reset";
- reg = <0x01c202d0 0x4>;
- };
-
- apb2_rst: reset@01c202d8 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-clock-reset";
- reg = <0x01c202d8 0x4>;
+ lcd_rgb666_pins: lcd-rgb666@0 {
+ allwinner,pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
+ "PD10", "PD11", "PD12", "PD13", "PD14", "PD15",
+ "PD18", "PD19", "PD20", "PD21", "PD22", "PD23",
+ "PD24", "PD25", "PD26", "PD27";
+ allwinner,function = "lcd0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
timer@01c20c00 {
@@ -469,8 +389,8 @@
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 16>;
- resets = <&apb2_rst 16>;
+ clocks = <&ccu CLK_BUS_UART0>;
+ resets = <&ccu RST_BUS_UART0>;
dmas = <&dma 6>, <&dma 6>;
dma-names = "rx", "tx";
status = "disabled";
@@ -482,8 +402,8 @@
interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 17>;
- resets = <&apb2_rst 17>;
+ clocks = <&ccu CLK_BUS_UART1>;
+ resets = <&ccu RST_BUS_UART1>;
dmas = <&dma 7>, <&dma 7>;
dma-names = "rx", "tx";
status = "disabled";
@@ -495,8 +415,8 @@
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 18>;
- resets = <&apb2_rst 18>;
+ clocks = <&ccu CLK_BUS_UART2>;
+ resets = <&ccu RST_BUS_UART2>;
dmas = <&dma 8>, <&dma 8>;
dma-names = "rx", "tx";
status = "disabled";
@@ -508,8 +428,8 @@
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 19>;
- resets = <&apb2_rst 19>;
+ clocks = <&ccu CLK_BUS_UART3>;
+ resets = <&ccu RST_BUS_UART3>;
dmas = <&dma 9>, <&dma 9>;
dma-names = "rx", "tx";
status = "disabled";
@@ -521,8 +441,8 @@
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&apb2_gates 20>;
- resets = <&apb2_rst 20>;
+ clocks = <&ccu CLK_BUS_UART4>;
+ resets = <&ccu RST_BUS_UART4>;
dmas = <&dma 10>, <&dma 10>;
dma-names = "rx", "tx";
status = "disabled";
@@ -532,8 +452,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2ac00 0x400>;
interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 0>;
- resets = <&apb2_rst 0>;
+ clocks = <&ccu CLK_BUS_I2C0>;
+ resets = <&ccu RST_BUS_I2C0>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -543,8 +463,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2b000 0x400>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 1>;
- resets = <&apb2_rst 1>;
+ clocks = <&ccu CLK_BUS_I2C1>;
+ resets = <&ccu RST_BUS_I2C1>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -554,8 +474,8 @@
compatible = "allwinner,sun6i-a31-i2c";
reg = <0x01c2b400 0x400>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 2>;
- resets = <&apb2_rst 2>;
+ clocks = <&ccu CLK_BUS_I2C2>;
+ resets = <&ccu RST_BUS_I2C2>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts b/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts
index b2ce284a65a2..e3c7a25ca37d 100644
--- a/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts
+++ b/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts
@@ -42,70 +42,27 @@
/dts-v1/;
#include "sun8i-a23.dtsi"
-#include "sunxi-common-regulators.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
-#include <dt-bindings/pwm/pwm.h>
+#include "sun8i-reference-design-tablet.dtsi"
/ {
model = "Allwinner GT90H Dual Core Tablet (v4)";
compatible = "allwinner,gt90h-v4", "allwinner,sun8i-a23";
-
- aliases {
- serial0 = &r_uart;
- };
-
- backlight: backlight {
- compatible = "pwm-backlight";
- pinctrl-names = "default";
- pinctrl-0 = <&bl_en_pin_gt90h>;
- pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
- brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
- default-brightness-level = <8>;
- enable-gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
};
&ehci0 {
status = "okay";
};
-&i2c0 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-};
-
-&i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
+&touchscreen {
+ reg = <0x40>;
+ compatible = "silead,gsl3675";
+ firmware-name = "gsl3675-gt90h.fw";
+ touchscreen-size-x = <1792>;
+ touchscreen-size-y = <1024>;
status = "okay";
};
&lradc {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@200 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <200000>;
- };
-
- button@400 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <400000>;
- };
-
button@600 {
label = "Back";
linux,code = <KEY_BACK>;
@@ -114,144 +71,6 @@
};
};
-&mmc0 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_gt90h>;
- vmmc-supply = <&reg_aldo1>;
- bus-width = <4>;
- cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
- cd-inverted;
- status = "okay";
-};
-
-&pio {
- bl_en_pin_gt90h: bl_en_pin@0 {
- allwinner,pins = "PH6";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- mmc0_cd_pin_gt90h: mmc0_cd_pin@0 {
- allwinner,pins = "PB4";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-};
-
-&pwm {
- pinctrl-names = "default";
- pinctrl-0 = <&pwm0_pins>;
- status = "okay";
-};
-
-&r_rsb {
- status = "okay";
-
- axp22x: pmic@3a3 {
- compatible = "x-powers,axp223";
- reg = <0x3a3>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- eldoin-supply = <&reg_dcdc1>;
- };
-};
-
-&r_uart {
- pinctrl-names = "default";
- pinctrl-0 = <&r_uart_pins_a>;
- status = "okay";
-};
-
-#include "axp22x.dtsi"
-
-&reg_aldo1 {
- regulator-always-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-name = "vcc-io";
-};
-
-&reg_aldo2 {
- regulator-always-on;
- regulator-min-microvolt = <2350000>;
- regulator-max-microvolt = <2650000>;
- regulator-name = "vdd-dll";
-};
-
-&reg_aldo3 {
- regulator-always-on;
- regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "vcc-pll-avcc";
-};
-
-&reg_dc1sw {
- regulator-name = "vcc-lcd";
-};
-
-&reg_dc5ldo {
- regulator-always-on;
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1400000>;
- regulator-name = "vdd-cpus";
-};
-
-&reg_dcdc1 {
- regulator-always-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-name = "vcc-3v0";
-};
-
-&reg_dcdc2 {
- regulator-always-on;
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1400000>;
- regulator-name = "vdd-sys";
-};
-
-&reg_dcdc3 {
- regulator-always-on;
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1400000>;
- regulator-name = "vdd-cpu";
-};
-
-&reg_dcdc5 {
- regulator-always-on;
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
- regulator-name = "vcc-dram";
-};
-
-&reg_dldo1 {
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "vcc-wifi";
-};
-
-&reg_rtc_ldo {
- regulator-name = "vcc-rtc";
-};
-
-&simplefb_lcd {
- vcc-lcd-supply = <&reg_dc1sw>;
-};
-
-/*
- * FIXME for now we only support host mode and rely on u-boot to have
- * turned on Vbus which is controlled by the axp223 pmic on the board.
- *
- * Once we have axp223 support we should switch to fully supporting otg.
- */
-&usb_otg {
- dr_mode = "host";
- status = "okay";
-};
-
&usbphy {
usb1_vbus-supply = <&reg_dldo1>;
- status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-a23-inet86dz.dts b/arch/arm/boot/dts/sun8i-a23-inet86dz.dts
index 0f9f71b14047..d4405752a414 100644
--- a/arch/arm/boot/dts/sun8i-a23-inet86dz.dts
+++ b/arch/arm/boot/dts/sun8i-a23-inet86dz.dts
@@ -53,6 +53,15 @@
status = "okay";
};
+&touchscreen {
+ reg = <0x40>;
+ compatible = "silead,gsl1680";
+ firmware-name = "gsl1680-inet86dz.fw";
+ touchscreen-size-x = <960>;
+ touchscreen-size-y = <640>;
+ status = "okay";
+};
+
&usbphy {
usb1_vbus-supply = <&reg_dldo1>;
};
diff --git a/arch/arm/boot/dts/sun8i-a23-polaroid-mid2407pxe03.dts b/arch/arm/boot/dts/sun8i-a23-polaroid-mid2407pxe03.dts
index e3004428e7a7..a86cbedda34c 100644
--- a/arch/arm/boot/dts/sun8i-a23-polaroid-mid2407pxe03.dts
+++ b/arch/arm/boot/dts/sun8i-a23-polaroid-mid2407pxe03.dts
@@ -47,4 +47,72 @@
/ {
model = "Polaroid MID2407PXE03 tablet";
compatible = "polaroid,mid2407pxe03", "allwinner,sun8i-a23";
+
+ aliases {
+ ethernet0 = &esp8089;
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_pwrseq_pin_mid2407>;
+ reset-gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL6 */
+ /* The esp8089 needs 200 ms after driving wifi-en high */
+ post-power-on-delay-ms = <200>;
+ };
+};
+
+&i2c1 {
+ mma7660: accelerometer@4c {
+ reg = <0x4c>;
+ compatible = "fsl,mma7660";
+ };
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_dldo1>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ esp8089: sdio_wifi@1 {
+ compatible = "esp,esp8089";
+ reg = <1>;
+ esp,crystal-26M-en = <2>;
+ };
+};
+
+&mmc1_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&r_pio {
+ wifi_pwrseq_pin_mid2407: wifi_pwrseq_pin@0 {
+ allwinner,pins = "PL6";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_ldo_io1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-touchscreen";
+ status = "okay";
+};
+
+&touchscreen {
+ reg = <0x40>;
+ compatible = "silead,gsl1680";
+ firmware-name = "gsl1680-polaroid-mid2407pxe03.fw";
+ touchscreen-size-x = <960>;
+ touchscreen-size-y = <640>;
+ touchscreen-inverted-x;
+ touchscreen-inverted-y;
+ vddio-supply = <&reg_ldo_io1>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-a23-polaroid-mid2809pxe04.dts b/arch/arm/boot/dts/sun8i-a23-polaroid-mid2809pxe04.dts
index 6d06e24d446b..9955f85f9147 100644
--- a/arch/arm/boot/dts/sun8i-a23-polaroid-mid2809pxe04.dts
+++ b/arch/arm/boot/dts/sun8i-a23-polaroid-mid2809pxe04.dts
@@ -47,4 +47,55 @@
/ {
model = "Polaroid MID2809PXE04 tablet";
compatible = "polaroid,mid2809pxe04", "allwinner,sun8i-a23";
+
+ aliases {
+ ethernet0 = &esp8089;
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_pwrseq_pin_mid2809>;
+ reset-gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL6 */
+ /* The esp8089 needs 200 ms after driving wifi-en high */
+ post-power-on-delay-ms = <200>;
+ };
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_dldo1>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ esp8089: sdio_wifi@1 {
+ compatible = "esp,esp8089";
+ reg = <1>;
+ esp,crystal-26M-en = <2>;
+ };
+};
+
+&mmc1_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&r_pio {
+ wifi_pwrseq_pin_mid2809: wifi_pwrseq_pin@0 {
+ allwinner,pins = "PL6";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&touchscreen {
+ reg = <0x40>;
+ compatible = "silead,gsl3670";
+ firmware-name = "gsl3670-polaroid-mid2809pxe04.fw";
+ touchscreen-size-x = <1660>;
+ touchscreen-size-y = <890>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 92e6616979ea..54d045dab825 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -48,74 +48,10 @@
memory {
reg = <0x40000000 0x40000000>;
};
+};
- clocks {
- ahb1_gates: clk@01c20060 {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
- reg = <0x01c20060 0x8>;
- clocks = <&ahb1>;
- clock-indices = <1>, <6>,
- <8>, <9>, <10>,
- <13>, <14>,
- <19>, <20>,
- <21>, <24>, <26>,
- <29>, <32>, <36>,
- <40>, <44>, <46>,
- <52>, <53>,
- <54>, <57>;
- clock-output-names = "ahb1_mipidsi", "ahb1_dma",
- "ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
- "ahb1_nand", "ahb1_sdram",
- "ahb1_hstimer", "ahb1_spi0",
- "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
- "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
- "ahb1_csi", "ahb1_be", "ahb1_fe",
- "ahb1_gpu", "ahb1_msgbox",
- "ahb1_spinlock", "ahb1_drc";
- };
-
- mbus_clk: clk@01c2015c {
- #clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-mbus-clk";
- reg = <0x01c2015c 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5>;
- clock-output-names = "mbus";
- };
- };
-
- soc@01c00000 {
- usb_otg: usb@01c19000 {
- compatible = "allwinner,sun6i-a31-musb";
- reg = <0x01c19000 0x0400>;
- clocks = <&ahb1_gates 24>;
- resets = <&ahb1_rst 24>;
- interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "mc";
- phys = <&usbphy 0>;
- phy-names = "usb";
- extcon = <&usbphy 0>;
- status = "disabled";
- };
-
- usbphy: phy@01c19400 {
- compatible = "allwinner,sun8i-a23-usb-phy";
- reg = <0x01c19400 0x10>,
- <0x01c1a800 0x4>;
- reg-names = "phy_ctrl",
- "pmu1";
- clocks = <&usb_clk 8>,
- <&usb_clk 9>;
- clock-names = "usb0_phy",
- "usb1_phy";
- resets = <&usb_clk 0>,
- <&usb_clk 1>;
- reset-names = "usb0_reset",
- "usb1_reset";
- status = "disabled";
- #phy-cells = <1>;
- };
- };
+&ccu {
+ compatible = "allwinner,sun8i-a23-ccu";
};
&pio {
@@ -124,3 +60,13 @@
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
+
+&usb_otg {
+ compatible = "allwinner,sun6i-a31-musb";
+};
+
+&usbphy {
+ compatible = "allwinner,sun8i-a23-usb-phy";
+ reg = <0x01c19400 0x10>, <0x01c1a800 0x4>;
+ reg-names = "phy_ctrl", "pmu1";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts b/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts
index 65660324005c..f71159987cac 100644
--- a/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts
+++ b/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts
@@ -47,12 +47,27 @@
/ {
model = "Allwinner GA10H Quad Core Tablet (v1.1)";
compatible = "allwinner,ga10h-v1.1", "allwinner,sun8i-a33";
+
+ aliases {
+ /* Make u-boot set mac-address for rtl8703as (no eeprom) */
+ ethernet0 = &rtl8703as;
+ };
};
&ehci0 {
status = "okay";
};
+&touchscreen {
+ reg = <0x40>;
+ compatible = "silead,gsl3675";
+ firmware-name = "gsl3675-ga10h.fw";
+ touchscreen-size-x = <1630>;
+ touchscreen-size-y = <990>;
+ touchscreen-inverted-y;
+ status = "okay";
+};
+
&lradc {
button@600 {
label = "Back";
@@ -62,6 +77,19 @@
};
};
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_dldo1>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ rtl8703as: sdio_wifi@1 {
+ reg = <1>;
+ };
+};
+
&ohci0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts b/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts
new file mode 100644
index 000000000000..fb4665576dff
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33-inet-d978-rev2.dts
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ * Copyright 2016 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "sun8i-a33.dtsi"
+#include "sun8i-reference-design-tablet.dtsi"
+
+/ {
+ model = "INet-D978 Rev 02";
+ compatible = "primux,inet-d978-rev2", "allwinner,sun8i-a33";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ chosen {
+ /* Delete debug UART as serial0 is the UART for bluetooth */
+ /delete-property/stdout-path;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pin_d978>;
+
+ home {
+ label = "d978:blue:home";
+ gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 */
+ };
+ };
+};
+
+&mmc1_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_dldo1>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ rtl8723bs: sdio_wifi@1 {
+ reg = <1>;
+ };
+};
+
+&r_pio {
+ led_pin_d978: led_pin_d978@0 {
+ allwinner,pins = "PL5";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&r_uart {
+ status = "disabled";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_a>,
+ <&uart1_pins_cts_rts_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
new file mode 100644
index 000000000000..9ea637e82b2d
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2016 - Stefan Mavrodiev <stefan.mavrodiev@gmail.com>
+ * Olimex LTD. <support@olimex.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "sun8i-a33.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Olimex A33-OLinuXino";
+ compatible = "olimex,a33-olinuxino","allwinner,sun8i-a33";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pin_olinuxino>;
+
+ green {
+ label = "a33-olinuxino:green:usr";
+ gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino>;
+ vmmc-supply = <&reg_dcdc1>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ led_pin_olinuxino: led_pins@0 {
+ allwinner,pins = "PB7";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PB3";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&r_rsb {
+ status = "okay";
+
+ axp22x: pmic@3a3 {
+ compatible = "x-powers,axp223";
+ reg = <0x3a3>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ eldoin-supply = <&reg_dcdc1>;
+ x-powers,drive-vbus-en;
+ };
+};
+
+#include "axp22x.dtsi"
+
+&reg_aldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-io";
+};
+
+&reg_aldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <2350000>;
+ regulator-max-microvolt = <2650000>;
+ regulator-name = "vdd-dll";
+};
+
+&reg_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-avcc";
+};
+
+&reg_dc1sw {
+ regulator-name = "vcc-lcd";
+};
+
+&reg_dc5ldo {
+ regulator-always-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpus";
+};
+
+&reg_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-3v3";
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-sys";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+&reg_drivevbus {
+ regulator-name = "usb0-vbus";
+ status = "okay";
+};
+
+&reg_rtc_ldo {
+ regulator-name = "vcc-rtc";
+};
+
+&simplefb_lcd {
+ vcc-lcd-supply = <&reg_dc1sw>;
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_b>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_drivevbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 001d8402ca18..fd1e1cddd4a8 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -59,107 +59,179 @@
};
};
+ de: display-engine {
+ compatible = "allwinner,sun8i-a33-display-engine";
+ allwinner,pipelines = <&fe0>;
+ status = "disabled";
+ };
+
memory {
reg = <0x40000000 0x80000000>;
};
- clocks {
- /* Dummy clock for pll11 (DDR1) until actually implemented */
- pll11: pll11_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
- clock-output-names = "pll11";
- };
+ soc@01c00000 {
+ tcon0: lcd-controller@01c0c000 {
+ compatible = "allwinner,sun8i-a33-tcon";
+ reg = <0x01c0c000 0x1000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_LCD>,
+ <&ccu CLK_LCD_CH0>;
+ clock-names = "ahb",
+ "tcon-ch0";
+ clock-output-names = "tcon-pixel-clock";
+ resets = <&ccu RST_BUS_LCD>;
+ reset-names = "lcd";
+ status = "disabled";
- ahb1_gates: clk@01c20060 {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a33-ahb1-gates-clk";
- reg = <0x01c20060 0x8>;
- clocks = <&ahb1>;
- clock-indices = <1>, <5>,
- <6>, <8>, <9>,
- <10>, <13>, <14>,
- <19>, <20>,
- <21>, <24>, <26>,
- <29>, <32>, <36>,
- <40>, <44>, <46>,
- <52>, <53>,
- <54>, <57>,
- <58>;
- clock-output-names = "ahb1_mipidsi", "ahb1_ss",
- "ahb1_dma","ahb1_mmc0", "ahb1_mmc1",
- "ahb1_mmc2", "ahb1_nand", "ahb1_sdram",
- "ahb1_hstimer", "ahb1_spi0",
- "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
- "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
- "ahb1_csi", "ahb1_be", "ahb1_fe",
- "ahb1_gpu", "ahb1_msgbox",
- "ahb1_spinlock", "ahb1_drc",
- "ahb1_sat";
- };
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- ss_clk: clk@01c2009c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c2009c 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- clock-output-names = "ss";
- };
+ tcon0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
- mbus_clk: clk@01c2015c {
- #clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-mbus-clk";
- reg = <0x01c2015c 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5>, <&pll11>;
- clock-output-names = "mbus";
+ tcon0_in_drc0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&drc0_out_tcon0>;
+ };
+ };
+
+ tcon0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ };
};
- };
- soc@01c00000 {
crypto: crypto-engine@01c15000 {
compatible = "allwinner,sun4i-a10-crypto";
reg = <0x01c15000 0x1000>;
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 5>, <&ss_clk>;
+ clocks = <&ccu CLK_BUS_SS>, <&ccu CLK_SS>;
clock-names = "ahb", "mod";
- resets = <&ahb1_rst 5>;
+ resets = <&ccu RST_BUS_SS>;
reset-names = "ahb";
};
- usb_otg: usb@01c19000 {
- compatible = "allwinner,sun8i-a33-musb";
- reg = <0x01c19000 0x0400>;
- clocks = <&ahb1_gates 24>;
- resets = <&ahb1_rst 24>;
- interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "mc";
- phys = <&usbphy 0>;
- phy-names = "usb";
- extcon = <&usbphy 0>;
+ fe0: display-frontend@01e00000 {
+ compatible = "allwinner,sun8i-a33-display-frontend";
+ reg = <0x01e00000 0x20000>;
+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_DE_FE>, <&ccu CLK_DE_FE>,
+ <&ccu CLK_DRAM_DE_FE>;
+ clock-names = "ahb", "mod",
+ "ram";
+ resets = <&ccu RST_BUS_DE_FE>;
status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fe0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ fe0_out_be0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&be0_in_fe0>;
+ };
+ };
+ };
};
- usbphy: phy@01c19400 {
- compatible = "allwinner,sun8i-a33-usb-phy";
- reg = <0x01c19400 0x14>,
- <0x01c1a800 0x4>;
- reg-names = "phy_ctrl",
- "pmu1";
- clocks = <&usb_clk 8>,
- <&usb_clk 9>;
- clock-names = "usb0_phy",
- "usb1_phy";
- resets = <&usb_clk 0>,
- <&usb_clk 1>;
- reset-names = "usb0_reset",
- "usb1_reset";
- status = "disabled";
- #phy-cells = <1>;
+ be0: display-backend@01e60000 {
+ compatible = "allwinner,sun8i-a33-display-backend";
+ reg = <0x01e60000 0x10000>, <0x01e80000 0x1000>;
+ reg-names = "be", "sat";
+ interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_DE_BE>, <&ccu CLK_DE_BE>,
+ <&ccu CLK_DRAM_DE_BE>, <&ccu CLK_BUS_SAT>;
+ clock-names = "ahb", "mod",
+ "ram", "sat";
+ resets = <&ccu RST_BUS_DE_BE>, <&ccu RST_BUS_SAT>;
+ reset-names = "be", "sat";
+ assigned-clocks = <&ccu CLK_DE_BE>;
+ assigned-clock-rates = <300000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ be0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ be0_in_fe0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&fe0_out_be0>;
+ };
+ };
+
+ be0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ be0_out_drc0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&drc0_in_be0>;
+ };
+ };
+ };
+ };
+
+ drc0: drc@01e70000 {
+ compatible = "allwinner,sun8i-a33-drc";
+ reg = <0x01e70000 0x10000>;
+ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_DRC>, <&ccu CLK_DRC>,
+ <&ccu CLK_DRAM_DRC>;
+ clock-names = "ahb", "mod", "ram";
+ resets = <&ccu RST_BUS_DRC>;
+
+ assigned-clocks = <&ccu CLK_DRC>;
+ assigned-clock-rates = <300000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ drc0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ drc0_in_be0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&be0_out_drc0>;
+ };
+ };
+
+ drc0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ drc0_out_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_in_drc0>;
+ };
+ };
+ };
};
};
};
+&ccu {
+ compatible = "allwinner,sun8i-a33-ccu";
+};
+
&pio {
compatible = "allwinner,sun8i-a33-pinctrl";
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
@@ -173,3 +245,13 @@
};
};
+
+&usb_otg {
+ compatible = "allwinner,sun8i-a33-musb";
+};
+
+&usbphy {
+ compatible = "allwinner,sun8i-a33-usb-phy";
+ reg = <0x01c19400 0x14>, <0x01c1a800 0x4>;
+ reg-names = "phy_ctrl", "pmu1";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
index f3b1d5f6dbd2..06fddaae8edd 100644
--- a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
@@ -185,7 +185,7 @@
&uart1 {
pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins_a>;
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
new file mode 100644
index 000000000000..3d64cafc1e90
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 James Pettigrew <james@innovum.com.au>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "FriendlyARM NanoPi NEO";
+ compatible = "friendlyarm,nanopi-neo", "allwinner,sun8i-h3";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
+
+ pwr {
+ label = "nanopi:green:pwr";
+ gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+ default-state = "on";
+ };
+
+ status {
+ label = "nanopi:blue:status";
+ gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */
+ };
+ };
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&pio {
+ leds_opc: led-pins {
+ allwinner,pins = "PA10";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&r_pio {
+ leds_r_opc: led-pins {
+ allwinner,pins = "PL10";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ /* USB VBUS is always on */
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
index f93f5d1695c4..e5bcaba3e87f 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
@@ -54,6 +54,8 @@
aliases {
serial0 = &uart0;
+ /* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
+ ethernet1 = &rtl8189;
};
chosen {
@@ -131,6 +133,14 @@
bus-width = <4>;
non-removable;
status = "okay";
+
+ /*
+ * Explicitly define the sdio device, so that we can add an ethernet
+ * alias for it (which e.g. makes u-boot set a mac-address).
+ */
+ rtl8189: sdio_wifi@1 {
+ reg = <1>;
+ };
};
&pio {
@@ -176,6 +186,24 @@
status = "okay";
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "disabled";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "disabled";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ status = "disabled";
+};
+
&usb1_vbus_pin_a {
allwinner,pins = "PG13";
};
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
new file mode 100644
index 000000000000..1550fee1ec68
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Xunlong Orange Pi Lite";
+ compatible = "xunlong,orangepi-lite", "allwinner,sun8i-h3";
+
+ aliases {
+ /* The H3 emac is not used so the wifi is ethernet0 */
+ ethernet0 = &rtl8189ftv;
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
+
+ pwr_led {
+ label = "orangepi:green:pwr";
+ gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+
+ status_led {
+ label = "orangepi:red:status";
+ gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ r_gpio_keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sw_r_opc>;
+
+ sw4 {
+ label = "sw4";
+ linux,code = <BTN_0>;
+ gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ /*
+ * Explicitly define the sdio device, so that we can add an ethernet
+ * alias for it (which e.g. makes u-boot set a mac-address).
+ */
+ rtl8189ftv: sdio_wifi@1 {
+ reg = <1>;
+ };
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
+&pio {
+ leds_opc: led_pins@0 {
+ allwinner,pins = "PA15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&r_pio {
+ leds_r_opc: led_pins@0 {
+ allwinner,pins = "PL10";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ sw_r_opc: key_pins@0 {
+ allwinner,pins = "PL3";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ /* USB VBUS is always on */
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index 0adf932fd923..5c9b5bfa5c21 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -139,6 +139,24 @@
status = "okay";
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "disabled";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "disabled";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ status = "disabled";
+};
+
&usbphy {
/* USB VBUS is always on */
status = "okay";
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
new file mode 100644
index 000000000000..851fd2c2cc8c
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/* The Orange Pi PC Plus is an extended version of the regular PC */
+#include "sun8i-h3-orangepi-pc.dts"
+
+/ {
+ model = "Xunlong Orange Pi PC Plus";
+ compatible = "xunlong,orangepi-pc-plus", "allwinner,sun8i-h3";
+
+ aliases {
+ /* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
+ ethernet1 = &rtl8189ftv;
+ };
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ /*
+ * Explicitly define the sdio device, so that we can add an ethernet
+ * alias for it (which e.g. makes u-boot set a mac-address).
+ */
+ rtl8189ftv: sdio_wifi@1 {
+ reg = <1>;
+ };
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ status = "okay";
+};
+
+&mmc2_8bit_pins {
+ /* Increase drive strength for DDR modes */
+ allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+ /* eMMC is missing pull-ups */
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index daf50b9a6657..3ec971285aa3 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -161,6 +161,24 @@
status = "okay";
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "disabled";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "disabled";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ status = "disabled";
+};
+
&usbphy {
/* USB VBUS is always on */
status = "okay";
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
index b0cb41787e09..bb585918cf54 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
@@ -44,7 +44,7 @@
#include "sun8i-h3-orangepi-2.dts"
/ {
- model = "Xunlong Orange Pi Plus";
+ model = "Xunlong Orange Pi Plus / Plus 2";
compatible = "xunlong,orangepi-plus", "allwinner,sun8i-h3";
reg_usb3_vbus: usb3-vbus {
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
new file mode 100644
index 000000000000..5851a47a3089
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/*
+ * The Orange Pi Plus 2E is an extended version of the Orange Pi PC Plus,
+ * with 2G RAM and an external gbit ethernet phy.
+ */
+
+#include "sun8i-h3-orangepi-pc-plus.dts"
+
+/ {
+ model = "Xunlong Orange Pi Plus 2E";
+ compatible = "xunlong,orangepi-plus2e", "allwinner,sun8i-h3";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 8a95e3613488..75a865406d3e 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -327,6 +327,27 @@
interrupt-controller;
#interrupt-cells = <3>;
+ i2c0_pins: i2c0 {
+ allwinner,pins = "PA11", "PA12";
+ allwinner,function = "i2c0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c1_pins: i2c1 {
+ allwinner,pins = "PA18", "PA19";
+ allwinner,function = "i2c1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c2_pins: i2c2 {
+ allwinner,pins = "PE12", "PE13";
+ allwinner,function = "i2c2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc0_pins_a: mmc0@0 {
allwinner,pins = "PF0", "PF1", "PF2", "PF3",
"PF4", "PF5";
@@ -367,12 +388,33 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- uart1_pins_a: uart1@0 {
- allwinner,pins = "PG6", "PG7", "PG8", "PG9";
+ uart1_pins: uart1 {
+ allwinner,pins = "PG6", "PG7";
+ allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ uart1_rts_cts_pins: uart1_rts_cts {
+ allwinner,pins = "PG8", "PG9";
allwinner,function = "uart1";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ uart2_pins: uart2 {
+ allwinner,pins = "PA0", "PA1";
+ allwinner,function = "uart2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ uart3_pins: uart3 {
+ allwinner,pins = "PG13", "PG14";
+ allwinner,function = "uart3";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
timer@01c20c00 {
@@ -389,6 +431,14 @@
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
};
+ pwm: pwm@01c21400 {
+ compatible = "allwinner,sun8i-h3-pwm";
+ reg = <0x01c21400 0x8>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
@@ -441,6 +491,45 @@
status = "disabled";
};
+ i2c0: i2c@01c2ac00 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2ac00 0x400>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C0>;
+ resets = <&ccu RST_BUS_I2C0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C1>;
+ resets = <&ccu RST_BUS_I2C1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C2>;
+ resets = <&ccu RST_BUS_I2C2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
gic: interrupt-controller@01c81000 {
compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
reg = <0x01c81000 0x1000>,
diff --git a/arch/arm/boot/dts/sun8i-q8-common.dtsi b/arch/arm/boot/dts/sun8i-q8-common.dtsi
index 60fa9585022b..29f837a47771 100644
--- a/arch/arm/boot/dts/sun8i-q8-common.dtsi
+++ b/arch/arm/boot/dts/sun8i-q8-common.dtsi
@@ -42,10 +42,59 @@
#include "sunxi-reference-design-tablet.dtsi"
#include "sun8i-reference-design-tablet.dtsi"
+/ {
+ aliases {
+ serial0 = &r_uart;
+ /* Make u-boot set mac-address for wifi without an eeprom */
+ ethernet0 = &sdio_wifi;
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ /*
+ * Q8 boards use various PL# pins as wifi-en. On other boards
+ * these may be connected to a wifi module output pin. To avoid
+ * short-circuits we configure these as inputs with pull-ups via
+ * pinctrl, instead of listing them as active-low reset-gpios.
+ */
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_pwrseq_pin_q8>;
+ /* The esp8089 needs 200 ms after driving wifi-en high */
+ post-power-on-delay-ms = <200>;
+ };
+};
+
&ehci0 {
status = "okay";
};
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_dldo1>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ sdio_wifi: sdio_wifi@1 {
+ reg = <1>;
+ };
+};
+
+&mmc1_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&r_pio {
+ wifi_pwrseq_pin_q8: wifi_pwrseq_pin@0 {
+ allwinner,pins = "PL6", "PL7", "PL11";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
&usbphy {
usb1_vbus-supply = <&reg_dldo1>;
};
diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
index 9d9036140511..08cd00143635 100644
--- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
@@ -63,6 +63,25 @@
};
};
+&i2c0 {
+ /*
+ * The gsl1680 is rated at 400KHz and it will not work reliable at
+ * 100KHz, this has been confirmed on multiple different q8 tablets.
+ * The gsl1680 is the only device on this bus.
+ */
+ clock-frequency = <400000>;
+
+ touchscreen: touchscreen@0 {
+ interrupt-parent = <&pio>;
+ interrupts = <1 5 IRQ_TYPE_EDGE_FALLING>; /* PB5 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_power_pin>;
+ power-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ /* Tablet dts must provide reg and compatible */
+ status = "disabled";
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -88,6 +107,13 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+ ts_power_pin: ts_power_pin@0 {
+ allwinner,pins = "PH1";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
usb0_id_detect_pin: usb0_id_detect_pin@0 {
allwinner,pins = "PH8";
allwinner,function = "gpio_in";
diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
index 1526b41c70f1..439847acd41e 100644
--- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -103,6 +103,11 @@
allwinner,drive = <SUN4I_PINCTRL_40_MA>;
};
+&osc32k {
+ /* osc32k input is from AC100 */
+ clocks = <&ac100_rtc 0>;
+};
+
&pio {
led_pins_cubieboard4: led-pins@0 {
allwinner,pins = "PH6", "PH17";
@@ -248,6 +253,146 @@
reg_rtc_ldo: rtc_ldo {
regulator-name = "vcc-rtc-vdd1v8-io";
};
+
+ sw {
+ /* unused */
+ };
+ };
+ };
+
+ axp806: pmic@745 {
+ compatible = "x-powers,axp806";
+ reg = <0x745>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ bldoin-supply = <&reg_dcdce>;
+
+ regulators {
+ reg_s_aldo1: aldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+ };
+
+ aldo2 {
+ /*
+ * unused, but use a different name to
+ * avoid name clash with axp809's aldo's
+ */
+ regulator-name = "s_aldo2";
+ };
+
+ aldo3 {
+ /*
+ * unused, but use a different name to
+ * avoid name clash with axp809's aldo's
+ */
+ regulator-name = "s_aldo3";
+ };
+
+ reg_bldo1: bldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-name = "vcc18-efuse-adc-display-csi";
+ };
+
+ reg_bldo2: bldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-name =
+ "vdd18-drampll-vcc18-pll-cpvdd";
+ };
+
+ bldo3 {
+ /* unused */
+ };
+
+ reg_bldo4: bldo4 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-name = "vcc12-hsic";
+ };
+
+ reg_cldo1: cldo1 {
+ /*
+ * This was 3V in the original design, but
+ * 3.3V is the recommended supply voltage
+ * for the Ethernet PHY.
+ */
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-gmac-phy";
+ };
+
+ reg_cldo2: cldo2 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-name = "afvcc-cam";
+ };
+
+ reg_cldo3: cldo3 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-io-wifi-codec-io2";
+ };
+
+ reg_dcdca: dcdca {
+ regulator-always-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-cpub";
+ };
+
+ reg_dcdcd: dcdcd {
+ regulator-always-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-vpu";
+ };
+
+ reg_dcdce: dcdce {
+ regulator-always-on;
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ regulator-name = "vcc-bldo-codec-ldoin";
+ };
+
+ sw {
+ /*
+ * unused, but use a different name to
+ * avoid name clash with axp809's sw
+ */
+ regulator-name = "s_sw";
+ };
+ };
+ };
+
+ ac100: codec@e89 {
+ compatible = "x-powers,ac100";
+ reg = <0xe89>;
+
+ ac100_codec: codec {
+ compatible = "x-powers,ac100-codec";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+ #clock-cells = <0>;
+ clock-output-names = "4M_adda";
+ };
+
+ ac100_rtc: rtc {
+ compatible = "x-powers,ac100-rtc";
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&ac100_codec>;
+ #clock-cells = <1>;
+ clock-output-names = "cko1_rtc",
+ "cko2_rtc",
+ "cko3_rtc";
};
};
};
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 7fd22e888602..ceb6ef15d669 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -112,7 +112,8 @@
};
&ehci1 {
- status = "okay";
+ /* Enable if HSIC peripheral is connected */
+ status = "disabled";
};
&ehci2 {
@@ -152,6 +153,11 @@
status = "okay";
};
+&osc32k {
+ /* osc32k input is from AC100 */
+ clocks = <&ac100_rtc 0>;
+};
+
&pio {
led_pins_optimus: led-pins@0 {
allwinner,pins = "PH0", "PH1";
@@ -320,6 +326,146 @@
reg_rtc_ldo: rtc_ldo {
regulator-name = "vcc-rtc-vdd1v8-io";
};
+
+ sw {
+ /* unused */
+ };
+ };
+ };
+
+ axp806: pmic@745 {
+ compatible = "x-powers,axp806";
+ reg = <0x745>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ bldoin-supply = <&reg_dcdce>;
+
+ regulators {
+ reg_s_aldo1: aldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+ };
+
+ aldo2 {
+ /*
+ * unused, but use a different name to
+ * avoid name clash with axp809's aldo's
+ */
+ regulator-name = "s_aldo2";
+ };
+
+ aldo3 {
+ /*
+ * unused, but use a different name to
+ * avoid name clash with axp809's aldo's
+ */
+ regulator-name = "s_aldo3";
+ };
+
+ reg_bldo1: bldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-name = "vcc18-efuse-adc-display-csi";
+ };
+
+ reg_bldo2: bldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-name =
+ "vdd18-drampll-vcc18-pll-cpvdd";
+ };
+
+ bldo3 {
+ /* unused */
+ };
+
+ reg_bldo4: bldo4 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-name = "vcc12-hsic";
+ };
+
+ reg_cldo1: cldo1 {
+ /*
+ * This was 3V in the original design, but
+ * 3.3V is the recommended supply voltage
+ * for the Ethernet PHY.
+ */
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-gmac-phy";
+ };
+
+ reg_cldo2: cldo2 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-name = "afvcc-cam";
+ };
+
+ reg_cldo3: cldo3 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-io-wifi-codec-io2";
+ };
+
+ reg_dcdca: dcdca {
+ regulator-always-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-cpub";
+ };
+
+ reg_dcdcd: dcdcd {
+ regulator-always-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-vpu";
+ };
+
+ reg_dcdce: dcdce {
+ regulator-always-on;
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ regulator-name = "vcc-bldo-codec-ldoin";
+ };
+
+ sw {
+ /*
+ * unused, but use a different name to
+ * avoid name clash with axp809's sw
+ */
+ regulator-name = "s_sw";
+ };
+ };
+ };
+
+ ac100: codec@e89 {
+ compatible = "x-powers,ac100";
+ reg = <0xe89>;
+
+ ac100_codec: codec {
+ compatible = "x-powers,ac100-codec";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+ #clock-cells = <0>;
+ clock-output-names = "4M_adda";
+ };
+
+ ac100_rtc: rtc {
+ compatible = "x-powers,ac100-rtc";
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&ac100_codec>;
+ #clock-cells = <1>;
+ clock-output-names = "cko1_rtc",
+ "cko2_rtc",
+ "cko3_rtc";
};
};
};
@@ -338,7 +484,9 @@
};
&usbphy2 {
- status = "okay";
+ phy-supply = <&reg_bldo4>;
+ /* Enable if HSIC peripheral is connected */
+ status = "disabled";
};
&usbphy3 {
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index f68b3242b33a..3c5214cbe4e6 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -148,15 +148,14 @@
/*
* The 32k clock is from an external source, normally the
- * AC100 codec/RTC chip. This clock is by default enabled
- * and clocked at 32768 Hz, from the oscillator connected
- * to the AC100. It is configurable, but no such driver or
- * bindings exist yet.
+ * AC100 codec/RTC chip. This serves as a placeholder for
+ * board dts files to specify the source.
*/
osc32k: osc32k_clk {
#clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32768>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
clock-output-names = "osc32k";
};
@@ -899,8 +898,7 @@
resets = <&apbs_rst 0>;
gpio-controller;
interrupt-controller;
- #address-cells = <1>;
- #size-cells = <0>;
+ #interrupt-cells = <3>;
#gpio-cells = <3>;
r_ir_pins: r_ir {
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index cb9393a53422..8932ea3afd5f 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -672,7 +672,7 @@
};
usb@7d000000 {
- compatible = "nvidia,tegra30-ehci", "usb-ehci";
+ compatible = "nvidia,tegra114-ehci", "nvidia,tegra30-ehci", "usb-ehci";
reg = <0x7d000000 0x4000>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
phy_type = "utmi";
@@ -684,7 +684,7 @@
};
phy1: usb-phy@7d000000 {
- compatible = "nvidia,tegra30-usb-phy";
+ compatible = "nvidia,tegra114-usb-phy", "nvidia,tegra30-usb-phy";
reg = <0x7d000000 0x4000 0x7d000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA114_CLK_USBD>,
@@ -708,7 +708,7 @@
};
usb@7d008000 {
- compatible = "nvidia,tegra30-ehci", "usb-ehci";
+ compatible = "nvidia,tegra114-ehci", "nvidia,tegra30-ehci", "usb-ehci";
reg = <0x7d008000 0x4000>;
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
phy_type = "utmi";
@@ -720,7 +720,7 @@
};
phy3: usb-phy@7d008000 {
- compatible = "nvidia,tegra30-usb-phy";
+ compatible = "nvidia,tegra114-usb-phy", "nvidia,tegra30-usb-phy";
reg = <0x7d008000 0x4000 0x7d000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA114_CLK_USB3>,
diff --git a/arch/arm/boot/dts/uniphier-common32.dtsi b/arch/arm/boot/dts/uniphier-common32.dtsi
index 03f60ec340b5..8c8a85176b64 100644
--- a/arch/arm/boot/dts/uniphier-common32.dtsi
+++ b/arch/arm/boot/dts/uniphier-common32.dtsi
@@ -1,7 +1,8 @@
/*
* Device Tree Source commonly used by UniPhier ARM SoCs
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,6 +46,11 @@
/include/ "skeleton.dtsi"
/ {
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
clocks {
refclk: ref {
#clock-cells = <0>;
@@ -66,7 +72,7 @@
interrupts = <0 33 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart0>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 0>;
};
serial1: serial@54006900 {
@@ -76,7 +82,7 @@
interrupts = <0 35 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 1>;
};
serial2: serial@54006a00 {
@@ -86,7 +92,7 @@
interrupts = <0 37 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 2>;
};
serial3: serial@54006b00 {
@@ -96,7 +102,7 @@
interrupts = <0 177 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart3>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 3>;
};
system_bus: system-bus@58c00000 {
@@ -114,6 +120,34 @@
reg = <0x59801000 0x400>;
};
+ mioctrl@59810000 {
+ compatible = "socionext,uniphier-mioctrl",
+ "simple-mfd", "syscon";
+ reg = <0x59810000 0x800>;
+
+ mio_clk: clock {
+ #clock-cells = <1>;
+ };
+
+ mio_rst: reset {
+ #reset-cells = <1>;
+ };
+ };
+
+ perictrl@59820000 {
+ compatible = "socionext,uniphier-perictrl",
+ "simple-mfd", "syscon";
+ reg = <0x59820000 0x200>;
+
+ peri_clk: clock {
+ #clock-cells = <1>;
+ };
+
+ peri_rst: reset {
+ #reset-cells = <1>;
+ };
+ };
+
timer@60000200 {
compatible = "arm,cortex-a9-global-timer";
reg = <0x60000200 0x20>;
@@ -137,11 +171,26 @@
};
soc-glue@5f800000 {
- compatible = "simple-mfd", "syscon";
+ compatible = "socionext,uniphier-soc-glue",
+ "simple-mfd", "syscon";
reg = <0x5f800000 0x2000>;
pinctrl: pinctrl {
- /* specify compatible in each SoC DTSI */
+ /* specify compatible in each SoC DTSI */
+ };
+ };
+
+ sysctrl@61840000 {
+ compatible = "socionext,uniphier-sysctrl",
+ "simple-mfd", "syscon";
+ reg = <0x61840000 0x4000>;
+
+ sys_clk: clock {
+ #clock-cells = <1>;
+ };
+
+ sys_rst: reset {
+ #reset-cells = <1>;
};
};
};
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts b/arch/arm/boot/dts/uniphier-ld4-ref.dts
index ec94b7a661f2..110031bc0e7e 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ld4-ref.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-LD4 Reference Board
+ * Device Tree Source for UniPhier LD4 Reference Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,13 +44,13 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-ld4.dtsi"
+/include/ "uniphier-ld4.dtsi"
/include/ "uniphier-ref-daughter.dtsi"
/include/ "uniphier-support-card.dtsi"
/ {
- model = "UniPhier PH1-LD4 Reference Board";
- compatible = "socionext,ph1-ld4-ref", "socionext,ph1-ld4";
+ model = "UniPhier LD4 Reference Board";
+ compatible = "socionext,uniphier-ld4-ref", "socionext,uniphier-ld4";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi b/arch/arm/boot/dts/uniphier-ld4.dtsi
index debad7ffef05..95f342c9d9c1 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
+++ b/arch/arm/boot/dts/uniphier-ld4.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-LD4 SoC
+ * Device Tree Source for UniPhier LD4 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,7 +46,7 @@
/include/ "uniphier-common32.dtsi"
/ {
- compatible = "socionext,ph1-ld4";
+ compatible = "socionext,uniphier-ld4";
cpus {
#address-cells = <1>;
@@ -55,6 +56,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
};
@@ -65,18 +67,6 @@
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <36864000>;
- };
-
- iobus_clk: iobus_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <100000000>;
- };
};
};
@@ -101,7 +91,7 @@
interrupts = <0 41 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 4>;
clock-frequency = <100000>;
};
@@ -114,7 +104,7 @@
interrupts = <0 42 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 5>;
clock-frequency = <100000>;
};
@@ -127,7 +117,7 @@
interrupts = <0 43 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 6>;
clock-frequency = <400000>;
};
@@ -140,7 +130,7 @@
interrupts = <0 44 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 7>;
clock-frequency = <100000>;
};
@@ -151,6 +141,8 @@
interrupts = <0 80 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb0>;
+ clocks = <&mio_clk 7>, <&mio_clk 8>, <&mio_clk 12>;
+ resets = <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>, <&sys_rst 8>;
};
usb1: usb@5a810100 {
@@ -160,6 +152,8 @@
interrupts = <0 81 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb1>;
+ clocks = <&mio_clk 7>, <&mio_clk 9>, <&mio_clk 13>;
+ resets = <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>, <&sys_rst 8>;
};
usb2: usb@5a820100 {
@@ -169,6 +163,8 @@
interrupts = <0 82 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2>;
+ clocks = <&mio_clk 7>, <&mio_clk 10>, <&mio_clk 14>;
+ resets = <&mio_rst 7>, <&mio_rst 10>, <&mio_rst 14>, <&sys_rst 8>;
};
};
@@ -181,6 +177,31 @@
interrupts = <0 29 4>;
};
+&mio_clk {
+ compatible = "socionext,uniphier-ld4-mio-clock";
+};
+
+&mio_rst {
+ compatible = "socionext,uniphier-ld4-mio-reset";
+ resets = <&sys_rst 7>;
+};
+
+&peri_clk {
+ compatible = "socionext,uniphier-ld4-peri-clock";
+};
+
+&peri_rst {
+ compatible = "socionext,uniphier-ld4-peri-reset";
+};
+
&pinctrl {
compatible = "socionext,uniphier-ld4-pinctrl";
};
+
+&sys_clk {
+ compatible = "socionext,uniphier-ld4-clock";
+};
+
+&sys_rst {
+ compatible = "socionext,uniphier-ld4-reset";
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts b/arch/arm/boot/dts/uniphier-ld6b-ref.dts
index b8134c6e094b..c05d631dcf02 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ld6b-ref.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-LD6b Reference Board
+ * Device Tree Source for UniPhier LD6b Reference Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,13 +44,13 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-ld6b.dtsi"
+/include/ "uniphier-ld6b.dtsi"
/include/ "uniphier-ref-daughter.dtsi"
/include/ "uniphier-support-card.dtsi"
/ {
- model = "UniPhier PH1-LD6b Reference Board";
- compatible = "socionext,ph1-ld6b-ref", "socionext,ph1-ld6b";
+ model = "UniPhier LD6b Reference Board";
+ compatible = "socionext,uniphier-ld6b-ref", "socionext,uniphier-ld6b";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi b/arch/arm/boot/dts/uniphier-ld6b.dtsi
index 19c107c66bae..905c77d499eb 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld6b.dtsi
+++ b/arch/arm/boot/dts/uniphier-ld6b.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-LD6b SoC
+ * Device Tree Source for UniPhier LD6b SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,14 +44,14 @@
*/
/*
- * PH1-LD6b consists of two silicon dies: D-chip and A-chip.
- * The D-chip (digital chip) is the same as the ProXstream2 die.
- * Reuse the ProXstream2 device tree with some properties overridden.
+ * LD6b consists of two silicon dies: D-chip and A-chip.
+ * The D-chip (digital chip) is the same as the PXs2 die.
+ * Reuse the PXs2 device tree with some properties overridden.
*/
-/include/ "uniphier-proxstream2.dtsi"
+/include/ "uniphier-pxs2.dtsi"
/ {
- compatible = "socionext,ph1-ld6b";
+ compatible = "socionext,uniphier-ld6b";
};
/* UART3 unavailable: the pads are not wired to the package balls */
@@ -59,7 +60,7 @@
};
/*
- * PH1-LD6b and ProXstream2 have completely different packages,
+ * LD6b and PXs2 have completely different packages,
* which makes the pinctrl driver unshareable.
*/
&pinctrl {
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-ace.dts b/arch/arm/boot/dts/uniphier-pro4-ace.dts
index d34358632bec..0ab0a40c041e 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4-ace.dts
+++ b/arch/arm/boot/dts/uniphier-pro4-ace.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-Pro4 Ace Board
+ * Device Tree Source for UniPhier Pro4 Ace Board
*
- * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,11 +44,11 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-pro4.dtsi"
+/include/ "uniphier-pro4.dtsi"
/ {
- model = "UniPhier PH1-Pro4 Ace Board";
- compatible = "socionext,ph1-pro4-ace", "socionext,ph1-pro4";
+ model = "UniPhier Pro4 Ace Board";
+ compatible = "socionext,uniphier-pro4-ace", "socionext,uniphier-pro4";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts b/arch/arm/boot/dts/uniphier-pro4-ref.dts
index 95f631a3de35..9e92e60d25ce 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
+++ b/arch/arm/boot/dts/uniphier-pro4-ref.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-Pro4 Reference Board
+ * Device Tree Source for UniPhier Pro4 Reference Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,13 +44,13 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-pro4.dtsi"
+/include/ "uniphier-pro4.dtsi"
/include/ "uniphier-ref-daughter.dtsi"
/include/ "uniphier-support-card.dtsi"
/ {
- model = "UniPhier PH1-Pro4 Reference Board";
- compatible = "socionext,ph1-pro4-ref", "socionext,ph1-pro4";
+ model = "UniPhier Pro4 Reference Board";
+ compatible = "socionext,uniphier-pro4-ref", "socionext,uniphier-pro4";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-sanji.dts b/arch/arm/boot/dts/uniphier-pro4-sanji.dts
index 7c3a1fcc9f3c..dc4ea8832ce2 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4-sanji.dts
+++ b/arch/arm/boot/dts/uniphier-pro4-sanji.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-Pro4 Sanji Board
+ * Device Tree Source for UniPhier Pro4 Sanji Board
*
- * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,11 +44,11 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-pro4.dtsi"
+/include/ "uniphier-pro4.dtsi"
/ {
- model = "UniPhier PH1-Pro4 Sanji Board";
- compatible = "socionext,ph1-pro4-sanji", "socionext,ph1-pro4";
+ model = "UniPhier Pro4 Sanji Board";
+ compatible = "socionext,uniphier-pro4-sanji", "socionext,uniphier-pro4";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi b/arch/arm/boot/dts/uniphier-pro4.dtsi
index 7b9da0852005..ba700267ad66 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
+++ b/arch/arm/boot/dts/uniphier-pro4.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-Pro4 SoC
+ * Device Tree Source for UniPhier Pro4 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,17 +46,17 @@
/include/ "uniphier-common32.dtsi"
/ {
- compatible = "socionext,ph1-pro4";
+ compatible = "socionext,uniphier-pro4";
cpus {
#address-cells = <1>;
#size-cells = <0>;
- enable-method = "socionext,uniphier-smp";
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
@@ -63,6 +64,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
};
@@ -73,18 +75,6 @@
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <73728000>;
- };
-
- i2c_clk: i2c_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <50000000>;
- };
};
};
@@ -109,7 +99,7 @@
interrupts = <0 41 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 4>;
clock-frequency = <100000>;
};
@@ -122,7 +112,7 @@
interrupts = <0 42 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 5>;
clock-frequency = <100000>;
};
@@ -135,7 +125,7 @@
interrupts = <0 43 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 6>;
clock-frequency = <100000>;
};
@@ -148,7 +138,7 @@
interrupts = <0 44 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 7>;
clock-frequency = <100000>;
};
@@ -161,7 +151,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 9>;
clock-frequency = <400000>;
};
@@ -172,7 +162,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 26 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 10>;
clock-frequency = <400000>;
};
@@ -183,6 +173,8 @@
interrupts = <0 80 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2>;
+ clocks = <&mio_clk 7>, <&mio_clk 8>, <&mio_clk 12>;
+ resets = <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>, <&sys_rst 8>;
};
usb3: usb@5a810100 {
@@ -192,6 +184,8 @@
interrupts = <0 81 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb3>;
+ clocks = <&mio_clk 7>, <&mio_clk 9>, <&mio_clk 13>;
+ resets = <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>, <&sys_rst 8>;
};
};
@@ -199,6 +193,31 @@
clock-frequency = <25000000>;
};
+&mio_clk {
+ compatible = "socionext,uniphier-pro4-mio-clock";
+};
+
+&mio_rst {
+ compatible = "socionext,uniphier-pro4-mio-reset";
+ resets = <&sys_rst 7>;
+};
+
+&peri_clk {
+ compatible = "socionext,uniphier-pro4-peri-clock";
+};
+
+&peri_rst {
+ compatible = "socionext,uniphier-pro4-peri-reset";
+};
+
&pinctrl {
compatible = "socionext,uniphier-pro4-pinctrl";
};
+
+&sys_clk {
+ compatible = "socionext,uniphier-pro4-clock";
+};
+
+&sys_rst {
+ compatible = "socionext,uniphier-pro4-reset";
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi b/arch/arm/boot/dts/uniphier-pro5.dtsi
index 7e4aa2fde719..2c49c3614bda 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
+++ b/arch/arm/boot/dts/uniphier-pro5.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-Pro5 SoC
+ * Device Tree Source for UniPhier Pro5 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,17 +46,17 @@
/include/ "uniphier-common32.dtsi"
/ {
- compatible = "socionext,ph1-pro5";
+ compatible = "socionext,uniphier-pro5";
cpus {
#address-cells = <1>;
#size-cells = <0>;
- enable-method = "socionext,uniphier-smp";
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
@@ -63,6 +64,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
};
@@ -73,18 +75,6 @@
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <73728000>;
- };
-
- i2c_clk: i2c_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <50000000>;
- };
};
};
@@ -121,7 +111,7 @@
interrupts = <0 41 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 4>;
clock-frequency = <100000>;
};
@@ -134,7 +124,7 @@
interrupts = <0 42 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 5>;
clock-frequency = <100000>;
};
@@ -147,7 +137,7 @@
interrupts = <0 43 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 6>;
clock-frequency = <100000>;
};
@@ -160,7 +150,7 @@
interrupts = <0 44 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 7>;
clock-frequency = <100000>;
};
@@ -173,7 +163,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 9>;
clock-frequency = <400000>;
};
@@ -184,7 +174,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 26 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 10>;
clock-frequency = <400000>;
};
};
@@ -193,6 +183,30 @@
clock-frequency = <20000000>;
};
+&mio_clk {
+ compatible = "socionext,uniphier-pro5-mio-clock";
+};
+
+&mio_rst {
+ compatible = "socionext,uniphier-pro5-mio-reset";
+};
+
+&peri_clk {
+ compatible = "socionext,uniphier-pro5-peri-clock";
+};
+
+&peri_rst {
+ compatible = "socionext,uniphier-pro5-peri-reset";
+};
+
&pinctrl {
compatible = "socionext,uniphier-pro5-pinctrl";
};
+
+&sys_clk {
+ compatible = "socionext,uniphier-pro5-clock";
+};
+
+&sys_rst {
+ compatible = "socionext,uniphier-pro5-reset";
+};
diff --git a/arch/arm/boot/dts/uniphier-proxstream2-gentil.dts b/arch/arm/boot/dts/uniphier-pxs2-gentil.dts
index 98d895b7af1d..373818ace086 100644
--- a/arch/arm/boot/dts/uniphier-proxstream2-gentil.dts
+++ b/arch/arm/boot/dts/uniphier-pxs2-gentil.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier ProXstream2 Gentil Board
+ * Device Tree Source for UniPhier PXs2 Gentil Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,11 +44,12 @@
*/
/dts-v1/;
-/include/ "uniphier-proxstream2.dtsi"
+/include/ "uniphier-pxs2.dtsi"
/ {
- model = "UniPhier ProXstream2 Gentil Board";
- compatible = "socionext,proxstream2-gentil", "socionext,proxstream2";
+ model = "UniPhier PXs2 Gentil Board";
+ compatible = "socionext,uniphier-pxs2-gentil",
+ "socionext,uniphier-pxs2";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-proxstream2-vodka.dts b/arch/arm/boot/dts/uniphier-pxs2-vodka.dts
index 1fb8bd7bb686..51a3eacddfc6 100644
--- a/arch/arm/boot/dts/uniphier-proxstream2-vodka.dts
+++ b/arch/arm/boot/dts/uniphier-pxs2-vodka.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier ProXstream2 Vodka Board
+ * Device Tree Source for UniPhier PXs2 Vodka Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,11 +44,11 @@
*/
/dts-v1/;
-/include/ "uniphier-proxstream2.dtsi"
+/include/ "uniphier-pxs2.dtsi"
/ {
- model = "UniPhier ProXstream2 Vodka Board";
- compatible = "socionext,proxstream2-vodka", "socionext,proxstream2";
+ model = "UniPhier PXs2 Vodka Board";
+ compatible = "socionext,uniphier-pxs2-vodka", "socionext,uniphier-pxs2";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-proxstream2.dtsi b/arch/arm/boot/dts/uniphier-pxs2.dtsi
index d00d6f5c2668..8789cd518933 100644
--- a/arch/arm/boot/dts/uniphier-proxstream2.dtsi
+++ b/arch/arm/boot/dts/uniphier-pxs2.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier ProXstream2 SoC
+ * Device Tree Source for UniPhier PXs2 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,17 +46,17 @@
/include/ "uniphier-common32.dtsi"
/ {
- compatible = "socionext,proxstream2";
+ compatible = "socionext,uniphier-pxs2";
cpus {
#address-cells = <1>;
#size-cells = <0>;
- enable-method = "socionext,uniphier-smp";
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
@@ -63,6 +64,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
@@ -70,6 +72,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <2>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
@@ -77,6 +80,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <3>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
};
@@ -87,18 +91,6 @@
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <88900000>;
- };
-
- i2c_clk: i2c_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <50000000>;
- };
};
};
@@ -123,7 +115,7 @@
interrupts = <0 41 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 4>;
clock-frequency = <100000>;
};
@@ -136,7 +128,7 @@
interrupts = <0 42 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 5>;
clock-frequency = <100000>;
};
@@ -149,7 +141,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
interrupts = <0 43 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 6>;
clock-frequency = <100000>;
};
@@ -162,7 +154,7 @@
interrupts = <0 44 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 7>;
clock-frequency = <100000>;
};
@@ -173,7 +165,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 45 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 8>;
clock-frequency = <400000>;
};
@@ -184,7 +176,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 9>;
clock-frequency = <400000>;
};
@@ -195,7 +187,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 26 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 10>;
clock-frequency = <400000>;
};
};
@@ -204,6 +196,30 @@
clock-frequency = <25000000>;
};
+&mio_clk {
+ compatible = "socionext,uniphier-pxs2-mio-clock";
+};
+
+&mio_rst {
+ compatible = "socionext,uniphier-pxs2-mio-reset";
+};
+
+&peri_clk {
+ compatible = "socionext,uniphier-pxs2-peri-clock";
+};
+
+&peri_rst {
+ compatible = "socionext,uniphier-pxs2-peri-reset";
+};
+
&pinctrl {
compatible = "socionext,uniphier-pxs2-pinctrl";
};
+
+&sys_clk {
+ compatible = "socionext,uniphier-pxs2-clock";
+};
+
+&sys_rst {
+ compatible = "socionext,uniphier-pxs2-reset";
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts b/arch/arm/boot/dts/uniphier-sld3-ref.dts
index acb420492b36..ac792ae07ae0 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
+++ b/arch/arm/boot/dts/uniphier-sld3-ref.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-sLD3 Reference Board
+ * Device Tree Source for UniPhier sLD3 Reference Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,13 +44,13 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-sld3.dtsi"
+/include/ "uniphier-sld3.dtsi"
/include/ "uniphier-ref-daughter.dtsi"
/include/ "uniphier-support-card.dtsi"
/ {
- model = "UniPhier PH1-sLD3 Reference Board";
- compatible = "socionext,ph1-sld3-ref", "socionext,ph1-sld3";
+ model = "UniPhier sLD3 Reference Board";
+ compatible = "socionext,uniphier-sld3-ref", "socionext,uniphier-sld3";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi b/arch/arm/boot/dts/uniphier-sld3.dtsi
index 03292f443305..5fa96c939b5c 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
+++ b/arch/arm/boot/dts/uniphier-sld3.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-sLD3 SoC
+ * Device Tree Source for UniPhier sLD3 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,17 +46,17 @@
/include/ "skeleton.dtsi"
/ {
- compatible = "socionext,ph1-sld3";
+ compatible = "socionext,uniphier-sld3";
cpus {
#address-cells = <1>;
#size-cells = <0>;
- enable-method = "socionext,uniphier-smp";
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
@@ -63,10 +64,16 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
};
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
clocks {
refclk: ref {
#clock-cells = <0>;
@@ -79,18 +86,6 @@
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <36864000>;
- };
-
- iobus_clk: iobus_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <100000000>;
- };
};
soc {
@@ -139,7 +134,7 @@
status = "disabled";
reg = <0x54006800 0x40>;
interrupts = <0 33 4>;
- clocks = <&uart_clk>;
+ clocks = <&sys_clk 0>;
fifo-size = <64>;
};
@@ -148,7 +143,7 @@
status = "disabled";
reg = <0x54006900 0x40>;
interrupts = <0 35 4>;
- clocks = <&uart_clk>;
+ clocks = <&sys_clk 0>;
fifo-size = <64>;
};
@@ -157,7 +152,7 @@
status = "disabled";
reg = <0x54006a00 0x40>;
interrupts = <0 37 4>;
- clocks = <&uart_clk>;
+ clocks = <&sys_clk 0>;
fifo-size = <64>;
};
@@ -168,7 +163,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 41 1>;
- clocks = <&iobus_clk>;
+ clocks = <&sys_clk 1>;
clock-frequency = <100000>;
};
@@ -179,7 +174,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 42 1>;
- clocks = <&iobus_clk>;
+ clocks = <&sys_clk 1>;
clock-frequency = <100000>;
};
@@ -190,7 +185,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 43 1>;
- clocks = <&iobus_clk>;
+ clocks = <&sys_clk 1>;
clock-frequency = <100000>;
};
@@ -201,7 +196,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 44 1>;
- clocks = <&iobus_clk>;
+ clocks = <&sys_clk 1>;
clock-frequency = <100000>;
};
@@ -212,7 +207,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 45 1>;
- clocks = <&iobus_clk>;
+ clocks = <&sys_clk 1>;
clock-frequency = <400000>;
};
@@ -229,6 +224,22 @@
reg = <0x59801000 0x400>;
};
+ mioctrl@59810000 {
+ compatible = "socionext,uniphier-mioctrl",
+ "simple-mfd", "syscon";
+ reg = <0x59810000 0x800>;
+
+ mio_clk: clock {
+ compatible = "socionext,uniphier-sld3-mio-clock";
+ #clock-cells = <1>;
+ };
+
+ mio_rst: reset {
+ compatible = "socionext,uniphier-sld3-mio-reset";
+ #reset-cells = <1>;
+ };
+ };
+
usb0: usb@5a800100 {
compatible = "socionext,uniphier-ehci", "generic-ehci";
status = "disabled";
@@ -256,5 +267,21 @@
reg = <0x5a830100 0x100>;
interrupts = <0 83 4>;
};
+
+ sysctrl@f1840000 {
+ compatible = "socionext,uniphier-sysctrl",
+ "simple-mfd", "syscon";
+ reg = <0xf1840000 0x4000>;
+
+ sys_clk: clock {
+ compatible = "socionext,uniphier-sld3-clock";
+ #clock-cells = <1>;
+ };
+
+ sys_rst: reset {
+ compatible = "socionext,uniphier-sld3-reset";
+ #reset-cells = <1>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts b/arch/arm/boot/dts/uniphier-sld8-ref.dts
index d594f40e7f76..a8291f988066 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
+++ b/arch/arm/boot/dts/uniphier-sld8-ref.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-sLD8 Reference Board
+ * Device Tree Source for UniPhier sLD8 Reference Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,13 +44,13 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-sld8.dtsi"
+/include/ "uniphier-sld8.dtsi"
/include/ "uniphier-ref-daughter.dtsi"
/include/ "uniphier-support-card.dtsi"
/ {
- model = "UniPhier PH1-sLD8 Reference Board";
- compatible = "socionext,ph1-sld8-ref", "socionext,ph1-sld8";
+ model = "UniPhier sLD8 Reference Board";
+ compatible = "socionext,uniphier-sld8-ref", "socionext,uniphier-sld8";
memory {
device_type = "memory";
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi b/arch/arm/boot/dts/uniphier-sld8.dtsi
index 467f9d8e9873..d8cf0e7e11ea 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
+++ b/arch/arm/boot/dts/uniphier-sld8.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-sLD8 SoC
+ * Device Tree Source for UniPhier sLD8 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,7 +46,7 @@
/include/ "uniphier-common32.dtsi"
/ {
- compatible = "socionext,ph1-sld8";
+ compatible = "socionext,uniphier-sld8";
cpus {
#address-cells = <1>;
@@ -55,6 +56,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ enable-method = "psci";
next-level-cache = <&l2>;
};
};
@@ -65,18 +67,6 @@
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <80000000>;
- };
-
- iobus_clk: iobus_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <100000000>;
- };
};
};
@@ -101,7 +91,7 @@
interrupts = <0 41 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 4>;
clock-frequency = <100000>;
};
@@ -114,7 +104,7 @@
interrupts = <0 42 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 5>;
clock-frequency = <100000>;
};
@@ -127,7 +117,7 @@
interrupts = <0 43 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 6>;
clock-frequency = <400000>;
};
@@ -140,7 +130,7 @@
interrupts = <0 44 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
- clocks = <&iobus_clk>;
+ clocks = <&peri_clk 7>;
clock-frequency = <100000>;
};
@@ -151,6 +141,8 @@
interrupts = <0 80 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb0>;
+ clocks = <&mio_clk 7>, <&mio_clk 8>, <&mio_clk 12>;
+ resets = <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>, <&sys_rst 8>;
};
usb1: usb@5a810100 {
@@ -160,6 +152,8 @@
interrupts = <0 81 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb1>;
+ clocks = <&mio_clk 7>, <&mio_clk 9>, <&mio_clk 13>;
+ resets = <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>, <&sys_rst 8>;
};
usb2: usb@5a820100 {
@@ -169,6 +163,8 @@
interrupts = <0 82 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2>;
+ clocks = <&mio_clk 7>, <&mio_clk 10>, <&mio_clk 14>;
+ resets = <&mio_rst 7>, <&mio_rst 10>, <&mio_rst 14>, <&sys_rst 8>;
};
};
@@ -180,6 +176,31 @@
interrupts = <0 29 4>;
};
+&mio_clk {
+ compatible = "socionext,uniphier-sld8-mio-clock";
+};
+
+&mio_rst {
+ compatible = "socionext,uniphier-sld8-mio-reset";
+ resets = <&sys_rst 7>;
+};
+
+&peri_clk {
+ compatible = "socionext,uniphier-sld8-peri-clock";
+};
+
+&peri_rst {
+ compatible = "socionext,uniphier-sld8-peri-reset";
+};
+
&pinctrl {
compatible = "socionext,uniphier-sld8-pinctrl";
};
+
+&sys_clk {
+ compatible = "socionext,uniphier-sld8-clock";
+};
+
+&sys_rst {
+ compatible = "socionext,uniphier-sld8-reset";
+};
diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
index a8a8e434fb27..1e0b823f7e8f 100644
--- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -53,6 +53,12 @@
panel: panel {
compatible = "edt,et057090dhu";
backlight = <&bl>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dcu_out>;
+ };
+ };
};
reg_3v3: regulator-3v3 {
@@ -91,8 +97,13 @@
&dcu0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dcu0_1>;
- fsl,panel = <&panel>;
status = "okay";
+
+ port {
+ dcu_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
};
&dspi1 {
diff --git a/arch/arm/boot/dts/vf610m4.dtsi b/arch/arm/boot/dts/vf610m4.dtsi
index 9ffe2eb68ed4..9f2c731839f2 100644
--- a/arch/arm/boot/dts/vf610m4.dtsi
+++ b/arch/arm/boot/dts/vf610m4.dtsi
@@ -42,6 +42,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "skeleton.dtsi"
#include "armv7-m.dtsi"
#include "vfxxx.dtsi"
diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig
index 0b9211b2b73b..3146ad055716 100644
--- a/arch/arm/configs/colibri_pxa270_defconfig
+++ b/arch/arm/configs/colibri_pxa270_defconfig
@@ -83,7 +83,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_IDE=y
CONFIG_NETDEVICES=y
CONFIG_PHYLIB=y
CONFIG_NET_ETHERNET=y
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index f33d042b1273..5e5dd6bc5ed9 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -1,8 +1,8 @@
-CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
-CONFIG_FHANDLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -14,16 +14,16 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
CONFIG_ARCH_DAVINCI=y
CONFIG_ARCH_DAVINCI_DM644x=y
CONFIG_ARCH_DAVINCI_DM355=y
CONFIG_ARCH_DAVINCI_DM646x=y
-CONFIG_ARCH_DAVINCI_DM365=y
CONFIG_ARCH_DAVINCI_DA830=y
CONFIG_ARCH_DAVINCI_DA850=y
-CONFIG_MACH_DA8XX_DT=y
+CONFIG_ARCH_DAVINCI_DM365=y
CONFIG_MACH_SFFSDR=y
CONFIG_MACH_NEUROS_OSD2=y
CONFIG_MACH_DM355_LEOPARD=y
@@ -32,13 +32,8 @@ CONFIG_MACH_OMAPL138_HAWKBOARD=y
CONFIG_DAVINCI_MUX_DEBUG=y
CONFIG_DAVINCI_MUX_WARNINGS=y
CONFIG_DAVINCI_RESET_CLOCKS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_LEDS=y
-CONFIG_USE_OF=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
@@ -50,22 +45,18 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_ONDEMAND=m
CONFIG_CPU_IDLE=y
-CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_LRO is not set
CONFIG_NETFILTER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_FW_LOADER is not set
CONFIG_MTD=m
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=m
CONFIG_MTD_BLOCK=m
CONFIG_MTD_CFI=m
CONFIG_MTD_CFI_INTELEXT=m
@@ -75,7 +66,8 @@ CONFIG_MTD_M25P80=m
CONFIG_MTD_NAND=m
CONFIG_MTD_NAND_DAVINCI=m
CONFIG_MTD_SPI_NOR=m
-CONFIG_PROC_DEVICETREE=y
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_BLOCK=y
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
@@ -86,25 +78,23 @@ CONFIG_BLK_DEV_PALMCHIP_BK3710=m
CONFIG_SCSI=m
CONFIG_BLK_DEV_SD=m
CONFIG_NETDEVICES=y
+CONFIG_NETCONSOLE=y
CONFIG_TUN=m
+CONFIG_DM9000=y
+CONFIG_TI_DAVINCI_EMAC=y
CONFIG_LXT_PHY=y
+CONFIG_SMSC_PHY=y
CONFIG_LSI_ET1011C_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_TI_DAVINCI_EMAC=y
-CONFIG_DM9000=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
CONFIG_PPP=m
+CONFIG_PPP_DEFLATE=m
CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_NETCONSOLE=y
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_ATKBD=m
CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
CONFIG_KEYBOARD_XTKBD=m
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
@@ -115,8 +105,9 @@ CONFIG_SERIO_LIBPS2=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=3
-# CONFIG_HW_RANDOM is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DAVINCI=y
@@ -124,26 +115,25 @@ CONFIG_SPI=y
CONFIG_SPI_DAVINCI=m
CONFIG_PINCTRL_SINGLE=y
CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_PCF857X=y
+CONFIG_GPIO_PCA953X=y
CONFIG_WATCHDOG=y
CONFIG_DAVINCI_WATCHDOG=m
CONFIG_MFD_DM355EVM_MSP=y
CONFIG_TPS6507X=y
-CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_TPS6507X=y
CONFIG_FB=y
-CONFIG_FB_DA8XX=y
CONFIG_FIRMWARE_EDID=y
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB_DA8XX=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
CONFIG_SOUND=m
CONFIG_SND=m
CONFIG_SND_SOC=m
-CONFIG_SND_DAVINCI_SOC=m
-CONFIG_SND_DAVINCI_SOC_EVM=m
-CONFIG_SND_DM6467_SOC_EVM=m
+CONFIG_SND_EDMA_SOC=m
+CONFIG_SND_DA850_SOC_EVM=m
+CONFIG_SND_SIMPLE_CARD=m
CONFIG_HID=m
CONFIG_HID_A4TECH=m
CONFIG_HID_APPLE=m
@@ -163,10 +153,9 @@ CONFIG_HID_SONY=m
CONFIG_HID_SUNPLUS=m
CONFIG_USB=m
CONFIG_USB_MON=m
+CONFIG_USB_STORAGE=m
CONFIG_USB_MUSB_HDRC=m
-CONFIG_USB_GADGET_MUSB_HDRC=y
CONFIG_MUSB_PIO_ONLY=y
-CONFIG_USB_STORAGE=m
CONFIG_USB_TEST=m
CONFIG_USB_GADGET=m
CONFIG_USB_GADGET_DEBUG_FILES=y
@@ -188,8 +177,11 @@ CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=m
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_OMAP=m
CONFIG_DMADEVICES=y
CONFIG_TI_EDMA=y
+CONFIG_MEMORY=y
+CONFIG_TI_AEMIF=m
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_XFS_FS=m
@@ -198,30 +190,22 @@ CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_JFFS2_FS=m
+CONFIG_UBIFS_FS=m
CONFIG_CRAMFS=y
CONFIG_MINIX_FS=m
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=m
CONFIG_NFSD_V3=y
-CONFIG_SMB_FS=m
-CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=m
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=m
CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_ARM_UNWIND is not set
CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_T10DIF=m
-CONFIG_GPIO_PCA953X=y
-CONFIG_KEYBOARD_GPIO_POLLED=y
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index 36cc7cc012f9..4e484f406419 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -17,6 +17,7 @@ CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_CMA=y
+CONFIG_SECCOMP=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
@@ -35,6 +36,8 @@ CONFIG_ARM_EXYNOS_CPUIDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_KERNEL_MODE_NEON=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_ADVANCED_DEBUG=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -219,6 +222,12 @@ CONFIG_CROS_EC_CHARDEV=y
CONFIG_COMMON_CLK_MAX77686=y
CONFIG_COMMON_CLK_MAX77802=y
CONFIG_COMMON_CLK_S2MPS11=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+CONFIG_ARM_EXYNOS_BUS_DEVFREQ=y
+CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=y
CONFIG_EXTCON=y
CONFIG_EXTCON_MAX14577=y
CONFIG_EXTCON_MAX77693=y
diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index 9083399a8ab1..5f013c9fc1ed 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -22,14 +22,13 @@ CONFIG_ARCH_MULTI_V4T=y
CONFIG_ARCH_MULTI_V5=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_MXC=y
-CONFIG_MACH_SCB9328=y
-CONFIG_MACH_APF9328=y
CONFIG_MACH_MX21ADS=y
CONFIG_MACH_MX27ADS=y
CONFIG_MACH_MX27_3DS=y
CONFIG_MACH_IMX27_VISSTRIM_M10=y
CONFIG_MACH_PCA100=y
CONFIG_MACH_IMX27_DT=y
+CONFIG_SOC_IMX1=y
CONFIG_SOC_IMX25=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 3219480b9dbf..8ec4dbbb50b0 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -1,6 +1,5 @@
CONFIG_KERNEL_LZO=y
CONFIG_SYSVIPC=y
-CONFIG_FHANDLE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
@@ -72,7 +71,6 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
CONFIG_NETFILTER=y
CONFIG_CAN=y
CONFIG_CAN_FLEXCAN=y
@@ -228,7 +226,6 @@ CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
-CONFIG_VIDEO_MX3=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_CODA=y
CONFIG_SOC_CAMERA_OV2640=y
@@ -241,6 +238,7 @@ CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
CONFIG_DRM_IMX_TVE=y
CONFIG_DRM_IMX_LDB=y
CONFIG_DRM_IMX_HDMI=y
+CONFIG_DRM_ETNAVIV=y
CONFIG_FB_MXS=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_L4F00242T03=y
@@ -264,6 +262,7 @@ CONFIG_SND_SOC_IMX_MC13783=y
CONFIG_SND_SOC_FSL_ASOC_CARD=y
CONFIG_SND_SOC_CS42XX8_I2C=y
CONFIG_SND_SOC_TLV320AIC3X=y
+CONFIG_SND_SOC_WM8960=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
@@ -276,6 +275,7 @@ CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_FTDI_SIO=m
CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_TEST=m
CONFIG_USB_EHSET_TEST_FIXTURE=m
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_MXS_PHY=y
@@ -293,7 +293,14 @@ CONFIG_USB_CONFIGFS_EEM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_LB_SS=y
CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
CONFIG_USB_ETH=m
CONFIG_USB_G_NCM=m
CONFIG_USB_GADGETFS=m
@@ -329,13 +336,12 @@ CONFIG_FSL_EDMA=y
CONFIG_IMX_SDMA=y
CONFIG_MXS_DMA=y
CONFIG_STAGING=y
-# CONFIG_IOMMU_SUPPORT is not set
CONFIG_IIO=y
CONFIG_VF610_ADC=y
+CONFIG_MPL3115=y
CONFIG_PWM=y
CONFIG_PWM_FSL_FTM=y
CONFIG_PWM_IMX=y
-CONFIG_NVMEM=y
CONFIG_NVMEM_IMX_OCOTP=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
@@ -355,7 +361,6 @@ CONFIG_ZISOFS=y
CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_UBIFS_FS=y
CONFIG_NFS_FS=y
diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig
index 71f14675d009..869faae67201 100644
--- a/arch/arm/configs/integrator_defconfig
+++ b/arch/arm/configs/integrator_defconfig
@@ -13,15 +13,8 @@ CONFIG_ARCH_MULTI_V5=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_INTEGRATOR=y
CONFIG_ARCH_INTEGRATOR_AP=y
-CONFIG_ARCH_INTEGRATOR_CP=y
CONFIG_INTEGRATOR_IMPD1=y
-CONFIG_CPU_ARM720T=y
-CONFIG_CPU_ARM920T=y
-CONFIG_CPU_ARM922T=y
-CONFIG_CPU_ARM926T=y
-CONFIG_CPU_ARM1020=y
-CONFIG_CPU_ARM1022=y
-CONFIG_CPU_ARM1026=y
+CONFIG_ARCH_INTEGRATOR_CP=y
CONFIG_PCI=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
@@ -33,7 +26,6 @@ CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_FPE_NWFPE=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -51,7 +43,7 @@ CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_PHYSMAP=y
-CONFIG_PROC_DEVICETREE=y
+CONFIG_MTD_PHYSMAP_OF=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
@@ -71,6 +63,7 @@ CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
diff --git a/arch/arm/configs/lpd270_defconfig b/arch/arm/configs/lpd270_defconfig
index 1c8c9ee71d31..a9dd1e93b556 100644
--- a/arch/arm/configs/lpd270_defconfig
+++ b/arch/arm/configs/lpd270_defconfig
@@ -31,7 +31,6 @@ CONFIG_MTD_CFI_GEOMETRY=y
# CONFIG_MTD_CFI_I1 is not set
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_BLK_DEV_NBD=y
-CONFIG_IDE=y
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=y
diff --git a/arch/arm/configs/multi_v4t_defconfig b/arch/arm/configs/multi_v4t_defconfig
index 433eebb4103f..9a6390c172d6 100644
--- a/arch/arm/configs/multi_v4t_defconfig
+++ b/arch/arm/configs/multi_v4t_defconfig
@@ -20,9 +20,7 @@ CONFIG_INTEGRATOR_CM720T=y
CONFIG_INTEGRATOR_CM920T=y
CONFIG_INTEGRATOR_CM922T_XA10=y
CONFIG_ARCH_MXC=y
-CONFIG_MACH_SCB9328=y
-CONFIG_MACH_APF9328=y
-CONFIG_MACH_IMX1_DT=y
+CONFIG_SOC_IMX1=y
CONFIG_ARCH_NSPIRE=y
CONFIG_AEABI=y
# CONFIG_ATAGS is not set
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 58459105cadc..437d0740dec6 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -126,9 +126,11 @@ CONFIG_SMP=y
CONFIG_NR_CPUS=16
CONFIG_HIGHPTE=y
CONFIG_CMA=y
+CONFIG_SECCOMP=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_KEXEC=y
+CONFIG_EFI=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
@@ -136,6 +138,7 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=m
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_ARM_IMX6Q_CPUFREQ=y
CONFIG_QORIQ_CPUFREQ=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_CPUIDLE=y
@@ -220,6 +223,7 @@ CONFIG_SATA_AHCI=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_BRCM=y
CONFIG_AHCI_ST=y
+CONFIG_AHCI_IMX=y
CONFIG_AHCI_SUNXI=y
CONFIG_AHCI_TEGRA=y
CONFIG_SATA_HIGHBANK=y
@@ -277,7 +281,7 @@ CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_MOUSE_CYAPA=m
CONFIG_MOUSE_ELAN_I2C=y
CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
CONFIG_TOUCHSCREEN_MMS114=m
CONFIG_TOUCHSCREEN_ST1232=m
CONFIG_TOUCHSCREEN_STMPE=y
@@ -499,6 +503,7 @@ CONFIG_MFD_TPS65910=y
CONFIG_REGULATOR_ACT8945A=y
CONFIG_REGULATOR_AB8500=y
CONFIG_REGULATOR_ACT8865=y
+CONFIG_REGULATOR_ANATOP=y
CONFIG_REGULATOR_AS3711=y
CONFIG_REGULATOR_AS3722=y
CONFIG_REGULATOR_AXP20X=m
@@ -593,6 +598,7 @@ CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_STI=m
CONFIG_DRM_VC4=y
CONFIG_FB_ARMCLCD=y
+CONFIG_FB_EFI=y
CONFIG_FB_WM8505=y
CONFIG_FB_SH_MOBILE_LCDC=y
CONFIG_FB_SIMPLE=y
@@ -750,6 +756,7 @@ CONFIG_RTC_DRV_S35390A=m
CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_EM3027=y
CONFIG_RTC_DRV_DA9063=m
+CONFIG_RTC_DRV_EFI=m
CONFIG_RTC_DRV_DIGICOLOR=m
CONFIG_RTC_DRV_S5M=m
CONFIG_RTC_DRV_S3C=m
@@ -867,6 +874,8 @@ CONFIG_NVMEM=y
CONFIG_NVMEM_SUNXI_SID=y
CONFIG_BCM2835_MBOX=y
CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_EFI_VARS=m
+CONFIG_EFI_CAPSULE_LOADER=m
CONFIG_EXT4_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig
index 6051c51ca188..f7f6039419aa 100644
--- a/arch/arm/configs/mvebu_v5_defconfig
+++ b/arch/arm/configs/mvebu_v5_defconfig
@@ -91,10 +91,7 @@ CONFIG_SATA_AHCI=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
CONFIG_NET_DSA_MV88E6060=y
-CONFIG_NET_DSA_MV88E6131=y
-CONFIG_NET_DSA_MV88E6123=y
-CONFIG_NET_DSA_MV88E6171=y
-CONFIG_NET_DSA_MV88E6352=y
+CONFIG_NET_DSA_MV88E6XXX=y
CONFIG_MV643XX_ETH=y
CONFIG_R8169=y
CONFIG_MARVELL_PHY=y
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index 486a4cabb0dd..f1a0e2503cbe 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -48,6 +48,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
@@ -59,6 +60,7 @@ CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_PXA3xx=y
CONFIG_MTD_SPI_NOR=y
CONFIG_SRAM=y
+CONFIG_MTD_UBI=y
CONFIG_EEPROM_AT24=y
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
@@ -140,6 +142,7 @@ CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
+CONFIG_UBIFS_FS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 487c6c3b13fd..53e1a884a1ea 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -139,7 +139,6 @@ CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
CONFIG_SENSORS_TSL2550=m
-CONFIG_BMP085_I2C=m
CONFIG_SRAM=y
CONFIG_EEPROM_AT24=m
CONFIG_SENSORS_LIS3_I2C=m
@@ -428,6 +427,7 @@ CONFIG_EXTCON_USB_GPIO=m
CONFIG_TI_EMIF=m
CONFIG_IIO=m
CONFIG_TI_AM335X_ADC=m
+CONFIG_BMP280=m
CONFIG_PWM=y
CONFIG_PWM_OMAP_DMTIMER=m
CONFIG_PWM_TIECAP=m
diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig
index 917a070b4bb9..088627ad875f 100644
--- a/arch/arm/configs/pxa255-idp_defconfig
+++ b/arch/arm/configs/pxa255-idp_defconfig
@@ -28,7 +28,6 @@ CONFIG_MTD_CFI_GEOMETRY=y
# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
# CONFIG_MTD_CFI_I1 is not set
CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_IDE=y
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=y
diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig
index dc5517eaf09f..a016ecc0084b 100644
--- a/arch/arm/configs/pxa_defconfig
+++ b/arch/arm/configs/pxa_defconfig
@@ -26,8 +26,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_LDM_PARTITION=y
CONFIG_CMDLINE_PARTITION=y
CONFIG_ARCH_PXA=y
-CONFIG_MACH_PXA27X_DT=y
-CONFIG_MACH_PXA3XX_DT=y
CONFIG_ARCH_LUBBOCK=y
CONFIG_MACH_MAINSTONE=y
CONFIG_MACH_ZYLONITE300=y
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index b3ade552a2a5..bc4bfe02e611 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -76,7 +76,6 @@ CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig
index 0ada29d568ec..492f7f3eb4ac 100644
--- a/arch/arm/configs/trizeps4_defconfig
+++ b/arch/arm/configs/trizeps4_defconfig
@@ -94,8 +94,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECS=m
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
diff --git a/arch/arm/crypto/ghash-ce-glue.c b/arch/arm/crypto/ghash-ce-glue.c
index 1568cb5cd870..7546b3c02466 100644
--- a/arch/arm/crypto/ghash-ce-glue.c
+++ b/arch/arm/crypto/ghash-ce-glue.c
@@ -138,7 +138,7 @@ static struct shash_alg ghash_alg = {
.setkey = ghash_setkey,
.descsize = sizeof(struct ghash_desc_ctx),
.base = {
- .cra_name = "ghash",
+ .cra_name = "__ghash",
.cra_driver_name = "__driver-ghash-ce",
.cra_priority = 0,
.cra_flags = CRYPTO_ALG_TYPE_SHASH | CRYPTO_ALG_INTERNAL,
@@ -220,6 +220,27 @@ static int ghash_async_digest(struct ahash_request *req)
}
}
+static int ghash_async_import(struct ahash_request *req, const void *in)
+{
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+
+ desc->tfm = cryptd_ahash_child(ctx->cryptd_tfm);
+ desc->flags = req->base.flags;
+
+ return crypto_shash_import(desc, in);
+}
+
+static int ghash_async_export(struct ahash_request *req, void *out)
+{
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+
+ return crypto_shash_export(desc, out);
+}
+
static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
{
@@ -268,7 +289,10 @@ static struct ahash_alg ghash_async_alg = {
.final = ghash_async_final,
.setkey = ghash_async_setkey,
.digest = ghash_async_digest,
+ .import = ghash_async_import,
+ .export = ghash_async_export,
.halg.digestsize = GHASH_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct ghash_desc_ctx),
.halg.base = {
.cra_name = "ghash",
.cra_driver_name = "ghash-ce",
diff --git a/arch/arm/crypto/sha1-armv7-neon.S b/arch/arm/crypto/sha1-armv7-neon.S
index dcd01f3f0bb0..2468fade49cf 100644
--- a/arch/arm/crypto/sha1-armv7-neon.S
+++ b/arch/arm/crypto/sha1-armv7-neon.S
@@ -12,7 +12,6 @@
#include <asm/assembler.h>
.syntax unified
-.code 32
.fpu neon
.text
diff --git a/arch/arm/include/asm/hardware/cache-uniphier.h b/arch/arm/include/asm/hardware/cache-uniphier.h
index 102e3fbe1e10..eaa60da7dac3 100644
--- a/arch/arm/include/asm/hardware/cache-uniphier.h
+++ b/arch/arm/include/asm/hardware/cache-uniphier.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.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
@@ -19,28 +20,11 @@
#ifdef CONFIG_CACHE_UNIPHIER
int uniphier_cache_init(void);
-int uniphier_cache_l2_is_enabled(void);
-void uniphier_cache_l2_touch_range(unsigned long start, unsigned long end);
-void uniphier_cache_l2_set_locked_ways(u32 way_mask);
#else
static inline int uniphier_cache_init(void)
{
return -ENODEV;
}
-
-static inline int uniphier_cache_l2_is_enabled(void)
-{
- return 0;
-}
-
-static inline void uniphier_cache_l2_touch_range(unsigned long start,
- unsigned long end)
-{
-}
-
-static inline void uniphier_cache_l2_set_locked_ways(u32 way_mask)
-{
-}
#endif
#endif /* __CACHE_UNIPHIER_H */
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 1bd9510de1b9..e53638c8ed8a 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -36,8 +36,9 @@ extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
#endif
#ifdef CONFIG_SMP
-extern void arch_trigger_all_cpu_backtrace(bool);
-#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
+extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask,
+ bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
#endif
static inline int nr_legacy_irqs(void)
diff --git a/arch/arm/include/debug/brcmstb.S b/arch/arm/include/debug/brcmstb.S
new file mode 100644
index 000000000000..9113d7b33ae0
--- /dev/null
+++ b/arch/arm/include/debug/brcmstb.S
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/serial_reg.h>
+
+/* Physical register offset and virtual register offset */
+#define REG_PHYS_BASE 0xf0000000
+#define REG_VIRT_BASE 0xfc000000
+#define REG_PHYS_ADDR(x) ((x) + REG_PHYS_BASE)
+
+/* Product id can be read from here */
+#define SUN_TOP_CTRL_BASE REG_PHYS_ADDR(0x404000)
+
+#define UARTA_3390 REG_PHYS_ADDR(0x40a900)
+#define UARTA_7250 REG_PHYS_ADDR(0x40b400)
+#define UARTA_7268 REG_PHYS_ADDR(0x40c000)
+#define UARTA_7271 UARTA_7268
+#define UARTA_7364 REG_PHYS_ADDR(0x40b000)
+#define UARTA_7366 UARTA_7364
+#define UARTA_74371 REG_PHYS_ADDR(0x406b00)
+#define UARTA_7439 REG_PHYS_ADDR(0x40a900)
+#define UARTA_7445 REG_PHYS_ADDR(0x40ab00)
+
+#define UART_SHIFT 2
+
+#define checkuart(rp, rv, family_id, family) \
+ /* Load family id */ \
+ ldr rp, =family_id ; \
+ /* Compare SUN_TOP_CTRL value against it */ \
+ cmp rp, rv ; \
+ /* Passed test, load address */ \
+ ldreq rp, =UARTA_##family ; \
+ /* Jump to save UART address */ \
+ beq 91f
+
+ .macro addruart, rp, rv, tmp
+ adr \rp, 99f @ actual addr of 99f
+ ldr \rv, [\rp] @ linked addr is stored there
+ sub \rv, \rv, \rp @ offset between the two
+ ldr \rp, [\rp, #4] @ linked brcmstb_uart_config
+ sub \tmp, \rp, \rv @ actual brcmstb_uart_config
+ ldr \rp, [\tmp] @ Load brcmstb_uart_config
+ cmp \rp, #1 @ needs initialization?
+ bne 100f @ no; go load the addresses
+ mov \rv, #0 @ yes; record init is done
+ str \rv, [\tmp]
+
+ /* Check SUN_TOP_CTRL base */
+ ldr \rp, =SUN_TOP_CTRL_BASE @ load SUN_TOP_CTRL PA
+ ldr \rv, [\rp, #0] @ get register contents
+ and \rv, \rv, #0xffffff00 @ strip revision bits [7:0]
+
+ /* Chip specific detection starts here */
+20: checkuart(\rp, \rv, 0x33900000, 3390)
+21: checkuart(\rp, \rv, 0x72500000, 7250)
+22: checkuart(\rp, \rv, 0x72680000, 7268)
+23: checkuart(\rp, \rv, 0x72710000, 7271)
+24: checkuart(\rp, \rv, 0x73640000, 7364)
+25: checkuart(\rp, \rv, 0x73660000, 7366)
+26: checkuart(\rp, \rv, 0x07437100, 74371)
+27: checkuart(\rp, \rv, 0x74390000, 7439)
+28: checkuart(\rp, \rv, 0x74450000, 7445)
+
+ /* No valid UART found */
+90: mov \rp, #0
+ /* fall through */
+
+ /* Record whichever UART we chose */
+91: str \rp, [\tmp, #4] @ Store in brcmstb_uart_phys
+ cmp \rp, #0 @ Valid UART address?
+ bne 92f @ Yes, go process it
+ str \rp, [\tmp, #8] @ Store 0 in brcmstb_uart_virt
+ b 100f @ Done
+92: and \rv, \rp, #0xffffff @ offset within 16MB section
+ add \rv, \rv, #REG_VIRT_BASE
+ str \rv, [\tmp, #8] @ Store in brcmstb_uart_virt
+ b 100f
+
+ .align
+99: .word .
+ .word brcmstb_uart_config
+ .ltorg
+
+ /* Load previously selected UART address */
+100: ldr \rp, [\tmp, #4] @ Load brcmstb_uart_phys
+ ldr \rv, [\tmp, #8] @ Load brcmstb_uart_virt
+ .endm
+
+ .macro store, rd, rx:vararg
+ str \rd, \rx
+ .endm
+
+ .macro load, rd, rx:vararg
+ ldr \rd, \rx
+ .endm
+
+ .macro senduart,rd,rx
+ store \rd, [\rx, #UART_TX << UART_SHIFT]
+ .endm
+
+ .macro busyuart,rd,rx
+1002: load \rd, [\rx, #UART_LSR << UART_SHIFT]
+ and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+ teq \rd, #UART_LSR_TEMT | UART_LSR_THRE
+ bne 1002b
+ .endm
+
+ .macro waituart,rd,rx
+ .endm
+
+/*
+ * Storage for the state maintained by the macros above.
+ *
+ * In the kernel proper, this data is located in arch/arm/mach-bcm/brcmstb.c.
+ * That's because this header is included from multiple files, and we only
+ * want a single copy of the data. In particular, the UART probing code above
+ * assumes it's running using physical addresses. This is true when this file
+ * is included from head.o, but not when included from debug.o. So we need
+ * to share the probe results between the two copies, rather than having
+ * to re-run the probing again later.
+ *
+ * In the decompressor, we put the symbol/storage right here, since common.c
+ * isn't included in the decompressor build. This symbol gets put in .text
+ * even though it's really data, since .data is discarded from the
+ * decompressor. Luckily, .text is writeable in the decompressor, unless
+ * CONFIG_ZBOOT_ROM. That dependency is handled in arch/arm/Kconfig.debug.
+ */
+#if defined(ZIMAGE)
+brcmstb_uart_config:
+ /* Debug UART initialization required */
+ .word 1
+ /* Debug UART physical address */
+ .word 0
+ /* Debug UART virtual address */
+ .word 0
+#endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 937c8920d741..7dd14e8395e6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -748,19 +748,10 @@ core_initcall(register_cpufreq_notifier);
static void raise_nmi(cpumask_t *mask)
{
- /*
- * Generate the backtrace directly if we are running in a calling
- * context that is not preemptible by the backtrace IPI. Note
- * that nmi_cpu_backtrace() automatically removes the current cpu
- * from mask.
- */
- if (cpumask_test_cpu(smp_processor_id(), mask) && irqs_disabled())
- nmi_cpu_backtrace(NULL);
-
smp_cross_call(mask, IPI_CPU_BACKTRACE);
}
-void arch_trigger_all_cpu_backtrace(bool include_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
{
- nmi_trigger_all_cpu_backtrace(include_self, raise_nmi);
+ nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi);
}
diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S
index cba1ec899a69..7fa487ef7e2f 100644
--- a/arch/arm/kernel/vmlinux-xip.lds.S
+++ b/arch/arm/kernel/vmlinux-xip.lds.S
@@ -98,6 +98,7 @@ SECTIONS
IRQENTRY_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.gnu.warning)
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index d24e5dd2aa7a..f7f55df0bf7b 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -111,6 +111,7 @@ SECTIONS
SOFTIRQENTRY_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
HYPERVISOR_TEXT
KPROBES_TEXT
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 5204395efda8..841e924143f9 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -55,7 +55,6 @@ config SOC_AT91RM9200
select ATMEL_ST
select CPU_ARM920T
select HAVE_AT91_USB_CLK
- select MIGHT_HAVE_PCI
select PINCTRL_AT91
select SOC_SAM_V4_V5
select SRAM if PM
diff --git a/arch/arm/mach-axxia/Kconfig b/arch/arm/mach-axxia/Kconfig
index 6c6d5e76565b..fe627cbcfdc5 100644
--- a/arch/arm/mach-axxia/Kconfig
+++ b/arch/arm/mach-axxia/Kconfig
@@ -7,8 +7,6 @@ config ARCH_AXXIA
select ARM_TIMER_SP804
select HAVE_ARM_ARCH_TIMER
select MFD_SYSCON
- select MIGHT_HAVE_PCI
- select PCI_DOMAINS if PCI
select ZONE_DMA
help
This enables support for the LSI Axxia devices.
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 7bf3ae76f782..a0e66d8200c5 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -158,6 +158,20 @@ config ARCH_BCM2835
This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
This SoC is used in the Raspberry Pi and Roku 2 devices.
+config ARCH_BCM_53573
+ bool "Broadcom BCM53573 SoC series support"
+ depends on ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
+ select HAVE_ARM_ARCH_TIMER
+ help
+ BCM53573 series is set of SoCs using ARM Cortex-A7 CPUs with wireless
+ embedded in the chipset.
+ This SoC line is mostly used in home routers and is some cheaper
+ alternative for Northstar family.
+
+ The base chip is BCM53573 and there are some packaging modifications
+ like BCM47189 and BCM47452.
+
config ARCH_BCM_63XX
bool "Broadcom BCM63xx DSL SoC"
depends on ARCH_MULTI_V7
diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c
index 99a67cfb7c0d..07e3a86c6466 100644
--- a/arch/arm/mach-bcm/brcmstb.c
+++ b/arch/arm/mach-bcm/brcmstb.c
@@ -19,6 +19,22 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+/*
+ * Storage for debug-macro.S's state.
+ *
+ * This must be in .data not .bss so that it gets initialized each time the
+ * kernel is loaded. The data is declared here rather than debug-macro.S so
+ * that multiple inclusions of debug-macro.S point at the same data.
+ */
+u32 brcmstb_uart_config[3] = {
+ /* Debug UART initialization required */
+ 1,
+ /* Debug UART physical address */
+ 0,
+ /* Debug UART virtual address */
+ 0,
+};
+
static void __init brcmstb_init_irq(void)
{
irqchip_init();
diff --git a/arch/arm/mach-clps711x/Makefile.boot b/arch/arm/mach-clps711x/Makefile.boot
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/arch/arm/mach-clps711x/Makefile.boot
+++ /dev/null
diff --git a/arch/arm/mach-clps711x/board-autcpu12.c b/arch/arm/mach-clps711x/board-autcpu12.c
deleted file mode 100644
index ba3d7d1b28f8..000000000000
--- a/arch/arm/mach-clps711x/board-autcpu12.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * linux/arch/arm/mach-clps711x/autcpu12.c
- *
- * (c) 2001 Thomas Gleixner, autronix automation <gleixner@autronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/plat-ram.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand-gpio.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/driver.h>
-
-#include <mach/hardware.h>
-#include <asm/sizes.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "devices.h"
-
-/* NOR flash */
-#define AUTCPU12_FLASH_BASE (CS0_PHYS_BASE)
-
-/* Board specific hardware definitions */
-#define AUTCPU12_CHAR_LCD_BASE (CS1_PHYS_BASE + 0x00000000)
-#define AUTCPU12_CSAUX1_BASE (CS1_PHYS_BASE + 0x04000000)
-#define AUTCPU12_CAN_BASE (CS1_PHYS_BASE + 0x08000000)
-#define AUTCPU12_TOUCH_BASE (CS1_PHYS_BASE + 0x0a000000)
-#define AUTCPU12_IO_BASE (CS1_PHYS_BASE + 0x0c000000)
-#define AUTCPU12_LPT_BASE (CS1_PHYS_BASE + 0x0e000000)
-
-/* NVRAM */
-#define AUTCPU12_NVRAM_BASE (CS1_PHYS_BASE + 0x02000000)
-
-/* SmartMedia flash */
-#define AUTCPU12_SMC_BASE (CS1_PHYS_BASE + 0x06000000)
-#define AUTCPU12_SMC_SEL_BASE (AUTCPU12_SMC_BASE + 0x10)
-
-/* Ethernet */
-#define AUTCPU12_CS8900_BASE (CS2_PHYS_BASE + 0x300)
-#define AUTCPU12_CS8900_IRQ (IRQ_EINT3)
-
-/* NAND flash */
-#define AUTCPU12_MMGPIO_BASE (CLPS711X_NR_GPIO)
-#define AUTCPU12_SMC_NCE (AUTCPU12_MMGPIO_BASE + 0) /* Bit 0 */
-#define AUTCPU12_SMC_RDY CLPS711X_GPIO(1, 2)
-#define AUTCPU12_SMC_ALE CLPS711X_GPIO(1, 3)
-#define AUTCPU12_SMC_CLE CLPS711X_GPIO(1, 4)
-
-/* LCD contrast digital potentiometer */
-#define AUTCPU12_DPOT_CS CLPS711X_GPIO(4, 0)
-#define AUTCPU12_DPOT_CLK CLPS711X_GPIO(4, 1)
-#define AUTCPU12_DPOT_UD CLPS711X_GPIO(4, 2)
-
-static struct resource autcpu12_cs8900_resource[] __initdata = {
- DEFINE_RES_MEM(AUTCPU12_CS8900_BASE, SZ_1K),
- DEFINE_RES_IRQ(AUTCPU12_CS8900_IRQ),
-};
-
-static struct resource autcpu12_nand_resource[] __initdata = {
- DEFINE_RES_MEM(AUTCPU12_SMC_BASE, SZ_16),
-};
-
-static struct mtd_partition autcpu12_nand_parts[] __initdata = {
- {
- .name = "Flash partition 1",
- .offset = 0,
- .size = SZ_8M,
- },
- {
- .name = "Flash partition 2",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static void __init autcpu12_adjust_parts(struct gpio_nand_platdata *pdata,
- size_t sz)
-{
- switch (sz) {
- case SZ_16M:
- case SZ_32M:
- break;
- case SZ_64M:
- case SZ_128M:
- pdata->parts[0].size = SZ_16M;
- break;
- default:
- pr_warn("Unsupported SmartMedia device size %u\n", sz);
- break;
- }
-}
-
-static struct gpio_nand_platdata autcpu12_nand_pdata __initdata = {
- .gpio_rdy = AUTCPU12_SMC_RDY,
- .gpio_nce = AUTCPU12_SMC_NCE,
- .gpio_ale = AUTCPU12_SMC_ALE,
- .gpio_cle = AUTCPU12_SMC_CLE,
- .gpio_nwp = -1,
- .chip_delay = 20,
- .parts = autcpu12_nand_parts,
- .num_parts = ARRAY_SIZE(autcpu12_nand_parts),
- .adjust_parts = autcpu12_adjust_parts,
-};
-
-static struct platform_device autcpu12_nand_pdev __initdata = {
- .name = "gpio-nand",
- .id = -1,
- .resource = autcpu12_nand_resource,
- .num_resources = ARRAY_SIZE(autcpu12_nand_resource),
- .dev = {
- .platform_data = &autcpu12_nand_pdata,
- },
-};
-
-static struct resource autcpu12_mmgpio_resource[] __initdata = {
- DEFINE_RES_MEM_NAMED(AUTCPU12_SMC_SEL_BASE, SZ_1, "dat"),
-};
-
-static struct bgpio_pdata autcpu12_mmgpio_pdata __initdata = {
- .base = AUTCPU12_MMGPIO_BASE,
- .ngpio = 8,
-};
-
-static struct platform_device autcpu12_mmgpio_pdev __initdata = {
- .name = "basic-mmio-gpio",
- .id = -1,
- .resource = autcpu12_mmgpio_resource,
- .num_resources = ARRAY_SIZE(autcpu12_mmgpio_resource),
- .dev = {
- .platform_data = &autcpu12_mmgpio_pdata,
- },
-};
-
-static const struct gpio const autcpu12_gpios[] __initconst = {
- { AUTCPU12_DPOT_CS, GPIOF_OUT_INIT_HIGH, "DPOT CS" },
- { AUTCPU12_DPOT_CLK, GPIOF_OUT_INIT_LOW, "DPOT CLK" },
- { AUTCPU12_DPOT_UD, GPIOF_OUT_INIT_LOW, "DPOT UD" },
-};
-
-static struct mtd_partition autcpu12_flash_partitions[] = {
- {
- .name = "NOR.0",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct physmap_flash_data autcpu12_flash_pdata = {
- .width = 4,
- .parts = autcpu12_flash_partitions,
- .nr_parts = ARRAY_SIZE(autcpu12_flash_partitions),
-};
-
-static struct resource autcpu12_flash_resources[] __initdata = {
- DEFINE_RES_MEM(AUTCPU12_FLASH_BASE, SZ_8M),
-};
-
-static struct platform_device autcpu12_flash_pdev __initdata = {
- .name = "physmap-flash",
- .id = 0,
- .resource = autcpu12_flash_resources,
- .num_resources = ARRAY_SIZE(autcpu12_flash_resources),
- .dev = {
- .platform_data = &autcpu12_flash_pdata,
- },
-};
-
-static struct resource autcpu12_nvram_resource[] __initdata = {
- DEFINE_RES_MEM(AUTCPU12_NVRAM_BASE, 0),
-};
-
-static struct platdata_mtd_ram autcpu12_nvram_pdata = {
- .bankwidth = 4,
-};
-
-static struct platform_device autcpu12_nvram_pdev __initdata = {
- .name = "mtd-ram",
- .id = 0,
- .resource = autcpu12_nvram_resource,
- .num_resources = ARRAY_SIZE(autcpu12_nvram_resource),
- .dev = {
- .platform_data = &autcpu12_nvram_pdata,
- },
-};
-
-static void __init autcpu12_nvram_init(void)
-{
- void __iomem *nvram;
- unsigned int save[2];
- resource_size_t nvram_size = SZ_128K;
-
- /*
- * Check for 32K/128K
- * Read ofs 0K
- * Read ofs 64K
- * Write complement to ofs 64K
- * Read and check result on ofs 0K
- * Restore contents
- */
- nvram = ioremap(autcpu12_nvram_resource[0].start, SZ_128K);
- if (nvram) {
- save[0] = readl(nvram + 0);
- save[1] = readl(nvram + SZ_64K);
- writel(~save[0], nvram + SZ_64K);
- if (readl(nvram + 0) != save[0]) {
- writel(save[0], nvram + 0);
- nvram_size = SZ_32K;
- } else
- writel(save[1], nvram + SZ_64K);
- iounmap(nvram);
-
- autcpu12_nvram_resource[0].end =
- autcpu12_nvram_resource[0].start + nvram_size - 1;
- platform_device_register(&autcpu12_nvram_pdev);
- } else
- pr_err("Failed to remap NVRAM resource\n");
-}
-
-static void __init autcpu12_init(void)
-{
- clps711x_devices_init();
- platform_device_register(&autcpu12_flash_pdev);
- platform_device_register_simple("video-clps711x", 0, NULL, 0);
- platform_device_register_simple("cs89x0", 0, autcpu12_cs8900_resource,
- ARRAY_SIZE(autcpu12_cs8900_resource));
- platform_device_register(&autcpu12_mmgpio_pdev);
- autcpu12_nvram_init();
-}
-
-static void __init autcpu12_init_late(void)
-{
- gpio_request_array(autcpu12_gpios, ARRAY_SIZE(autcpu12_gpios));
- platform_device_register(&autcpu12_nand_pdev);
-}
-
-MACHINE_START(AUTCPU12, "autronix autcpu12")
- /* Maintainer: Thomas Gleixner */
- .atag_offset = 0x20000,
- .map_io = clps711x_map_io,
- .init_irq = clps711x_init_irq,
- .init_time = clps711x_timer_init,
- .init_machine = autcpu12_init,
- .init_late = autcpu12_init_late,
- .restart = clps711x_restart,
-MACHINE_END
-
diff --git a/arch/arm/mach-clps711x/board-cdb89712.c b/arch/arm/mach-clps711x/board-cdb89712.c
deleted file mode 100644
index 972abdb10028..000000000000
--- a/arch/arm/mach-clps711x/board-cdb89712.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * linux/arch/arm/mach-clps711x/cdb89712.c
- *
- * Copyright (C) 2000-2001 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/plat-ram.h>
-#include <linux/mtd/partitions.h>
-
-#include <mach/hardware.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "devices.h"
-
-#define CDB89712_CS8900_BASE (CS2_PHYS_BASE + 0x300)
-#define CDB89712_CS8900_IRQ (IRQ_EINT3)
-
-static struct resource cdb89712_cs8900_resource[] __initdata = {
- DEFINE_RES_MEM(CDB89712_CS8900_BASE, SZ_1K),
- DEFINE_RES_IRQ(CDB89712_CS8900_IRQ),
-};
-
-static struct mtd_partition cdb89712_flash_partitions[] __initdata = {
- {
- .name = "Flash",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct physmap_flash_data cdb89712_flash_pdata __initdata = {
- .width = 4,
- .probe_type = "map_rom",
- .parts = cdb89712_flash_partitions,
- .nr_parts = ARRAY_SIZE(cdb89712_flash_partitions),
-};
-
-static struct resource cdb89712_flash_resources[] __initdata = {
- DEFINE_RES_MEM(CS0_PHYS_BASE, SZ_8M),
-};
-
-static struct platform_device cdb89712_flash_pdev __initdata = {
- .name = "physmap-flash",
- .id = 0,
- .resource = cdb89712_flash_resources,
- .num_resources = ARRAY_SIZE(cdb89712_flash_resources),
- .dev = {
- .platform_data = &cdb89712_flash_pdata,
- },
-};
-
-static struct mtd_partition cdb89712_bootrom_partitions[] __initdata = {
- {
- .name = "BootROM",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct physmap_flash_data cdb89712_bootrom_pdata __initdata = {
- .width = 4,
- .probe_type = "map_rom",
- .parts = cdb89712_bootrom_partitions,
- .nr_parts = ARRAY_SIZE(cdb89712_bootrom_partitions),
-};
-
-static struct resource cdb89712_bootrom_resources[] __initdata = {
- DEFINE_RES_NAMED(CS7_PHYS_BASE, SZ_128, "BOOTROM", IORESOURCE_MEM |
- IORESOURCE_READONLY),
-};
-
-static struct platform_device cdb89712_bootrom_pdev __initdata = {
- .name = "physmap-flash",
- .id = 1,
- .resource = cdb89712_bootrom_resources,
- .num_resources = ARRAY_SIZE(cdb89712_bootrom_resources),
- .dev = {
- .platform_data = &cdb89712_bootrom_pdata,
- },
-};
-
-static struct platdata_mtd_ram cdb89712_sram_pdata __initdata = {
- .bankwidth = 4,
-};
-
-static struct resource cdb89712_sram_resources[] __initdata = {
- DEFINE_RES_MEM(CLPS711X_SRAM_BASE, CLPS711X_SRAM_SIZE),
-};
-
-static struct platform_device cdb89712_sram_pdev __initdata = {
- .name = "mtd-ram",
- .id = 0,
- .resource = cdb89712_sram_resources,
- .num_resources = ARRAY_SIZE(cdb89712_sram_resources),
- .dev = {
- .platform_data = &cdb89712_sram_pdata,
- },
-};
-
-static void __init cdb89712_init(void)
-{
- clps711x_devices_init();
- platform_device_register(&cdb89712_flash_pdev);
- platform_device_register(&cdb89712_bootrom_pdev);
- platform_device_register(&cdb89712_sram_pdev);
- platform_device_register_simple("cs89x0", 0, cdb89712_cs8900_resource,
- ARRAY_SIZE(cdb89712_cs8900_resource));
-}
-
-MACHINE_START(CDB89712, "Cirrus-CDB89712")
- /* Maintainer: Ray Lehtiniemi */
- .atag_offset = 0x100,
- .map_io = clps711x_map_io,
- .init_irq = clps711x_init_irq,
- .init_time = clps711x_timer_init,
- .init_machine = cdb89712_init,
- .restart = clps711x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-clps711x/board-clep7312.c b/arch/arm/mach-clps711x/board-clep7312.c
deleted file mode 100644
index f9ca22b646bf..000000000000
--- a/arch/arm/mach-clps711x/board-clep7312.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/arch/arm/mach-clps711x/clep7312.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/memblock.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include "common.h"
-#include "devices.h"
-
-static void __init
-fixup_clep7312(struct tag *tags, char **cmdline)
-{
- memblock_add(0xc0000000, 0x01000000);
-}
-
-MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
- /* Maintainer: Nobody */
- .atag_offset = 0x0100,
- .fixup = fixup_clep7312,
- .map_io = clps711x_map_io,
- .init_irq = clps711x_init_irq,
- .init_time = clps711x_timer_init,
- .init_machine = clps711x_devices_init,
- .restart = clps711x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-clps711x/board-edb7211.c b/arch/arm/mach-clps711x/board-edb7211.c
deleted file mode 100644
index f33979784f38..000000000000
--- a/arch/arm/mach-clps711x/board-edb7211.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Blue Mug, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/memblock.h>
-#include <linux/types.h>
-#include <linux/i2c-gpio.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/pwm.h>
-#include <linux/pwm_backlight.h>
-#include <linux/memblock.h>
-
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/setup.h>
-#include <asm/mach/map.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-
-#include <video/platform_lcd.h>
-
-#include <mach/hardware.h>
-
-#include "common.h"
-#include "devices.h"
-
-#define VIDEORAM_SIZE SZ_128K
-
-#define EDB7211_LCD_DC_DC_EN CLPS711X_GPIO(3, 1)
-#define EDB7211_LCDEN CLPS711X_GPIO(3, 2)
-#define EDB7211_LCDBL CLPS711X_GPIO(3, 3)
-
-#define EDB7211_I2C_SDA CLPS711X_GPIO(3, 4)
-#define EDB7211_I2C_SCL CLPS711X_GPIO(3, 5)
-
-#define EDB7211_FLASH0_BASE (CS0_PHYS_BASE)
-#define EDB7211_FLASH1_BASE (CS1_PHYS_BASE)
-
-#define EDB7211_CS8900_BASE (CS2_PHYS_BASE + 0x300)
-#define EDB7211_CS8900_IRQ (IRQ_EINT3)
-
-/* The extra 8 lines of the keyboard matrix */
-#define EDB7211_EXTKBD_BASE (CS3_PHYS_BASE)
-
-static struct i2c_gpio_platform_data edb7211_i2c_pdata __initdata = {
- .sda_pin = EDB7211_I2C_SDA,
- .scl_pin = EDB7211_I2C_SCL,
- .scl_is_output_only = 1,
-};
-
-static struct resource edb7211_cs8900_resource[] __initdata = {
- DEFINE_RES_MEM(EDB7211_CS8900_BASE, SZ_1K),
- DEFINE_RES_IRQ(EDB7211_CS8900_IRQ),
-};
-
-static struct mtd_partition edb7211_flash_partitions[] __initdata = {
- {
- .name = "Flash",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct physmap_flash_data edb7211_flash_pdata __initdata = {
- .width = 4,
- .parts = edb7211_flash_partitions,
- .nr_parts = ARRAY_SIZE(edb7211_flash_partitions),
-};
-
-static struct resource edb7211_flash_resources[] __initdata = {
- DEFINE_RES_MEM(EDB7211_FLASH0_BASE, SZ_8M),
- DEFINE_RES_MEM(EDB7211_FLASH1_BASE, SZ_8M),
-};
-
-static struct platform_device edb7211_flash_pdev __initdata = {
- .name = "physmap-flash",
- .id = 0,
- .resource = edb7211_flash_resources,
- .num_resources = ARRAY_SIZE(edb7211_flash_resources),
- .dev = {
- .platform_data = &edb7211_flash_pdata,
- },
-};
-
-static void edb7211_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
-{
- if (power) {
- gpio_set_value(EDB7211_LCDEN, 1);
- udelay(100);
- gpio_set_value(EDB7211_LCD_DC_DC_EN, 1);
- } else {
- gpio_set_value(EDB7211_LCD_DC_DC_EN, 0);
- udelay(100);
- gpio_set_value(EDB7211_LCDEN, 0);
- }
-}
-
-static struct plat_lcd_data edb7211_lcd_power_pdata = {
- .set_power = edb7211_lcd_power_set,
-};
-
-static struct pwm_lookup edb7211_pwm_lookup[] = {
- PWM_LOOKUP("clps711x-pwm", 0, "pwm-backlight.0", NULL,
- 0, PWM_POLARITY_NORMAL),
-};
-
-static struct platform_pwm_backlight_data pwm_bl_pdata = {
- .dft_brightness = 0x01,
- .max_brightness = 0x0f,
- .enable_gpio = EDB7211_LCDBL,
-};
-
-static struct resource clps711x_pwm_res =
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + PMPCON, SZ_4);
-
-static struct gpio edb7211_gpios[] __initconst = {
- { EDB7211_LCD_DC_DC_EN, GPIOF_OUT_INIT_LOW, "LCD DC-DC" },
- { EDB7211_LCDEN, GPIOF_OUT_INIT_LOW, "LCD POWER" },
-};
-
-/* Reserve screen memory region at the start of main system memory. */
-static void __init edb7211_reserve(void)
-{
- memblock_reserve(PHYS_OFFSET, VIDEORAM_SIZE);
-}
-
-static void __init
-fixup_edb7211(struct tag *tags, char **cmdline)
-{
- /*
- * Bank start addresses are not present in the information
- * passed in from the boot loader. We could potentially
- * detect them, but instead we hard-code them.
- *
- * Banks sizes _are_ present in the param block, but we're
- * not using that information yet.
- */
- memblock_add(0xc0000000, SZ_8M);
- memblock_add(0xc1000000, SZ_8M);
-}
-
-static void __init edb7211_init_late(void)
-{
- gpio_request_array(edb7211_gpios, ARRAY_SIZE(edb7211_gpios));
-
- platform_device_register(&edb7211_flash_pdev);
-
- platform_device_register_data(NULL, "platform-lcd", 0,
- &edb7211_lcd_power_pdata,
- sizeof(edb7211_lcd_power_pdata));
-
- platform_device_register_simple("clps711x-pwm", PLATFORM_DEVID_NONE,
- &clps711x_pwm_res, 1);
- pwm_add_table(edb7211_pwm_lookup, ARRAY_SIZE(edb7211_pwm_lookup));
-
- platform_device_register_data(&platform_bus, "pwm-backlight", 0,
- &pwm_bl_pdata, sizeof(pwm_bl_pdata));
-
- platform_device_register_simple("video-clps711x", 0, NULL, 0);
- platform_device_register_simple("cs89x0", 0, edb7211_cs8900_resource,
- ARRAY_SIZE(edb7211_cs8900_resource));
- platform_device_register_data(NULL, "i2c-gpio", 0,
- &edb7211_i2c_pdata,
- sizeof(edb7211_i2c_pdata));
-}
-
-MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
- /* Maintainer: Jon McClintock */
- .atag_offset = VIDEORAM_SIZE + 0x100,
- .fixup = fixup_edb7211,
- .reserve = edb7211_reserve,
- .map_io = clps711x_map_io,
- .init_irq = clps711x_init_irq,
- .init_time = clps711x_timer_init,
- .init_machine = clps711x_devices_init,
- .init_late = edb7211_init_late,
- .restart = clps711x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-clps711x/board-p720t.c b/arch/arm/mach-clps711x/board-p720t.c
deleted file mode 100644
index 80a16a8b3776..000000000000
--- a/arch/arm/mach-clps711x/board-p720t.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * linux/arch/arm/mach-clps711x/p720t.c
- *
- * Copyright (C) 2000-2001 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-#include <linux/sizes.h>
-#include <linux/backlight.h>
-#include <linux/gpio/driver.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand-gpio.h>
-
-#include <mach/hardware.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <video/platform_lcd.h>
-
-#include "common.h"
-#include "devices.h"
-
-#define P720T_USERLED CLPS711X_GPIO(3, 0)
-#define P720T_NAND_CLE CLPS711X_GPIO(4, 0)
-#define P720T_NAND_ALE CLPS711X_GPIO(4, 1)
-#define P720T_NAND_NCE CLPS711X_GPIO(4, 2)
-
-#define P720T_NAND_BASE (CLPS711X_SDRAM1_BASE)
-
-#define P720T_MMGPIO_BASE (CLPS711X_NR_GPIO)
-
-#define SYSPLD_PHYS_BASE IOMEM(CS1_PHYS_BASE)
-
-#define PLD_INT (SYSPLD_PHYS_BASE + 0x000000)
-#define PLD_INT_MMGPIO_BASE (P720T_MMGPIO_BASE + 0)
-#define PLD_INT_PENIRQ (PLD_INT_MMGPIO_BASE + 5)
-#define PLD_INT_UCB_IRQ (PLD_INT_MMGPIO_BASE + 1)
-#define PLD_INT_KBD_ATN (PLD_INT_MMGPIO_BASE + 0) /* EINT1 */
-
-#define PLD_PWR (SYSPLD_PHYS_BASE + 0x000004)
-#define PLD_PWR_MMGPIO_BASE (P720T_MMGPIO_BASE + 8)
-#define PLD_PWR_EXT (PLD_PWR_MMGPIO_BASE + 5)
-#define PLD_PWR_MODE (PLD_PWR_MMGPIO_BASE + 4) /* 1 = PWM, 0 = PFM */
-#define PLD_S4_ON (PLD_PWR_MMGPIO_BASE + 3) /* LCD bias voltage enable */
-#define PLD_S3_ON (PLD_PWR_MMGPIO_BASE + 2) /* LCD backlight enable */
-#define PLD_S2_ON (PLD_PWR_MMGPIO_BASE + 1) /* LCD 3V3 supply enable */
-#define PLD_S1_ON (PLD_PWR_MMGPIO_BASE + 0) /* LCD 3V supply enable */
-
-#define PLD_KBD (SYSPLD_PHYS_BASE + 0x000008)
-#define PLD_KBD_MMGPIO_BASE (P720T_MMGPIO_BASE + 16)
-#define PLD_KBD_WAKE (PLD_KBD_MMGPIO_BASE + 1)
-#define PLD_KBD_EN (PLD_KBD_MMGPIO_BASE + 0)
-
-#define PLD_SPI (SYSPLD_PHYS_BASE + 0x00000c)
-#define PLD_SPI_MMGPIO_BASE (P720T_MMGPIO_BASE + 24)
-#define PLD_SPI_EN (PLD_SPI_MMGPIO_BASE + 0)
-
-#define PLD_IO (SYSPLD_PHYS_BASE + 0x000010)
-#define PLD_IO_MMGPIO_BASE (P720T_MMGPIO_BASE + 32)
-#define PLD_IO_BOOTSEL (PLD_IO_MMGPIO_BASE + 6) /* Boot sel switch */
-#define PLD_IO_USER (PLD_IO_MMGPIO_BASE + 5) /* User defined switch */
-#define PLD_IO_LED3 (PLD_IO_MMGPIO_BASE + 4)
-#define PLD_IO_LED2 (PLD_IO_MMGPIO_BASE + 3)
-#define PLD_IO_LED1 (PLD_IO_MMGPIO_BASE + 2)
-#define PLD_IO_LED0 (PLD_IO_MMGPIO_BASE + 1)
-#define PLD_IO_LEDEN (PLD_IO_MMGPIO_BASE + 0)
-
-#define PLD_IRDA (SYSPLD_PHYS_BASE + 0x000014)
-#define PLD_IRDA_MMGPIO_BASE (P720T_MMGPIO_BASE + 40)
-#define PLD_IRDA_EN (PLD_IRDA_MMGPIO_BASE + 0)
-
-#define PLD_COM2 (SYSPLD_PHYS_BASE + 0x000018)
-#define PLD_COM2_MMGPIO_BASE (P720T_MMGPIO_BASE + 48)
-#define PLD_COM2_EN (PLD_COM2_MMGPIO_BASE + 0)
-
-#define PLD_COM1 (SYSPLD_PHYS_BASE + 0x00001c)
-#define PLD_COM1_MMGPIO_BASE (P720T_MMGPIO_BASE + 56)
-#define PLD_COM1_EN (PLD_COM1_MMGPIO_BASE + 0)
-
-#define PLD_AUD (SYSPLD_PHYS_BASE + 0x000020)
-#define PLD_AUD_MMGPIO_BASE (P720T_MMGPIO_BASE + 64)
-#define PLD_AUD_DIV1 (PLD_AUD_MMGPIO_BASE + 6)
-#define PLD_AUD_DIV0 (PLD_AUD_MMGPIO_BASE + 5)
-#define PLD_AUD_CLK_SEL1 (PLD_AUD_MMGPIO_BASE + 4)
-#define PLD_AUD_CLK_SEL0 (PLD_AUD_MMGPIO_BASE + 3)
-#define PLD_AUD_MIC_PWR (PLD_AUD_MMGPIO_BASE + 2)
-#define PLD_AUD_MIC_GAIN (PLD_AUD_MMGPIO_BASE + 1)
-#define PLD_AUD_CODEC_EN (PLD_AUD_MMGPIO_BASE + 0)
-
-#define PLD_CF (SYSPLD_PHYS_BASE + 0x000024)
-#define PLD_CF_MMGPIO_BASE (P720T_MMGPIO_BASE + 72)
-#define PLD_CF2_SLEEP (PLD_CF_MMGPIO_BASE + 5)
-#define PLD_CF1_SLEEP (PLD_CF_MMGPIO_BASE + 4)
-#define PLD_CF2_nPDREQ (PLD_CF_MMGPIO_BASE + 3)
-#define PLD_CF1_nPDREQ (PLD_CF_MMGPIO_BASE + 2)
-#define PLD_CF2_nIRQ (PLD_CF_MMGPIO_BASE + 1)
-#define PLD_CF1_nIRQ (PLD_CF_MMGPIO_BASE + 0)
-
-#define PLD_SDC (SYSPLD_PHYS_BASE + 0x000028)
-#define PLD_SDC_MMGPIO_BASE (P720T_MMGPIO_BASE + 80)
-#define PLD_SDC_INT_EN (PLD_SDC_MMGPIO_BASE + 2)
-#define PLD_SDC_WP (PLD_SDC_MMGPIO_BASE + 1)
-#define PLD_SDC_CD (PLD_SDC_MMGPIO_BASE + 0)
-
-#define PLD_CODEC (SYSPLD_PHYS_BASE + 0x400000)
-#define PLD_CODEC_MMGPIO_BASE (P720T_MMGPIO_BASE + 88)
-#define PLD_CODEC_IRQ3 (PLD_CODEC_MMGPIO_BASE + 4)
-#define PLD_CODEC_IRQ2 (PLD_CODEC_MMGPIO_BASE + 3)
-#define PLD_CODEC_IRQ1 (PLD_CODEC_MMGPIO_BASE + 2)
-#define PLD_CODEC_EN (PLD_CODEC_MMGPIO_BASE + 0)
-
-#define PLD_BRITE (SYSPLD_PHYS_BASE + 0x400004)
-#define PLD_BRITE_MMGPIO_BASE (P720T_MMGPIO_BASE + 96)
-#define PLD_BRITE_UP (PLD_BRITE_MMGPIO_BASE + 1)
-#define PLD_BRITE_DN (PLD_BRITE_MMGPIO_BASE + 0)
-
-#define PLD_LCDEN (SYSPLD_PHYS_BASE + 0x400008)
-#define PLD_LCDEN_MMGPIO_BASE (P720T_MMGPIO_BASE + 104)
-#define PLD_LCDEN_EN (PLD_LCDEN_MMGPIO_BASE + 0)
-
-#define PLD_TCH (SYSPLD_PHYS_BASE + 0x400010)
-#define PLD_TCH_MMGPIO_BASE (P720T_MMGPIO_BASE + 112)
-#define PLD_TCH_PENIRQ (PLD_TCH_MMGPIO_BASE + 1)
-#define PLD_TCH_EN (PLD_TCH_MMGPIO_BASE + 0)
-
-#define PLD_GPIO (SYSPLD_PHYS_BASE + 0x400014)
-#define PLD_GPIO_MMGPIO_BASE (P720T_MMGPIO_BASE + 120)
-#define PLD_GPIO2 (PLD_GPIO_MMGPIO_BASE + 2)
-#define PLD_GPIO1 (PLD_GPIO_MMGPIO_BASE + 1)
-#define PLD_GPIO0 (PLD_GPIO_MMGPIO_BASE + 0)
-
-static struct gpio p720t_gpios[] __initconst = {
- { PLD_S1_ON, GPIOF_OUT_INIT_LOW, "PLD_S1_ON" },
- { PLD_S2_ON, GPIOF_OUT_INIT_LOW, "PLD_S2_ON" },
- { PLD_S3_ON, GPIOF_OUT_INIT_LOW, "PLD_S3_ON" },
- { PLD_S4_ON, GPIOF_OUT_INIT_LOW, "PLD_S4_ON" },
- { PLD_KBD_EN, GPIOF_OUT_INIT_LOW, "PLD_KBD_EN" },
- { PLD_SPI_EN, GPIOF_OUT_INIT_LOW, "PLD_SPI_EN" },
- { PLD_IO_USER, GPIOF_OUT_INIT_LOW, "PLD_IO_USER" },
- { PLD_IO_LED0, GPIOF_OUT_INIT_LOW, "PLD_IO_LED0" },
- { PLD_IO_LED1, GPIOF_OUT_INIT_LOW, "PLD_IO_LED1" },
- { PLD_IO_LED2, GPIOF_OUT_INIT_LOW, "PLD_IO_LED2" },
- { PLD_IO_LED3, GPIOF_OUT_INIT_LOW, "PLD_IO_LED3" },
- { PLD_IO_LEDEN, GPIOF_OUT_INIT_LOW, "PLD_IO_LEDEN" },
- { PLD_IRDA_EN, GPIOF_OUT_INIT_LOW, "PLD_IRDA_EN" },
- { PLD_COM1_EN, GPIOF_OUT_INIT_HIGH, "PLD_COM1_EN" },
- { PLD_COM2_EN, GPIOF_OUT_INIT_HIGH, "PLD_COM2_EN" },
- { PLD_CODEC_EN, GPIOF_OUT_INIT_LOW, "PLD_CODEC_EN" },
- { PLD_LCDEN_EN, GPIOF_OUT_INIT_LOW, "PLD_LCDEN_EN" },
- { PLD_TCH_EN, GPIOF_OUT_INIT_LOW, "PLD_TCH_EN" },
- { P720T_USERLED,GPIOF_OUT_INIT_LOW, "USER_LED" },
-};
-
-static struct resource p720t_mmgpio_resource[] __initdata = {
- DEFINE_RES_MEM_NAMED(0, 4, "dat"),
-};
-
-static struct bgpio_pdata p720t_mmgpio_pdata = {
- .ngpio = 8,
-};
-
-static struct platform_device p720t_mmgpio __initdata = {
- .name = "basic-mmio-gpio",
- .id = -1,
- .resource = p720t_mmgpio_resource,
- .num_resources = ARRAY_SIZE(p720t_mmgpio_resource),
- .dev = {
- .platform_data = &p720t_mmgpio_pdata,
- },
-};
-
-static void __init p720t_mmgpio_init(void __iomem *addrbase, int gpiobase)
-{
- p720t_mmgpio_resource[0].start = (unsigned long)addrbase;
- p720t_mmgpio_pdata.base = gpiobase;
-
- platform_device_register(&p720t_mmgpio);
-}
-
-static struct {
- void __iomem *addrbase;
- int gpiobase;
-} mmgpios[] __initconst = {
- { PLD_INT, PLD_INT_MMGPIO_BASE },
- { PLD_PWR, PLD_PWR_MMGPIO_BASE },
- { PLD_KBD, PLD_KBD_MMGPIO_BASE },
- { PLD_SPI, PLD_SPI_MMGPIO_BASE },
- { PLD_IO, PLD_IO_MMGPIO_BASE },
- { PLD_IRDA, PLD_IRDA_MMGPIO_BASE },
- { PLD_COM2, PLD_COM2_MMGPIO_BASE },
- { PLD_COM1, PLD_COM1_MMGPIO_BASE },
- { PLD_AUD, PLD_AUD_MMGPIO_BASE },
- { PLD_CF, PLD_CF_MMGPIO_BASE },
- { PLD_SDC, PLD_SDC_MMGPIO_BASE },
- { PLD_CODEC, PLD_CODEC_MMGPIO_BASE },
- { PLD_BRITE, PLD_BRITE_MMGPIO_BASE },
- { PLD_LCDEN, PLD_LCDEN_MMGPIO_BASE },
- { PLD_TCH, PLD_TCH_MMGPIO_BASE },
- { PLD_GPIO, PLD_GPIO_MMGPIO_BASE },
-};
-
-static struct resource p720t_nand_resource[] __initdata = {
- DEFINE_RES_MEM(P720T_NAND_BASE, SZ_4),
-};
-
-static struct mtd_partition p720t_nand_parts[] __initdata = {
- {
- .name = "Flash partition 1",
- .offset = 0,
- .size = SZ_2M,
- },
- {
- .name = "Flash partition 2",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct gpio_nand_platdata p720t_nand_pdata __initdata = {
- .gpio_rdy = -1,
- .gpio_nce = P720T_NAND_NCE,
- .gpio_ale = P720T_NAND_ALE,
- .gpio_cle = P720T_NAND_CLE,
- .gpio_nwp = -1,
- .chip_delay = 15,
- .parts = p720t_nand_parts,
- .num_parts = ARRAY_SIZE(p720t_nand_parts),
-};
-
-static struct platform_device p720t_nand_pdev __initdata = {
- .name = "gpio-nand",
- .id = -1,
- .resource = p720t_nand_resource,
- .num_resources = ARRAY_SIZE(p720t_nand_resource),
- .dev = {
- .platform_data = &p720t_nand_pdata,
- },
-};
-
-static void p720t_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
-{
- if (power) {
- gpio_set_value(PLD_LCDEN_EN, 1);
- gpio_set_value(PLD_S1_ON, 1);
- gpio_set_value(PLD_S2_ON, 1);
- gpio_set_value(PLD_S4_ON, 1);
- } else {
- gpio_set_value(PLD_S1_ON, 0);
- gpio_set_value(PLD_S2_ON, 0);
- gpio_set_value(PLD_S4_ON, 0);
- gpio_set_value(PLD_LCDEN_EN, 0);
- }
-}
-
-static struct plat_lcd_data p720t_lcd_power_pdata = {
- .set_power = p720t_lcd_power_set,
-};
-
-static void p720t_lcd_backlight_set_intensity(int intensity)
-{
- gpio_set_value(PLD_S3_ON, intensity);
-}
-
-static struct generic_bl_info p720t_lcd_backlight_pdata = {
- .name = "lcd-backlight.0",
- .default_intensity = 0x01,
- .max_intensity = 0x01,
- .set_bl_intensity = p720t_lcd_backlight_set_intensity,
-};
-
-static void __init
-fixup_p720t(struct tag *tag, char **cmdline)
-{
- /*
- * Our bootloader doesn't setup any tags (yet).
- */
- if (tag->hdr.tag != ATAG_CORE) {
- tag->hdr.tag = ATAG_CORE;
- tag->hdr.size = tag_size(tag_core);
- tag->u.core.flags = 0;
- tag->u.core.pagesize = PAGE_SIZE;
- tag->u.core.rootdev = 0x0100;
-
- tag = tag_next(tag);
- tag->hdr.tag = ATAG_MEM;
- tag->hdr.size = tag_size(tag_mem32);
- tag->u.mem.size = 4096;
- tag->u.mem.start = PHYS_OFFSET;
-
- tag = tag_next(tag);
- tag->hdr.tag = ATAG_NONE;
- tag->hdr.size = 0;
- }
-}
-
-static struct gpio_led p720t_gpio_leds[] = {
- {
- .name = "User LED",
- .default_trigger = "heartbeat",
- .gpio = P720T_USERLED,
- },
-};
-
-static struct gpio_led_platform_data p720t_gpio_led_pdata __initdata = {
- .leds = p720t_gpio_leds,
- .num_leds = ARRAY_SIZE(p720t_gpio_leds),
-};
-
-static void __init p720t_init(void)
-{
- int i;
-
- clps711x_devices_init();
-
- for (i = 0; i < ARRAY_SIZE(mmgpios); i++)
- p720t_mmgpio_init(mmgpios[i].addrbase, mmgpios[i].gpiobase);
-
- platform_device_register(&p720t_nand_pdev);
-}
-
-static void __init p720t_init_late(void)
-{
- WARN_ON(gpio_request_array(p720t_gpios, ARRAY_SIZE(p720t_gpios)));
-
- platform_device_register_data(NULL, "platform-lcd", 0,
- &p720t_lcd_power_pdata,
- sizeof(p720t_lcd_power_pdata));
- platform_device_register_data(NULL, "generic-bl", 0,
- &p720t_lcd_backlight_pdata,
- sizeof(p720t_lcd_backlight_pdata));
- platform_device_register_simple("video-clps711x", 0, NULL, 0);
- platform_device_register_data(NULL, "leds-gpio", 0,
- &p720t_gpio_led_pdata,
- sizeof(p720t_gpio_led_pdata));
-}
-
-MACHINE_START(P720T, "ARM-Prospector720T")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .fixup = fixup_p720t,
- .map_io = clps711x_map_io,
- .init_irq = clps711x_init_irq,
- .init_time = clps711x_timer_init,
- .init_machine = p720t_init,
- .init_late = p720t_init_late,
- .restart = clps711x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
deleted file mode 100644
index 6466da8f3c11..000000000000
--- a/arch/arm/mach-clps711x/common.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * linux/arch/arm/mach-clps711x/core.c
- *
- * Core support for the CLPS711x-based machines.
- *
- * Copyright (C) 2001,2011 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in 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/sizes.h>
-
-#include <asm/mach/map.h>
-#include <asm/system_misc.h>
-
-#include <mach/hardware.h>
-
-#include "common.h"
-
-/*
- * This maps the generic CLPS711x registers
- */
-static struct map_desc clps711x_io_desc[] __initdata = {
- {
- .virtual = (unsigned long)CLPS711X_VIRT_BASE,
- .pfn = __phys_to_pfn(CLPS711X_PHYS_BASE),
- .length = 48 * SZ_1K,
- .type = MT_DEVICE,
- }
-};
-
-void __init clps711x_map_io(void)
-{
- iotable_init(clps711x_io_desc, ARRAY_SIZE(clps711x_io_desc));
-}
-
-void __init clps711x_init_irq(void)
-{
- clps711x_intc_init(CLPS711X_PHYS_BASE, SZ_16K);
-}
-
-void __init clps711x_timer_init(void)
-{
- clps711x_clk_init(CLPS711X_VIRT_BASE);
- clps711x_clksrc_init(CLPS711X_VIRT_BASE + TC1D,
- CLPS711X_VIRT_BASE + TC2D, IRQ_TC2OI);
-}
-
-void clps711x_restart(enum reboot_mode mode, const char *cmd)
-{
- soft_restart(0);
-}
diff --git a/arch/arm/mach-clps711x/common.h b/arch/arm/mach-clps711x/common.h
deleted file mode 100644
index 370200b26333..000000000000
--- a/arch/arm/mach-clps711x/common.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * linux/arch/arm/mach-clps711x/common.h
- *
- * Common bits.
- */
-
-#include <linux/reboot.h>
-
-#define CLPS711X_NR_GPIO (4 * 8 + 3)
-#define CLPS711X_GPIO(prt, bit) ((prt) * 8 + (bit))
-
-extern void clps711x_map_io(void);
-extern void clps711x_init_irq(void);
-extern void clps711x_timer_init(void);
-extern void clps711x_restart(enum reboot_mode mode, const char *cmd);
-
-/* drivers/irqchip/irq-clps711x.c */
-void clps711x_intc_init(phys_addr_t, resource_size_t);
-/* drivers/clk/clk-clps711x.c */
-void clps711x_clk_init(void __iomem *base);
-/* drivers/clocksource/clps711x-timer.c */
-void clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base,
- unsigned int irq);
diff --git a/arch/arm/mach-clps711x/devices.c b/arch/arm/mach-clps711x/devices.c
deleted file mode 100644
index 77a9617c216d..000000000000
--- a/arch/arm/mach-clps711x/devices.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * CLPS711X common devices definitions
- *
- * Author: Alexander Shiyan <shc_work@mail.ru>, 2013-2014
- *
- * This program is free software; 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/io.h>
-#include <linux/of_fdt.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-#include <linux/sys_soc.h>
-
-#include <asm/system_info.h>
-
-#include <mach/hardware.h>
-
-static const struct resource clps711x_cpuidle_res __initconst =
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + HALT, SZ_128);
-
-static void __init clps711x_add_cpuidle(void)
-{
- platform_device_register_simple("clps711x-cpuidle", PLATFORM_DEVID_NONE,
- &clps711x_cpuidle_res, 1);
-}
-
-static const phys_addr_t clps711x_gpios[][2] __initconst = {
- { PADR, PADDR },
- { PBDR, PBDDR },
- { PCDR, PCDDR },
- { PDDR, PDDDR },
- { PEDR, PEDDR },
-};
-
-static void __init clps711x_add_gpio(void)
-{
- unsigned i;
- struct resource gpio_res[2];
-
- memset(gpio_res, 0, sizeof(gpio_res));
-
- gpio_res[0].flags = IORESOURCE_MEM;
- gpio_res[1].flags = IORESOURCE_MEM;
-
- for (i = 0; i < ARRAY_SIZE(clps711x_gpios); i++) {
- gpio_res[0].start = CLPS711X_PHYS_BASE + clps711x_gpios[i][0];
- gpio_res[0].end = gpio_res[0].start;
- gpio_res[1].start = CLPS711X_PHYS_BASE + clps711x_gpios[i][1];
- gpio_res[1].end = gpio_res[1].start;
-
- platform_device_register_simple("clps711x-gpio", i,
- gpio_res, ARRAY_SIZE(gpio_res));
- }
-}
-
-const struct resource clps711x_syscon_res[] __initconst = {
- /* SYSCON1, SYSFLG1 */
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + SYSCON1, SZ_128),
- /* SYSCON2, SYSFLG2 */
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + SYSCON2, SZ_128),
- /* SYSCON3 */
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + SYSCON3, SZ_64),
-};
-
-static void __init clps711x_add_syscon(void)
-{
- unsigned i;
-
- for (i = 0; i < ARRAY_SIZE(clps711x_syscon_res); i++)
- platform_device_register_simple("syscon", i + 1,
- &clps711x_syscon_res[i], 1);
-}
-
-static const struct resource clps711x_uart1_res[] __initconst = {
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR1, SZ_128),
- DEFINE_RES_IRQ(IRQ_UTXINT1),
- DEFINE_RES_IRQ(IRQ_URXINT1),
-};
-
-static const struct resource clps711x_uart2_res[] __initconst = {
- DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR2, SZ_128),
- DEFINE_RES_IRQ(IRQ_UTXINT2),
- DEFINE_RES_IRQ(IRQ_URXINT2),
-};
-
-static void __init clps711x_add_uart(void)
-{
- platform_device_register_simple("clps711x-uart", 0, clps711x_uart1_res,
- ARRAY_SIZE(clps711x_uart1_res));
- platform_device_register_simple("clps711x-uart", 1, clps711x_uart2_res,
- ARRAY_SIZE(clps711x_uart2_res));
-};
-
-static void __init clps711x_soc_init(void)
-{
- struct soc_device_attribute *soc_dev_attr;
- struct soc_device *soc_dev;
- void __iomem *base;
- u32 id[5];
-
- base = ioremap(CLPS711X_PHYS_BASE, SZ_32K);
- if (!base)
- return;
-
- id[0] = readl(base + UNIQID);
- id[1] = readl(base + RANDID0);
- id[2] = readl(base + RANDID1);
- id[3] = readl(base + RANDID2);
- id[4] = readl(base + RANDID3);
- system_rev = SYSFLG1_VERID(readl(base + SYSFLG1));
-
- add_device_randomness(id, sizeof(id));
-
- system_serial_low = id[0];
-
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- goto out_unmap;
-
- soc_dev_attr->machine = of_flat_dt_get_machine_name();
- soc_dev_attr->family = "Cirrus Logic CLPS711X";
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u", system_rev);
- soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%08x", id[0]);
-
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr->revision);
- kfree(soc_dev_attr->soc_id);
- kfree(soc_dev_attr);
- }
-
-out_unmap:
- iounmap(base);
-}
-
-void __init clps711x_devices_init(void)
-{
- clps711x_add_cpuidle();
- clps711x_add_gpio();
- clps711x_add_syscon();
- clps711x_add_uart();
- clps711x_soc_init();
-}
diff --git a/arch/arm/mach-clps711x/devices.h b/arch/arm/mach-clps711x/devices.h
deleted file mode 100644
index a5efc1744b84..000000000000
--- a/arch/arm/mach-clps711x/devices.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * CLPS711X common devices definitions
- *
- * Copyright (C) 2013 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-void clps711x_devices_init(void);
diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig
index eb14a0ff0093..5fd836be2701 100644
--- a/arch/arm/mach-cns3xxx/Kconfig
+++ b/arch/arm/mach-cns3xxx/Kconfig
@@ -2,7 +2,6 @@ menuconfig ARCH_CNS3XXX
bool "Cavium Networks CNS3XXX family"
depends on ARCH_MULTI_V6
select ARM_GIC
- select PCI_DOMAINS if PCI
help
Support for Cavium Networks CNS3XXX platform.
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 0d046accb35b..ed3d0e9f72ac 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -501,6 +501,7 @@ static struct clk_lookup da850_clks[] = {
CLK("da8xx_lcdc.0", "fck", &lcdc_clk),
CLK("da830-mmc.0", NULL, &mmcsd0_clk),
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
+ CLK("ti-aemif", NULL, &aemif_clk),
CLK(NULL, "aemif", &aemif_clk),
CLK(NULL, "usb11", &usb11_clk),
CLK(NULL, "usb20", &usb20_clk),
diff --git a/arch/arm/mach-davinci/da8xx-dt.c b/arch/arm/mach-davinci/da8xx-dt.c
index 754f478110b4..c9f7e9274aa8 100644
--- a/arch/arm/mach-davinci/da8xx-dt.c
+++ b/arch/arm/mach-davinci/da8xx-dt.c
@@ -37,6 +37,7 @@ static struct of_dev_auxdata da850_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("ti,davinci-dm6467-emac", 0x01e20000, "davinci_emac.1",
NULL),
OF_DEV_AUXDATA("ti,da830-mcasp-audio", 0x01d00000, "davinci-mcasp.0", NULL),
+ OF_DEV_AUXDATA("ti,da850-aemif", 0x68000000, "ti-aemif", NULL),
{}
};
@@ -49,6 +50,7 @@ static void __init da850_init_machine(void)
static const char *const da850_boards_compat[] __initconst = {
"enbw,cmc",
+ "ti,da850-lcdk",
"ti,da850-evm",
"ti,da850",
NULL,
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 8f820de890b4..0bb63b8d21e7 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -12,6 +12,7 @@ menuconfig ARCH_EXYNOS
depends on ARCH_MULTI_V7
select ARCH_HAS_BANDGAP
select ARCH_HAS_HOLES_MEMORYMODEL
+ select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
select ARM_GIC
select COMMON_CLK_SAMSUNG
@@ -126,8 +127,6 @@ config SOC_EXYNOS5440
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select HAVE_ARM_ARCH_TIMER
select AUTO_ZRELADDR
- select MIGHT_HAVE_PCI
- select PCI_DOMAINS if PCI
select PINCTRL_EXYNOS5440
select PM_OPP
help
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index acabf0bffc5d..757fc11de30d 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -30,25 +30,10 @@
static struct map_desc exynos4_iodesc[] __initdata = {
{
- .virtual = (unsigned long)S5P_VA_CMU,
- .pfn = __phys_to_pfn(EXYNOS4_PA_CMU),
- .length = SZ_128K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_COREPERI_BASE,
.pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI),
.length = SZ_8K,
.type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S5P_VA_DMC0,
- .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
- .length = SZ_64K,
- .type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S5P_VA_DMC1,
- .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1),
- .length = SZ_64K,
- .type = MT_DEVICE,
},
};
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c48ba4fbdfd2..5fb0040cc6d3 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -18,11 +18,6 @@
#define EXYNOS_PA_CHIPID 0x10000000
-#define EXYNOS4_PA_CMU 0x10030000
-
-#define EXYNOS4_PA_DMC0 0x10400000
-#define EXYNOS4_PA_DMC1 0x10410000
-
#define EXYNOS4_PA_COREPERI 0x10500000
#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index ee9a318cab31..9155b639c9aa 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -64,13 +64,6 @@ config IMX_HAVE_IOMUX_V1
config ARCH_MXC_IOMUX_V3
bool
-config SOC_IMX1
- bool
- select CPU_ARM920T
- select IMX_HAVE_IOMUX_V1
- select MXC_AVIC
- select PINCTRL_IMX1
-
config SOC_IMX21
bool
select CPU_ARM926T
@@ -88,7 +81,6 @@ config SOC_IMX31
bool
select CPU_V6
select MXC_AVIC
- select SMP_ON_UP if SMP
config SOC_IMX35
bool
@@ -96,35 +88,6 @@ config SOC_IMX35
select HAVE_EPIT
select MXC_AVIC
select PINCTRL_IMX35
- select SMP_ON_UP if SMP
-
-if ARCH_MULTI_V4T
-
-comment "MX1 platforms:"
-
-config MACH_SCB9328
- bool "Synertronixx scb9328"
- select IMX_HAVE_PLATFORM_IMX_UART
- select SOC_IMX1
- help
- Say Y here if you are using a Synertronixx scb9328 board
-
-config MACH_APF9328
- bool "APF9328"
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select SOC_IMX1
- help
- Say Yes here if you are using the Armadeus APF9328 development board
-
-config MACH_IMX1_DT
- bool "Support i.MX1 platforms from device tree"
- select SOC_IMX1
- help
- Include support for Freescale i.MX1 based platforms
- using the device tree for discovery.
-
-endif
if ARCH_MULTI_V5
@@ -461,6 +424,18 @@ endif
comment "Device tree only"
+if ARCH_MULTI_V4T
+
+config SOC_IMX1
+ bool "i.MX1 support"
+ select CPU_ARM920T
+ select MXC_AVIC
+ select PINCTRL_IMX1
+ help
+ This enables support for Freescale i.MX1 processor
+
+endif
+
if ARCH_MULTI_V5
config SOC_IMX25
@@ -523,7 +498,6 @@ config SOC_IMX6Q
select ARM_ERRATA_764369 if SMP
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD
- select PCI_DOMAINS if PCI
select PINCTRL_IMX6Q
select SOC_IMX6
@@ -569,7 +543,6 @@ config SOC_LS1021A
bool "Freescale LS1021A support"
select ARM_GIC
select HAVE_ARM_ARCH_TIMER
- select PCI_DOMAINS if PCI
select ZONE_DMA if ARM_LPAE
help
This enables support for Freescale LS1021A processor.
@@ -585,7 +558,6 @@ config SOC_VF610
select ARM_GIC if ARCH_MULTI_V7
select PINCTRL_VF610
select PL310_ERRATA_769419 if CACHE_L2X0
- select SMP_ON_UP if SMP
help
This enables support for Freescale Vybrid VF610 processor.
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 9f5fffd62702..cab128913e72 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,6 +1,5 @@
obj-y := cpu.o system.o irq-common.o
-obj-$(CONFIG_SOC_IMX1) += mm-imx1.o
obj-$(CONFIG_SOC_IMX21) += mm-imx21.o
obj-$(CONFIG_SOC_IMX25) += cpu-imx25.o mach-imx25.o pm-imx25.o
@@ -28,6 +27,7 @@ obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o
+obj-$(CONFIG_SOC_IMX6UL) += cpuidle-imx6sx.o
endif
ifdef CONFIG_SND_IMX_SOC
@@ -35,11 +35,6 @@ obj-y += ssi-fiq.o
obj-y += ssi-fiq-ksym.o
endif
-# i.MX1 based machines
-obj-$(CONFIG_MACH_SCB9328) += mach-scb9328.o
-obj-$(CONFIG_MACH_APF9328) += mach-apf9328.o
-obj-$(CONFIG_MACH_IMX1_DT) += imx1-dt.o
-
# i.MX21 based machines
obj-$(CONFIG_MACH_MX21ADS) += mach-mx21ads.o
@@ -93,6 +88,7 @@ obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o
endif
obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
+obj-$(CONFIG_SOC_IMX1) += mach-imx1.o
obj-$(CONFIG_SOC_IMX50) += mach-imx50.o
obj-$(CONFIG_SOC_IMX51) += mach-imx51.o
obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index a8f469333027..c4436d9c52ff 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -21,29 +21,24 @@ struct device_node;
enum mxc_cpu_pwr_mode;
struct of_device_id;
-void mx1_map_io(void);
void mx21_map_io(void);
void mx27_map_io(void);
void mx31_map_io(void);
void mx35_map_io(void);
-void imx1_init_early(void);
void imx21_init_early(void);
void imx27_init_early(void);
void imx31_init_early(void);
void imx35_init_early(void);
void mxc_init_irq(void __iomem *);
-void mx1_init_irq(void);
void mx21_init_irq(void);
void mx27_init_irq(void);
void mx31_init_irq(void);
void mx35_init_irq(void);
-void imx1_soc_init(void);
void imx21_soc_init(void);
void imx27_soc_init(void);
void imx31_soc_init(void);
void imx35_soc_init(void);
void epit_timer_init(void __iomem *base, int irq);
-int mx1_clocks_init(unsigned long fref);
int mx21_clocks_init(unsigned long lref, unsigned long fref);
int mx27_clocks_init(unsigned long fref);
int mx31_clocks_init(unsigned long fref);
@@ -109,7 +104,7 @@ void imx_anatop_init(void);
void imx_anatop_pre_suspend(void);
void imx_anatop_post_resume(void);
int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
-void imx6q_set_int_mem_clk_lpm(bool enable);
+void imx6_set_int_mem_clk_lpm(bool enable);
void imx6sl_set_wait_clk(bool enter);
int imx_mmdc_get_ddr_type(void);
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index db0f48c4b17e..bfeb25aaf9a2 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -85,7 +85,7 @@ EXPORT_SYMBOL_GPL(imx6q_cpuidle_fec_irqs_unused);
int __init imx6q_cpuidle_init(void)
{
/* Set INT_MEM_CLK_LPM bit to get a reliable WAIT mode support */
- imx6q_set_int_mem_clk_lpm(true);
+ imx6_set_int_mem_clk_lpm(true);
return cpuidle_register(&imx6q_cpuidle_driver, NULL);
}
diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c
index 3c6672b3796b..c5a5c3a70ab1 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sx.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sx.c
@@ -9,6 +9,7 @@
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/module.h>
+#include <asm/cacheflush.h>
#include <asm/cpuidle.h>
#include <asm/suspend.h>
@@ -17,6 +18,15 @@
static int imx6sx_idle_finish(unsigned long val)
{
+ /*
+ * for Cortex-A7 which has an internal L2
+ * cache, need to flush it before powering
+ * down ARM platform, since flushing L1 cache
+ * here again has very small overhead, compared
+ * to adding conditional code for L2 cache type,
+ * just call flush_cache_all() is fine.
+ */
+ flush_cache_all();
cpu_do_idle();
return 0;
@@ -90,6 +100,7 @@ static struct cpuidle_driver imx6sx_cpuidle_driver = {
int __init imx6sx_cpuidle_init(void)
{
+ imx6_set_int_mem_clk_lpm(true);
imx6_enable_rbc(false);
/*
* set ARM power up/down timing to the fastest,
diff --git a/arch/arm/mach-imx/devices-imx1.h b/arch/arm/mach-imx/devices-imx1.h
deleted file mode 100644
index f9b5afc6bcd1..000000000000
--- a/arch/arm/mach-imx/devices-imx1.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 Pengutronix
- * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
- */
-#include "devices/devices-common.h"
-
-extern const struct imx_imx_fb_data imx1_imx_fb_data;
-#define imx1_add_imx_fb(pdata) \
- imx_add_imx_fb(&imx1_imx_fb_data, pdata)
-
-extern const struct imx_imx_i2c_data imx1_imx_i2c_data;
-#define imx1_add_imx_i2c(pdata) \
- imx_add_imx_i2c(&imx1_imx_i2c_data, pdata)
-
-extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[];
-#define imx1_add_imx_uart(id, pdata) \
- imx_add_imx_uart_3irq(&imx1_imx_uart_data[id], pdata)
-#define imx1_add_imx_uart0(pdata) imx1_add_imx_uart(0, pdata)
-#define imx1_add_imx_uart1(pdata) imx1_add_imx_uart(1, pdata)
-
-extern const struct imx_spi_imx_data imx1_cspi_data[];
-#define imx1_add_cspi(id, pdata) \
- imx_add_spi_imx(&imx1_cspi_data[id], pdata)
-
-#define imx1_add_spi_imx0(pdata) imx1_add_cspi(0, pdata)
-#define imx1_add_spi_imx1(pdata) imx1_add_cspi(1, pdata)
diff --git a/arch/arm/mach-imx/devices/Makefile b/arch/arm/mach-imx/devices/Makefile
index e5cf587bc1a0..aa6cee870795 100644
--- a/arch/arm/mach-imx/devices/Makefile
+++ b/arch/arm/mach-imx/devices/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_CAMERA) += platform-mx2-camera.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI) += platform-mxc-ehci.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_MMC) += platform-mxc-mmc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o
-obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RNGA) += platform-mxc_rnga.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RTC) += platform-mxc_rtc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h
index 09cebd8cef2b..6920e356f4e5 100644
--- a/arch/arm/mach-imx/devices/devices-common.h
+++ b/arch/arm/mach-imx/devices/devices-common.h
@@ -154,18 +154,6 @@ struct platform_device *__init imx_add_imx_ssi(
const struct imx_ssi_platform_data *pdata);
#include <linux/platform_data/serial-imx.h>
-struct imx_imx_uart_3irq_data {
- int id;
- resource_size_t iobase;
- resource_size_t iosize;
- resource_size_t irqrx;
- resource_size_t irqtx;
- resource_size_t irqrts;
-};
-struct platform_device *__init imx_add_imx_uart_3irq(
- const struct imx_imx_uart_3irq_data *data,
- const struct imxuart_platform_data *pdata);
-
struct imx_imx_uart_1irq_data {
int id;
resource_size_t iobase;
diff --git a/arch/arm/mach-imx/devices/platform-imx-fb.c b/arch/arm/mach-imx/devices/platform-imx-fb.c
index 7df6328306f9..aa00272252e0 100644
--- a/arch/arm/mach-imx/devices/platform-imx-fb.c
+++ b/arch/arm/mach-imx/devices/platform-imx-fb.c
@@ -19,11 +19,6 @@
.irq = soc ## _INT_LCDC, \
}
-#ifdef CONFIG_SOC_IMX1
-const struct imx_imx_fb_data imx1_imx_fb_data __initconst =
- imx_imx_fb_data_entry_single(MX1, "imx1-fb", SZ_4K);
-#endif /* ifdef CONFIG_SOC_IMX1 */
-
#ifdef CONFIG_SOC_IMX21
const struct imx_imx_fb_data imx21_imx_fb_data __initconst =
imx_imx_fb_data_entry_single(MX21, "imx21-fb", SZ_4K);
diff --git a/arch/arm/mach-imx/devices/platform-imx-i2c.c b/arch/arm/mach-imx/devices/platform-imx-i2c.c
index ae9791522fc8..9822bedb5d09 100644
--- a/arch/arm/mach-imx/devices/platform-imx-i2c.c
+++ b/arch/arm/mach-imx/devices/platform-imx-i2c.c
@@ -21,11 +21,6 @@
#define imx_imx_i2c_data_entry(soc, _devid, _id, _hwid, _size) \
[_id] = imx_imx_i2c_data_entry_single(soc, _devid, _id, _hwid, _size)
-#ifdef CONFIG_SOC_IMX1
-const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst =
- imx_imx_i2c_data_entry_single(MX1, "imx1-i2c", 0, , SZ_4K);
-#endif /* ifdef CONFIG_SOC_IMX1 */
-
#ifdef CONFIG_SOC_IMX21
const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst =
imx_imx_i2c_data_entry_single(MX21, "imx21-i2c", 0, , SZ_4K);
diff --git a/arch/arm/mach-imx/devices/platform-imx-uart.c b/arch/arm/mach-imx/devices/platform-imx-uart.c
index 6962cff4a950..e3c89e9caf93 100644
--- a/arch/arm/mach-imx/devices/platform-imx-uart.c
+++ b/arch/arm/mach-imx/devices/platform-imx-uart.c
@@ -27,15 +27,6 @@
.irq = soc ## _INT_UART ## _hwid, \
}
-#ifdef CONFIG_SOC_IMX1
-const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst = {
-#define imx1_imx_uart_data_entry(_id, _hwid) \
- imx_imx_uart_3irq_data_entry(MX1, _id, _hwid, 0xd0)
- imx1_imx_uart_data_entry(0, 1),
- imx1_imx_uart_data_entry(1, 2),
-};
-#endif /* ifdef CONFIG_SOC_IMX1 */
-
#ifdef CONFIG_SOC_IMX21
const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst = {
#define imx21_imx_uart_data_entry(_id, _hwid) \
@@ -82,34 +73,6 @@ const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX35 */
-struct platform_device *__init imx_add_imx_uart_3irq(
- const struct imx_imx_uart_3irq_data *data,
- const struct imxuart_platform_data *pdata)
-{
- struct resource res[] = {
- {
- .start = data->iobase,
- .end = data->iobase + data->iosize - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = data->irqrx,
- .end = data->irqrx,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = data->irqtx,
- .end = data->irqtx,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = data->irqrts,
- .end = data->irqrx,
- .flags = IORESOURCE_IRQ,
- },
- };
-
- return imx_add_platform_device("imx1-uart", data->id, res,
- ARRAY_SIZE(res), pdata, sizeof(*pdata));
-}
-
struct platform_device *__init imx_add_imx_uart_1irq(
const struct imx_imx_uart_1irq_data *data,
const struct imxuart_platform_data *pdata)
diff --git a/arch/arm/mach-imx/devices/platform-spi_imx.c b/arch/arm/mach-imx/devices/platform-spi_imx.c
index 5e9707b47f92..d93c446c9c02 100644
--- a/arch/arm/mach-imx/devices/platform-spi_imx.c
+++ b/arch/arm/mach-imx/devices/platform-spi_imx.c
@@ -21,15 +21,6 @@
#define imx_spi_imx_data_entry(soc, type, devid, id, hwid, size) \
[id] = imx_spi_imx_data_entry_single(soc, type, devid, id, hwid, size)
-#ifdef CONFIG_SOC_IMX1
-const struct imx_spi_imx_data imx1_cspi_data[] __initconst = {
-#define imx1_cspi_data_entry(_id, _hwid) \
- imx_spi_imx_data_entry(MX1, CSPI, "imx1-cspi", _id, _hwid, SZ_4K)
- imx1_cspi_data_entry(0, 1),
- imx1_cspi_data_entry(1, 2),
-};
-#endif
-
#ifdef CONFIG_SOC_IMX21
const struct imx_spi_imx_data imx21_cspi_data[] __initconst = {
#define imx21_cspi_data_entry(_id, _hwid) \
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h
index d737f95ebb07..90e10cbd8fd1 100644
--- a/arch/arm/mach-imx/hardware.h
+++ b/arch/arm/mach-imx/hardware.h
@@ -112,7 +112,6 @@
#include "mx2x.h"
#include "mx21.h"
#include "mx27.h"
-#include "mx1.h"
#define imx_map_entry(soc, name, _type) { \
.virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR), \
@@ -121,7 +120,7 @@
.type = _type, \
}
-/* There's a off-by-one betweem the gpio bank number and the gpiochip */
+/* There's an off-by-one between the gpio bank number and the gpiochip */
/* range e.g. GPIO_1_5 is gpio 5 under linux */
#define IMX_GPIO_NR(bank, nr) (((bank) - 1) * 32 + (nr))
diff --git a/arch/arm/mach-imx/iomux-mx1.h b/arch/arm/mach-imx/iomux-mx1.h
deleted file mode 100644
index 95f4681d85d7..000000000000
--- a/arch/arm/mach-imx/iomux-mx1.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in 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 __MACH_IOMUX_MX1_H__
-#define __MACH_IOMUX_MX1_H__
-
-#include "iomux-v1.h"
-
-#define PA0_AIN_SPI2_CLK (GPIO_PORTA | GPIO_AIN | GPIO_OUT | 0)
-#define PA0_AF_ETMTRACESYNC (GPIO_PORTA | GPIO_AF | 0)
-#define PA1_AOUT_SPI2_RXD (GPIO_PORTA | GPIO_AOUT | GPIO_IN | 1)
-#define PA1_PF_TIN (GPIO_PORTA | GPIO_PF | 1)
-#define PA2_PF_PWM0 (GPIO_PORTA | GPIO_PF | GPIO_OUT | 2)
-#define PA3_PF_CSI_MCLK (GPIO_PORTA | GPIO_PF | 3)
-#define PA4_PF_CSI_D0 (GPIO_PORTA | GPIO_PF | 4)
-#define PA5_PF_CSI_D1 (GPIO_PORTA | GPIO_PF | 5)
-#define PA6_PF_CSI_D2 (GPIO_PORTA | GPIO_PF | 6)
-#define PA7_PF_CSI_D3 (GPIO_PORTA | GPIO_PF | 7)
-#define PA8_PF_CSI_D4 (GPIO_PORTA | GPIO_PF | 8)
-#define PA9_PF_CSI_D5 (GPIO_PORTA | GPIO_PF | 9)
-#define PA10_PF_CSI_D6 (GPIO_PORTA | GPIO_PF | 10)
-#define PA11_PF_CSI_D7 (GPIO_PORTA | GPIO_PF | 11)
-#define PA12_PF_CSI_VSYNC (GPIO_PORTA | GPIO_PF | 12)
-#define PA13_PF_CSI_HSYNC (GPIO_PORTA | GPIO_PF | 13)
-#define PA14_PF_CSI_PIXCLK (GPIO_PORTA | GPIO_PF | 14)
-#define PA15_PF_I2C_SDA (GPIO_PORTA | GPIO_PF | GPIO_OUT | 15)
-#define PA16_PF_I2C_SCL (GPIO_PORTA | GPIO_PF | GPIO_OUT | 16)
-#define PA17_AF_ETMTRACEPKT4 (GPIO_PORTA | GPIO_AF | 17)
-#define PA17_AIN_SPI2_SS (GPIO_PORTA | GPIO_AIN | GPIO_OUT | 17)
-#define PA18_AF_ETMTRACEPKT5 (GPIO_PORTA | GPIO_AF | 18)
-#define PA19_AF_ETMTRACEPKT6 (GPIO_PORTA | GPIO_AF | 19)
-#define PA20_AF_ETMTRACEPKT7 (GPIO_PORTA | GPIO_AF | 20)
-#define PA21_PF_A0 (GPIO_PORTA | GPIO_PF | 21)
-#define PA22_PF_CS4 (GPIO_PORTA | GPIO_PF | 22)
-#define PA23_PF_CS5 (GPIO_PORTA | GPIO_PF | 23)
-#define PA24_PF_A16 (GPIO_PORTA | GPIO_PF | 24)
-#define PA24_AF_ETMTRACEPKT0 (GPIO_PORTA | GPIO_AF | 24)
-#define PA25_PF_A17 (GPIO_PORTA | GPIO_PF | 25)
-#define PA25_AF_ETMTRACEPKT1 (GPIO_PORTA | GPIO_AF | 25)
-#define PA26_PF_A18 (GPIO_PORTA | GPIO_PF | 26)
-#define PA26_AF_ETMTRACEPKT2 (GPIO_PORTA | GPIO_AF | 26)
-#define PA27_PF_A19 (GPIO_PORTA | GPIO_PF | 27)
-#define PA27_AF_ETMTRACEPKT3 (GPIO_PORTA | GPIO_AF | 27)
-#define PA28_PF_A20 (GPIO_PORTA | GPIO_PF | 28)
-#define PA28_AF_ETMPIPESTAT0 (GPIO_PORTA | GPIO_AF | 28)
-#define PA29_PF_A21 (GPIO_PORTA | GPIO_PF | 29)
-#define PA29_AF_ETMPIPESTAT1 (GPIO_PORTA | GPIO_AF | 29)
-#define PA30_PF_A22 (GPIO_PORTA | GPIO_PF | 30)
-#define PA30_AF_ETMPIPESTAT2 (GPIO_PORTA | GPIO_AF | 30)
-#define PA31_PF_A23 (GPIO_PORTA | GPIO_PF | 31)
-#define PA31_AF_ETMTRACECLK (GPIO_PORTA | GPIO_AF | 31)
-#define PB8_PF_SD_DAT0 (GPIO_PORTB | GPIO_PF | GPIO_PUEN | 8)
-#define PB8_AF_MS_PIO (GPIO_PORTB | GPIO_AF | 8)
-#define PB9_PF_SD_DAT1 (GPIO_PORTB | GPIO_PF | GPIO_PUEN | 9)
-#define PB9_AF_MS_PI1 (GPIO_PORTB | GPIO_AF | 9)
-#define PB10_PF_SD_DAT2 (GPIO_PORTB | GPIO_PF | GPIO_PUEN | 10)
-#define PB10_AF_MS_SCLKI (GPIO_PORTB | GPIO_AF | 10)
-#define PB11_PF_SD_DAT3 (GPIO_PORTB | GPIO_PF | 11)
-#define PB11_AF_MS_SDIO (GPIO_PORTB | GPIO_AF | 11)
-#define PB12_PF_SD_CLK (GPIO_PORTB | GPIO_PF | 12)
-#define PB12_AF_MS_SCLK0 (GPIO_PORTB | GPIO_AF | 12)
-#define PB13_PF_SD_CMD (GPIO_PORTB | GPIO_PF | GPIO_PUEN | 13)
-#define PB13_AF_MS_BS (GPIO_PORTB | GPIO_AF | 13)
-#define PB14_AF_SSI_RXFS (GPIO_PORTB | GPIO_AF | 14)
-#define PB15_AF_SSI_RXCLK (GPIO_PORTB | GPIO_AF | 15)
-#define PB16_AF_SSI_RXDAT (GPIO_PORTB | GPIO_AF | GPIO_IN | 16)
-#define PB17_AF_SSI_TXDAT (GPIO_PORTB | GPIO_AF | GPIO_OUT | 17)
-#define PB18_AF_SSI_TXFS (GPIO_PORTB | GPIO_AF | 18)
-#define PB19_AF_SSI_TXCLK (GPIO_PORTB | GPIO_AF | 19)
-#define PB20_PF_USBD_AFE (GPIO_PORTB | GPIO_PF | 20)
-#define PB21_PF_USBD_OE (GPIO_PORTB | GPIO_PF | 21)
-#define PB22_PF_USBD_RCV (GPIO_PORTB | GPIO_PF | 22)
-#define PB23_PF_USBD_SUSPND (GPIO_PORTB | GPIO_PF | 23)
-#define PB24_PF_USBD_VP (GPIO_PORTB | GPIO_PF | 24)
-#define PB25_PF_USBD_VM (GPIO_PORTB | GPIO_PF | 25)
-#define PB26_PF_USBD_VPO (GPIO_PORTB | GPIO_PF | 26)
-#define PB27_PF_USBD_VMO (GPIO_PORTB | GPIO_PF | 27)
-#define PB28_PF_UART2_CTS (GPIO_PORTB | GPIO_PF | GPIO_OUT | 28)
-#define PB29_PF_UART2_RTS (GPIO_PORTB | GPIO_PF | GPIO_IN | 29)
-#define PB30_PF_UART2_TXD (GPIO_PORTB | GPIO_PF | GPIO_OUT | 30)
-#define PB31_PF_UART2_RXD (GPIO_PORTB | GPIO_PF | GPIO_IN | 31)
-#define PC3_PF_SSI_RXFS (GPIO_PORTC | GPIO_PF | 3)
-#define PC4_PF_SSI_RXCLK (GPIO_PORTC | GPIO_PF | 4)
-#define PC5_PF_SSI_RXDAT (GPIO_PORTC | GPIO_PF | GPIO_IN | 5)
-#define PC6_PF_SSI_TXDAT (GPIO_PORTC | GPIO_PF | GPIO_OUT | 6)
-#define PC7_PF_SSI_TXFS (GPIO_PORTC | GPIO_PF | 7)
-#define PC8_PF_SSI_TXCLK (GPIO_PORTC | GPIO_PF | 8)
-#define PC9_PF_UART1_CTS (GPIO_PORTC | GPIO_PF | GPIO_OUT | 9)
-#define PC10_PF_UART1_RTS (GPIO_PORTC | GPIO_PF | GPIO_IN | 10)
-#define PC11_PF_UART1_TXD (GPIO_PORTC | GPIO_PF | GPIO_OUT | 11)
-#define PC12_PF_UART1_RXD (GPIO_PORTC | GPIO_PF | GPIO_IN | 12)
-#define PC13_PF_SPI1_SPI_RDY (GPIO_PORTC | GPIO_PF | 13)
-#define PC14_PF_SPI1_SCLK (GPIO_PORTC | GPIO_PF | 14)
-#define PC15_PF_SPI1_SS (GPIO_PORTC | GPIO_PF | 15)
-#define PC16_PF_SPI1_MISO (GPIO_PORTC | GPIO_PF | 16)
-#define PC17_PF_SPI1_MOSI (GPIO_PORTC | GPIO_PF | 17)
-#define PC24_BIN_UART3_RI (GPIO_PORTC | GPIO_BIN | GPIO_OUT | 24)
-#define PC25_BIN_UART3_DSR (GPIO_PORTC | GPIO_BIN | GPIO_OUT | 25)
-#define PC26_AOUT_UART3_DTR (GPIO_PORTC | GPIO_AOUT | GPIO_IN | 26)
-#define PC27_BIN_UART3_DCD (GPIO_PORTC | GPIO_BIN | GPIO_OUT | 27)
-#define PC28_BIN_UART3_CTS (GPIO_PORTC | GPIO_BIN | GPIO_OUT | 28)
-#define PC29_AOUT_UART3_RTS (GPIO_PORTC | GPIO_AOUT | GPIO_IN | 29)
-#define PC30_BIN_UART3_TX (GPIO_PORTC | GPIO_BIN | 30)
-#define PC31_AOUT_UART3_RX (GPIO_PORTC | GPIO_AOUT | GPIO_IN | 31)
-#define PD6_PF_LSCLK (GPIO_PORTD | GPIO_PF | GPIO_OUT | 6)
-#define PD7_PF_REV (GPIO_PORTD | GPIO_PF | 7)
-#define PD7_AF_UART2_DTR (GPIO_PORTD | GPIO_AF | GPIO_IN | 7)
-#define PD7_AIN_SPI2_SCLK (GPIO_PORTD | GPIO_AIN | 7)
-#define PD8_PF_CLS (GPIO_PORTD | GPIO_PF | 8)
-#define PD8_AF_UART2_DCD (GPIO_PORTD | GPIO_AF | GPIO_OUT | 8)
-#define PD8_AIN_SPI2_SS (GPIO_PORTD | GPIO_AIN | 8)
-#define PD9_PF_PS (GPIO_PORTD | GPIO_PF | 9)
-#define PD9_AF_UART2_RI (GPIO_PORTD | GPIO_AF | GPIO_OUT | 9)
-#define PD9_AOUT_SPI2_RXD (GPIO_PORTD | GPIO_AOUT | GPIO_IN | 9)
-#define PD10_PF_SPL_SPR (GPIO_PORTD | GPIO_PF | GPIO_OUT | 10)
-#define PD10_AF_UART2_DSR (GPIO_PORTD | GPIO_AF | GPIO_OUT | 10)
-#define PD10_AIN_SPI2_TXD (GPIO_PORTD | GPIO_AIN | GPIO_OUT | 10)
-#define PD11_PF_CONTRAST (GPIO_PORTD | GPIO_PF | GPIO_OUT | 11)
-#define PD12_PF_ACD_OE (GPIO_PORTD | GPIO_PF | GPIO_OUT | 12)
-#define PD13_PF_LP_HSYNC (GPIO_PORTD | GPIO_PF | GPIO_OUT | 13)
-#define PD14_PF_FLM_VSYNC (GPIO_PORTD | GPIO_PF | GPIO_OUT | 14)
-#define PD15_PF_LD0 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 15)
-#define PD16_PF_LD1 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 16)
-#define PD17_PF_LD2 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 17)
-#define PD18_PF_LD3 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 18)
-#define PD19_PF_LD4 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 19)
-#define PD20_PF_LD5 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 20)
-#define PD21_PF_LD6 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 21)
-#define PD22_PF_LD7 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 22)
-#define PD23_PF_LD8 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 23)
-#define PD24_PF_LD9 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 24)
-#define PD25_PF_LD10 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 25)
-#define PD26_PF_LD11 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 26)
-#define PD27_PF_LD12 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 27)
-#define PD28_PF_LD13 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 28)
-#define PD29_PF_LD14 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 29)
-#define PD30_PF_LD15 (GPIO_PORTD | GPIO_PF | GPIO_OUT | 30)
-#define PD31_PF_TMR2OUT (GPIO_PORTD | GPIO_PF | 31)
-#define PD31_BIN_SPI2_TXD (GPIO_PORTD | GPIO_BIN | 31)
-
-#endif /* ifndef __MACH_IOMUX_MX1_H__ */
diff --git a/arch/arm/mach-imx/iomux-mx3.h b/arch/arm/mach-imx/iomux-mx3.h
index 2e4a0ddca76c..368667b32760 100644
--- a/arch/arm/mach-imx/iomux-mx3.h
+++ b/arch/arm/mach-imx/iomux-mx3.h
@@ -598,10 +598,7 @@ enum iomux_pins {
#define MX31_PIN_CONTRAST__CONTRAST IOMUX_MODE(MX31_PIN_CONTRAST, IOMUX_CONFIG_FUNC)
#define MX31_PIN_D3_SPL__D3_SPL IOMUX_MODE(MX31_PIN_D3_SPL, IOMUX_CONFIG_FUNC)
#define MX31_PIN_D3_CLS__D3_CLS IOMUX_MODE(MX31_PIN_D3_CLS, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_LCS0__GPI03_23 IOMUX_MODE(MX31_PIN_LCS0, IOMUX_CONFIG_GPIO)
#define MX31_PIN_GPIO1_1__GPIO IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_I2C_CLK__SCL IOMUX_MODE(MX31_PIN_I2C_CLK, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_I2C_DAT__SDA IOMUX_MODE(MX31_PIN_I2C_DAT, IOMUX_CONFIG_FUNC)
#define MX31_PIN_DCD_DTE1__I2C2_SDA IOMUX_MODE(MX31_PIN_DCD_DTE1, IOMUX_CONFIG_ALT2)
#define MX31_PIN_RI_DTE1__I2C2_SCL IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_ALT2)
#define MX31_PIN_CSPI2_SS2__I2C3_SDA IOMUX_MODE(MX31_PIN_CSPI2_SS2, IOMUX_CONFIG_ALT1)
@@ -665,37 +662,6 @@ enum iomux_pins {
#define MX31_PIN_USB_OC__GPIO1_30 IOMUX_MODE(MX31_PIN_USB_OC, IOMUX_CONFIG_GPIO)
#define MX31_PIN_I2C_DAT__I2C1_SDA IOMUX_MODE(MX31_PIN_I2C_DAT, IOMUX_CONFIG_FUNC)
#define MX31_PIN_I2C_CLK__I2C1_SCL IOMUX_MODE(MX31_PIN_I2C_CLK, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_DCD_DTE1__I2C2_SDA IOMUX_MODE(MX31_PIN_DCD_DTE1, IOMUX_CONFIG_ALT2)
-#define MX31_PIN_RI_DTE1__I2C2_SCL IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_ALT2)
-#define MX31_PIN_ATA_CS0__GPIO3_26 IOMUX_MODE(MX31_PIN_ATA_CS0, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_ATA_CS1__GPIO3_27 IOMUX_MODE(MX31_PIN_ATA_CS1, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_PC_PWRON__SD2_DATA3 IOMUX_MODE(MX31_PIN_PC_PWRON, IOMUX_CONFIG_ALT1)
-#define MX31_PIN_PC_VS1__SD2_DATA2 IOMUX_MODE(MX31_PIN_PC_VS1, IOMUX_CONFIG_ALT1)
-#define MX31_PIN_PC_READY__SD2_DATA1 IOMUX_MODE(MX31_PIN_PC_READY, IOMUX_CONFIG_ALT1)
-#define MX31_PIN_PC_WAIT_B__SD2_DATA0 IOMUX_MODE(MX31_PIN_PC_WAIT_B, IOMUX_CONFIG_ALT1)
-#define MX31_PIN_PC_CD2_B__SD2_CLK IOMUX_MODE(MX31_PIN_PC_CD2_B, IOMUX_CONFIG_ALT1)
-#define MX31_PIN_PC_CD1_B__SD2_CMD IOMUX_MODE(MX31_PIN_PC_CD1_B, IOMUX_CONFIG_ALT1)
-#define MX31_PIN_ATA_DIOR__GPIO3_28 IOMUX_MODE(MX31_PIN_ATA_DIOR, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_ATA_DIOW__GPIO3_29 IOMUX_MODE(MX31_PIN_ATA_DIOW, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_CSI_D4__CSI_D4 IOMUX_MODE(MX31_PIN_CSI_D4, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D5__CSI_D5 IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D6__CSI_D6 IOMUX_MODE(MX31_PIN_CSI_D6, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D7__CSI_D7 IOMUX_MODE(MX31_PIN_CSI_D7, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D8__CSI_D8 IOMUX_MODE(MX31_PIN_CSI_D8, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D9__CSI_D9 IOMUX_MODE(MX31_PIN_CSI_D9, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D10__CSI_D10 IOMUX_MODE(MX31_PIN_CSI_D10, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D11__CSI_D11 IOMUX_MODE(MX31_PIN_CSI_D11, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D12__CSI_D12 IOMUX_MODE(MX31_PIN_CSI_D12, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D13__CSI_D13 IOMUX_MODE(MX31_PIN_CSI_D13, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D14__CSI_D14 IOMUX_MODE(MX31_PIN_CSI_D14, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_D15__CSI_D15 IOMUX_MODE(MX31_PIN_CSI_D15, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_HSYNC__CSI_HSYNC IOMUX_MODE(MX31_PIN_CSI_HSYNC, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_MCLK__CSI_MCLK IOMUX_MODE(MX31_PIN_CSI_MCLK, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_PIXCLK__CSI_PIXCLK IOMUX_MODE(MX31_PIN_CSI_PIXCLK, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_CSI_VSYNC__CSI_VSYNC IOMUX_MODE(MX31_PIN_CSI_VSYNC, IOMUX_CONFIG_FUNC)
-#define MX31_PIN_GPIO3_0__GPIO3_0 IOMUX_MODE(MX31_PIN_GPIO3_0, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_GPIO3_1__GPIO3_1 IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO)
-#define MX31_PIN_TXD2__GPIO1_28 IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_GPIO)
#define MX31_PIN_GPIO1_0__GPIO1_0 IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO)
#define MX31_PIN_SVEN0__GPIO2_0 IOMUX_MODE(MX31_PIN_SVEN0, IOMUX_CONFIG_GPIO)
#define MX31_PIN_STX0__GPIO2_1 IOMUX_MODE(MX31_PIN_STX0, IOMUX_CONFIG_GPIO)
diff --git a/arch/arm/mach-imx/mach-apf9328.c b/arch/arm/mach-imx/mach-apf9328.c
deleted file mode 100644
index ebbb5ab63529..000000000000
--- a/arch/arm/mach-imx/mach-apf9328.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * linux/arch/arm/mach-imx/mach-apf9328.c
- *
- * Copyright (c) 2005-2011 ARMadeus systems <support@armadeus.com>
- *
- * This work is based on mach-scb9328.c which is:
- * Copyright (c) 2004 Sascha Hauer <saschahauer@web.de>
- * Copyright (c) 2006-2008 Juergen Beisert <jbeisert@netscape.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/dm9000.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-#include "devices-imx1.h"
-#include "hardware.h"
-#include "iomux-mx1.h"
-
-static const int apf9328_pins[] __initconst = {
- /* UART1 */
- PC9_PF_UART1_CTS,
- PC10_PF_UART1_RTS,
- PC11_PF_UART1_TXD,
- PC12_PF_UART1_RXD,
- /* UART2 */
- PB28_PF_UART2_CTS,
- PB29_PF_UART2_RTS,
- PB30_PF_UART2_TXD,
- PB31_PF_UART2_RXD,
- /* I2C */
- PA15_PF_I2C_SDA,
- PA16_PF_I2C_SCL,
-};
-
-/*
- * The APF9328 can have up to 32MB NOR Flash
- */
-static struct resource flash_resource = {
- .start = MX1_CS0_PHYS,
- .end = MX1_CS0_PHYS + SZ_32M - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct physmap_flash_data apf9328_flash_data = {
- .width = 2,
-};
-
-static struct platform_device apf9328_flash_device = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &apf9328_flash_data,
- },
- .resource = &flash_resource,
- .num_resources = 1,
-};
-
-/*
- * APF9328 has a DM9000 Ethernet controller
- */
-static struct dm9000_plat_data dm9000_setup = {
- .flags = DM9000_PLATF_16BITONLY
-};
-
-static struct resource dm9000_resources[] = {
- {
- .start = MX1_CS4_PHYS + 0x00C00000,
- .end = MX1_CS4_PHYS + 0x00C00001,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MX1_CS4_PHYS + 0x00C00002,
- .end = MX1_CS4_PHYS + 0x00C00003,
- .flags = IORESOURCE_MEM,
- }, {
- /* irq number is run-time assigned */
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct platform_device dm9000x_device = {
- .name = "dm9000",
- .id = 0,
- .num_resources = ARRAY_SIZE(dm9000_resources),
- .resource = dm9000_resources,
- .dev = {
- .platform_data = &dm9000_setup,
- }
-};
-
-static const struct imxuart_platform_data uart1_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static const struct imxi2c_platform_data apf9328_i2c_data __initconst = {
- .bitrate = 100000,
-};
-
-static struct platform_device *devices[] __initdata = {
- &apf9328_flash_device,
- &dm9000x_device,
-};
-
-static void __init apf9328_init(void)
-{
- imx1_soc_init();
-
- mxc_gpio_setup_multiple_pins(apf9328_pins,
- ARRAY_SIZE(apf9328_pins),
- "APF9328");
-
- imx1_add_imx_uart0(NULL);
- imx1_add_imx_uart1(&uart1_pdata);
-
- imx1_add_imx_i2c(&apf9328_i2c_data);
-
- dm9000_resources[2].start = gpio_to_irq(IMX_GPIO_NR(2, 14));
- dm9000_resources[2].end = gpio_to_irq(IMX_GPIO_NR(2, 14));
- platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-static void __init apf9328_timer_init(void)
-{
- mx1_clocks_init(32768);
-}
-
-MACHINE_START(APF9328, "Armadeus APF9328")
- /* Maintainer: Gwenhael Goavec-Merou, ARMadeus Systems */
- .map_io = mx1_map_io,
- .init_early = imx1_init_early,
- .init_irq = mx1_init_irq,
- .init_time = apf9328_timer_init,
- .init_machine = apf9328_init,
- .restart = mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c
index eaee47a2fcc0..17a97ba2cecf 100644
--- a/arch/arm/mach-imx/mach-armadillo5x0.c
+++ b/arch/arm/mach-imx/mach-armadillo5x0.c
@@ -493,24 +493,12 @@ static void __init armadillo5x0_init(void)
regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
- armadillo5x0_smc911x_resources[1].start =
- gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_0));
- armadillo5x0_smc911x_resources[1].end =
- gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_0));
- platform_add_devices(devices, ARRAY_SIZE(devices));
- imx_add_gpio_keys(&armadillo5x0_button_data);
imx31_add_imx_i2c1(NULL);
/* Register UART */
imx31_add_imx_uart0(&uart_pdata);
imx31_add_imx_uart1(&uart_pdata);
- /* SMSC9118 IRQ pin */
- gpio_direction_input(MX31_PIN_GPIO1_0);
-
- /* Register SDHC */
- imx31_add_mxc_mmc(0, &sdhc_pdata);
-
/* Register FB */
imx31_add_ipu_core();
imx31_add_mx3_sdc_fb(&mx3fb_pdata);
@@ -527,21 +515,39 @@ static void __init armadillo5x0_init(void)
/* set NAND page size to 2k if not configured via boot mode pins */
imx_writel(imx_readl(mx3_ccm_base + MXC_CCM_RCSR) | (1 << 30),
mx3_ccm_base + MXC_CCM_RCSR);
+}
+
+static void __init armadillo5x0_late(void)
+{
+ armadillo5x0_smc911x_resources[1].start =
+ gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_0));
+ armadillo5x0_smc911x_resources[1].end =
+ gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_0));
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+
+ imx_add_gpio_keys(&armadillo5x0_button_data);
+
+ /* SMSC9118 IRQ pin */
+ gpio_direction_input(MX31_PIN_GPIO1_0);
+
+ /* Register SDHC */
+ imx31_add_mxc_mmc(0, &sdhc_pdata);
/* RTC */
/* Get RTC IRQ and register the chip */
- if (gpio_request(ARMADILLO5X0_RTC_GPIO, "rtc") == 0) {
- if (gpio_direction_input(ARMADILLO5X0_RTC_GPIO) == 0)
- armadillo5x0_i2c_rtc.irq = gpio_to_irq(ARMADILLO5X0_RTC_GPIO);
+ if (!gpio_request(ARMADILLO5X0_RTC_GPIO, "rtc")) {
+ if (!gpio_direction_input(ARMADILLO5X0_RTC_GPIO))
+ armadillo5x0_i2c_rtc.irq =
+ gpio_to_irq(ARMADILLO5X0_RTC_GPIO);
else
gpio_free(ARMADILLO5X0_RTC_GPIO);
}
+
if (armadillo5x0_i2c_rtc.irq == 0)
pr_warn("armadillo5x0_init: failed to get RTC IRQ\n");
i2c_register_board_info(1, &armadillo5x0_i2c_rtc, 1);
/* USB */
-
usbotg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
ULPI_OTG_DRVVBUS_EXT);
if (usbotg_pdata.otg)
@@ -565,5 +571,6 @@ MACHINE_START(ARMADILLO5X0, "Armadillo-500")
.init_irq = mx31_init_irq,
.init_time = armadillo5x0_timer_init,
.init_machine = armadillo5x0_init,
+ .init_late = armadillo5x0_late,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/imx1-dt.c b/arch/arm/mach-imx/mach-imx1.c
index 6f915b0961c4..de5ab8d88549 100644
--- a/arch/arm/mach-imx/imx1-dt.c
+++ b/arch/arm/mach-imx/mach-imx1.c
@@ -9,8 +9,27 @@
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
#include "common.h"
+#include "hardware.h"
+
+#define MX1_AVIC_ADDR 0x00223000
+
+static void __init imx1_init_early(void)
+{
+ mxc_set_cpu_type(MXC_CPU_MX1);
+}
+
+static void __init imx1_init_irq(void)
+{
+ void __iomem *avic_addr;
+
+ avic_addr = ioremap(MX1_AVIC_ADDR, SZ_4K);
+ WARN_ON(!avic_addr);
+
+ mxc_init_irq(avic_addr);
+}
static const char * const imx1_dt_board_compat[] __initconst = {
"fsl,imx1",
@@ -18,9 +37,9 @@ static const char * const imx1_dt_board_compat[] __initconst = {
};
DT_MACHINE_START(IMX1_DT, "Freescale i.MX1 (Device Tree Support)")
- .map_io = mx1_map_io,
+ .map_io = debug_ll_io_init,
.init_early = imx1_init_early,
- .init_irq = mx1_init_irq,
+ .init_irq = imx1_init_irq,
.dt_compat = imx1_dt_board_compat,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index ede2bdbb5dd5..dd75a4756761 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -540,7 +540,6 @@ static void __init visstrim_m10_revision(void)
static void __init visstrim_m10_board_init(void)
{
int ret;
- int mo_version;
imx27_soc_init();
visstrim_m10_revision();
@@ -550,11 +549,6 @@ static void __init visstrim_m10_board_init(void)
if (ret)
pr_err("Failed to setup pins (%d)\n", ret);
- ret = gpio_request_array(visstrim_m10_gpios,
- ARRAY_SIZE(visstrim_m10_gpios));
- if (ret)
- pr_err("Failed to request gpios (%d)\n", ret);
-
imx27_add_imx_ssi(0, &visstrim_m10_ssi_pdata);
imx27_add_imx_uart0(&uart_pdata);
@@ -566,12 +560,26 @@ static void __init visstrim_m10_board_init(void)
imx27_add_mxc_mmc(0, &visstrim_m10_sdhc_pdata);
imx27_add_mxc_ehci_otg(&visstrim_m10_usbotg_pdata);
imx27_add_fec(NULL);
- imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);
+
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init visstrim_m10_late_init(void)
+{
+ int mo_version, ret;
+
+ ret = gpio_request_array(visstrim_m10_gpios,
+ ARRAY_SIZE(visstrim_m10_gpios));
+ if (ret)
+ pr_err("Failed to request gpios (%d)\n", ret);
+
+ imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);
+
imx_add_platform_device("mx27vis", 0, NULL, 0, &snd_mx27vis_pdata,
sizeof(snd_mx27vis_pdata));
platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
&iclink_tvp5150, sizeof(iclink_tvp5150));
+
gpio_led_register_device(0, &visstrim_m10_led_data);
/* Use mother board version to decide what video devices we shall use */
@@ -591,6 +599,7 @@ static void __init visstrim_m10_board_init(void)
visstrim_deinterlace_init();
visstrim_analog_camera_init();
}
+
visstrim_coda_init();
}
@@ -607,5 +616,6 @@ MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
.init_irq = mx27_init_irq,
.init_time = visstrim_m10_timer_init,
.init_machine = visstrim_m10_board_init,
+ .init_late = visstrim_m10_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c
index 6bb7d9cf1e38..58a2b88233e6 100644
--- a/arch/arm/mach-imx/mach-imx6ul.c
+++ b/arch/arm/mach-imx/mach-imx6ul.c
@@ -16,6 +16,7 @@
#include <asm/mach/map.h>
#include "common.h"
+#include "cpuidle.h"
static void __init imx6ul_enet_clk_init(void)
{
@@ -80,6 +81,8 @@ static void __init imx6ul_init_irq(void)
static void __init imx6ul_init_late(void)
{
+ imx6sx_cpuidle_init();
+
if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
}
diff --git a/arch/arm/mach-imx/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c
index 31df4361996f..ab847e2c822a 100644
--- a/arch/arm/mach-imx/mach-kzm_arm11_01.c
+++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c
@@ -63,7 +63,7 @@
*/
#define KZM_ARM11_16550 (MX31_CS4_BASE_ADDR + 0x1050)
-#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+#if IS_ENABLED(CONFIG_SERIAL_8250)
/*
* KZM-ARM11-01 has an external UART on FPGA
*/
@@ -141,7 +141,7 @@ static inline int kzm_init_ext_uart(void)
/*
* SMSC LAN9118
*/
-#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#if IS_ENABLED(CONFIG_SMSC911X)
static struct smsc911x_platform_config kzm_smsc9118_config = {
.phy_interface = PHY_INTERFACE_MODE_MII,
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
@@ -201,7 +201,7 @@ static inline int kzm_init_smsc9118(void)
}
#endif
-#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
+#if IS_ENABLED(CONFIG_SERIAL_IMX)
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
@@ -245,13 +245,17 @@ static void __init kzm_board_init(void)
mxc_iomux_setup_multiple_pins(kzm_pins,
ARRAY_SIZE(kzm_pins), "kzm");
- kzm_init_ext_uart();
- kzm_init_smsc9118();
kzm_init_imx_uart();
pr_info("Clock input source is 26MHz\n");
}
+static void __init kzm_late_init(void)
+{
+ kzm_init_ext_uart();
+ kzm_init_smsc9118();
+}
+
/*
* This structure defines static mappings for the kzm-arm11-01 board.
*/
@@ -291,5 +295,6 @@ MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01")
.init_irq = mx31_init_irq,
.init_time = kzm_timer_init,
.init_machine = kzm_board_init,
+ .init_late = kzm_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 9986f9a697c8..5e366824814f 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -302,12 +302,16 @@ 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_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);
+}
+
+static void __init mx21ads_late_init(void)
+{
+ imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata);
+
+ platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
mx21ads_cs8900_resources[1].start =
gpio_to_irq(MX21ADS_CS8900A_IRQ_GPIO);
@@ -328,6 +332,7 @@ MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
.init_early = imx21_init_early,
.init_irq = mx21_init_irq,
.init_time = mx21ads_timer_init,
- .init_machine = mx21ads_board_init,
+ .init_machine = mx21ads_board_init,
+ .init_late = mx21ads_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index 9ef4640f3660..7ba651a9b5b8 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -485,17 +485,32 @@ static const struct imxi2c_platform_data mx27_3ds_i2c0_data __initconst = {
static void __init mx27pdk_init(void)
{
- int ret;
imx27_soc_init();
mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
"mx27pdk");
- mx27_3ds_sdhc1_enable_level_translator();
imx27_add_imx_uart0(&uart_pdata);
imx27_add_fec(NULL);
imx27_add_imx_keypad(&mx27_3ds_keymap_data);
- imx27_add_mxc_mmc(0, &sdhc1_pdata);
imx27_add_imx2_wdt();
+
+ imx27_add_spi_imx1(&spi2_pdata);
+ imx27_add_spi_imx0(&spi1_pdata);
+
+ imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data);
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ imx27_add_imx_fb(&mx27_3ds_fb_data);
+
+ imx27_add_imx_ssi(0, &mx27_3ds_ssi_pdata);
+}
+
+static void __init mx27pdk_late_init(void)
+{
+ int ret;
+
+ mx27_3ds_sdhc1_enable_level_translator();
+ imx27_add_mxc_mmc(0, &sdhc1_pdata);
+
otg_phy_init();
if (otg_mode_host) {
@@ -509,17 +524,12 @@ static void __init mx27pdk_init(void)
if (!otg_mode_host)
imx27_add_fsl_usb2_udc(&otg_device_pdata);
- imx27_add_spi_imx1(&spi2_pdata);
- imx27_add_spi_imx0(&spi1_pdata);
mx27_3ds_spi_devs[0].irq = gpio_to_irq(PMIC_INT);
spi_register_board_info(mx27_3ds_spi_devs,
- ARRAY_SIZE(mx27_3ds_spi_devs));
+ ARRAY_SIZE(mx27_3ds_spi_devs));
if (mxc_expio_init(MX27_CS5_BASE_ADDR, IMX_GPIO_NR(3, 28)))
pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n");
- imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data);
- platform_add_devices(devices, ARRAY_SIZE(devices));
- imx27_add_imx_fb(&mx27_3ds_fb_data);
ret = gpio_request_array(mx27_3ds_camera_gpios,
ARRAY_SIZE(mx27_3ds_camera_gpios));
@@ -529,7 +539,6 @@ static void __init mx27pdk_init(void)
}
imx27_add_mx2_camera(&mx27_3ds_cam_pdata);
- imx27_add_imx_ssi(0, &mx27_3ds_ssi_pdata);
imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
}
@@ -547,5 +556,6 @@ MACHINE_START(MX27_3DS, "Freescale MX27PDK")
.init_irq = mx27_init_irq,
.init_time = mx27pdk_timer_init,
.init_machine = mx27pdk_init,
+ .init_late = mx27pdk_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c
index a4c389eae31a..a04bb094ded1 100644
--- a/arch/arm/mach-imx/mach-mx27ads.c
+++ b/arch/arm/mach-imx/mach-mx27ads.c
@@ -352,14 +352,20 @@ static void __init mx27ads_board_init(void)
i2c_register_board_info(1, mx27ads_i2c_devices,
ARRAY_SIZE(mx27ads_i2c_devices));
imx27_add_imx_i2c(1, &mx27ads_i2c1_data);
- mx27ads_regulator_init();
imx27_add_imx_fb(&mx27ads_fb_data);
+
+ imx27_add_fec(NULL);
+ imx27_add_mxc_w1();
+}
+
+static void __init mx27ads_late_init(void)
+{
+ mx27ads_regulator_init();
+
imx27_add_mxc_mmc(0, &sdhc1_pdata);
imx27_add_mxc_mmc(1, &sdhc2_pdata);
- imx27_add_fec(NULL);
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
- imx27_add_mxc_w1();
}
static void __init mx27ads_timer_init(void)
@@ -395,5 +401,6 @@ MACHINE_START(MX27ADS, "Freescale i.MX27ADS")
.init_irq = mx27_init_irq,
.init_time = mx27ads_timer_init,
.init_machine = mx27ads_board_init,
+ .init_late = mx27ads_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index 65a0dc06a97c..12b8a52c9cb4 100644
--- a/arch/arm/mach-imx/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -694,8 +694,6 @@ static struct platform_device *devices[] __initdata = {
static void __init mx31_3ds_init(void)
{
- int ret;
-
imx31_soc_init();
/* Configure SPI1 IOMUX */
@@ -708,14 +706,31 @@ static void __init mx31_3ds_init(void)
imx31_add_mxc_nand(&mx31_3ds_nand_board_info);
imx31_add_spi_imx1(&spi1_pdata);
+
+ imx31_add_imx_keypad(&mx31_3ds_keymap_data);
+
+ imx31_add_imx2_wdt();
+ imx31_add_imx_i2c0(&mx31_3ds_i2c0_data);
+
+ imx31_add_spi_imx0(&spi0_pdata);
+ imx31_add_ipu_core();
+ imx31_add_mx3_sdc_fb(&mx3fb_pdata);
+
+ imx31_add_imx_ssi(0, &mx31_3ds_ssi_pdata);
+
+ imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
+}
+
+static void __init mx31_3ds_late(void)
+{
+ int ret;
+
mx31_3ds_spi_devs[0].irq = gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
spi_register_board_info(mx31_3ds_spi_devs,
- ARRAY_SIZE(mx31_3ds_spi_devs));
+ ARRAY_SIZE(mx31_3ds_spi_devs));
platform_add_devices(devices, ARRAY_SIZE(devices));
- imx31_add_imx_keypad(&mx31_3ds_keymap_data);
-
mx31_3ds_usbotg_init();
if (otg_mode_host) {
otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
@@ -733,14 +748,9 @@ static void __init mx31_3ds_init(void)
if (mxc_expio_init(MX31_CS5_BASE_ADDR, IOMUX_TO_GPIO(MX31_PIN_GPIO1_1)))
printk(KERN_WARNING "Init of the debug board failed, all "
- "devices on the debug board are unusable.\n");
- imx31_add_imx2_wdt();
- imx31_add_imx_i2c0(&mx31_3ds_i2c0_data);
- imx31_add_mxc_mmc(0, &sdhc1_pdata);
+ "devices on the debug board are unusable.\n");
- imx31_add_spi_imx0(&spi0_pdata);
- imx31_add_ipu_core();
- imx31_add_mx3_sdc_fb(&mx3fb_pdata);
+ imx31_add_mxc_mmc(0, &sdhc1_pdata);
/* CSI */
/* Camera power: default - off */
@@ -752,10 +762,6 @@ static void __init mx31_3ds_init(void)
}
mx31_3ds_init_camera();
-
- imx31_add_imx_ssi(0, &mx31_3ds_ssi_pdata);
-
- imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
}
static void __init mx31_3ds_timer_init(void)
@@ -778,6 +784,7 @@ MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
.init_irq = mx31_init_irq,
.init_time = mx31_3ds_timer_init,
.init_machine = mx31_3ds_init,
+ .init_late = mx31_3ds_late,
.reserve = mx31_3ds_reserve,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c
index 4f2c56d44ba1..766b8b93fb97 100644
--- a/arch/arm/mach-imx/mach-mx31ads.c
+++ b/arch/arm/mach-imx/mach-mx31ads.c
@@ -554,20 +554,19 @@ static void __init mx31ads_map_io(void)
iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
}
-static void __init mx31ads_init_irq(void)
-{
- mx31_init_irq();
- mx31ads_init_expio();
-}
-
static void __init mx31ads_init(void)
{
imx31_soc_init();
- mxc_init_extuart();
mxc_init_imx_uart();
- mxc_init_i2c();
mxc_init_audio();
+}
+
+static void __init mx31ads_late(void)
+{
+ mx31ads_init_expio();
+ mxc_init_extuart();
+ mxc_init_i2c();
mxc_init_ext_ethernet();
}
@@ -581,8 +580,9 @@ MACHINE_START(MX31ADS, "Freescale MX31ADS")
.atag_offset = 0x100,
.map_io = mx31ads_map_io,
.init_early = imx31_init_early,
- .init_irq = mx31ads_init_irq,
+ .init_irq = mx31_init_irq,
.init_time = mx31ads_timer_init,
.init_machine = mx31ads_init,
+ .init_late = mx31ads_late,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c
index e9549a3c0223..6fd463642954 100644
--- a/arch/arm/mach-imx/mach-mx31lilly.c
+++ b/arch/arm/mach-imx/mach-mx31lilly.c
@@ -56,6 +56,26 @@
* appropriate baseboard support code.
*/
+static unsigned int mx31lilly_pins[] __initdata = {
+ MX31_PIN_CTS1__CTS1,
+ MX31_PIN_RTS1__RTS1,
+ MX31_PIN_TXD1__TXD1,
+ MX31_PIN_RXD1__RXD1,
+ MX31_PIN_CTS2__CTS2,
+ MX31_PIN_RTS2__RTS2,
+ MX31_PIN_TXD2__TXD2,
+ MX31_PIN_RXD2__RXD2,
+ MX31_PIN_CSPI3_MOSI__RXD3,
+ MX31_PIN_CSPI3_MISO__TXD3,
+ MX31_PIN_CSPI3_SCLK__RTS3,
+ MX31_PIN_CSPI3_SPI_RDY__CTS3,
+};
+
+/* UART */
+static const struct imxuart_platform_data uart_pdata __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
/* SMSC ethernet support */
static struct resource smsc91x_resources[] = {
@@ -252,16 +272,12 @@ static void __init mx31lilly_board_init(void)
{
imx31_soc_init();
- switch (mx31lilly_baseboard) {
- case MX31LILLY_NOBOARD:
- break;
- case MX31LILLY_DB:
- mx31lilly_db_init();
- break;
- default:
- printk(KERN_ERR "Illegal mx31lilly_baseboard type %d\n",
- mx31lilly_baseboard);
- }
+ mxc_iomux_setup_multiple_pins(mx31lilly_pins,
+ ARRAY_SIZE(mx31lilly_pins), "mx31lily");
+
+ imx31_add_imx_uart0(&uart_pdata);
+ imx31_add_imx_uart1(&uart_pdata);
+ imx31_add_imx_uart2(&uart_pdata);
mxc_iomux_alloc_pin(MX31_PIN_CS4__CS4, "Ethernet CS");
@@ -284,10 +300,17 @@ static void __init mx31lilly_board_init(void)
imx31_add_spi_imx0(&spi0_pdata);
imx31_add_spi_imx1(&spi1_pdata);
- mc13783_dev.irq = gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
- spi_register_board_info(&mc13783_dev, 1);
regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+}
+
+static void __init mx31lilly_late_init(void)
+{
+ if (mx31lilly_baseboard == MX31LILLY_DB)
+ mx31lilly_db_init();
+
+ mc13783_dev.irq = gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
+ spi_register_board_info(&mc13783_dev, 1);
smsc91x_resources[1].start =
gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_0));
@@ -310,6 +333,7 @@ MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.init_time = mx31lilly_timer_init,
- .init_machine = mx31lilly_board_init,
+ .init_machine = mx31lilly_board_init,
+ .init_late = mx31lilly_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index 4822a1738de4..f033a57d5694 100644
--- a/arch/arm/mach-imx/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -52,6 +52,19 @@
*/
static unsigned int mx31lite_pins[] = {
+ /* UART1 */
+ MX31_PIN_CTS1__CTS1,
+ MX31_PIN_RTS1__RTS1,
+ MX31_PIN_TXD1__TXD1,
+ MX31_PIN_RXD1__RXD1,
+ /* SPI 0 */
+ MX31_PIN_CSPI1_SCLK__SCLK,
+ MX31_PIN_CSPI1_MOSI__MOSI,
+ MX31_PIN_CSPI1_MISO__MISO,
+ MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
+ MX31_PIN_CSPI1_SS0__SS0,
+ MX31_PIN_CSPI1_SS1__SS1,
+ MX31_PIN_CSPI1_SS2__SS2,
/* LAN9117 IRQ pin */
IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO),
/* SPI 1 */
@@ -64,6 +77,23 @@ static unsigned int mx31lite_pins[] = {
MX31_PIN_CSPI2_SS2__SS2,
};
+/* UART */
+static const struct imxuart_platform_data uart_pdata __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* SPI */
+static int spi0_internal_chipselect[] = {
+ MXC_SPI_CS(0),
+ MXC_SPI_CS(1),
+ MXC_SPI_CS(2),
+};
+
+static const struct spi_imx_master spi0_pdata __initconst = {
+ .chipselect = spi0_internal_chipselect,
+ .num_chipselect = ARRAY_SIZE(spi0_internal_chipselect),
+};
+
static const struct mxc_nand_platform_data
mx31lite_nand_board_info __initconst = {
.width = 1,
@@ -103,13 +133,13 @@ static struct platform_device smsc911x_device = {
* The MC13783 is the only hard-wired SPI device on the module.
*/
-static int spi_internal_chipselect[] = {
+static int spi1_internal_chipselect[] = {
MXC_SPI_CS(0),
};
static const struct spi_imx_master spi1_pdata __initconst = {
- .chipselect = spi_internal_chipselect,
- .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
+ .chipselect = spi1_internal_chipselect,
+ .num_chipselect = ARRAY_SIZE(spi1_internal_chipselect),
};
static struct mc13xxx_platform_data mc13783_pdata __initdata = {
@@ -200,8 +230,6 @@ static struct platform_device physmap_flash_device = {
.num_resources = 1,
};
-
-
/*
* This structure defines the MX31 memory map.
*/
@@ -233,29 +261,30 @@ static struct regulator_consumer_supply dummy_supplies[] = {
static void __init mx31lite_init(void)
{
- int ret;
-
imx31_soc_init();
- switch (mx31lite_baseboard) {
- case MX31LITE_NOBOARD:
- break;
- case MX31LITE_DB:
- mx31lite_db_init();
- break;
- default:
- printk(KERN_ERR "Illegal mx31lite_baseboard type %d\n",
- mx31lite_baseboard);
- }
-
mxc_iomux_setup_multiple_pins(mx31lite_pins, ARRAY_SIZE(mx31lite_pins),
"mx31lite");
+ imx31_add_imx_uart0(&uart_pdata);
+ imx31_add_spi_imx0(&spi0_pdata);
+
/* NOR and NAND flash */
platform_device_register(&physmap_flash_device);
imx31_add_mxc_nand(&mx31lite_nand_board_info);
imx31_add_spi_imx1(&spi1_pdata);
+
+ regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+}
+
+static void __init mx31lite_late(void)
+{
+ int ret;
+
+ if (mx31lite_baseboard == MX31LITE_DB)
+ mx31lite_db_init();
+
mc13783_spi_dev.irq = gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
spi_register_board_info(&mc13783_spi_dev, 1);
@@ -265,8 +294,6 @@ static void __init mx31lite_init(void)
if (usbh2_pdata.otg)
imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
- regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
-
/* SMSC9117 IRQ pin */
ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
if (ret)
@@ -294,5 +321,6 @@ MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
.init_irq = mx31_init_irq,
.init_time = mx31lite_timer_init,
.init_machine = mx31lite_init,
+ .init_late = mx31lite_late,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index 4f2d99888afd..cc867682520e 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -526,11 +526,9 @@ static void __init mx31moboard_init(void)
"moboard");
platform_add_devices(devices, ARRAY_SIZE(devices));
- gpio_led_register_device(-1, &mx31moboard_led_pdata);
imx31_add_imx2_wdt();
- moboard_uart0_init();
imx31_add_imx_uart0(&uart0_pdata);
imx31_add_imx_uart4(&uart4_pdata);
@@ -540,6 +538,19 @@ static void __init mx31moboard_init(void)
imx31_add_spi_imx1(&moboard_spi1_pdata);
imx31_add_spi_imx2(&moboard_spi2_pdata);
+ mx31moboard_init_cam();
+
+ imx31_add_imx_ssi(0, &moboard_ssi_pdata);
+
+ pm_power_off = mx31moboard_poweroff;
+}
+
+static void __init mx31moboard_late(void)
+{
+ gpio_led_register_device(-1, &mx31moboard_led_pdata);
+
+ moboard_uart0_init();
+
gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3), "pmic-irq");
gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3));
moboard_spi_board_info[0].irq =
@@ -549,18 +560,11 @@ static void __init mx31moboard_init(void)
imx31_add_mxc_mmc(0, &sdhc1_pdata);
- mx31moboard_init_cam();
-
usb_xcvr_reset();
-
moboard_usbh2_init();
- imx31_add_imx_ssi(0, &moboard_ssi_pdata);
-
imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
- pm_power_off = mx31moboard_poweroff;
-
switch (mx31moboard_baseboard) {
case MX31NOBOARD:
break;
@@ -601,5 +605,6 @@ MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
.init_irq = mx31_init_irq,
.init_time = mx31moboard_timer_init,
.init_machine = mx31moboard_init,
+ .init_late = mx31moboard_late,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c
index 7e315f00648d..c8c2e0956048 100644
--- a/arch/arm/mach-imx/mach-mx35_3ds.c
+++ b/arch/arm/mach-imx/mach-mx35_3ds.c
@@ -555,8 +555,6 @@ static const struct imxi2c_platform_data mx35_3ds_i2c0_data __initconst = {
*/
static void __init mx35_3ds_init(void)
{
- struct platform_device *imx35_fb_pdev;
-
imx35_soc_init();
mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
@@ -579,9 +577,6 @@ static void __init mx35_3ds_init(void)
imx35_add_mxc_nand(&mx35pdk_nand_board_info);
imx35_add_sdhci_esdhc_imx(0, NULL);
- if (mxc_expio_init(MX35_CS5_BASE_ADDR, IMX_GPIO_NR(1, 1)))
- pr_warn("Init of the debugboard failed, all "
- "devices on the debugboard are unusable.\n");
imx35_add_imx_i2c0(&mx35_3ds_i2c0_data);
i2c_register_board_info(
@@ -590,6 +585,15 @@ static void __init mx35_3ds_init(void)
imx35_add_ipu_core();
platform_device_register(&mx35_3ds_ov2640);
imx35_3ds_init_camera();
+}
+
+static void __init mx35_3ds_late_init(void)
+{
+ struct platform_device *imx35_fb_pdev;
+
+ if (mxc_expio_init(MX35_CS5_BASE_ADDR, IMX_GPIO_NR(1, 1)))
+ pr_warn("Init of the debugboard failed, all "
+ "devices on the debugboard are unusable.\n");
imx35_fb_pdev = imx35_add_mx3_sdc_fb(&mx3fb_pdata);
mx35_3ds_lcd.dev.parent = &imx35_fb_pdev->dev;
@@ -618,6 +622,7 @@ MACHINE_START(MX35_3DS, "Freescale MX35PDK")
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
+ .init_late = mx35_3ds_late_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c
index 2d1c50bd8bdf..ed675863655b 100644
--- a/arch/arm/mach-imx/mach-pca100.c
+++ b/arch/arm/mach-imx/mach-pca100.c
@@ -362,12 +362,8 @@ static void __init pca100_init(void)
if (ret)
printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret);
- imx27_add_imx_ssi(0, &pca100_ssi_pdata);
-
imx27_add_imx_uart0(&uart_pdata);
- imx27_add_mxc_mmc(1, &sdhc_pdata);
-
imx27_add_mxc_nand(&pca100_nand_board_info);
/* only the i2c master 1 is used on this CPU card */
@@ -382,6 +378,19 @@ static void __init pca100_init(void)
ARRAY_SIZE(pca100_spi_board_info));
imx27_add_spi_imx0(&pca100_spi0_data);
+ imx27_add_imx_fb(&pca100_fb_data);
+
+ imx27_add_fec(NULL);
+ imx27_add_imx2_wdt();
+ imx27_add_mxc_w1();
+}
+
+static void __init pca100_late_init(void)
+{
+ imx27_add_imx_ssi(0, &pca100_ssi_pdata);
+
+ imx27_add_mxc_mmc(1, &sdhc_pdata);
+
gpio_request(OTG_PHY_CS_GPIO, "usb-otg-cs");
gpio_direction_output(OTG_PHY_CS_GPIO, 1);
gpio_request(USBH2_PHY_CS_GPIO, "usb-host2-cs");
@@ -403,12 +412,6 @@ static void __init pca100_init(void)
if (usbh2_pdata.otg)
imx27_add_mxc_ehci_hs(2, &usbh2_pdata);
-
- imx27_add_imx_fb(&pca100_fb_data);
-
- imx27_add_fec(NULL);
- imx27_add_imx2_wdt();
- imx27_add_mxc_w1();
}
static void __init pca100_timer_init(void)
@@ -421,7 +424,8 @@ MACHINE_START(PCA100, "phyCARD-i.MX27")
.map_io = mx27_map_io,
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
- .init_machine = pca100_init,
+ .init_machine = pca100_init,
+ .init_late = pca100_late_init,
.init_time = pca100_timer_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c
index 6d879417db49..9f0f55b0422c 100644
--- a/arch/arm/mach-imx/mach-pcm037.c
+++ b/arch/arm/mach-imx/mach-pcm037.c
@@ -149,7 +149,7 @@ static unsigned int pcm037_pins[] = {
MX31_PIN_CONTRAST__CONTRAST,
MX31_PIN_D3_SPL__D3_SPL,
MX31_PIN_D3_CLS__D3_CLS,
- MX31_PIN_LCS0__GPI03_23,
+ MX31_PIN_LCS0__GPIO3_23,
/* CSI */
IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_GPIO),
MX31_PIN_CSI_D6__CSI_D6,
@@ -576,8 +576,6 @@ static struct regulator_consumer_supply dummy_supplies[] = {
*/
static void __init pcm037_init(void)
{
- int ret;
-
imx31_soc_init();
regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
@@ -621,20 +619,6 @@ static void __init pcm037_init(void)
imx31_add_mxc_w1();
- /* LAN9217 IRQ pin */
- ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq");
- if (ret)
- pr_warn("could not get LAN irq gpio\n");
- else {
- gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
- smsc911x_resources[1].start =
- gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
- smsc911x_resources[1].end =
- gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
- platform_device_register(&pcm037_eth);
- }
-
-
/* I2C adapters and devices */
i2c_register_board_info(1, pcm037_i2c_devices,
ARRAY_SIZE(pcm037_i2c_devices));
@@ -643,26 +627,9 @@ static void __init pcm037_init(void)
imx31_add_imx_i2c2(&pcm037_i2c2_data);
imx31_add_mxc_nand(&pcm037_nand_board_info);
- imx31_add_mxc_mmc(0, &sdhc_pdata);
imx31_add_ipu_core();
imx31_add_mx3_sdc_fb(&mx3fb_pdata);
- /* CSI */
- /* Camera power: default - off */
- ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), "mt9t031-power");
- if (!ret)
- gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), 1);
- else
- iclink_mt9t031.power = NULL;
-
- pcm037_init_camera();
-
- pcm970_sja1000_resources[1].start =
- gpio_to_irq(IOMUX_TO_GPIO(IOMUX_PIN(48, 105)));
- pcm970_sja1000_resources[1].end =
- gpio_to_irq(IOMUX_TO_GPIO(IOMUX_PIN(48, 105)));
- platform_device_register(&pcm970_sja1000);
-
if (otg_mode_host) {
otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
ULPI_OTG_DRVVBUS_EXT);
@@ -677,7 +644,6 @@ static void __init pcm037_init(void)
if (!otg_mode_host)
imx31_add_fsl_usb2_udc(&otg_device_pdata);
-
}
static void __init pcm037_timer_init(void)
@@ -694,6 +660,39 @@ static void __init pcm037_reserve(void)
static void __init pcm037_init_late(void)
{
+ int ret;
+
+ /* LAN9217 IRQ pin */
+ ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq");
+ if (!ret) {
+ gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
+ smsc911x_resources[1].start =
+ gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
+ smsc911x_resources[1].end =
+ gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
+ platform_device_register(&pcm037_eth);
+ } else {
+ pr_warn("could not get LAN irq gpio\n");
+ }
+
+ imx31_add_mxc_mmc(0, &sdhc_pdata);
+
+ /* CSI */
+ /* Camera power: default - off */
+ ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), "mt9t031-power");
+ if (!ret)
+ gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), 1);
+ else
+ iclink_mt9t031.power = NULL;
+
+ pcm037_init_camera();
+
+ pcm970_sja1000_resources[1].start =
+ gpio_to_irq(IOMUX_TO_GPIO(IOMUX_PIN(48, 105)));
+ pcm970_sja1000_resources[1].end =
+ gpio_to_irq(IOMUX_TO_GPIO(IOMUX_PIN(48, 105)));
+ platform_device_register(&pcm970_sja1000);
+
pcm037_eet_init_devices();
}
diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index e447e59c0604..78e2bf8dcd96 100644
--- a/arch/arm/mach-imx/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -363,7 +363,6 @@ static void __init pcm043_init(void)
imx35_add_imx_uart0(&uart_pdata);
imx35_add_mxc_nand(&pcm037_nand_board_info);
- imx35_add_imx_ssi(0, &pcm043_ssi_pdata);
imx35_add_imx_uart1(&uart_pdata);
@@ -387,6 +386,12 @@ static void __init pcm043_init(void)
imx35_add_fsl_usb2_udc(&otg_device_pdata);
imx35_add_flexcan1();
+}
+
+static void __init pcm043_late_init(void)
+{
+ imx35_add_imx_ssi(0, &pcm043_ssi_pdata);
+
imx35_add_sdhci_esdhc_imx(0, &sd1_pdata);
}
@@ -402,6 +407,7 @@ MACHINE_START(PCM043, "Phytec Phycore pcm043")
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = pcm043_timer_init,
- .init_machine = pcm043_init,
+ .init_machine = pcm043_init,
+ .init_late = pcm043_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c
index 34df64f133ed..8c2cbd693d21 100644
--- a/arch/arm/mach-imx/mach-qong.c
+++ b/arch/arm/mach-imx/mach-qong.c
@@ -251,7 +251,6 @@ static void __init qong_init(void)
mxc_init_imx_uart();
qong_init_nor_mtd();
- qong_init_fpga();
imx31_add_imx2_wdt();
}
@@ -268,5 +267,6 @@ MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
.init_irq = mx31_init_irq,
.init_time = qong_timer_init,
.init_machine = qong_init,
+ .init_late = qong_init_fpga,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-scb9328.c b/arch/arm/mach-imx/mach-scb9328.c
deleted file mode 100644
index 1f6bc3f7ae14..000000000000
--- a/arch/arm/mach-imx/mach-scb9328.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * linux/arch/arm/mach-mx1/mach-scb9328.c
- *
- * Copyright (c) 2004 Sascha Hauer <saschahauer@web.de>
- * Copyright (c) 2006-2008 Juergen Beisert <jbeisert@netscape.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/interrupt.h>
-#include <linux/dm9000.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-#include "devices-imx1.h"
-#include "hardware.h"
-#include "iomux-mx1.h"
-
-/*
- * This scb9328 has a 32MiB flash
- */
-static struct resource flash_resource = {
- .start = MX1_CS0_PHYS,
- .end = MX1_CS0_PHYS + (32 * 1024 * 1024) - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct physmap_flash_data scb_flash_data = {
- .width = 2,
-};
-
-static struct platform_device scb_flash_device = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &scb_flash_data,
- },
- .resource = &flash_resource,
- .num_resources = 1,
-};
-
-/*
- * scb9328 has a DM9000 network controller
- * connected to CS5, with 16 bit data path
- * and interrupt connected to GPIO 3
- */
-
-/*
- * internal datapath is fixed 16 bit
- */
-static struct dm9000_plat_data dm9000_platdata = {
- .flags = DM9000_PLATF_16BITONLY,
-};
-
-/*
- * the DM9000 drivers wants two defined address spaces
- * to gain access to address latch registers and the data path.
- */
-static struct resource dm9000x_resources[] = {
- {
- .name = "address area",
- .start = MX1_CS5_PHYS,
- .end = MX1_CS5_PHYS + 1,
- .flags = IORESOURCE_MEM, /* address access */
- }, {
- .name = "data area",
- .start = MX1_CS5_PHYS + 4,
- .end = MX1_CS5_PHYS + 5,
- .flags = IORESOURCE_MEM, /* data access */
- }, {
- /* irq number is run-time assigned */
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct platform_device dm9000x_device = {
- .name = "dm9000",
- .id = 0,
- .num_resources = ARRAY_SIZE(dm9000x_resources),
- .resource = dm9000x_resources,
- .dev = {
- .platform_data = &dm9000_platdata,
- }
-};
-
-static const int mxc_uart1_pins[] = {
- PC9_PF_UART1_CTS,
- PC10_PF_UART1_RTS,
- PC11_PF_UART1_TXD,
- PC12_PF_UART1_RXD,
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static struct platform_device *devices[] __initdata = {
- &scb_flash_device,
- &dm9000x_device,
-};
-
-/*
- * scb9328_init - Init the CPU card itself
- */
-static void __init scb9328_init(void)
-{
- imx1_soc_init();
-
- mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
- ARRAY_SIZE(mxc_uart1_pins), "UART1");
-
- imx1_add_imx_uart0(&uart_pdata);
-
- printk(KERN_INFO"Scb9328: Adding devices\n");
- dm9000x_resources[2].start = gpio_to_irq(IMX_GPIO_NR(3, 3));
- dm9000x_resources[2].end = gpio_to_irq(IMX_GPIO_NR(3, 3));
- platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-static void __init scb9328_timer_init(void)
-{
- mx1_clocks_init(32000);
-}
-
-MACHINE_START(SCB9328, "Synertronixx scb9328")
- /* Sascha Hauer */
- .atag_offset = 100,
- .map_io = mx1_map_io,
- .init_early = imx1_init_early,
- .init_irq = mx1_init_irq,
- .init_time = scb9328_timer_init,
- .init_machine = scb9328_init,
- .restart = mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c
index 27a8f7e3ec08..5ff154c9a086 100644
--- a/arch/arm/mach-imx/mach-vpr200.c
+++ b/arch/arm/mach-imx/mach-vpr200.c
@@ -268,6 +268,22 @@ static void __init vpr200_board_init(void)
imx35_add_fec(NULL);
imx35_add_imx2_wdt();
+
+ imx35_add_imx_uart0(NULL);
+ imx35_add_imx_uart2(NULL);
+
+ imx35_add_ipu_core();
+ imx35_add_mx3_sdc_fb(&mx3fb_pdata);
+
+ imx35_add_fsl_usb2_udc(&otg_device_pdata);
+ imx35_add_mxc_ehci_hs(&usb_host_pdata);
+
+ imx35_add_mxc_nand(&vpr200_nand_board_info);
+ imx35_add_sdhci_esdhc_imx(0, NULL);
+}
+
+static void __init vpr200_late_init(void)
+{
imx_add_gpio_keys(&vpr200_gpio_keys_data);
platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -282,18 +298,6 @@ static void __init vpr200_board_init(void)
else
gpio_direction_input(GPIO_PMIC_INT);
- imx35_add_imx_uart0(NULL);
- imx35_add_imx_uart2(NULL);
-
- imx35_add_ipu_core();
- imx35_add_mx3_sdc_fb(&mx3fb_pdata);
-
- imx35_add_fsl_usb2_udc(&otg_device_pdata);
- imx35_add_mxc_ehci_hs(&usb_host_pdata);
-
- imx35_add_mxc_nand(&vpr200_nand_board_info);
- imx35_add_sdhci_esdhc_imx(0, NULL);
-
vpr200_i2c_devices[1].irq = gpio_to_irq(GPIO_PMIC_INT);
i2c_register_board_info(0, vpr200_i2c_devices,
ARRAY_SIZE(vpr200_i2c_devices));
@@ -313,5 +317,6 @@ MACHINE_START(VPR200, "VPR200")
.init_irq = mx35_init_irq,
.init_time = vpr200_timer_init,
.init_machine = vpr200_board_init,
+ .init_late = vpr200_late_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c
deleted file mode 100644
index 9a42f19be81e..000000000000
--- a/arch/arm/mach-imx/mm-imx1.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * author: Sascha Hauer
- * Created: april 20th, 2004
- * Copyright: Synertronixx GmbH
- *
- * Common code for i.MX1 machines
- *
- * This program is free software; 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/init.h>
-#include <linux/io.h>
-#include <linux/pinctrl/machine.h>
-
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "devices/devices-common.h"
-#include "hardware.h"
-#include "iomux-v1.h"
-
-static struct map_desc imx_io_desc[] __initdata = {
- imx_map_entry(MX1, IO, MT_DEVICE),
-};
-
-void __init mx1_map_io(void)
-{
- iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
-}
-
-void __init imx1_init_early(void)
-{
- mxc_set_cpu_type(MXC_CPU_MX1);
- imx_iomuxv1_init(MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR),
- MX1_NUM_GPIO_PORT);
-}
-
-void __init mx1_init_irq(void)
-{
- mxc_init_irq(MX1_IO_ADDRESS(MX1_AVIC_BASE_ADDR));
-}
-
-void __init imx1_soc_init(void)
-{
- imx1_reset_init(MX1_IO_ADDRESS(MX1_WDT_BASE_ADDR));
- mxc_device_init();
-
- mxc_register_gpio("imx1-gpio", 0, MX1_GPIO1_BASE_ADDR, SZ_256,
- MX1_GPIO_INT_PORTA, 0);
- mxc_register_gpio("imx1-gpio", 1, MX1_GPIO2_BASE_ADDR, SZ_256,
- MX1_GPIO_INT_PORTB, 0);
- mxc_register_gpio("imx1-gpio", 2, MX1_GPIO3_BASE_ADDR, SZ_256,
- MX1_GPIO_INT_PORTC, 0);
- mxc_register_gpio("imx1-gpio", 3, MX1_GPIO4_BASE_ADDR, SZ_256,
- MX1_GPIO_INT_PORTD, 0);
- imx_add_imx_dma("imx1-dma", MX1_DMA_BASE_ADDR,
- MX1_DMA_INT, MX1_DMA_ERR);
- pinctrl_provide_dummies();
-}
diff --git a/arch/arm/mach-imx/mx1.h b/arch/arm/mach-imx/mx1.h
deleted file mode 100644
index 45bd31cc34d6..000000000000
--- a/arch/arm/mach-imx/mx1.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 1997,1998 Russell King
- * Copyright (C) 1999 ARM Limited
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __MACH_MX1_H__
-#define __MACH_MX1_H__
-
-/*
- * Memory map
- */
-#define MX1_IO_BASE_ADDR 0x00200000
-#define MX1_IO_SIZE SZ_1M
-
-#define MX1_CS0_PHYS 0x10000000
-#define MX1_CS0_SIZE 0x02000000
-
-#define MX1_CS1_PHYS 0x12000000
-#define MX1_CS1_SIZE 0x01000000
-
-#define MX1_CS2_PHYS 0x13000000
-#define MX1_CS2_SIZE 0x01000000
-
-#define MX1_CS3_PHYS 0x14000000
-#define MX1_CS3_SIZE 0x01000000
-
-#define MX1_CS4_PHYS 0x15000000
-#define MX1_CS4_SIZE 0x01000000
-
-#define MX1_CS5_PHYS 0x16000000
-#define MX1_CS5_SIZE 0x01000000
-
-/*
- * Register BASEs, based on OFFSETs
- */
-#define MX1_AIPI1_BASE_ADDR (0x00000 + MX1_IO_BASE_ADDR)
-#define MX1_WDT_BASE_ADDR (0x01000 + MX1_IO_BASE_ADDR)
-#define MX1_TIM1_BASE_ADDR (0x02000 + MX1_IO_BASE_ADDR)
-#define MX1_TIM2_BASE_ADDR (0x03000 + MX1_IO_BASE_ADDR)
-#define MX1_RTC_BASE_ADDR (0x04000 + MX1_IO_BASE_ADDR)
-#define MX1_LCDC_BASE_ADDR (0x05000 + MX1_IO_BASE_ADDR)
-#define MX1_UART1_BASE_ADDR (0x06000 + MX1_IO_BASE_ADDR)
-#define MX1_UART2_BASE_ADDR (0x07000 + MX1_IO_BASE_ADDR)
-#define MX1_PWM_BASE_ADDR (0x08000 + MX1_IO_BASE_ADDR)
-#define MX1_DMA_BASE_ADDR (0x09000 + MX1_IO_BASE_ADDR)
-#define MX1_AIPI2_BASE_ADDR (0x10000 + MX1_IO_BASE_ADDR)
-#define MX1_SIM_BASE_ADDR (0x11000 + MX1_IO_BASE_ADDR)
-#define MX1_USBD_BASE_ADDR (0x12000 + MX1_IO_BASE_ADDR)
-#define MX1_CSPI1_BASE_ADDR (0x13000 + MX1_IO_BASE_ADDR)
-#define MX1_MMC_BASE_ADDR (0x14000 + MX1_IO_BASE_ADDR)
-#define MX1_ASP_BASE_ADDR (0x15000 + MX1_IO_BASE_ADDR)
-#define MX1_BTA_BASE_ADDR (0x16000 + MX1_IO_BASE_ADDR)
-#define MX1_I2C_BASE_ADDR (0x17000 + MX1_IO_BASE_ADDR)
-#define MX1_SSI_BASE_ADDR (0x18000 + MX1_IO_BASE_ADDR)
-#define MX1_CSPI2_BASE_ADDR (0x19000 + MX1_IO_BASE_ADDR)
-#define MX1_MSHC_BASE_ADDR (0x1A000 + MX1_IO_BASE_ADDR)
-#define MX1_CCM_BASE_ADDR (0x1B000 + MX1_IO_BASE_ADDR)
-#define MX1_SCM_BASE_ADDR (0x1B804 + MX1_IO_BASE_ADDR)
-#define MX1_GPIO_BASE_ADDR (0x1C000 + MX1_IO_BASE_ADDR)
-#define MX1_GPIO1_BASE_ADDR (0x1C000 + MX1_IO_BASE_ADDR)
-#define MX1_GPIO2_BASE_ADDR (0x1C100 + MX1_IO_BASE_ADDR)
-#define MX1_GPIO3_BASE_ADDR (0x1C200 + MX1_IO_BASE_ADDR)
-#define MX1_GPIO4_BASE_ADDR (0x1C300 + MX1_IO_BASE_ADDR)
-#define MX1_EIM_BASE_ADDR (0x20000 + MX1_IO_BASE_ADDR)
-#define MX1_SDRAMC_BASE_ADDR (0x21000 + MX1_IO_BASE_ADDR)
-#define MX1_MMA_BASE_ADDR (0x22000 + MX1_IO_BASE_ADDR)
-#define MX1_AVIC_BASE_ADDR (0x23000 + MX1_IO_BASE_ADDR)
-#define MX1_CSI_BASE_ADDR (0x24000 + MX1_IO_BASE_ADDR)
-
-/* macro to get at IO space when running virtually */
-#define MX1_IO_P2V(x) IMX_IO_P2V(x)
-#define MX1_IO_ADDRESS(x) IOMEM(MX1_IO_P2V(x))
-
-/* fixed interrput numbers */
-#include <asm/irq.h>
-#define MX1_INT_SOFTINT (NR_IRQS_LEGACY + 0)
-#define MX1_INT_CSI (NR_IRQS_LEGACY + 6)
-#define MX1_DSPA_MAC_INT (NR_IRQS_LEGACY + 7)
-#define MX1_DSPA_INT (NR_IRQS_LEGACY + 8)
-#define MX1_COMP_INT (NR_IRQS_LEGACY + 9)
-#define MX1_MSHC_XINT (NR_IRQS_LEGACY + 10)
-#define MX1_GPIO_INT_PORTA (NR_IRQS_LEGACY + 11)
-#define MX1_GPIO_INT_PORTB (NR_IRQS_LEGACY + 12)
-#define MX1_GPIO_INT_PORTC (NR_IRQS_LEGACY + 13)
-#define MX1_INT_LCDC (NR_IRQS_LEGACY + 14)
-#define MX1_SIM_INT (NR_IRQS_LEGACY + 15)
-#define MX1_SIM_DATA_INT (NR_IRQS_LEGACY + 16)
-#define MX1_RTC_INT (NR_IRQS_LEGACY + 17)
-#define MX1_RTC_SAMINT (NR_IRQS_LEGACY + 18)
-#define MX1_INT_UART2PFERR (NR_IRQS_LEGACY + 19)
-#define MX1_INT_UART2RTS (NR_IRQS_LEGACY + 20)
-#define MX1_INT_UART2DTR (NR_IRQS_LEGACY + 21)
-#define MX1_INT_UART2UARTC (NR_IRQS_LEGACY + 22)
-#define MX1_INT_UART2TX (NR_IRQS_LEGACY + 23)
-#define MX1_INT_UART2RX (NR_IRQS_LEGACY + 24)
-#define MX1_INT_UART1PFERR (NR_IRQS_LEGACY + 25)
-#define MX1_INT_UART1RTS (NR_IRQS_LEGACY + 26)
-#define MX1_INT_UART1DTR (NR_IRQS_LEGACY + 27)
-#define MX1_INT_UART1UARTC (NR_IRQS_LEGACY + 28)
-#define MX1_INT_UART1TX (NR_IRQS_LEGACY + 29)
-#define MX1_INT_UART1RX (NR_IRQS_LEGACY + 30)
-#define MX1_VOICE_DAC_INT (NR_IRQS_LEGACY + 31)
-#define MX1_VOICE_ADC_INT (NR_IRQS_LEGACY + 32)
-#define MX1_PEN_DATA_INT (NR_IRQS_LEGACY + 33)
-#define MX1_PWM_INT (NR_IRQS_LEGACY + 34)
-#define MX1_SDHC_INT (NR_IRQS_LEGACY + 35)
-#define MX1_INT_I2C (NR_IRQS_LEGACY + 39)
-#define MX1_INT_CSPI2 (NR_IRQS_LEGACY + 40)
-#define MX1_INT_CSPI1 (NR_IRQS_LEGACY + 41)
-#define MX1_SSI_TX_INT (NR_IRQS_LEGACY + 42)
-#define MX1_SSI_TX_ERR_INT (NR_IRQS_LEGACY + 43)
-#define MX1_SSI_RX_INT (NR_IRQS_LEGACY + 44)
-#define MX1_SSI_RX_ERR_INT (NR_IRQS_LEGACY + 45)
-#define MX1_TOUCH_INT (NR_IRQS_LEGACY + 46)
-#define MX1_INT_USBD0 (NR_IRQS_LEGACY + 47)
-#define MX1_INT_USBD1 (NR_IRQS_LEGACY + 48)
-#define MX1_INT_USBD2 (NR_IRQS_LEGACY + 49)
-#define MX1_INT_USBD3 (NR_IRQS_LEGACY + 50)
-#define MX1_INT_USBD4 (NR_IRQS_LEGACY + 51)
-#define MX1_INT_USBD5 (NR_IRQS_LEGACY + 52)
-#define MX1_INT_USBD6 (NR_IRQS_LEGACY + 53)
-#define MX1_BTSYS_INT (NR_IRQS_LEGACY + 55)
-#define MX1_BTTIM_INT (NR_IRQS_LEGACY + 56)
-#define MX1_BTWUI_INT (NR_IRQS_LEGACY + 57)
-#define MX1_TIM2_INT (NR_IRQS_LEGACY + 58)
-#define MX1_TIM1_INT (NR_IRQS_LEGACY + 59)
-#define MX1_DMA_ERR (NR_IRQS_LEGACY + 60)
-#define MX1_DMA_INT (NR_IRQS_LEGACY + 61)
-#define MX1_GPIO_INT_PORTD (NR_IRQS_LEGACY + 62)
-#define MX1_WDT_INT (NR_IRQS_LEGACY + 63)
-
-/* DMA */
-#define MX1_DMA_REQ_UART3_T 2
-#define MX1_DMA_REQ_UART3_R 3
-#define MX1_DMA_REQ_SSI2_T 4
-#define MX1_DMA_REQ_SSI2_R 5
-#define MX1_DMA_REQ_CSI_STAT 6
-#define MX1_DMA_REQ_CSI_R 7
-#define MX1_DMA_REQ_MSHC 8
-#define MX1_DMA_REQ_DSPA_DCT_DOUT 9
-#define MX1_DMA_REQ_DSPA_DCT_DIN 10
-#define MX1_DMA_REQ_DSPA_MAC 11
-#define MX1_DMA_REQ_EXT 12
-#define MX1_DMA_REQ_SDHC 13
-#define MX1_DMA_REQ_SPI1_R 14
-#define MX1_DMA_REQ_SPI1_T 15
-#define MX1_DMA_REQ_SSI_T 16
-#define MX1_DMA_REQ_SSI_R 17
-#define MX1_DMA_REQ_ASP_DAC 18
-#define MX1_DMA_REQ_ASP_ADC 19
-#define MX1_DMA_REQ_USP_EP(x) (20 + (x))
-#define MX1_DMA_REQ_SPI2_R 26
-#define MX1_DMA_REQ_SPI2_T 27
-#define MX1_DMA_REQ_UART2_T 28
-#define MX1_DMA_REQ_UART2_R 29
-#define MX1_DMA_REQ_UART1_T 30
-#define MX1_DMA_REQ_UART1_R 31
-
-/*
- * This doesn't depend on IMX_NEEDS_DEPRECATED_SYMBOLS
- * to not break drivers/usb/gadget/imx_udc. Should go
- * away after this driver uses the new name.
- */
-#define USBD_INT0 MX1_INT_USBD0
-
-#endif /* ifndef __MACH_MX1_H__ */
diff --git a/arch/arm/mach-imx/mx31lilly-db.c b/arch/arm/mach-imx/mx31lilly-db.c
index 649fe49ce85e..231f900a1de7 100644
--- a/arch/arm/mach-imx/mx31lilly-db.c
+++ b/arch/arm/mach-imx/mx31lilly-db.c
@@ -43,18 +43,6 @@
*/
static unsigned int lilly_db_board_pins[] __initdata = {
- MX31_PIN_CTS1__CTS1,
- MX31_PIN_RTS1__RTS1,
- MX31_PIN_TXD1__TXD1,
- MX31_PIN_RXD1__RXD1,
- MX31_PIN_CTS2__CTS2,
- MX31_PIN_RTS2__RTS2,
- MX31_PIN_TXD2__TXD2,
- MX31_PIN_RXD2__RXD2,
- MX31_PIN_CSPI3_MOSI__RXD3,
- MX31_PIN_CSPI3_MISO__TXD3,
- MX31_PIN_CSPI3_SCLK__RTS3,
- MX31_PIN_CSPI3_SPI_RDY__CTS3,
MX31_PIN_SD1_DATA3__SD1_DATA3,
MX31_PIN_SD1_DATA2__SD1_DATA2,
MX31_PIN_SD1_DATA1__SD1_DATA1,
@@ -86,11 +74,6 @@ static unsigned int lilly_db_board_pins[] __initdata = {
MX31_PIN_CONTRAST__CONTRAST,
};
-/* UART */
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
/* MMC support */
static int mxc_mmc1_get_ro(struct device *dev)
@@ -203,9 +186,6 @@ void __init mx31lilly_db_init(void)
mxc_iomux_setup_multiple_pins(lilly_db_board_pins,
ARRAY_SIZE(lilly_db_board_pins),
"development board pins");
- imx31_add_imx_uart0(&uart_pdata);
- imx31_add_imx_uart1(&uart_pdata);
- imx31_add_imx_uart2(&uart_pdata);
imx31_add_mxc_mmc(0, &mmc_pdata);
mx31lilly_init_fb();
}
diff --git a/arch/arm/mach-imx/mx31lite-db.c b/arch/arm/mach-imx/mx31lite-db.c
index 5a160b7e4fce..c66a006bf2fd 100644
--- a/arch/arm/mach-imx/mx31lite-db.c
+++ b/arch/arm/mach-imx/mx31lite-db.c
@@ -45,19 +45,6 @@
*/
static unsigned int litekit_db_board_pins[] __initdata = {
- /* UART1 */
- MX31_PIN_CTS1__CTS1,
- MX31_PIN_RTS1__RTS1,
- MX31_PIN_TXD1__TXD1,
- MX31_PIN_RXD1__RXD1,
- /* SPI 0 */
- MX31_PIN_CSPI1_SCLK__SCLK,
- MX31_PIN_CSPI1_MOSI__MOSI,
- MX31_PIN_CSPI1_MISO__MISO,
- MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
- MX31_PIN_CSPI1_SS0__SS0,
- MX31_PIN_CSPI1_SS1__SS1,
- MX31_PIN_CSPI1_SS2__SS2,
/* SDHC1 */
MX31_PIN_SD1_DATA0__SD1_DATA0,
MX31_PIN_SD1_DATA1__SD1_DATA1,
@@ -67,11 +54,6 @@ static unsigned int litekit_db_board_pins[] __initdata = {
MX31_PIN_SD1_CMD__SD1_CMD,
};
-/* UART */
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
/* MMC */
static int gpio_det, gpio_wp;
@@ -146,19 +128,6 @@ static const struct imxmmc_platform_data mmc_pdata __initconst = {
.exit = mxc_mmc1_exit,
};
-/* SPI */
-
-static int spi_internal_chipselect[] = {
- MXC_SPI_CS(0),
- MXC_SPI_CS(1),
- MXC_SPI_CS(2),
-};
-
-static const struct spi_imx_master spi0_pdata __initconst = {
- .chipselect = spi_internal_chipselect,
- .num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
-};
-
/* GPIO LEDs */
static const struct gpio_led litekit_leds[] __initconst = {
@@ -187,9 +156,7 @@ void __init mx31lite_db_init(void)
mxc_iomux_setup_multiple_pins(litekit_db_board_pins,
ARRAY_SIZE(litekit_db_board_pins),
"development board pins");
- imx31_add_imx_uart0(&uart_pdata);
imx31_add_mxc_mmc(0, &mmc_pdata);
- imx31_add_spi_imx0(&spi0_pdata);
gpio_led_register_device(-1, &litekit_led_platform_data);
imx31_add_imx2_wdt();
imx31_add_mxc_rtc();
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index fe708e26d021..1515e498d348 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -217,7 +217,7 @@ struct imx6_cpu_pm_info {
u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */
} __aligned(8);
-void imx6q_set_int_mem_clk_lpm(bool enable)
+void imx6_set_int_mem_clk_lpm(bool enable)
{
u32 val = readl_relaxed(ccm_base + CGPR);
@@ -367,7 +367,7 @@ static int imx6q_pm_enter(suspend_state_t state)
switch (state) {
case PM_SUSPEND_STANDBY:
imx6_set_lpm(STOP_POWER_ON);
- imx6q_set_int_mem_clk_lpm(true);
+ imx6_set_int_mem_clk_lpm(true);
imx_gpc_pre_suspend(false);
if (cpu_is_imx6sl())
imx6sl_set_wait_clk(true);
@@ -380,7 +380,7 @@ static int imx6q_pm_enter(suspend_state_t state)
break;
case PM_SUSPEND_MEM:
imx6_set_lpm(STOP_POWER_OFF);
- imx6q_set_int_mem_clk_lpm(false);
+ imx6_set_int_mem_clk_lpm(false);
imx6q_enable_wb(true);
/*
* For suspend into ocram, asm code already take care of
@@ -398,7 +398,7 @@ static int imx6q_pm_enter(suspend_state_t state)
imx_gpc_post_resume();
imx6_enable_rbc(false);
imx6q_enable_wb(false);
- imx6q_set_int_mem_clk_lpm(true);
+ imx6_set_int_mem_clk_lpm(true);
imx6_set_lpm(WAIT_CLOCKED);
break;
default:
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index 599f973e10d8..cefe44f6889b 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -21,7 +21,6 @@ if ARCH_INTEGRATOR
config ARCH_INTEGRATOR_AP
bool "Support Integrator/AP and Integrator/PP2 platforms"
select INTEGRATOR_AP_TIMER
- select MIGHT_HAVE_PCI
select SERIAL_AMBA_PL010 if TTY
select SERIAL_AMBA_PL010_CONSOLE if TTY
select SOC_BUS
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index c7bb83205f5b..23b98fd414bf 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -17,33 +17,19 @@
* 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/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/string.h>
#include <linux/syscore_ops.h>
#include <linux/amba/bus.h>
-#include <linux/amba/kmi.h>
#include <linux/io.h>
#include <linux/irqchip.h>
-#include <linux/platform_data/clk-integrator.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <linux/stat.h>
#include <linux/termios.h>
-#include <asm/setup.h>
-#include <asm/param.h> /* HZ */
-#include <asm/mach-types.h>
-
#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
#include <asm/mach/map.h>
-#include <asm/mach/time.h>
#include "hardware.h"
#include "cm.h"
@@ -68,14 +54,8 @@ static void __iomem *ebi_base;
/*
* Logical Physical
- * ef000000 Cache flush
- * f1100000 11000000 System controller registers
- * f1300000 13000000 Counter/Timer
* f1400000 14000000 Interrupt controller
* f1600000 16000000 UART 0
- * f1700000 17000000 UART 1
- * f1a00000 1a000000 Debug LEDs
- * f1b00000 1b000000 GPIO
*/
static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
@@ -89,16 +69,6 @@ static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
.pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),
.length = SZ_4K,
.type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(INTEGRATOR_AP_GPIO_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_AP_GPIO_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
}
};
@@ -196,16 +166,10 @@ static void __init ap_init_irq_of(void)
/* For the Device Tree, add in the UART callbacks as AUXDATA */
static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE,
- "rtc", NULL),
OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
"uart0", &ap_uart_data),
OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
"uart1", &ap_uart_data),
- OF_DEV_AUXDATA("arm,primecell", KMI0_BASE,
- "kmi0", NULL),
- OF_DEV_AUXDATA("arm,primecell", KMI1_BASE,
- "kmi1", NULL),
{ /* sentinel */ },
};
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 825298349bf5..772a7cf2010e 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -7,67 +7,40 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*/
-#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/kmi.h>
-#include <linux/amba/clcd.h>
-#include <linux/platform_data/video-clcd-versatile.h>
#include <linux/amba/mmci.h>
#include <linux/io.h>
#include <linux/irqchip.h>
-#include <linux/gfp.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/sched_clock.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
#include <asm/mach/map.h>
-#include <asm/mach/time.h>
#include "hardware.h"
#include "cm.h"
#include "common.h"
+/* Base address to the core module header */
+static struct regmap *cm_map;
/* Base address to the CP controller */
static void __iomem *intcp_con_base;
-#define INTCP_PA_CLCD_BASE 0xc0000000
+#define CM_COUNTER_OFFSET 0x28
/*
* Logical Physical
- * f1000000 10000000 Core module registers
- * f1300000 13000000 Counter/Timer
* f1400000 14000000 Interrupt controller
* f1600000 16000000 UART 0
- * f1700000 17000000 UART 1
- * f1a00000 1a000000 Debug LEDs
- * fc900000 c9000000 GPIO
* fca00000 ca000000 SIC
*/
static struct map_desc intcp_io_desc[] __initdata __maybe_unused = {
{
- .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
.length = SZ_4K,
@@ -78,16 +51,6 @@ static struct map_desc intcp_io_desc[] __initdata __maybe_unused = {
.length = SZ_4K,
.type = MT_DEVICE
}, {
- .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = IO_ADDRESS(INTEGRATOR_CP_GPIO_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_CP_GPIO_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
.virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE),
.length = SZ_4K,
@@ -121,66 +84,20 @@ static struct mmci_platform_data mmc_data = {
.gpio_cd = -1,
};
-/*
- * CLCD support
- */
-/*
- * Ensure VGA is selected.
- */
-static void cp_clcd_enable(struct clcd_fb *fb)
-{
- struct fb_var_screeninfo *var = &fb->fb.var;
- u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2
- | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1;
-
- if (var->bits_per_pixel <= 8 ||
- (var->bits_per_pixel == 16 && var->green.length == 5))
- /* Pseudocolor, RGB555, BGR555 */
- val |= CM_CTRL_LCDMUXSEL_VGA555_TFT555;
- else if (fb->fb.var.bits_per_pixel <= 16)
- /* truecolor RGB565 */
- val |= CM_CTRL_LCDMUXSEL_VGA565_TFT555;
- else
- val = 0; /* no idea for this, don't trust the docs */
-
- cm_control(CM_CTRL_LCDMUXSEL_MASK|
- CM_CTRL_LCDEN0|
- CM_CTRL_LCDEN1|
- CM_CTRL_STATIC1|
- CM_CTRL_STATIC2|
- CM_CTRL_STATIC|
- CM_CTRL_n24BITEN, val);
-}
-
-static int cp_clcd_setup(struct clcd_fb *fb)
-{
- fb->panel = versatile_clcd_get_panel("VGA");
- if (!fb->panel)
- return -EINVAL;
-
- return versatile_clcd_setup_dma(fb, SZ_1M);
-}
-
-static struct clcd_board clcd_data = {
- .name = "Integrator/CP",
- .caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 | CLCD_CAP_888,
- .check = clcdfb_check,
- .decode = clcdfb_decode,
- .enable = cp_clcd_enable,
- .setup = cp_clcd_setup,
- .mmap = versatile_clcd_mmap_dma,
- .remove = versatile_clcd_remove_dma,
-};
-
-#define REFCOUNTER (__io_address(INTEGRATOR_HDR_BASE) + 0x28)
-
static u64 notrace intcp_read_sched_clock(void)
{
- return readl(REFCOUNTER);
+ unsigned int val;
+
+ /* MMIO so discard return code */
+ regmap_read(cm_map, CM_COUNTER_OFFSET, &val);
+ return val;
}
static void __init intcp_init_early(void)
{
+ cm_map = syscon_regmap_lookup_by_compatible("arm,core-module-integrator");
+ if (IS_ERR(cm_map))
+ return;
sched_clock_register(intcp_read_sched_clock, 32, 24000000);
}
@@ -195,22 +112,8 @@ static void __init intcp_init_irq_of(void)
* and enforce the bus names since these are used for clock lookups.
*/
static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE,
- "rtc", NULL),
- OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
- "uart0", NULL),
- OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
- "uart1", NULL),
- OF_DEV_AUXDATA("arm,primecell", KMI0_BASE,
- "kmi0", NULL),
- OF_DEV_AUXDATA("arm,primecell", KMI1_BASE,
- "kmi1", NULL),
OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE,
"mmci", &mmc_data),
- OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_AACI_BASE,
- "aaci", &mmc_data),
- OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE,
- "clcd", &clcd_data),
{ /* sentinel */ },
};
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index 8ff61be1a29f..24bd64dabdfc 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -8,8 +8,6 @@ config ARCH_KEYSTONE
select COMMON_CLK_KEYSTONE
select ARCH_SUPPORTS_BIG_ENDIAN
select ZONE_DMA if ARM_LPAE
- select MIGHT_HAVE_PCI
- select PCI_DOMAINS if PCI
select PINCTRL
help
Support for boards based on the Texas Instruments Keystone family of
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 6af5430d0d97..f72e1e9f5fc5 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -219,7 +219,6 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
{
orion_ge01_init(eth_data,
GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
- NO_IRQ,
MV643XX_TX_CSUM_DEFAULT_LIMIT);
}
@@ -242,9 +241,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
eth_data->duplex = DUPLEX_FULL;
}
- orion_ge10_init(eth_data,
- GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM,
- NO_IRQ);
+ orion_ge10_init(eth_data, GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM);
}
@@ -266,9 +263,7 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
eth_data->duplex = DUPLEX_FULL;
}
- orion_ge11_init(eth_data,
- GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM,
- NO_IRQ);
+ orion_ge11_init(eth_data, GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM);
}
/*****************************************************************************
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index 0b7fe74ff46d..e4f21086b42b 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -268,80 +268,6 @@ static void __init apx4devkit_init(void)
apx4devkit_phy_fixup);
}
-#define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0)
-#define ENET0_MDIO__GPIO_4_1 MXS_GPIO_NR(4, 1)
-#define ENET0_RX_EN__GPIO_4_2 MXS_GPIO_NR(4, 2)
-#define ENET0_RXD0__GPIO_4_3 MXS_GPIO_NR(4, 3)
-#define ENET0_RXD1__GPIO_4_4 MXS_GPIO_NR(4, 4)
-#define ENET0_TX_EN__GPIO_4_6 MXS_GPIO_NR(4, 6)
-#define ENET0_TXD0__GPIO_4_7 MXS_GPIO_NR(4, 7)
-#define ENET0_TXD1__GPIO_4_8 MXS_GPIO_NR(4, 8)
-#define ENET_CLK__GPIO_4_16 MXS_GPIO_NR(4, 16)
-
-#define TX28_FEC_PHY_POWER MXS_GPIO_NR(3, 29)
-#define TX28_FEC_PHY_RESET MXS_GPIO_NR(4, 13)
-#define TX28_FEC_nINT MXS_GPIO_NR(4, 5)
-
-static const struct gpio const tx28_gpios[] __initconst = {
- { ENET0_MDC__GPIO_4_0, GPIOF_OUT_INIT_LOW, "GPIO_4_0" },
- { ENET0_MDIO__GPIO_4_1, GPIOF_OUT_INIT_LOW, "GPIO_4_1" },
- { ENET0_RX_EN__GPIO_4_2, GPIOF_OUT_INIT_LOW, "GPIO_4_2" },
- { ENET0_RXD0__GPIO_4_3, GPIOF_OUT_INIT_LOW, "GPIO_4_3" },
- { ENET0_RXD1__GPIO_4_4, GPIOF_OUT_INIT_LOW, "GPIO_4_4" },
- { ENET0_TX_EN__GPIO_4_6, GPIOF_OUT_INIT_LOW, "GPIO_4_6" },
- { ENET0_TXD0__GPIO_4_7, GPIOF_OUT_INIT_LOW, "GPIO_4_7" },
- { ENET0_TXD1__GPIO_4_8, GPIOF_OUT_INIT_LOW, "GPIO_4_8" },
- { ENET_CLK__GPIO_4_16, GPIOF_OUT_INIT_LOW, "GPIO_4_16" },
- { TX28_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" },
- { TX28_FEC_PHY_RESET, GPIOF_OUT_INIT_LOW, "fec-phy-reset" },
- { TX28_FEC_nINT, GPIOF_DIR_IN, "fec-int" },
-};
-
-static void __init tx28_post_init(void)
-{
- struct device_node *np;
- struct platform_device *pdev;
- struct pinctrl *pctl;
- int ret;
-
- enable_clk_enet_out();
-
- np = of_find_compatible_node(NULL, NULL, "fsl,imx28-fec");
- pdev = of_find_device_by_node(np);
- if (!pdev) {
- pr_err("%s: failed to find fec device\n", __func__);
- return;
- }
-
- pctl = pinctrl_get_select(&pdev->dev, "gpio_mode");
- if (IS_ERR(pctl)) {
- pr_err("%s: failed to get pinctrl state\n", __func__);
- return;
- }
-
- ret = gpio_request_array(tx28_gpios, ARRAY_SIZE(tx28_gpios));
- if (ret) {
- pr_err("%s: failed to request gpios: %d\n", __func__, ret);
- return;
- }
-
- /* Power up fec phy */
- gpio_set_value(TX28_FEC_PHY_POWER, 1);
- msleep(26); /* 25ms according to data sheet */
-
- /* Mode strap pins */
- gpio_set_value(ENET0_RX_EN__GPIO_4_2, 1);
- gpio_set_value(ENET0_RXD0__GPIO_4_3, 1);
- gpio_set_value(ENET0_RXD1__GPIO_4_4, 1);
-
- udelay(100); /* minimum assertion time for nRST */
-
- /* Deasserting FEC PHY RESET */
- gpio_set_value(TX28_FEC_PHY_RESET, 1);
-
- pinctrl_put(pctl);
-}
-
static void __init crystalfontz_init(void)
{
update_fec_mac_prop(OUI_CRYSTALFONTZ);
@@ -501,9 +427,6 @@ static void __init mxs_machine_init(void)
of_platform_default_populate(NULL, NULL, parent);
mxs_restart_init();
-
- if (of_machine_is_compatible("karo,tx28"))
- tx28_post_init();
}
#define MXS_CLKCTRL_RESET_CHIP (1 << 1)
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig
index b7e9801fdaa4..3ae45b8d7b0a 100644
--- a/arch/arm/mach-nomadik/Kconfig
+++ b/arch/arm/mach-nomadik/Kconfig
@@ -7,6 +7,7 @@ menuconfig ARCH_NOMADIK
select CLKSRC_NOMADIK_MTU_SCHED_CLOCK
select CPU_ARM926T
select GPIOLIB
+ select MFD_SYSCON
select MIGHT_HAVE_CACHE_L2X0
select PINCTRL
select PINCTRL_NOMADIK
diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c
index 7119ef28e0ad..357be2debc9d 100644
--- a/arch/arm/mach-omap1/board-h2-mmc.c
+++ b/arch/arm/mach-omap1/board-h2-mmc.c
@@ -19,7 +19,7 @@
#include "board-h2.h"
#include "mmc.h"
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
static int mmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index cd146ed0538d..675254ee4b1e 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -349,7 +349,7 @@ static struct omap_usb_config h2_usb_config __initdata = {
#if IS_ENABLED(CONFIG_USB_OMAP)
.hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */
/* .hmc_mode = 21,*/ /* 0:host(off) 1:dev(loopback) 2:host(loopback) */
-#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#elif IS_ENABLED(CONFIG_USB_OHCI_HCD)
/* needs OTG cable, or NONSTANDARD (B-to-MiniB) */
.hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */
#endif
diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c
index 43aab63cbc39..4f58bfa5e754 100644
--- a/arch/arm/mach-omap1/board-h3-mmc.c
+++ b/arch/arm/mach-omap1/board-h3-mmc.c
@@ -20,7 +20,7 @@
#include "board-h3.h"
#include "mmc.h"
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
static int mmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index f7c8c63dd532..e62f9d454f10 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -368,7 +368,7 @@ static struct omap_usb_config h3_usb_config __initdata = {
#if IS_ENABLED(CONFIG_USB_OMAP)
.hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */
-#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#elif IS_ENABLED(CONFIG_USB_OHCI_HCD)
/* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
.hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */
#endif
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index 9525ef9bc6c0..e424df901dbd 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -401,7 +401,7 @@ static struct platform_device lcd_device = {
};
/* MMC Card */
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
static struct omap_mmc_platform_data htc_mmc1_data = {
.nr_slots = 1,
.switch_slot = NULL,
@@ -586,7 +586,7 @@ static void __init htcherald_init(void)
omap_register_i2c_bus(1, 100, NULL, 0);
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
htc_mmc_data[0] = &htc_mmc1_data;
omap1_init_mmc(htc_mmc_data, 1);
#endif
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index ae90bd02b3bf..67e188271643 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -315,7 +315,7 @@ static struct omap_usb_config h2_usb_config __initdata = {
#if IS_ENABLED(CONFIG_USB_OMAP)
.hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */
/* .hmc_mode = 21,*/ /* 0:host(off) 1:dev(loopback) 2:host(loopback) */
-#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#elif IS_ENABLED(CONFIG_USB_OHCI_HCD)
/* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
.hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */
#endif
@@ -328,7 +328,7 @@ static struct omap_lcd_config innovator1610_lcd_config __initdata = {
};
#endif
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
static int mmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index dd3a3ad797ea..ee8d9f553db4 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -159,7 +159,7 @@ static struct omap_usb_config nokia770_usb_config __initdata = {
.extcon = "tahvo-usb",
};
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
#define NOKIA770_GPIO_MMC_POWER 41
#define NOKIA770_GPIO_MMC_SWITCH 23
@@ -216,7 +216,7 @@ static inline void nokia770_mmc_init(void)
}
#endif
-#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE)
+#if IS_ENABLED(CONFIG_I2C_CBUS_GPIO)
static struct i2c_cbus_platform_data nokia770_cbus_data = {
.clk_gpio = OMAP_MPUIO(9),
.dat_gpio = OMAP_MPUIO(10),
diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c
index a9373570bbb1..79f0af8bfae0 100644
--- a/arch/arm/mach-omap1/board-sx1-mmc.c
+++ b/arch/arm/mach-omap1/board-sx1-mmc.c
@@ -20,7 +20,7 @@
#include "mmc.h"
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
static int mmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 8c8be861fff2..baaf902b7016 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -33,7 +33,7 @@
#include "mmc.h"
#include "sram.h"
-#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_RTC_DRV_OMAP)
#define OMAP_RTC_BASE 0xfffb4800
@@ -72,7 +72,7 @@ static inline void omap_init_mbox(void) { }
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
int controller_nr)
@@ -230,7 +230,7 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
/*-------------------------------------------------------------------------*/
/* OMAP7xx SPI support */
-#if defined(CONFIG_SPI_OMAP_100K) || defined(CONFIG_SPI_OMAP_100K_MODULE)
+#if IS_ENABLED(CONFIG_SPI_OMAP_100K)
struct platform_device omap_spi1 = {
.name = "omap1_spi100k",
@@ -312,7 +312,7 @@ static inline void omap_init_sti(void) {}
* mcbsp1..3 = 5..7
*/
-#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE)
+#if IS_ENABLED(CONFIG_SPI_OMAP_UWIRE)
#define OMAP_UWIRE_BASE 0xfffb3000
@@ -418,7 +418,7 @@ static int __init omap1_init_devices(void)
}
arch_initcall(omap1_init_devices);
-#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+#if IS_ENABLED(CONFIG_OMAP_WATCHDOG)
static struct resource wdt_resources[] = {
{
diff --git a/arch/arm/mach-omap1/fb.c b/arch/arm/mach-omap1/fb.c
index c770d45c7226..ddab04087b7a 100644
--- a/arch/arm/mach-omap1/fb.c
+++ b/arch/arm/mach-omap1/fb.c
@@ -33,7 +33,7 @@
#include <asm/mach/map.h>
-#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_FB_OMAP)
static bool omapfb_lcd_configured;
static struct omapfb_platform_data omapfb_config;
diff --git a/arch/arm/mach-omap1/include/mach/usb.h b/arch/arm/mach-omap1/include/mach/usb.h
index 2c263051dc51..a7c5559caef2 100644
--- a/arch/arm/mach-omap1/include/mach/usb.h
+++ b/arch/arm/mach-omap1/include/mach/usb.h
@@ -12,7 +12,7 @@
void omap_otg_init(struct omap_usb_config *config);
-#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
+#if IS_ENABLED(CONFIG_USB)
void omap1_usb_init(struct omap_usb_config *pdata);
#else
static inline void omap1_usb_init(struct omap_usb_config *pdata)
diff --git a/arch/arm/mach-omap1/mmc.h b/arch/arm/mach-omap1/mmc.h
index 39c2b13de884..d7b46880e4ca 100644
--- a/arch/arm/mach-omap1/mmc.h
+++ b/arch/arm/mach-omap1/mmc.h
@@ -7,7 +7,7 @@
#define OMAP1_MMC1_BASE 0xfffb7800
#define OMAP1_MMC2_BASE 0xfffb7c00 /* omap16xx only */
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP)
void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
int nr_controllers);
#else
diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c
index 4118db50d5e8..2506e598a067 100644
--- a/arch/arm/mach-omap1/usb.c
+++ b/arch/arm/mach-omap1/usb.c
@@ -136,7 +136,7 @@ omap_otg_init(struct omap_usb_config *config)
}
#endif
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
if (config->otg || config->register_host) {
struct platform_device *ohci_device = config->ohci_device;
int status;
@@ -221,7 +221,7 @@ static inline void udc_device_init(struct omap_usb_config *pdata)
#endif
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;
@@ -612,7 +612,7 @@ static void __init omap_1510_usb_init(struct omap_usb_config *config)
}
#endif
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
if (config->register_host) {
int status;
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 5a0b380a8166..a9afeebd59f2 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -192,12 +192,6 @@ config MACH_OMAP2_TUSB6010
depends on ARCH_OMAP2 && SOC_OMAP2420
default y if MACH_NOKIA_N8X0
-config MACH_OMAP_LDP
- bool "OMAP3 LDP board"
- depends on ARCH_OMAP3
- default y
- select OMAP_PACKAGE_CBB
-
config MACH_OMAP3517EVM
bool "OMAP3517/ AM3517 EVM board"
depends on ARCH_OMAP3
@@ -222,12 +216,6 @@ config MACH_NOKIA_N8X0
select MACH_NOKIA_N810
select MACH_NOKIA_N810_WIMAX
-config MACH_NOKIA_RX51
- bool "Nokia N900 (RX-51) phone"
- depends on ARCH_OMAP3
- default y
- select OMAP_PACKAGE_CBB
-
config OMAP3_SDRC_AC_TIMING
bool "Enable SDRC AC timing register changes"
depends on ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index a7f2d051f524..5b37ec29996e 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -231,11 +231,7 @@ obj-$(CONFIG_SOC_OMAP2420) += msdi.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o pdata-quirks.o
-obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o
obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o
-obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o sdram-nokia.o
-obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-peripherals.o
-obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-video.o
# Platform specific device init code
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 70b21cc279ba..2188dc30e232 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -81,8 +81,7 @@ __init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
pr_err("Unable to register NOR device\n");
}
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
- defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
static struct omap_onenand_platform_data board_onenand_data = {
.dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
};
@@ -97,10 +96,9 @@ __init board_onenand_init(struct mtd_partition *onenand_parts,
gpmc_onenand_init(&board_onenand_data);
}
-#endif /* CONFIG_MTD_ONENAND_OMAP2 || CONFIG_MTD_ONENAND_OMAP2_MODULE */
+#endif /* IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2) */
-#if defined(CONFIG_MTD_NAND_OMAP2) || \
- defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
/* Note that all values in this struct are in nanoseconds */
struct gpmc_timings nand_default_timings[1] = {
@@ -144,7 +142,7 @@ __init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs,
board_nand_data.ecc_opt = OMAP_ECC_HAM1_CODE_SW;
gpmc_nand_init(&board_nand_data, gpmc_t);
}
-#endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */
+#endif /* IS_ENABLED(CONFIG_MTD_NAND_OMAP2) */
/**
* get_gpmc0_type - Reads the FPGA DIP_SWITCH_INPUT_REGISTER2 to get
diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h
index ea9aaebe11e7..8b39eec07318 100644
--- a/arch/arm/mach-omap2/board-flash.h
+++ b/arch/arm/mach-omap2/board-flash.h
@@ -23,10 +23,7 @@ struct flash_partitions {
int nr_parts;
};
-#if defined(CONFIG_MTD_NAND_OMAP2) || \
- defined(CONFIG_MTD_NAND_OMAP2_MODULE) || \
- defined(CONFIG_MTD_ONENAND_OMAP2) || \
- defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2) || IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
extern void board_flash_init(struct flash_partitions [],
char chip_sel[][GPMC_CS_NUM], int nand_type);
#else
@@ -36,8 +33,7 @@ static inline void board_flash_init(struct flash_partitions part[],
}
#endif
-#if defined(CONFIG_MTD_NAND_OMAP2) || \
- defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
extern void board_nand_init(struct mtd_partition *nand_parts,
u8 nr_parts, u8 cs, int nand_type, struct gpmc_timings *gpmc_t);
extern struct gpmc_timings nand_default_timings[];
@@ -49,8 +45,7 @@ static inline void board_nand_init(struct mtd_partition *nand_parts,
#define nand_default_timings NULL
#endif
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
- defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
extern void board_onenand_init(struct mtd_partition *nand_parts,
u8 nr_parts, u8 cs);
#else
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
deleted file mode 100644
index 390795b334c3..000000000000
--- a/arch/arm/mach-omap2/board-ldp.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-ldp.c
- *
- * Copyright (C) 2008 Texas Instruments Inc.
- * Nishant Kamat <nskamat@ti.com>
- *
- * Modified from mach-omap2/board-3430sdp.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/gpio_keys.h>
-#include <linux/workqueue.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-#include <linux/i2c/twl.h>
-#include <linux/io.h>
-#include <linux/smsc911x.h>
-#include <linux/mmc/host.h>
-#include <linux/usb/phy.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "gpmc.h"
-#include "gpmc-smsc911x.h"
-
-#include <linux/platform_data/omapdss.h>
-#include <video/omap-panel-data.h>
-
-#include "board-flash.h"
-#include "mux.h"
-#include "hsmmc.h"
-#include "control.h"
-#include "common-board-devices.h"
-#include "display.h"
-
-#define LDP_SMSC911X_CS 1
-#define LDP_SMSC911X_GPIO 152
-#define DEBUG_BASE 0x08000000
-#define LDP_ETHR_START DEBUG_BASE
-
-static uint32_t board_keymap[] = {
- KEY(0, 0, KEY_1),
- KEY(1, 0, KEY_2),
- KEY(2, 0, KEY_3),
- KEY(0, 1, KEY_4),
- KEY(1, 1, KEY_5),
- KEY(2, 1, KEY_6),
- KEY(3, 1, KEY_F5),
- KEY(0, 2, KEY_7),
- KEY(1, 2, KEY_8),
- KEY(2, 2, KEY_9),
- KEY(3, 2, KEY_F6),
- KEY(0, 3, KEY_F7),
- KEY(1, 3, KEY_0),
- KEY(2, 3, KEY_F8),
- PERSISTENT_KEY(4, 5),
- KEY(4, 4, KEY_VOLUMEUP),
- KEY(5, 5, KEY_VOLUMEDOWN),
- 0
-};
-
-static struct matrix_keymap_data board_map_data = {
- .keymap = board_keymap,
- .keymap_size = ARRAY_SIZE(board_keymap),
-};
-
-static struct twl4030_keypad_data ldp_kp_twl4030_data = {
- .keymap_data = &board_map_data,
- .rows = 6,
- .cols = 6,
- .rep = 1,
-};
-
-static struct gpio_keys_button ldp_gpio_keys_buttons[] = {
- [0] = {
- .code = KEY_ENTER,
- .gpio = 101,
- .desc = "enter sw",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [1] = {
- .code = KEY_F1,
- .gpio = 102,
- .desc = "func 1",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [2] = {
- .code = KEY_F2,
- .gpio = 103,
- .desc = "func 2",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [3] = {
- .code = KEY_F3,
- .gpio = 104,
- .desc = "func 3",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [4] = {
- .code = KEY_F4,
- .gpio = 105,
- .desc = "func 4",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [5] = {
- .code = KEY_LEFT,
- .gpio = 106,
- .desc = "left sw",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [6] = {
- .code = KEY_RIGHT,
- .gpio = 107,
- .desc = "right sw",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [7] = {
- .code = KEY_UP,
- .gpio = 108,
- .desc = "up sw",
- .active_low = 1,
- .debounce_interval = 30,
- },
- [8] = {
- .code = KEY_DOWN,
- .gpio = 109,
- .desc = "down sw",
- .active_low = 1,
- .debounce_interval = 30,
- },
-};
-
-static struct gpio_keys_platform_data ldp_gpio_keys = {
- .buttons = ldp_gpio_keys_buttons,
- .nbuttons = ARRAY_SIZE(ldp_gpio_keys_buttons),
- .rep = 1,
-};
-
-static struct platform_device ldp_gpio_keys_device = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &ldp_gpio_keys,
- },
-};
-
-static struct omap_smsc911x_platform_data smsc911x_cfg = {
- .cs = LDP_SMSC911X_CS,
- .gpio_irq = LDP_SMSC911X_GPIO,
- .gpio_reset = -EINVAL,
- .flags = SMSC911X_USE_32BIT,
-};
-
-static inline void __init ldp_init_smsc911x(void)
-{
- gpmc_smsc911x_init(&smsc911x_cfg);
-}
-
-/* LCD */
-
-#define LCD_PANEL_RESET_GPIO 55
-#define LCD_PANEL_QVGA_GPIO 56
-
-static const struct display_timing ldp_lcd_videomode = {
- .pixelclock = { 0, 5400000, 0 },
-
- .hactive = { 0, 240, 0 },
- .hfront_porch = { 0, 3, 0 },
- .hback_porch = { 0, 39, 0 },
- .hsync_len = { 0, 3, 0 },
-
- .vactive = { 0, 320, 0 },
- .vfront_porch = { 0, 2, 0 },
- .vback_porch = { 0, 7, 0 },
- .vsync_len = { 0, 1, 0 },
-
- .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
- DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE,
-};
-
-static struct panel_dpi_platform_data ldp_lcd_pdata = {
- .name = "lcd",
- .source = "dpi.0",
-
- .data_lines = 18,
-
- .display_timing = &ldp_lcd_videomode,
-
- .enable_gpio = -1, /* filled in code */
- .backlight_gpio = -1, /* filled in code */
-};
-
-static struct platform_device ldp_lcd_device = {
- .name = "panel-dpi",
- .id = 0,
- .dev.platform_data = &ldp_lcd_pdata,
-};
-
-static struct omap_dss_board_info ldp_dss_data = {
- .default_display_name = "lcd",
-};
-
-static void __init ldp_display_init(void)
-{
- int r;
-
- static struct gpio gpios[] __initdata = {
- {LCD_PANEL_RESET_GPIO, GPIOF_OUT_INIT_HIGH, "LCD RESET"},
- {LCD_PANEL_QVGA_GPIO, GPIOF_OUT_INIT_HIGH, "LCD QVGA"},
- };
-
- r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
- if (r) {
- pr_err("Cannot request LCD GPIOs, error %d\n", r);
- return;
- }
-
- omap_display_init(&ldp_dss_data);
-}
-
-static int ldp_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio)
-{
- int res;
-
- /* LCD enable GPIO */
- ldp_lcd_pdata.enable_gpio = gpio + 7;
-
- /* Backlight enable GPIO */
- ldp_lcd_pdata.backlight_gpio = gpio + 15;
-
- res = platform_device_register(&ldp_lcd_device);
- if (res)
- pr_err("Unable to register LCD: %d\n", res);
-
- return 0;
-}
-
-static struct twl4030_gpio_platform_data ldp_gpio_data = {
- .setup = ldp_twl_gpio_setup,
-};
-
-static struct regulator_consumer_supply ldp_vmmc1_supply[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
-};
-
-/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
-static struct regulator_init_data ldp_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ldp_vmmc1_supply),
- .consumer_supplies = ldp_vmmc1_supply,
-};
-
-/* ads7846 on SPI */
-static struct regulator_consumer_supply ldp_vaux1_supplies[] = {
- REGULATOR_SUPPLY("vcc", "spi1.0"),
-};
-
-/* VAUX1 */
-static struct regulator_init_data ldp_vaux1 = {
- .constraints = {
- .min_uV = 3000000,
- .max_uV = 3000000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ldp_vaux1_supplies),
- .consumer_supplies = ldp_vaux1_supplies,
-};
-
-static struct regulator_consumer_supply ldp_vpll2_supplies[] = {
- REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
- REGULATOR_SUPPLY("vdds_dsi", "omapdss_dpi.0"),
- REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"),
-};
-
-static struct regulator_init_data ldp_vpll2 = {
- .constraints = {
- .name = "VDVI",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ldp_vpll2_supplies),
- .consumer_supplies = ldp_vpll2_supplies,
-};
-
-static struct twl4030_platform_data ldp_twldata = {
- /* platform_data for children goes here */
- .vmmc1 = &ldp_vmmc1,
- .vaux1 = &ldp_vaux1,
- .vpll2 = &ldp_vpll2,
- .gpio = &ldp_gpio_data,
- .keypad = &ldp_kp_twl4030_data,
-};
-
-static int __init omap_i2c_init(void)
-{
- omap3_pmic_get_config(&ldp_twldata,
- TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC, 0);
- omap3_pmic_init("twl4030", &ldp_twldata);
- omap_register_i2c_bus(2, 400, NULL, 0);
- omap_register_i2c_bus(3, 400, NULL, 0);
- return 0;
-}
-
-static struct omap2_hsmmc_info mmc[] __initdata = {
- {
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- },
- {} /* Terminator */
-};
-
-static struct platform_device *ldp_devices[] __initdata = {
- &ldp_gpio_keys_device,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static struct mtd_partition ldp_nand_partitions[] = {
- /* All the partition sizes are listed in terms of NAND block size */
- {
- .name = "X-Loader-NAND",
- .offset = 0,
- .size = 4 * (64 * 2048), /* 512KB, 0x80000 */
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "U-Boot-NAND",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
- .size = 10 * (64 * 2048), /* 1.25MB, 0x140000 */
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "Boot Env-NAND",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */
- .size = 2 * (64 * 2048), /* 256KB, 0x40000 */
- },
- {
- .name = "Kernel-NAND",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x0200000*/
- .size = 240 * (64 * 2048), /* 30M, 0x1E00000 */
- },
- {
- .name = "File System - NAND",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x2000000 */
- .size = MTDPART_SIZ_FULL, /* 96MB, 0x6000000 */
- },
-
-};
-
-static struct regulator_consumer_supply dummy_supplies[] = {
- REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
-};
-
-static void __init omap_ldp_init(void)
-{
- regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- ldp_init_smsc911x();
- omap_i2c_init();
- platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
- omap_ads7846_init(1, 54, 310, NULL);
- omap_serial_init();
- omap_sdrc_init(NULL, NULL);
- usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
- usb_musb_init(NULL);
- board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
- 0, 0, nand_default_timings);
-
- omap_hsmmc_init(mmc);
- ldp_display_init();
-}
-
-MACHINE_START(OMAP_LDP, "OMAP LDP board")
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = omap3430_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = omap_ldp_init,
- .init_late = omap3430_init_late,
- .init_time = omap_init_time,
- .restart = omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index b6443a4e0c78..6b6fda65fb3b 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -66,7 +66,7 @@ static void board_check_revision(void)
pr_err("Unknown board\n");
}
-#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
/*
* Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
* 1.5 V voltage regulators of PM companion chip. Companion chip will then
@@ -163,8 +163,7 @@ static struct spi_board_info n800_spi_board_info[] __initdata = {
},
};
-#if defined(CONFIG_MENELAUS) && \
- (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE))
+#if defined(CONFIG_MENELAUS) && IS_ENABLED(CONFIG_MMC_OMAP)
/*
* On both N800 and N810, only the first of the two MMC controllers is in use.
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
deleted file mode 100644
index 6d3af43ae3e4..000000000000
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-rx51-peripherals.c
- *
- * Copyright (C) 2008-2009 Nokia
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/spi/spi.h>
-#include <linux/wl12xx.h>
-#include <linux/spi/tsc2005.h>
-#include <linux/i2c.h>
-#include <linux/i2c/twl.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/regulator/machine.h>
-#include <linux/gpio.h>
-#include <linux/gpio_keys.h>
-#include <linux/gpio/machine.h>
-#include <linux/omap-gpmc.h>
-#include <linux/mmc/host.h>
-#include <linux/power/isp1704_charger.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/mtd-onenand-omap2.h>
-#include <linux/module.h>
-
-#include <plat/dmtimer.h>
-
-#include <asm/system_info.h>
-
-#include "common.h"
-#include <linux/omap-dma.h>
-
-#include "board-rx51.h"
-
-#include <sound/tlv320aic3x.h>
-#include <sound/tpa6130a2-plat.h>
-#include <linux/platform_data/media/si4713.h>
-#include <linux/platform_data/leds-lp55xx.h>
-
-#include <linux/platform_data/tsl2563.h>
-#include <linux/lis3lv02d.h>
-
-#include <video/omap-panel-data.h>
-
-#include <linux/platform_data/pwm_omap_dmtimer.h>
-#include <linux/platform_data/media/ir-rx51.h>
-
-#include "mux.h"
-#include "omap-pm.h"
-#include "hsmmc.h"
-#include "common-board-devices.h"
-#include "soc.h"
-#include "omap-secure.h"
-
-#define SYSTEM_REV_B_USES_VAUX3 0x1699
-#define SYSTEM_REV_S_USES_VAUX3 0x8
-
-#define RX51_WL1251_POWER_GPIO 87
-#define RX51_WL1251_IRQ_GPIO 42
-#define RX51_FMTX_RESET_GPIO 163
-#define RX51_FMTX_IRQ 53
-#define RX51_LP5523_CHIP_EN_GPIO 41
-
-#define RX51_USB_TRANSCEIVER_RST_GPIO 67
-
-#define RX51_TSC2005_RESET_GPIO 104
-#define RX51_TSC2005_IRQ_GPIO 100
-
-#define LIS302_IRQ1_GPIO 181
-#define LIS302_IRQ2_GPIO 180 /* Not yet in use */
-
-/* List all SPI devices here. Note that the list/probe order seems to matter! */
-enum {
- RX51_SPI_WL1251,
- RX51_SPI_TSC2005, /* Touch Controller */
- RX51_SPI_MIPID, /* LCD panel */
-};
-
-static struct wl1251_platform_data wl1251_pdata;
-static struct tsc2005_platform_data tsc2005_pdata;
-
-#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
-static int lis302_setup(void)
-{
- int err;
- int irq1 = LIS302_IRQ1_GPIO;
- int irq2 = LIS302_IRQ2_GPIO;
-
- /* gpio for interrupt pin 1 */
- err = gpio_request(irq1, "lis3lv02dl_irq1");
- if (err) {
- printk(KERN_ERR "lis3lv02dl: gpio request failed\n");
- goto out;
- }
-
- /* gpio for interrupt pin 2 */
- err = gpio_request(irq2, "lis3lv02dl_irq2");
- if (err) {
- gpio_free(irq1);
- printk(KERN_ERR "lis3lv02dl: gpio request failed\n");
- goto out;
- }
-
- gpio_direction_input(irq1);
- gpio_direction_input(irq2);
-
-out:
- return err;
-}
-
-static int lis302_release(void)
-{
- gpio_free(LIS302_IRQ1_GPIO);
- gpio_free(LIS302_IRQ2_GPIO);
-
- return 0;
-}
-
-static struct lis3lv02d_platform_data rx51_lis3lv02d_data = {
- .click_flags = LIS3_CLICK_SINGLE_X | LIS3_CLICK_SINGLE_Y |
- LIS3_CLICK_SINGLE_Z,
- /* Limits are 0.5g * value */
- .click_thresh_x = 8,
- .click_thresh_y = 8,
- .click_thresh_z = 10,
- /* Click must be longer than time limit */
- .click_time_limit = 9,
- /* Kind of debounce filter */
- .click_latency = 50,
-
- /* Limits for all axis. millig-value / 18 to get HW values */
- .wakeup_flags = LIS3_WAKEUP_X_HI | LIS3_WAKEUP_Y_HI,
- .wakeup_thresh = 800 / 18,
- .wakeup_flags2 = LIS3_WAKEUP_Z_HI ,
- .wakeup_thresh2 = 900 / 18,
-
- .hipass_ctrl = LIS3_HIPASS1_DISABLE | LIS3_HIPASS2_DISABLE,
-
- /* Interrupt line 2 for click detection, line 1 for thresholds */
- .irq_cfg = LIS3_IRQ2_CLICK | LIS3_IRQ1_FF_WU_12,
-
- .axis_x = LIS3_DEV_X,
- .axis_y = LIS3_INV_DEV_Y,
- .axis_z = LIS3_INV_DEV_Z,
- .setup_resources = lis302_setup,
- .release_resources = lis302_release,
- .st_min_limits = {-32, 3, 3},
- .st_max_limits = {-3, 32, 32},
-};
-#endif
-
-#if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE)
-static struct tsl2563_platform_data rx51_tsl2563_platform_data = {
- .cover_comp_gain = 16,
-};
-#endif
-
-#if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE)
-static struct lp55xx_led_config rx51_lp5523_led_config[] = {
- {
- .name = "lp5523:kb1",
- .chan_nr = 0,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:kb2",
- .chan_nr = 1,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:kb3",
- .chan_nr = 2,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:kb4",
- .chan_nr = 3,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:b",
- .chan_nr = 4,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:g",
- .chan_nr = 5,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:r",
- .chan_nr = 6,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:kb5",
- .chan_nr = 7,
- .led_current = 50,
- .max_current = 100,
- }, {
- .name = "lp5523:kb6",
- .chan_nr = 8,
- .led_current = 50,
- .max_current = 100,
- }
-};
-
-static struct lp55xx_platform_data rx51_lp5523_platform_data = {
- .led_config = rx51_lp5523_led_config,
- .num_channels = ARRAY_SIZE(rx51_lp5523_led_config),
- .clock_mode = LP55XX_CLOCK_AUTO,
- .enable_gpio = RX51_LP5523_CHIP_EN_GPIO,
-};
-#endif
-
-#define RX51_LCD_RESET_GPIO 90
-
-static struct panel_acx565akm_platform_data acx_pdata = {
- .name = "lcd",
- .source = "sdi.0",
- .reset_gpio = RX51_LCD_RESET_GPIO,
- .datapairs = 2,
-};
-
-static struct omap2_mcspi_device_config wl1251_mcspi_config = {
- .turbo_mode = 0,
-};
-
-static struct omap2_mcspi_device_config mipid_mcspi_config = {
- .turbo_mode = 0,
-};
-
-static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
- .turbo_mode = 0,
-};
-
-static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
- [RX51_SPI_WL1251] = {
- .modalias = "wl1251",
- .bus_num = 4,
- .chip_select = 0,
- .max_speed_hz = 48000000,
- .mode = SPI_MODE_3,
- .controller_data = &wl1251_mcspi_config,
- .platform_data = &wl1251_pdata,
- },
- [RX51_SPI_MIPID] = {
- .modalias = "acx565akm",
- .bus_num = 1,
- .chip_select = 2,
- .max_speed_hz = 6000000,
- .controller_data = &mipid_mcspi_config,
- .platform_data = &acx_pdata,
- },
- [RX51_SPI_TSC2005] = {
- .modalias = "tsc2005",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 6000000,
- .controller_data = &tsc2005_mcspi_config,
- .platform_data = &tsc2005_pdata,
- },
-};
-
-static struct platform_device rx51_battery_device = {
- .name = "rx51-battery",
- .id = -1,
-};
-
-static void rx51_charger_set_power(bool on)
-{
- gpio_set_value(RX51_USB_TRANSCEIVER_RST_GPIO, on);
-}
-
-static struct isp1704_charger_data rx51_charger_data = {
- .set_power = rx51_charger_set_power,
-};
-
-static struct platform_device rx51_charger_device = {
- .name = "isp1704_charger",
- .dev = {
- .platform_data = &rx51_charger_data,
- },
-};
-
-static void __init rx51_charger_init(void)
-{
- WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO,
- GPIOF_OUT_INIT_HIGH, "isp1704_reset"));
-
- platform_device_register(&rx51_battery_device);
- platform_device_register(&rx51_charger_device);
-}
-
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-
-#define RX51_GPIO_CAMERA_LENS_COVER 110
-#define RX51_GPIO_CAMERA_FOCUS 68
-#define RX51_GPIO_CAMERA_CAPTURE 69
-#define RX51_GPIO_KEYPAD_SLIDE 71
-#define RX51_GPIO_LOCK_BUTTON 113
-#define RX51_GPIO_PROXIMITY 89
-
-#define RX51_GPIO_DEBOUNCE_TIMEOUT 10
-
-static struct gpio_keys_button rx51_gpio_keys[] = {
- {
- .desc = "Camera Lens Cover",
- .type = EV_SW,
- .code = SW_CAMERA_LENS_COVER,
- .gpio = RX51_GPIO_CAMERA_LENS_COVER,
- .active_low = 1,
- .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT,
- }, {
- .desc = "Camera Focus",
- .type = EV_KEY,
- .code = KEY_CAMERA_FOCUS,
- .gpio = RX51_GPIO_CAMERA_FOCUS,
- .active_low = 1,
- .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT,
- }, {
- .desc = "Camera Capture",
- .type = EV_KEY,
- .code = KEY_CAMERA,
- .gpio = RX51_GPIO_CAMERA_CAPTURE,
- .active_low = 1,
- .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT,
- }, {
- .desc = "Lock Button",
- .type = EV_KEY,
- .code = KEY_SCREENLOCK,
- .gpio = RX51_GPIO_LOCK_BUTTON,
- .active_low = 1,
- .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT,
- }, {
- .desc = "Keypad Slide",
- .type = EV_SW,
- .code = SW_KEYPAD_SLIDE,
- .gpio = RX51_GPIO_KEYPAD_SLIDE,
- .active_low = 1,
- .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT,
- }, {
- .desc = "Proximity Sensor",
- .type = EV_SW,
- .code = SW_FRONT_PROXIMITY,
- .gpio = RX51_GPIO_PROXIMITY,
- .active_low = 0,
- .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT,
- }
-};
-
-static struct gpio_keys_platform_data rx51_gpio_keys_data = {
- .buttons = rx51_gpio_keys,
- .nbuttons = ARRAY_SIZE(rx51_gpio_keys),
-};
-
-static struct platform_device rx51_gpio_keys_device = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &rx51_gpio_keys_data,
- },
-};
-
-static void __init rx51_add_gpio_keys(void)
-{
- platform_device_register(&rx51_gpio_keys_device);
-}
-#else
-static void __init rx51_add_gpio_keys(void)
-{
-}
-#endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
-
-static uint32_t board_keymap[] = {
- /*
- * Note that KEY(x, 8, KEY_XXX) entries represent "entrire row
- * connected to the ground" matrix state.
- */
- KEY(0, 0, KEY_Q),
- KEY(0, 1, KEY_O),
- KEY(0, 2, KEY_P),
- KEY(0, 3, KEY_COMMA),
- KEY(0, 4, KEY_BACKSPACE),
- KEY(0, 6, KEY_A),
- KEY(0, 7, KEY_S),
-
- KEY(1, 0, KEY_W),
- KEY(1, 1, KEY_D),
- KEY(1, 2, KEY_F),
- KEY(1, 3, KEY_G),
- KEY(1, 4, KEY_H),
- KEY(1, 5, KEY_J),
- KEY(1, 6, KEY_K),
- KEY(1, 7, KEY_L),
-
- KEY(2, 0, KEY_E),
- KEY(2, 1, KEY_DOT),
- KEY(2, 2, KEY_UP),
- KEY(2, 3, KEY_ENTER),
- KEY(2, 5, KEY_Z),
- KEY(2, 6, KEY_X),
- KEY(2, 7, KEY_C),
- KEY(2, 8, KEY_F9),
-
- KEY(3, 0, KEY_R),
- KEY(3, 1, KEY_V),
- KEY(3, 2, KEY_B),
- KEY(3, 3, KEY_N),
- KEY(3, 4, KEY_M),
- KEY(3, 5, KEY_SPACE),
- KEY(3, 6, KEY_SPACE),
- KEY(3, 7, KEY_LEFT),
-
- KEY(4, 0, KEY_T),
- KEY(4, 1, KEY_DOWN),
- KEY(4, 2, KEY_RIGHT),
- KEY(4, 4, KEY_LEFTCTRL),
- KEY(4, 5, KEY_RIGHTALT),
- KEY(4, 6, KEY_LEFTSHIFT),
- KEY(4, 8, KEY_F10),
-
- KEY(5, 0, KEY_Y),
- KEY(5, 8, KEY_F11),
-
- KEY(6, 0, KEY_U),
-
- KEY(7, 0, KEY_I),
- KEY(7, 1, KEY_F7),
- KEY(7, 2, KEY_F8),
-};
-
-static struct matrix_keymap_data board_map_data = {
- .keymap = board_keymap,
- .keymap_size = ARRAY_SIZE(board_keymap),
-};
-
-static struct twl4030_keypad_data rx51_kp_data = {
- .keymap_data = &board_map_data,
- .rows = 8,
- .cols = 8,
- .rep = 1,
-};
-
-/* Enable input logic and pull all lines up when eMMC is on. */
-static struct omap_board_mux rx51_mmc2_on_mux[] = {
- OMAP3_MUX(SDMMC2_CMD, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT0, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT1, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT2, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT3, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT4, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT5, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT6, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT7, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-
-/* Disable input logic and pull all lines down when eMMC is off. */
-static struct omap_board_mux rx51_mmc2_off_mux[] = {
- OMAP3_MUX(SDMMC2_CMD, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT0, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT1, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT2, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT3, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT4, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT5, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT6, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- OMAP3_MUX(SDMMC2_DAT7, OMAP_PULL_ENA | OMAP_MUX_MODE0),
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-
-static struct omap_mux_partition *partition;
-
-/*
- * Current flows to eMMC when eMMC is off and the data lines are pulled up,
- * so pull them down. N.B. we pull 8 lines because we are using 8 lines.
- */
-static void rx51_mmc2_remux(struct device *dev, int power_on)
-{
- if (power_on)
- omap_mux_write_array(partition, rx51_mmc2_on_mux);
- else
- omap_mux_write_array(partition, rx51_mmc2_off_mux);
-}
-
-static struct omap2_hsmmc_info mmc[] __initdata = {
- {
- .name = "external",
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA,
- .cover_only = true,
- .gpio_cd = 160,
- .gpio_wp = -EINVAL,
- },
- {
- .name = "internal",
- .mmc = 2,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
- /* See also rx51_mmc2_remux */
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- .nonremovable = true,
- .remux = rx51_mmc2_remux,
- },
- {} /* Terminator */
-};
-
-static struct regulator_consumer_supply rx51_vmmc1_supply[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
-};
-
-static struct regulator_consumer_supply rx51_vaux2_supply[] = {
- REGULATOR_SUPPLY("vdds_csib", "omap3isp"),
-};
-
-static struct regulator_consumer_supply rx51_vaux3_supply[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
-};
-
-static struct regulator_consumer_supply rx51_vsim_supply[] = {
- REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1"),
-};
-
-static struct regulator_consumer_supply rx51_vmmc2_supplies[] = {
- /* tlv320aic3x analog supplies */
- REGULATOR_SUPPLY("AVDD", "2-0018"),
- REGULATOR_SUPPLY("DRVDD", "2-0018"),
- REGULATOR_SUPPLY("AVDD", "2-0019"),
- REGULATOR_SUPPLY("DRVDD", "2-0019"),
- /* tpa6130a2 */
- REGULATOR_SUPPLY("Vdd", "2-0060"),
- /* Keep vmmc as last item. It is not iterated for newer boards */
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
-};
-
-static struct regulator_consumer_supply rx51_vio_supplies[] = {
- /* tlv320aic3x digital supplies */
- REGULATOR_SUPPLY("IOVDD", "2-0018"),
- REGULATOR_SUPPLY("DVDD", "2-0018"),
- REGULATOR_SUPPLY("IOVDD", "2-0019"),
- REGULATOR_SUPPLY("DVDD", "2-0019"),
- /* Si4713 IO supply */
- REGULATOR_SUPPLY("vio", "2-0063"),
- /* lis3lv02d */
- REGULATOR_SUPPLY("Vdd_IO", "3-001d"),
-};
-
-static struct regulator_consumer_supply rx51_vaux1_consumers[] = {
- REGULATOR_SUPPLY("vdds_sdi", "omapdss"),
- REGULATOR_SUPPLY("vdds_sdi", "omapdss_sdi.0"),
- /* Si4713 supply */
- REGULATOR_SUPPLY("vdd", "2-0063"),
- /* lis3lv02d */
- REGULATOR_SUPPLY("Vdd", "3-001d"),
-};
-
-static struct regulator_init_data rx51_vaux1 = {
- .constraints = {
- .name = "V28",
- .min_uV = 2800000,
- .max_uV = 2800000,
- .always_on = true, /* due battery cover sensor */
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vaux1_consumers),
- .consumer_supplies = rx51_vaux1_consumers,
-};
-
-static struct regulator_init_data rx51_vaux2 = {
- .constraints = {
- .name = "VCSI",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vaux2_supply),
- .consumer_supplies = rx51_vaux2_supply,
-};
-
-/* VAUX3 - adds more power to VIO_18 rail */
-static struct regulator_init_data rx51_vaux3_cam = {
- .constraints = {
- .name = "VCAM_DIG_18",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
-};
-
-static struct regulator_init_data rx51_vaux3_mmc = {
- .constraints = {
- .name = "VMMC2_30",
- .min_uV = 2800000,
- .max_uV = 3000000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vaux3_supply),
- .consumer_supplies = rx51_vaux3_supply,
-};
-
-static struct regulator_init_data rx51_vaux4 = {
- .constraints = {
- .name = "VCAM_ANA_28",
- .min_uV = 2800000,
- .max_uV = 2800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
-};
-
-static struct regulator_init_data rx51_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vmmc1_supply),
- .consumer_supplies = rx51_vmmc1_supply,
-};
-
-static struct regulator_init_data rx51_vmmc2 = {
- .constraints = {
- .name = "V28_A",
- .min_uV = 2800000,
- .max_uV = 3000000,
- .always_on = true, /* due VIO leak to AIC34 VDDs */
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vmmc2_supplies),
- .consumer_supplies = rx51_vmmc2_supplies,
-};
-
-static struct regulator_init_data rx51_vpll1 = {
- .constraints = {
- .name = "VPLL",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE,
- },
-};
-
-static struct regulator_init_data rx51_vpll2 = {
- .constraints = {
- .name = "VSDI_CSI",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE,
- },
-};
-
-static struct regulator_init_data rx51_vsim = {
- .constraints = {
- .name = "VMMC2_IO_18",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vsim_supply),
- .consumer_supplies = rx51_vsim_supply,
-};
-
-static struct regulator_init_data rx51_vio = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 1800000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(rx51_vio_supplies),
- .consumer_supplies = rx51_vio_supplies,
-};
-
-static struct regulator_init_data rx51_vintana1 = {
- .constraints = {
- .name = "VINTANA1",
- .min_uV = 1500000,
- .max_uV = 1500000,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE,
- },
-};
-
-static struct regulator_init_data rx51_vintana2 = {
- .constraints = {
- .name = "VINTANA2",
- .min_uV = 2750000,
- .max_uV = 2750000,
- .apply_uV = true,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE,
- },
-};
-
-static struct regulator_init_data rx51_vintdig = {
- .constraints = {
- .name = "VINTDIG",
- .min_uV = 1500000,
- .max_uV = 1500000,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE,
- },
-};
-
-static struct gpiod_lookup_table rx51_fmtx_gpios_table = {
- .dev_id = "2-0063",
- .table = {
- GPIO_LOOKUP("gpio.6", 3, "reset", GPIO_ACTIVE_HIGH), /* 163 */
- { },
- },
-};
-
-static __init void rx51_gpio_init(void)
-{
- gpiod_add_lookup_table(&rx51_fmtx_gpios_table);
-}
-
-static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n)
-{
- /* FIXME this gpio setup is just a placeholder for now */
- gpio_request_one(gpio + 6, GPIOF_OUT_INIT_LOW, "backlight_pwm");
- gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "speaker_en");
-
- return 0;
-}
-
-static struct twl4030_gpio_platform_data rx51_gpio_data = {
- .pulldowns = BIT(0) | BIT(1) | BIT(2) | BIT(3)
- | BIT(4) | BIT(5)
- | BIT(8) | BIT(9) | BIT(10) | BIT(11)
- | BIT(12) | BIT(13) | BIT(14) | BIT(15)
- | BIT(16) | BIT(17) ,
- .setup = rx51_twlgpio_setup,
-};
-
-static struct twl4030_ins sleep_on_seq[] __initdata = {
-/*
- * Turn off everything
- */
- {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_SLEEP), 2},
-};
-
-static struct twl4030_script sleep_on_script __initdata = {
- .script = sleep_on_seq,
- .size = ARRAY_SIZE(sleep_on_seq),
- .flags = TWL4030_SLEEP_SCRIPT,
-};
-
-static struct twl4030_ins wakeup_seq[] __initdata = {
-/*
- * Reenable everything
- */
- {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
-};
-
-static struct twl4030_script wakeup_script __initdata = {
- .script = wakeup_seq,
- .size = ARRAY_SIZE(wakeup_seq),
- .flags = TWL4030_WAKEUP12_SCRIPT,
-};
-
-static struct twl4030_ins wakeup_p3_seq[] __initdata = {
-/*
- * Reenable everything
- */
- {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
-};
-
-static struct twl4030_script wakeup_p3_script __initdata = {
- .script = wakeup_p3_seq,
- .size = ARRAY_SIZE(wakeup_p3_seq),
- .flags = TWL4030_WAKEUP3_SCRIPT,
-};
-
-static struct twl4030_ins wrst_seq[] __initdata = {
-/*
- * Reset twl4030.
- * Reset VDD1 regulator.
- * Reset VDD2 regulator.
- * Reset VPLL1 regulator.
- * Enable sysclk output.
- * Reenable twl4030.
- */
- {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2},
- {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 0, 1, RES_STATE_ACTIVE),
- 0x13},
- {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 3, RES_STATE_OFF), 0x13},
- {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x13},
- {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x13},
- {MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x35},
- {MSG_SINGULAR(DEV_GRP_P3, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
- {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2},
-};
-
-static struct twl4030_script wrst_script __initdata = {
- .script = wrst_seq,
- .size = ARRAY_SIZE(wrst_seq),
- .flags = TWL4030_WRST_SCRIPT,
-};
-
-static struct twl4030_script *twl4030_scripts[] __initdata = {
- /* wakeup12 script should be loaded before sleep script, otherwise a
- board might hit retention before loading of wakeup script is
- completed. This can cause boot failures depending on timing issues.
- */
- &wakeup_script,
- &sleep_on_script,
- &wakeup_p3_script,
- &wrst_script,
-};
-
-static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
- { .resource = RES_VDD1, .devgroup = -1,
- .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
- .remap_sleep = RES_STATE_OFF
- },
- { .resource = RES_VDD2, .devgroup = -1,
- .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
- .remap_sleep = RES_STATE_OFF
- },
- { .resource = RES_VPLL1, .devgroup = -1,
- .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
- .remap_sleep = RES_STATE_OFF
- },
- { .resource = RES_VPLL2, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VAUX1, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VAUX2, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VAUX3, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VAUX4, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VMMC1, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VMMC2, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VDAC, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VSIM, .devgroup = -1,
- .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VINTANA1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VINTANA2, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VINTDIG, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_VIO, .devgroup = DEV_GRP_P3,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_CLKEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = 1, .type2 = -1 , .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_REGEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_SYSEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_32KCLKOUT, .devgroup = -1,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_RESET, .devgroup = -1,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { .resource = RES_MAIN_REF, .devgroup = -1,
- .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
- },
- { 0, 0},
-};
-
-static struct twl4030_power_data rx51_t2scripts_data __initdata = {
- .scripts = twl4030_scripts,
- .num = ARRAY_SIZE(twl4030_scripts),
- .resource_config = twl4030_rconfig,
-};
-
-static struct twl4030_vibra_data rx51_vibra_data __initdata = {
- .coexist = 0,
-};
-
-static struct twl4030_audio_data rx51_audio_data __initdata = {
- .audio_mclk = 26000000,
- .vibra = &rx51_vibra_data,
-};
-
-static struct twl4030_platform_data rx51_twldata __initdata = {
- /* platform_data for children goes here */
- .gpio = &rx51_gpio_data,
- .keypad = &rx51_kp_data,
- .power = &rx51_t2scripts_data,
- .audio = &rx51_audio_data,
-
- .vaux1 = &rx51_vaux1,
- .vaux2 = &rx51_vaux2,
- .vaux4 = &rx51_vaux4,
- .vmmc1 = &rx51_vmmc1,
- .vpll1 = &rx51_vpll1,
- .vpll2 = &rx51_vpll2,
- .vsim = &rx51_vsim,
- .vintana1 = &rx51_vintana1,
- .vintana2 = &rx51_vintana2,
- .vintdig = &rx51_vintdig,
- .vio = &rx51_vio,
-};
-
-static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata_or_module = {
- .power_gpio = 98,
-};
-
-/* Audio setup data */
-static struct aic3x_setup_data rx51_aic34_setup = {
- .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
- .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
-static struct aic3x_pdata rx51_aic3x_data = {
- .setup = &rx51_aic34_setup,
- .gpio_reset = 60,
-};
-
-static struct aic3x_pdata rx51_aic3x_data2 = {
- .gpio_reset = 60,
-};
-
-#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
-static struct si4713_platform_data rx51_si4713_platform_data = {
- .is_platform_device = true
-};
-#endif
-
-static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
-#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
- {
- I2C_BOARD_INFO("si4713", 0x63),
- .platform_data = &rx51_si4713_platform_data,
- },
-#endif
- {
- I2C_BOARD_INFO("tlv320aic3x", 0x18),
- .platform_data = &rx51_aic3x_data,
- },
- {
- I2C_BOARD_INFO("tlv320aic3x", 0x19),
- .platform_data = &rx51_aic3x_data2,
- },
-#if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE)
- {
- I2C_BOARD_INFO("tsl2563", 0x29),
- .platform_data = &rx51_tsl2563_platform_data,
- },
-#endif
-#if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE)
- {
- I2C_BOARD_INFO("lp5523", 0x32),
- .platform_data = &rx51_lp5523_platform_data,
- },
-#endif
- {
- I2C_BOARD_INFO("bq27200", 0x55),
- },
- {
- I2C_BOARD_INFO("tpa6130a2", 0x60),
- .platform_data = &rx51_tpa6130a2_data,
- }
-};
-
-static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_3[] = {
-#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
- {
- I2C_BOARD_INFO("lis3lv02d", 0x1d),
- .platform_data = &rx51_lis3lv02d_data,
- },
-#endif
-};
-
-static int __init rx51_i2c_init(void)
-{
-#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
- int err;
-#endif
-
- if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
- system_rev >= SYSTEM_REV_B_USES_VAUX3) {
- rx51_twldata.vaux3 = &rx51_vaux3_mmc;
- /* Only older boards use VMMC2 for internal MMC */
- rx51_vmmc2.num_consumer_supplies--;
- } else {
- rx51_twldata.vaux3 = &rx51_vaux3_cam;
- }
- rx51_twldata.vmmc2 = &rx51_vmmc2;
- omap3_pmic_get_config(&rx51_twldata,
- TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC,
- TWL_COMMON_REGULATOR_VDAC);
-
- rx51_twldata.vdac->constraints.apply_uV = true;
- rx51_twldata.vdac->constraints.name = "VDAC";
-
- omap_pmic_init(1, 2200, "twl5030", 7 + OMAP_INTC_START, &rx51_twldata);
-#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
- err = gpio_request_one(RX51_FMTX_IRQ, GPIOF_DIR_IN, "si4713 irq");
- if (err) {
- printk(KERN_ERR "Cannot request si4713 irq gpio. %d\n", err);
- return err;
- }
- rx51_peripherals_i2c_board_info_2[0].irq = gpio_to_irq(RX51_FMTX_IRQ);
-#endif
- omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2,
- ARRAY_SIZE(rx51_peripherals_i2c_board_info_2));
-#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
- rx51_lis3lv02d_data.irq2 = gpio_to_irq(LIS302_IRQ2_GPIO);
- rx51_peripherals_i2c_board_info_3[0].irq = gpio_to_irq(LIS302_IRQ1_GPIO);
-#endif
- omap_register_i2c_bus(3, 400, rx51_peripherals_i2c_board_info_3,
- ARRAY_SIZE(rx51_peripherals_i2c_board_info_3));
- return 0;
-}
-
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
- defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
-
-static struct mtd_partition onenand_partitions[] = {
- {
- .name = "bootloader",
- .offset = 0,
- .size = 0x20000,
- .mask_flags = MTD_WRITEABLE, /* Force read-only */
- },
- {
- .name = "config",
- .offset = MTDPART_OFS_APPEND,
- .size = 0x60000,
- },
- {
- .name = "log",
- .offset = MTDPART_OFS_APPEND,
- .size = 0x40000,
- },
- {
- .name = "kernel",
- .offset = MTDPART_OFS_APPEND,
- .size = 0x200000,
- },
- {
- .name = "initfs",
- .offset = MTDPART_OFS_APPEND,
- .size = 0x200000,
- },
- {
- .name = "rootfs",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct omap_onenand_platform_data board_onenand_data[] = {
- {
- .cs = 0,
- .gpio_irq = 65,
- .parts = onenand_partitions,
- .nr_parts = ARRAY_SIZE(onenand_partitions),
- .flags = ONENAND_SYNC_READWRITE,
- }
-};
-#endif
-
-static struct gpio rx51_wl1251_gpios[] __initdata = {
- { RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
-};
-
-static void __init rx51_init_wl1251(void)
-{
- int irq, ret;
-
- ret = gpio_request_array(rx51_wl1251_gpios,
- ARRAY_SIZE(rx51_wl1251_gpios));
- if (ret < 0)
- goto error;
-
- irq = gpio_to_irq(RX51_WL1251_IRQ_GPIO);
- if (irq < 0)
- goto err_irq;
-
- wl1251_pdata.power_gpio = RX51_WL1251_POWER_GPIO;
- rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
-
- return;
-
-err_irq:
- gpio_free(RX51_WL1251_IRQ_GPIO);
-error:
- printk(KERN_ERR "wl1251 board initialisation failed\n");
- wl1251_pdata.power_gpio = -1;
-
- /*
- * Now rx51_peripherals_spi_board_info[1].irq is zero and
- * set_power is null, and wl1251_probe() will fail.
- */
-}
-
-static struct tsc2005_platform_data tsc2005_pdata = {
- .ts_pressure_max = 2048,
- .ts_pressure_fudge = 2,
- .ts_x_max = 4096,
- .ts_x_fudge = 4,
- .ts_y_max = 4096,
- .ts_y_fudge = 7,
- .ts_x_plate_ohm = 280,
- .esd_timeout_ms = 8000,
-};
-
-static struct gpio rx51_tsc2005_gpios[] __initdata = {
- { RX51_TSC2005_IRQ_GPIO, GPIOF_IN, "tsc2005 IRQ" },
- { RX51_TSC2005_RESET_GPIO, GPIOF_OUT_INIT_HIGH, "tsc2005 reset" },
-};
-
-static void rx51_tsc2005_set_reset(bool enable)
-{
- gpio_set_value(RX51_TSC2005_RESET_GPIO, enable);
-}
-
-static void __init rx51_init_tsc2005(void)
-{
- int r;
-
- omap_mux_init_gpio(RX51_TSC2005_RESET_GPIO, OMAP_PIN_OUTPUT);
- omap_mux_init_gpio(RX51_TSC2005_IRQ_GPIO, OMAP_PIN_INPUT_PULLUP);
-
- r = gpio_request_array(rx51_tsc2005_gpios,
- ARRAY_SIZE(rx51_tsc2005_gpios));
- if (r < 0) {
- printk(KERN_ERR "tsc2005 board initialization failed\n");
- tsc2005_pdata.esd_timeout_ms = 0;
- return;
- }
-
- tsc2005_pdata.set_reset = rx51_tsc2005_set_reset;
- rx51_peripherals_spi_board_info[RX51_SPI_TSC2005].irq =
- gpio_to_irq(RX51_TSC2005_IRQ_GPIO);
-}
-
-#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
-static struct pwm_omap_dmtimer_pdata __maybe_unused pwm_dmtimer_pdata = {
- .request_by_node = omap_dm_timer_request_by_node,
- .request_specific = omap_dm_timer_request_specific,
- .request = omap_dm_timer_request,
- .set_source = omap_dm_timer_set_source,
- .get_irq = omap_dm_timer_get_irq,
- .set_int_enable = omap_dm_timer_set_int_enable,
- .set_int_disable = omap_dm_timer_set_int_disable,
- .free = omap_dm_timer_free,
- .enable = omap_dm_timer_enable,
- .disable = omap_dm_timer_disable,
- .get_fclk = omap_dm_timer_get_fclk,
- .start = omap_dm_timer_start,
- .stop = omap_dm_timer_stop,
- .set_load = omap_dm_timer_set_load,
- .set_match = omap_dm_timer_set_match,
- .set_pwm = omap_dm_timer_set_pwm,
- .set_prescaler = omap_dm_timer_set_prescaler,
- .read_counter = omap_dm_timer_read_counter,
- .write_counter = omap_dm_timer_write_counter,
- .read_status = omap_dm_timer_read_status,
- .write_status = omap_dm_timer_write_status,
-};
-#endif
-
-#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
-static struct lirc_rx51_platform_data rx51_lirc_data = {
- .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
-};
-
-static struct platform_device rx51_lirc_device = {
- .name = "lirc_rx51",
- .id = -1,
- .dev = {
- .platform_data = &rx51_lirc_data,
- },
-};
-
-static void __init rx51_init_lirc(void)
-{
- platform_device_register(&rx51_lirc_device);
-}
-#else
-static void __init rx51_init_lirc(void)
-{
-}
-#endif
-
-static struct platform_device madc_hwmon = {
- .name = "twl4030_madc_hwmon",
- .id = -1,
-};
-
-static void __init rx51_init_twl4030_hwmon(void)
-{
- platform_device_register(&madc_hwmon);
-}
-
-static struct platform_device omap3_rom_rng_device = {
- .name = "omap3-rom-rng",
- .id = -1,
- .dev = {
- .platform_data = rx51_secure_rng_call,
- },
-};
-
-static void __init rx51_init_omap3_rom_rng(void)
-{
- if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
- pr_info("RX-51: Registering OMAP3 HWRNG device\n");
- platform_device_register(&omap3_rom_rng_device);
- }
-}
-
-void __init rx51_peripherals_init(void)
-{
- rx51_gpio_init();
- rx51_i2c_init();
- regulator_has_full_constraints();
- gpmc_onenand_init(board_onenand_data);
- rx51_add_gpio_keys();
- rx51_init_wl1251();
- rx51_init_tsc2005();
- rx51_init_lirc();
- spi_register_board_info(rx51_peripherals_spi_board_info,
- ARRAY_SIZE(rx51_peripherals_spi_board_info));
-
- partition = omap_mux_get("core");
- if (partition)
- omap_hsmmc_init(mmc);
-
- rx51_charger_init();
- rx51_init_twl4030_hwmon();
- rx51_init_omap3_rom_rng();
-}
-
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
deleted file mode 100644
index 180c6aa633bd..000000000000
--- a/arch/arm/mach-omap2/board-rx51-video.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-rx51-video.c
- *
- * Copyright (C) 2010 Nokia
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/mm.h>
-#include <asm/mach-types.h>
-#include <linux/platform_data/omapdss.h>
-#include <video/omap-panel-data.h>
-
-#include <linux/platform_data/spi-omap2-mcspi.h>
-
-#include "soc.h"
-#include "board-rx51.h"
-#include "display.h"
-
-#include "mux.h"
-
-#define RX51_LCD_RESET_GPIO 90
-
-#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
-
-static struct connector_atv_platform_data rx51_tv_pdata = {
- .name = "tv",
- .source = "venc.0",
- .invert_polarity = false,
-};
-
-static struct platform_device rx51_tv_connector_device = {
- .name = "connector-analog-tv",
- .id = 0,
- .dev.platform_data = &rx51_tv_pdata,
-};
-
-static struct omap_dss_board_info rx51_dss_board_info = {
- .default_display_name = "lcd",
-};
-
-static int __init rx51_video_init(void)
-{
- if (!machine_is_nokia_rx51())
- return 0;
-
- if (omap_mux_init_gpio(RX51_LCD_RESET_GPIO, OMAP_PIN_OUTPUT)) {
- pr_err("%s cannot configure MUX for LCD RESET\n", __func__);
- return 0;
- }
-
- omap_display_init(&rx51_dss_board_info);
-
- platform_device_register(&rx51_tv_connector_device);
-
- return 0;
-}
-
-omap_subsys_initcall(rx51_video_init);
-#endif /* defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) */
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
deleted file mode 100644
index 41161ca97d74..000000000000
--- a/arch/arm/mach-omap2/board-rx51.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Board support file for Nokia N900 (aka RX-51).
- *
- * Copyright (C) 2007, 2008 Nokia
- * Copyright (C) 2012 Ivaylo Dimitrov <freemangordon@abv.bg>
- * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/leds.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/musb.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/omap-dma.h>
-
-#include "common.h"
-#include "mux.h"
-#include "gpmc.h"
-#include "pm.h"
-#include "soc.h"
-#include "sdram-nokia.h"
-#include "omap-secure.h"
-
-#define RX51_GPIO_SLEEP_IND 162
-
-static struct gpio_led gpio_leds[] = {
- {
- .name = "sleep_ind",
- .gpio = RX51_GPIO_SLEEP_IND,
- },
-};
-
-static struct gpio_led_platform_data gpio_led_info = {
- .leds = gpio_leds,
- .num_leds = ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device leds_gpio = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &gpio_led_info,
- },
-};
-
-/*
- * cpuidle C-states definition for rx51.
- *
- * The 'exit_latency' field is the sum of sleep
- * and wake-up latencies.
-
- ---------------------------------------------
- | state | exit_latency | target_residency |
- ---------------------------------------------
- | C1 | 110 + 162 | 5 |
- | C2 | 106 + 180 | 309 |
- | C3 | 107 + 410 | 46057 |
- | C4 | 121 + 3374 | 46057 |
- | C5 | 855 + 1146 | 46057 |
- | C6 | 7580 + 4134 | 484329 |
- | C7 | 7505 + 15274 | 484329 |
- ---------------------------------------------
-
-*/
-
-extern void __init rx51_peripherals_init(void);
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 0,
-};
-
-static void __init rx51_init(void)
-{
- struct omap_sdrc_params *sdrc_params;
-
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- omap_serial_init();
-
- sdrc_params = nokia_get_sdram_timings();
- omap_sdrc_init(sdrc_params, sdrc_params);
-
- usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
- usb_musb_init(&musb_board_data);
- rx51_peripherals_init();
-
- if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
-#ifdef CONFIG_ARM_ERRATA_430973
- pr_info("RX-51: Enabling ARM errata 430973 workaround\n");
- /* set IBE to 1 */
- rx51_secure_update_aux_cr(BIT(6), 0);
-#endif
- }
-
- /* Ensure SDRC pins are mux'd for self-refresh */
- omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
- omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
-
- platform_device_register(&leds_gpio);
-}
-
-static void __init rx51_reserve(void)
-{
- omap_reserve();
-}
-
-MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
- /* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
- .atag_offset = 0x100,
- .reserve = rx51_reserve,
- .map_io = omap3_map_io,
- .init_early = omap3430_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = rx51_init,
- .init_late = omap3430_init_late,
- .init_time = omap_init_time,
- .restart = omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rx51.h b/arch/arm/mach-omap2/board-rx51.h
deleted file mode 100644
index b76f49e7eed5..000000000000
--- a/arch/arm/mach-omap2/board-rx51.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Defines for rx51 boards
- */
-
-#ifndef _OMAP_BOARD_RX51_H
-#define _OMAP_BOARD_RX51_H
-
-extern void __init rx51_peripherals_init(void);
-extern void __init rx51_video_mem_init(void);
-
-#endif
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
index d246efd9f734..5388fcd3de72 100644
--- a/arch/arm/mach-omap2/common-board-devices.c
+++ b/arch/arm/mach-omap2/common-board-devices.c
@@ -29,8 +29,7 @@
#include "common.h"
#include "common-board-devices.h"
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
- defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_ADS7846)
static struct omap2_mcspi_device_config ads7846_mcspi_config = {
.turbo_mode = 0,
};
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index d7f1d69daf6d..60a20f3b44de 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -67,7 +67,7 @@ omap_postcore_initcall(omap3_l3_init);
static inline void omap_init_sti(void) {}
-#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
+#if IS_ENABLED(CONFIG_SPI_OMAP24XX)
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -163,9 +163,8 @@ static void __init omap_init_aes(void)
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_VIDEO_OMAP2_VOUT) || \
- defined(CONFIG_VIDEO_OMAP2_VOUT_MODULE)
-#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_OMAP2_VOUT)
+#if IS_ENABLED(CONFIG_FB_OMAP2)
static struct resource omap_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = {
};
#else
diff --git a/arch/arm/mach-omap2/drm.c b/arch/arm/mach-omap2/drm.c
index facd7406a03d..44fef961bb70 100644
--- a/arch/arm/mach-omap2/drm.c
+++ b/arch/arm/mach-omap2/drm.c
@@ -28,7 +28,7 @@
#include "soc.h"
#include "display.h"
-#if defined(CONFIG_DRM_OMAP) || defined(CONFIG_DRM_OMAP_MODULE)
+#if IS_ENABLED(CONFIG_DRM_OMAP)
static struct omap_drm_platform_data platform_data;
diff --git a/arch/arm/mach-omap2/fb.c b/arch/arm/mach-omap2/fb.c
index 1f1ecf8807eb..ecd00b63181e 100644
--- a/arch/arm/mach-omap2/fb.c
+++ b/arch/arm/mach-omap2/fb.c
@@ -90,7 +90,7 @@ int __init omap_init_vrfb(void)
int __init omap_init_vrfb(void) { return 0; }
#endif
-#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
+#if IS_ENABLED(CONFIG_FB_OMAP2)
static u64 omap_fb_dma_mask = ~(u32)0;
static struct omapfb_platform_data omapfb_config;
diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.h b/arch/arm/mach-omap2/gpmc-smsc911x.h
index ea6c9c88c725..99a05b8412fa 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.h
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.h
@@ -21,7 +21,7 @@ struct omap_smsc911x_platform_data {
u32 flags;
};
-#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#if IS_ENABLED(CONFIG_SMSC911X)
extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index cff079e563f4..478097741bce 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -26,7 +26,7 @@
#include "hsmmc.h"
#include "control.h"
-#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP_HS)
static u16 control_pbias_offset;
static u16 control_devconf1_offset;
diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h
index 148cd9b15499..69b619ddc765 100644
--- a/arch/arm/mach-omap2/hsmmc.h
+++ b/arch/arm/mach-omap2/hsmmc.h
@@ -28,7 +28,7 @@ struct omap2_hsmmc_info {
void (*init_card)(struct mmc_card *card);
};
-#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+#if IS_ENABLED(CONFIG_MMC_OMAP_HS)
void omap_hsmmc_init(struct omap2_hsmmc_info *);
void omap_hsmmc_late_init(struct omap2_hsmmc_info *);
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 292eca0e78ed..a72738eab009 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -532,8 +532,7 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
}
#endif /* CONFIG_ARCH_OMAP4 */
-#if defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) || \
- defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030_MODULE)
+#if IS_ENABLED(CONFIG_SND_OMAP_SOC_OMAP_TWL4030)
#include <linux/platform_data/omap-twl4030.h>
/* Commonly used configuration */
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 058994e99570..04910764c385 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -105,9 +105,9 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
/*****************************************************************************
* Ethernet switch
****************************************************************************/
-void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
+void __init orion5x_eth_switch_init(struct dsa_platform_data *d)
{
- orion_ge00_switch_init(d, irq);
+ orion_ge00_switch_init(d);
}
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index cd0389c6e822..8a4115bd441d 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -41,7 +41,7 @@ void orion5x_setup_wins(void);
void orion5x_ehci0_init(void);
void orion5x_ehci1_init(void);
void orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data);
-void orion5x_eth_switch_init(struct dsa_platform_data *d, int irq);
+void orion5x_eth_switch_init(struct dsa_platform_data *d);
void orion5x_i2c_init(void);
void orion5x_sata_init(struct mv_sata_platform_data *sata_data);
void orion5x_spi_init(void);
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index c742e7b40b0d..dccadf68ea2b 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -101,7 +101,7 @@ static struct dsa_chip_data rd88f5181l_fxo_switch_chip_data = {
.port_names[7] = "lan3",
};
-static struct dsa_platform_data rd88f5181l_fxo_switch_plat_data = {
+static struct dsa_platform_data __initdata rd88f5181l_fxo_switch_plat_data = {
.nr_chips = 1,
.chip = &rd88f5181l_fxo_switch_chip_data,
};
@@ -120,7 +120,7 @@ static void __init rd88f5181l_fxo_init(void)
*/
orion5x_ehci0_init();
orion5x_eth_init(&rd88f5181l_fxo_eth_data);
- orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ);
+ orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data);
orion5x_uart0_init();
mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 7e977b794b0c..affe5ec825de 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -102,7 +102,7 @@ static struct dsa_chip_data rd88f5181l_ge_switch_chip_data = {
.port_names[7] = "lan3",
};
-static struct dsa_platform_data rd88f5181l_ge_switch_plat_data = {
+static struct dsa_platform_data __initdata rd88f5181l_ge_switch_plat_data = {
.nr_chips = 1,
.chip = &rd88f5181l_ge_switch_chip_data,
};
@@ -125,8 +125,7 @@ static void __init rd88f5181l_ge_init(void)
*/
orion5x_ehci0_init();
orion5x_eth_init(&rd88f5181l_ge_eth_data);
- orion5x_eth_switch_init(&rd88f5181l_ge_switch_plat_data,
- gpio_to_irq(8));
+ orion5x_eth_switch_init(&rd88f5181l_ge_switch_plat_data);
orion5x_i2c_init();
orion5x_uart0_init();
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 4bf80dd5478c..67ee8571b03c 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -40,7 +40,7 @@ static struct dsa_chip_data rd88f6183ap_ge_switch_chip_data = {
.port_names[5] = "cpu",
};
-static struct dsa_platform_data rd88f6183ap_ge_switch_plat_data = {
+static struct dsa_platform_data __initdata rd88f6183ap_ge_switch_plat_data = {
.nr_chips = 1,
.chip = &rd88f6183ap_ge_switch_chip_data,
};
@@ -71,7 +71,6 @@ static struct spi_board_info __initdata rd88f6183ap_ge_spi_slave_info[] = {
{
.modalias = "m25p80",
.platform_data = &rd88f6183ap_ge_spi_slave_data,
- .irq = NO_IRQ,
.max_speed_hz = 20000000,
.bus_num = 0,
.chip_select = 0,
@@ -90,8 +89,7 @@ static void __init rd88f6183ap_ge_init(void)
*/
orion5x_ehci0_init();
orion5x_eth_init(&rd88f6183ap_ge_eth_data);
- orion5x_eth_switch_init(&rd88f6183ap_ge_switch_plat_data,
- gpio_to_irq(3));
+ orion5x_eth_switch_init(&rd88f6183ap_ge_switch_plat_data);
spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
orion5x_spi_init();
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 4e1e5c8f6111..4dbcdbe1de7c 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -106,7 +106,7 @@ static struct dsa_chip_data wnr854t_switch_chip_data = {
.port_names[7] = "lan2",
};
-static struct dsa_platform_data wnr854t_switch_plat_data = {
+static struct dsa_platform_data __initdata wnr854t_switch_plat_data = {
.nr_chips = 1,
.chip = &wnr854t_switch_chip_data,
};
@@ -124,7 +124,7 @@ static void __init wnr854t_init(void)
* Configure peripherals.
*/
orion5x_eth_init(&wnr854t_eth_data);
- orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ);
+ orion5x_eth_switch_init(&wnr854t_switch_plat_data);
orion5x_uart0_init();
mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index 61e9027ef224..a6a8c4648d74 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -191,7 +191,7 @@ static struct dsa_chip_data wrt350n_v2_switch_chip_data = {
.port_names[7] = "lan4",
};
-static struct dsa_platform_data wrt350n_v2_switch_plat_data = {
+static struct dsa_platform_data __initdata wrt350n_v2_switch_plat_data = {
.nr_chips = 1,
.chip = &wrt350n_v2_switch_chip_data,
};
@@ -210,7 +210,7 @@ static void __init wrt350n_v2_init(void)
*/
orion5x_ehci0_init();
orion5x_eth_init(&wrt350n_v2_eth_data);
- orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ);
+ orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data);
orion5x_uart0_init();
mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index cd894d69e766..76fbc115ec33 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations"
comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
+config MACH_PXA25X_DT
+ bool "Support PXA25x platforms from device tree"
+ select PINCTRL
+ select POWER_SUPPLY
+ select PXA25x
+ select USE_OF
+ help
+ Include support for Marvell PXA25x based platforms using
+ the device tree. Needn't select any other machine while
+ MACH_PXA25x_DT is enabled.
+
config MACH_PXA27X_DT
bool "Support PXA27x platforms from device tree"
select PINCTRL
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 2ceed407eda9..ef25dc597f30 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -19,8 +19,9 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o
# NOTE: keep the order of boards in accordance to their order in Kconfig
# Device Tree support
-obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o
+obj-$(CONFIG_MACH_PXA25X_DT) += pxa-dt.o
obj-$(CONFIG_MACH_PXA27X_DT) += pxa-dt.o
+obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o
# Intel/Marvell Dev Platforms
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index d9206811be9b..c71c483f410e 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -131,16 +131,11 @@ static int corgi_should_wakeup(unsigned int resume_on_alarm)
return is_resume;
}
-static unsigned long corgi_charger_wakeup(void)
+static bool corgi_charger_wakeup(void)
{
- unsigned long ret;
-
- ret = (!gpio_get_value(CORGI_GPIO_AC_IN) << GPIO_bit(CORGI_GPIO_AC_IN))
- | (!gpio_get_value(CORGI_GPIO_KEY_INT)
- << GPIO_bit(CORGI_GPIO_KEY_INT))
- | (!gpio_get_value(CORGI_GPIO_WAKEUP)
- << GPIO_bit(CORGI_GPIO_WAKEUP));
- return ret;
+ return !gpio_get_value(CORGI_GPIO_AC_IN) ||
+ !gpio_get_value(CORGI_GPIO_KEY_INT) ||
+ !gpio_get_value(CORGI_GPIO_WAKEUP);
}
unsigned long corgipm_read_devdata(int type)
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index 4a13c32fb705..04580c407276 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -54,3 +54,4 @@ extern struct platform_device pxa3xx_device_gpio;
extern struct platform_device pxa93x_device_gpio;
void __init pxa_register_device(struct platform_device *dev, void *data);
+void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors);
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 0b1dbb54871a..75e3f611e5d8 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -33,14 +33,12 @@ extern void __init pxa26x_init_irq(void);
#define pxa27x_handle_irq ichp_handle_irq
extern int __init pxa27x_clocks_init(void);
-extern void __init pxa27x_dt_init_irq(void);
extern unsigned pxa27x_get_clk_frequency_khz(int);
extern void __init pxa27x_init_irq(void);
extern void __init pxa27x_map_io(void);
#define pxa3xx_handle_irq ichp_handle_irq
extern int __init pxa3xx_clocks_init(void);
-extern void __init pxa3xx_dt_init_irq(void);
extern void __init pxa3xx_init_irq(void);
extern void __init pxa3xx_map_io(void);
diff --git a/arch/arm/mach-pxa/include/mach/dma.h b/arch/arm/mach-pxa/include/mach/dma.h
index 5bd55894a48d..20026bdc6b24 100644
--- a/arch/arm/mach-pxa/include/mach/dma.h
+++ b/arch/arm/mach-pxa/include/mach/dma.h
@@ -17,5 +17,4 @@
/* DMA Controller Registers Definitions */
#define DMAC_REGS_VIRT io_p2v(0x40000000)
-#include <plat/dma.h>
#endif /* _ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 265f48be32c1..b413e36506af 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -121,10 +121,6 @@ static unsigned long magician_pin_config[] __initdata = {
GPIO107_GPIO, /* DS1WM_IRQ */
GPIO108_GPIO, /* GSM_READY */
GPIO115_GPIO, /* nPEN_IRQ */
-
- /* I2C */
- GPIO117_I2C_SCL,
- GPIO118_I2C_SDA,
};
/*
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 388463b99090..e7450fb49d24 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -104,8 +104,9 @@ static int __init pxa_pm_init(void)
return -EINVAL;
}
- sleep_save = kmalloc(pxa_cpu_pm_fns->save_count * sizeof(unsigned long),
- GFP_KERNEL);
+ sleep_save = kmalloc_array(pxa_cpu_pm_fns->save_count,
+ sizeof(*sleep_save),
+ GFP_KERNEL);
if (!sleep_save) {
printk(KERN_ERR "failed to alloc memory for pm save\n");
return -ENOMEM;
diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c
index f128133a8f30..aa9b255f5570 100644
--- a/arch/arm/mach-pxa/pxa-dt.c
+++ b/arch/arm/mach-pxa/pxa-dt.c
@@ -18,20 +18,16 @@
#include "generic.h"
-#ifdef CONFIG_PXA3xx
-static const char *const pxa3xx_dt_board_compat[] __initconst = {
- "marvell,pxa300",
- "marvell,pxa310",
- "marvell,pxa320",
+#ifdef CONFIG_PXA25x
+static const char * const pxa25x_dt_board_compat[] __initconst = {
+ "marvell,pxa250",
NULL,
};
-DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
- .map_io = pxa3xx_map_io,
- .init_irq = pxa3xx_dt_init_irq,
- .handle_irq = pxa3xx_handle_irq,
+DT_MACHINE_START(PXA25X_DT, "Marvell PXA25x (Device Tree Support)")
+ .map_io = pxa25x_map_io,
.restart = pxa_restart,
- .dt_compat = pxa3xx_dt_board_compat,
+ .dt_compat = pxa25x_dt_board_compat,
MACHINE_END
#endif
@@ -41,11 +37,24 @@ static const char * const pxa27x_dt_board_compat[] __initconst = {
NULL,
};
-DT_MACHINE_START(PXA27X_DT, "Marvell PXA2xx (Device Tree Support)")
+DT_MACHINE_START(PXA27X_DT, "Marvell PXA27x (Device Tree Support)")
.map_io = pxa27x_map_io,
- .init_irq = pxa27x_dt_init_irq,
- .handle_irq = pxa27x_handle_irq,
.restart = pxa_restart,
.dt_compat = pxa27x_dt_board_compat,
MACHINE_END
#endif
+
+#ifdef CONFIG_PXA3xx
+static const char *const pxa3xx_dt_board_compat[] __initconst = {
+ "marvell,pxa300",
+ "marvell,pxa310",
+ "marvell,pxa320",
+ NULL,
+};
+
+DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
+ .map_io = pxa3xx_map_io,
+ .restart = pxa_restart,
+ .dt_compat = pxa3xx_dt_board_compat,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 823504f48f80..12b94357fbc1 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -25,6 +25,7 @@
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <asm/mach/map.h>
#include <asm/suspend.h>
@@ -151,6 +152,16 @@ void __init pxa26x_init_irq(void)
}
#endif
+static int __init __init
+pxa25x_dt_init_irq(struct device_node *node, struct device_node *parent)
+{
+ pxa_dt_irq_init(pxa25x_set_wake);
+ set_handle_irq(ichp_handle_irq);
+
+ return 0;
+}
+IRQCHIP_DECLARE(pxa25x_intc, "marvell,pxa-intc", pxa25x_dt_init_irq);
+
static struct map_desc pxa25x_io_desc[] __initdata = {
{ /* Mem Ctl */
.virtual = (unsigned long)SMEMC_VIRT,
@@ -198,20 +209,17 @@ static int __init pxa25x_init(void)
reset_status = RCSR;
- if ((ret = pxa_init_dma(IRQ_DMA, 16)))
- return ret;
-
pxa25x_init_pm();
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
- pxa2xx_set_dmac_info(16, 40);
- pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
- ret = platform_add_devices(pxa25x_devices,
- ARRAY_SIZE(pxa25x_devices));
- if (ret)
- return ret;
+ if (!of_have_populated_dt()) {
+ pxa2xx_set_dmac_info(16, 40);
+ pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
+ ret = platform_add_devices(pxa25x_devices,
+ ARRAY_SIZE(pxa25x_devices));
+ }
}
return ret;
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 2eaa341dd3f8..c0185c5c5a08 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/irqchip.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
@@ -233,11 +234,15 @@ void __init pxa27x_init_irq(void)
pxa_init_irq(34, pxa27x_set_wake);
}
-void __init pxa27x_dt_init_irq(void)
+static int __init
+pxa27x_dt_init_irq(struct device_node *node, struct device_node *parent)
{
- if (IS_ENABLED(CONFIG_OF))
- pxa_dt_irq_init(pxa27x_set_wake);
+ pxa_dt_irq_init(pxa27x_set_wake);
+ set_handle_irq(ichp_handle_irq);
+
+ return 0;
}
+IRQCHIP_DECLARE(pxa27x_intc, "marvell,pxa-intc", pxa27x_dt_init_irq);
static struct map_desc pxa27x_io_desc[] __initdata = {
{ /* Mem Ctl */
@@ -300,9 +305,6 @@ static int __init pxa27x_init(void)
reset_status = RCSR;
- if ((ret = pxa_init_dma(IRQ_DMA, 32)))
- return ret;
-
pxa27x_init_pm();
register_syscore_ops(&pxa_irq_syscore_ops);
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 3c9184d1d6b9..87acc96388c7 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -19,6 +19,7 @@
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/syscore_ops.h>
@@ -356,11 +357,16 @@ void __init pxa3xx_init_irq(void)
}
#ifdef CONFIG_OF
-void __init pxa3xx_dt_init_irq(void)
+static int __init __init
+pxa3xx_dt_init_irq(struct device_node *node, struct device_node *parent)
{
__pxa3xx_init_irq();
pxa_dt_irq_init(pxa3xx_set_wake);
+ set_handle_irq(ichp_handle_irq);
+
+ return 0;
}
+IRQCHIP_DECLARE(pxa3xx_intc, "marvell,pxa-intc", pxa3xx_dt_init_irq);
#endif /* CONFIG_OF */
static struct map_desc pxa3xx_io_desc[] __initdata = {
@@ -438,9 +444,6 @@ static int __init pxa3xx_init(void)
*/
NDCR = (NDCR & ~NDCR_ND_ARB_EN) | NDCR_ND_ARB_CNTL;
- if ((ret = pxa_init_dma(IRQ_DMA, 32)))
- return ret;
-
pxa3xx_init_pm();
register_syscore_ops(&pxa_irq_syscore_ops);
diff --git a/arch/arm/mach-pxa/pxa_cplds_irqs.c b/arch/arm/mach-pxa/pxa_cplds_irqs.c
index 2385052b0ce1..e362f865fcd2 100644
--- a/arch/arm/mach-pxa/pxa_cplds_irqs.c
+++ b/arch/arm/mach-pxa/pxa_cplds_irqs.c
@@ -41,30 +41,35 @@ static irqreturn_t cplds_irq_handler(int in_irq, void *d)
unsigned long pending;
unsigned int bit;
- pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
- for_each_set_bit(bit, &pending, CPLDS_NB_IRQ)
- generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit));
+ do {
+ pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
+ for_each_set_bit(bit, &pending, CPLDS_NB_IRQ) {
+ generic_handle_irq(irq_find_mapping(fpga->irqdomain,
+ bit));
+ }
+ } while (pending);
return IRQ_HANDLED;
}
-static void cplds_irq_mask_ack(struct irq_data *d)
+static void cplds_irq_mask(struct irq_data *d)
{
struct cplds *fpga = irq_data_get_irq_chip_data(d);
unsigned int cplds_irq = irqd_to_hwirq(d);
- unsigned int set, bit = BIT(cplds_irq);
+ unsigned int bit = BIT(cplds_irq);
fpga->irq_mask &= ~bit;
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
- set = readl(fpga->base + FPGA_IRQ_SET_CLR);
- writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
}
static void cplds_irq_unmask(struct irq_data *d)
{
struct cplds *fpga = irq_data_get_irq_chip_data(d);
unsigned int cplds_irq = irqd_to_hwirq(d);
- unsigned int bit = BIT(cplds_irq);
+ unsigned int set, bit = BIT(cplds_irq);
+
+ set = readl(fpga->base + FPGA_IRQ_SET_CLR);
+ writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
fpga->irq_mask |= bit;
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
@@ -72,7 +77,8 @@ static void cplds_irq_unmask(struct irq_data *d)
static struct irq_chip cplds_irq_chip = {
.name = "pxa_cplds",
- .irq_mask_ack = cplds_irq_mask_ack,
+ .irq_ack = cplds_irq_mask,
+ .irq_mask = cplds_irq_mask,
.irq_unmask = cplds_irq_unmask,
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
};
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index b80eab9993c5..249b7bd5fbc4 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -744,7 +744,7 @@ static int sharpsl_off_charge_battery(void)
time = RCNR;
while (1) {
/* Check if any wakeup event had occurred */
- if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+ if (sharpsl_pm.machinfo->charger_wakeup())
return 0;
/* Check for timeout */
if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
diff --git a/arch/arm/mach-pxa/sharpsl_pm.h b/arch/arm/mach-pxa/sharpsl_pm.h
index 905be6755f04..fa75b6df8134 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.h
+++ b/arch/arm/mach-pxa/sharpsl_pm.h
@@ -34,7 +34,7 @@ struct sharpsl_charger_machinfo {
#define SHARPSL_STATUS_LOCK 5
#define SHARPSL_STATUS_CHRGFULL 6
#define SHARPSL_STATUS_FATAL 7
- unsigned long (*charger_wakeup)(void);
+ bool (*charger_wakeup)(void);
int (*should_wakeup)(unsigned int resume_on_alarm);
void (*backlight_limit)(int);
int (*backlight_get_status) (void);
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index ea9f9034cb54..4e64a140252e 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -165,13 +165,10 @@ static int spitz_should_wakeup(unsigned int resume_on_alarm)
return is_resume;
}
-static unsigned long spitz_charger_wakeup(void)
+static bool spitz_charger_wakeup(void)
{
- unsigned long ret;
- ret = ((!gpio_get_value(SPITZ_GPIO_KEY_INT)
- << GPIO_bit(SPITZ_GPIO_KEY_INT))
- | gpio_get_value(SPITZ_GPIO_SYNC));
- return ret;
+ return !gpio_get_value(SPITZ_GPIO_KEY_INT) ||
+ gpio_get_value(SPITZ_GPIO_SYNC);
}
unsigned long spitzpm_read_devdata(int type)
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index e324375fa919..12878e9a2c0c 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -1,2 +1 @@
-obj-y := board.o
obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 70ab4a25a5f8..1d7c83e73ffb 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -2,34 +2,29 @@ menuconfig ARCH_REALVIEW
bool "ARM Ltd. RealView family"
depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7
select ARM_AMBA
+ select ARM_GIC
select ARM_TIMER_SP804
+ select CLK_SP810
select COMMON_CLK_VERSATILE
select GPIO_PL061 if GPIOLIB
- select ICST
- select PLAT_VERSATILE
- select PLAT_VERSATILE_SCHED_CLOCK
- help
- This enables support for ARM Ltd RealView boards.
-
-if ARCH_REALVIEW
-
-config REALVIEW_DT
- bool "Support RealView(R) Device Tree based boot"
- select ARM_GIC
- select CLK_SP810
- select HAVE_SMP
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select HAVE_PATA_PLATFORM
+ select HAVE_TCM
select ICST
select MACH_REALVIEW_EB if ARCH_MULTI_V5
select MFD_SYSCON
+ select PLAT_VERSATILE
+ select PLAT_VERSATILE_SCHED_CLOCK
select POWER_RESET
select POWER_RESET_VERSATILE
select POWER_SUPPLY
- select SMP_ON_UP if SMP
select SOC_REALVIEW
select USE_OF
help
- Include support for booting the ARM(R) RealView(R) evaluation
- boards using a device tree machine description.
+ This enables support for ARM Ltd RealView boards.
+
+if ARCH_REALVIEW
config MACH_REALVIEW_EB
bool "Support RealView(R) Emulation Baseboard"
@@ -60,8 +55,6 @@ config REALVIEW_EB_ARM1176
config REALVIEW_EB_A9MP
bool "Support Multicore Cortex-A9 Tile"
depends on MACH_REALVIEW_EB && ARCH_MULTI_V7
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
@@ -71,30 +64,15 @@ config REALVIEW_EB_A9MP
config REALVIEW_EB_ARM11MP
bool "Support ARM11MPCore Tile"
depends on MACH_REALVIEW_EB && ARCH_MULTI_V6
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
Enable support for the ARM11MPCore tile fitted to the Realview(R)
Emulation Baseboard platform.
-config REALVIEW_EB_ARM11MP_REVB
- bool "Support ARM11MPCore RevB Tile"
- depends on REALVIEW_EB_ARM11MP && ARCH_MULTI_V6
- help
- Enable support for the ARM11MPCore Revision B tile on the
- Realview(R) Emulation Baseboard platform. Since there are device
- address differences, a kernel built with this option enabled is
- not compatible with other revisions of the ARM11MPCore tile.
-
config MACH_REALVIEW_PB11MP
bool "Support RealView(R) Platform Baseboard for ARM11MPCore"
depends on ARCH_MULTI_V6
- select ARM_GIC
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
- select HAVE_PATA_PLATFORM
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
@@ -106,7 +84,6 @@ config MACH_REALVIEW_PB11MP
config MACH_REALVIEW_PB1176
bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S"
depends on ARCH_MULTI_V6
- select ARM_GIC
select CPU_V6
select HAVE_TCM
select MIGHT_HAVE_CACHE_L2X0
@@ -114,20 +91,9 @@ config MACH_REALVIEW_PB1176
Include support for the ARM(R) RealView(R) Platform Baseboard for
ARM1176JZF-S.
-config REALVIEW_PB1176_SECURE_FLASH
- bool "Allow access to the secure flash memory block"
- depends on MACH_REALVIEW_PB1176
- default n
- help
- Select this option if Linux will only run in secure mode on the
- RealView PB1176 platform and access to the secure flash memory
- block (64MB @ 0x3c000000) is required.
-
config MACH_REALVIEW_PBA8
bool "Support RealView(R) Platform Baseboard for Cortex(tm)-A8 platform"
depends on ARCH_MULTI_V7
- select ARM_GIC
- select HAVE_PATA_PLATFORM
help
Include support for the ARM(R) RealView Platform Baseboard for
Cortex(tm)-A8. This platform has an on-board Cortex-A8 and has
@@ -136,10 +102,6 @@ config MACH_REALVIEW_PBA8
config MACH_REALVIEW_PBX
bool "Support RealView(R) Platform Baseboard Explore for Cortex-A9"
depends on ARCH_MULTI_V7
- select ARM_GIC
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
- select HAVE_PATA_PLATFORM
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select ZONE_DMA
@@ -147,16 +109,4 @@ config MACH_REALVIEW_PBX
Include support for the ARM(R) RealView(R) Platform Baseboard
Explore.
-config REALVIEW_HIGH_PHYS_OFFSET
- bool "High physical base address for the RealView platform"
- depends on MMU && !MACH_REALVIEW_PB1176
- default y
- help
- RealView boards other than PB1176 have the RAM available at
- 0x70000000, 256MB of which being mirrored at 0x00000000. If
- the board supports 512MB of RAM, this option allows the
- memory to be accessed contiguously at the high physical
- offset. On the PBX board, disabling this option allows 1GB of
- RAM to be used with HIGHMEM.
-
endif
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 404882130956..adf39ad71cc3 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -3,16 +3,6 @@
#
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-versatile/include
-obj-y := core.o
-obj-$(CONFIG_REALVIEW_DT) += realview-dt.o
+obj-y += realview-dt.o
obj-$(CONFIG_SMP) += platsmp-dt.o
-
-ifdef CONFIG_ATAGS
-obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
-obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o
-obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o
-obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o
-obj-$(CONFIG_MACH_REALVIEW_PBX) += realview_pbx.o
-obj-$(CONFIG_SMP) += platsmp.o
-endif
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-realview/board-eb.h b/arch/arm/mach-realview/board-eb.h
deleted file mode 100644
index a850ae6945b0..000000000000
--- a/arch/arm/mach-realview/board-eb.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2007 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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_ARCH_BOARD_EB_H
-#define __ASM_ARCH_BOARD_EB_H
-
-#include "platform.h"
-
-/*
- * RealView EB + ARM11MPCore peripheral addresses
- */
-#define REALVIEW_EB_UART0_BASE 0x10009000 /* UART 0 */
-#define REALVIEW_EB_UART1_BASE 0x1000A000 /* UART 1 */
-#define REALVIEW_EB_UART2_BASE 0x1000B000 /* UART 2 */
-#define REALVIEW_EB_UART3_BASE 0x1000C000 /* UART 3 */
-#define REALVIEW_EB_SSP_BASE 0x1000D000 /* Synchronous Serial Port */
-#define REALVIEW_EB_WATCHDOG_BASE 0x10010000 /* watchdog interface */
-#define REALVIEW_EB_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */
-#define REALVIEW_EB_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */
-#define REALVIEW_EB_GPIO0_BASE 0x10013000 /* GPIO port 0 */
-#define REALVIEW_EB_RTC_BASE 0x10017000 /* Real Time Clock */
-#define REALVIEW_EB_CLCD_BASE 0x10020000 /* CLCD */
-#define REALVIEW_EB_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */
-#define REALVIEW_EB_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */
-#define REALVIEW_EB_SMC_BASE 0x10080000 /* Static memory controller */
-
-#define REALVIEW_EB_FLASH_BASE 0x40000000
-#define REALVIEW_EB_FLASH_SIZE SZ_64M
-#define REALVIEW_EB_ETH_BASE 0x4E000000 /* Ethernet */
-#define REALVIEW_EB_USB_BASE 0x4F000000 /* USB */
-
-#ifdef CONFIG_REALVIEW_EB_ARM11MP_REVB
-#define REALVIEW_EB11MP_PRIV_MEM_BASE 0x10100000
-#define REALVIEW_EB11MP_L220_BASE 0x10102000 /* L220 registers */
-#define REALVIEW_EB11MP_SYS_PLD_CTRL1 0xD8 /* Register offset for MPCore sysctl */
-#else
-#define REALVIEW_EB11MP_PRIV_MEM_BASE 0x1F000000
-#define REALVIEW_EB11MP_L220_BASE 0x1F002000 /* L220 registers */
-#define REALVIEW_EB11MP_SYS_PLD_CTRL1 0x74 /* Register offset for MPCore sysctl */
-#endif
-
-#define REALVIEW_EB11MP_PRIV_MEM_SIZE SZ_8K
-#define REALVIEW_EB11MP_PRIV_MEM_OFF(x) (REALVIEW_EB11MP_PRIV_MEM_BASE + (x))
-
-#define REALVIEW_EB11MP_SCU_BASE REALVIEW_EB11MP_PRIV_MEM_OFF(0) /* SCU registers */
-#define REALVIEW_EB11MP_GIC_CPU_BASE REALVIEW_EB11MP_PRIV_MEM_OFF(0x0100) /* Generic interrupt controller CPU interface */
-#define REALVIEW_EB11MP_TWD_BASE REALVIEW_EB11MP_PRIV_MEM_OFF(0x0600)
-#define REALVIEW_EB11MP_GIC_DIST_BASE REALVIEW_EB11MP_PRIV_MEM_OFF(0x1000) /* Generic interrupt controller distributor */
-
-/*
- * Core tile identification (REALVIEW_SYS_PROCID)
- */
-#define REALVIEW_EB_PROC_MASK 0xFF000000
-#define REALVIEW_EB_PROC_ARM7TDMI 0x00000000
-#define REALVIEW_EB_PROC_ARM9 0x02000000
-#define REALVIEW_EB_PROC_ARM11 0x04000000
-#define REALVIEW_EB_PROC_ARM11MP 0x06000000
-#define REALVIEW_EB_PROC_A9MP 0x0C000000
-
-#define check_eb_proc(proc_type) \
- ((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_EB_PROC_MASK) \
- == proc_type)
-
-#ifdef CONFIG_REALVIEW_EB_ARM11MP
-#define core_tile_eb11mp() check_eb_proc(REALVIEW_EB_PROC_ARM11MP)
-#else
-#define core_tile_eb11mp() 0
-#endif
-
-#ifdef CONFIG_REALVIEW_EB_A9MP
-#define core_tile_a9mp() check_eb_proc(REALVIEW_EB_PROC_A9MP)
-#else
-#define core_tile_a9mp() 0
-#endif
-
-#define machine_is_realview_eb_mp() \
- (machine_is_realview_eb() && (core_tile_eb11mp() || core_tile_a9mp()))
-
-#endif /* __ASM_ARCH_BOARD_EB_H */
diff --git a/arch/arm/mach-realview/board-pb1176.h b/arch/arm/mach-realview/board-pb1176.h
deleted file mode 100644
index 29c04a9e1344..000000000000
--- a/arch/arm/mach-realview/board-pb1176.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2008 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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_ARCH_BOARD_PB1176_H
-#define __ASM_ARCH_BOARD_PB1176_H
-
-#include "platform.h"
-
-/*
- * Peripheral addresses
- */
-#define REALVIEW_PB1176_UART4_BASE 0x10009000 /* UART 4 */
-#define REALVIEW_PB1176_SCTL_BASE 0x10100000 /* System controller */
-#define REALVIEW_PB1176_SMC_BASE 0x10111000 /* SMC */
-#define REALVIEW_PB1176_DMC_BASE 0x10109000 /* DMC configuration */
-#define REALVIEW_PB1176_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */
-#define REALVIEW_PB1176_FLASH_BASE 0x30000000
-#define REALVIEW_PB1176_FLASH_SIZE SZ_64M
-#define REALVIEW_PB1176_SEC_FLASH_BASE 0x3C000000 /* Secure flash */
-#define REALVIEW_PB1176_SEC_FLASH_SIZE SZ_64M
-
-#define REALVIEW_PB1176_TIMER0_1_BASE 0x10104000 /* Timer 0 and 1 */
-#define REALVIEW_PB1176_TIMER2_3_BASE 0x10105000 /* Timer 2 and 3 */
-#define REALVIEW_PB1176_TIMER4_5_BASE 0x10106000 /* Timer 4 and 5 */
-#define REALVIEW_PB1176_WATCHDOG_BASE 0x10107000 /* watchdog interface */
-#define REALVIEW_PB1176_RTC_BASE 0x10108000 /* Real Time Clock */
-#define REALVIEW_PB1176_GPIO0_BASE 0x1010A000 /* GPIO port 0 */
-#define REALVIEW_PB1176_SSP_BASE 0x1010B000 /* Synchronous Serial Port */
-#define REALVIEW_PB1176_UART0_BASE 0x1010C000 /* UART 0 */
-#define REALVIEW_PB1176_UART1_BASE 0x1010D000 /* UART 1 */
-#define REALVIEW_PB1176_UART2_BASE 0x1010E000 /* UART 2 */
-#define REALVIEW_PB1176_UART3_BASE 0x1010F000 /* UART 3 */
-#define REALVIEW_PB1176_CLCD_BASE 0x10112000 /* CLCD */
-#define REALVIEW_PB1176_ETH_BASE 0x3A000000 /* Ethernet */
-#define REALVIEW_PB1176_USB_BASE 0x3B000000 /* USB */
-
-/*
- * PCI regions
- */
-#define REALVIEW_PB1176_PCI_BASE 0x60000000 /* PCI self config */
-#define REALVIEW_PB1176_PCI_CFG_BASE 0x61000000 /* PCI config */
-#define REALVIEW_PB1176_PCI_IO_BASE0 0x62000000 /* PCI IO region */
-#define REALVIEW_PB1176_PCI_MEM_BASE0 0x63000000 /* Memory region 1 */
-#define REALVIEW_PB1176_PCI_MEM_BASE1 0x64000000 /* Memory region 2 */
-#define REALVIEW_PB1176_PCI_MEM_BASE2 0x68000000 /* Memory region 3 */
-
-#define REALVIEW_PB1176_PCI_BASE_SIZE 0x01000000 /* 16MB */
-#define REALVIEW_PB1176_PCI_CFG_BASE_SIZE 0x01000000 /* 16MB */
-#define REALVIEW_PB1176_PCI_IO_BASE0_SIZE 0x01000000 /* 16MB */
-#define REALVIEW_PB1176_PCI_MEM_BASE0_SIZE 0x01000000 /* 16MB */
-#define REALVIEW_PB1176_PCI_MEM_BASE1_SIZE 0x04000000 /* 64MB */
-#define REALVIEW_PB1176_PCI_MEM_BASE2_SIZE 0x08000000 /* 128MB */
-
-#define REALVIEW_DC1176_GIC_CPU_BASE 0x10120000 /* GIC CPU interface, on devchip */
-#define REALVIEW_DC1176_GIC_DIST_BASE 0x10121000 /* GIC distributor, on devchip */
-#define REALVIEW_DC1176_ROM_BASE 0x10200000 /* 16KiB NRAM preudo-ROM, on devchip */
-#define REALVIEW_PB1176_GIC_CPU_BASE 0x10040000 /* GIC CPU interface, on FPGA */
-#define REALVIEW_PB1176_GIC_DIST_BASE 0x10041000 /* GIC distributor, on FPGA */
-#define REALVIEW_PB1176_L220_BASE 0x10110000 /* L220 registers */
-
-/*
- * Control register SYS_RESETCTL Bit 8 is set to 1 to force a soft reset
- */
-#define REALVIEW_PB1176_SYS_SOFT_RESET 0x0100
-
-#endif /* __ASM_ARCH_BOARD_PB1176_H */
diff --git a/arch/arm/mach-realview/board-pb11mp.h b/arch/arm/mach-realview/board-pb11mp.h
deleted file mode 100644
index b16e6e85e92d..000000000000
--- a/arch/arm/mach-realview/board-pb11mp.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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_ARCH_BOARD_PB11MP_H
-#define __ASM_ARCH_BOARD_PB11MP_H
-
-#include "platform.h"
-
-/*
- * Peripheral addresses
- */
-#define REALVIEW_PB11MP_UART0_BASE 0x10009000 /* UART 0 */
-#define REALVIEW_PB11MP_UART1_BASE 0x1000A000 /* UART 1 */
-#define REALVIEW_PB11MP_UART2_BASE 0x1000B000 /* UART 2 */
-#define REALVIEW_PB11MP_UART3_BASE 0x1000C000 /* UART 3 */
-#define REALVIEW_PB11MP_SSP_BASE 0x1000D000 /* Synchronous Serial Port */
-#define REALVIEW_PB11MP_WATCHDOG0_BASE 0x1000F000 /* Watchdog 0 */
-#define REALVIEW_PB11MP_WATCHDOG_BASE 0x10010000 /* watchdog interface */
-#define REALVIEW_PB11MP_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */
-#define REALVIEW_PB11MP_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */
-#define REALVIEW_PB11MP_GPIO0_BASE 0x10013000 /* GPIO port 0 */
-#define REALVIEW_PB11MP_RTC_BASE 0x10017000 /* Real Time Clock */
-#define REALVIEW_PB11MP_TIMER4_5_BASE 0x10018000 /* Timer 4/5 */
-#define REALVIEW_PB11MP_TIMER6_7_BASE 0x10019000 /* Timer 6/7 */
-#define REALVIEW_PB11MP_SCTL_BASE 0x1001A000 /* System Controller */
-#define REALVIEW_PB11MP_CLCD_BASE 0x10020000 /* CLCD */
-#define REALVIEW_PB11MP_ONB_SRAM_BASE 0x10060000 /* On-board SRAM */
-#define REALVIEW_PB11MP_DMC_BASE 0x100E0000 /* DMC configuration */
-#define REALVIEW_PB11MP_SMC_BASE 0x100E1000 /* SMC configuration */
-#define REALVIEW_PB11MP_CAN_BASE 0x100E2000 /* CAN bus */
-#define REALVIEW_PB11MP_CF_BASE 0x18000000 /* Compact flash */
-#define REALVIEW_PB11MP_CF_MEM_BASE 0x18003000 /* SMC for Compact flash */
-#define REALVIEW_PB11MP_GIC_CPU_BASE 0x1E000000 /* Generic interrupt controller CPU interface */
-#define REALVIEW_PB11MP_FLASH0_BASE 0x40000000
-#define REALVIEW_PB11MP_FLASH0_SIZE SZ_64M
-#define REALVIEW_PB11MP_FLASH1_BASE 0x44000000
-#define REALVIEW_PB11MP_FLASH1_SIZE SZ_64M
-#define REALVIEW_PB11MP_ETH_BASE 0x4E000000 /* Ethernet */
-#define REALVIEW_PB11MP_USB_BASE 0x4F000000 /* USB */
-#define REALVIEW_PB11MP_GIC_DIST_BASE 0x1E001000 /* Generic interrupt controller distributor */
-#define REALVIEW_PB11MP_LT_BASE 0xC0000000 /* Logic Tile expansion */
-#define REALVIEW_PB11MP_SDRAM6_BASE 0x70000000 /* SDRAM bank 6 256MB */
-#define REALVIEW_PB11MP_SDRAM7_BASE 0x80000000 /* SDRAM bank 7 256MB */
-
-#define REALVIEW_PB11MP_SYS_PLD_CTRL1 0x74
-
-/*
- * PB11MPCore PCI regions
- */
-#define REALVIEW_PB11MP_PCI_BASE 0x90040000 /* PCI-X Unit base */
-#define REALVIEW_PB11MP_PCI_IO_BASE 0x90050000 /* IO Region on AHB */
-#define REALVIEW_PB11MP_PCI_MEM_BASE 0xA0000000 /* MEM Region on AHB */
-
-#define REALVIEW_PB11MP_PCI_BASE_SIZE 0x10000 /* 16 Kb */
-#define REALVIEW_PB11MP_PCI_IO_SIZE 0x1000 /* 4 Kb */
-#define REALVIEW_PB11MP_PCI_MEM_SIZE 0x20000000 /* 512 MB */
-
-/*
- * Testchip peripheral and fpga gic regions
- */
-#define REALVIEW_TC11MP_PRIV_MEM_BASE 0x1F000000
-#define REALVIEW_TC11MP_PRIV_MEM_SIZE SZ_8K
-#define REALVIEW_TC11MP_SCU_BASE 0x1F000000 /* IRQ, Test chip */
-#define REALVIEW_TC11MP_GIC_CPU_BASE 0x1F000100 /* Test chip interrupt controller CPU interface */
-#define REALVIEW_TC11MP_TWD_BASE 0x1F000600
-#define REALVIEW_TC11MP_GIC_DIST_BASE 0x1F001000 /* Test chip interrupt controller distributor */
-#define REALVIEW_TC11MP_L220_BASE 0x1F002000 /* L220 registers */
-
- /*
- * Values for REALVIEW_SYS_RESET_CTRL
- */
-#define REALVIEW_PB11MP_SYS_CTRL_RESET_CONFIGCLR 0x01
-#define REALVIEW_PB11MP_SYS_CTRL_RESET_CONFIGINIT 0x02
-#define REALVIEW_PB11MP_SYS_CTRL_RESET_DLLRESET 0x03
-#define REALVIEW_PB11MP_SYS_CTRL_RESET_PLLRESET 0x04
-#define REALVIEW_PB11MP_SYS_CTRL_RESET_POR 0x05
-#define REALVIEW_PB11MP_SYS_CTRL_RESET_DoC 0x06
-
-#define REALVIEW_PB11MP_SYS_CTRL_LED (1 << 0)
-
-#endif /* __ASM_ARCH_BOARD_PB11MP_H */
diff --git a/arch/arm/mach-realview/board-pba8.h b/arch/arm/mach-realview/board-pba8.h
deleted file mode 100644
index 6a1391f50373..000000000000
--- a/arch/arm/mach-realview/board-pba8.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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_ARCH_BOARD_PBA8_H
-#define __ASM_ARCH_BOARD_PBA8_H
-
-#include "platform.h"
-
-/*
- * Peripheral addresses
- */
-#define REALVIEW_PBA8_UART0_BASE 0x10009000 /* UART 0 */
-#define REALVIEW_PBA8_UART1_BASE 0x1000A000 /* UART 1 */
-#define REALVIEW_PBA8_UART2_BASE 0x1000B000 /* UART 2 */
-#define REALVIEW_PBA8_UART3_BASE 0x1000C000 /* UART 3 */
-#define REALVIEW_PBA8_SSP_BASE 0x1000D000 /* Synchronous Serial Port */
-#define REALVIEW_PBA8_WATCHDOG0_BASE 0x1000F000 /* Watchdog 0 */
-#define REALVIEW_PBA8_WATCHDOG_BASE 0x10010000 /* watchdog interface */
-#define REALVIEW_PBA8_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */
-#define REALVIEW_PBA8_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */
-#define REALVIEW_PBA8_GPIO0_BASE 0x10013000 /* GPIO port 0 */
-#define REALVIEW_PBA8_RTC_BASE 0x10017000 /* Real Time Clock */
-#define REALVIEW_PBA8_TIMER4_5_BASE 0x10018000 /* Timer 4/5 */
-#define REALVIEW_PBA8_TIMER6_7_BASE 0x10019000 /* Timer 6/7 */
-#define REALVIEW_PBA8_SCTL_BASE 0x1001A000 /* System Controller */
-#define REALVIEW_PBA8_CLCD_BASE 0x10020000 /* CLCD */
-#define REALVIEW_PBA8_ONB_SRAM_BASE 0x10060000 /* On-board SRAM */
-#define REALVIEW_PBA8_DMC_BASE 0x100E0000 /* DMC configuration */
-#define REALVIEW_PBA8_SMC_BASE 0x100E1000 /* SMC configuration */
-#define REALVIEW_PBA8_CAN_BASE 0x100E2000 /* CAN bus */
-#define REALVIEW_PBA8_GIC_CPU_BASE 0x1E000000 /* Generic interrupt controller CPU interface */
-#define REALVIEW_PBA8_FLASH0_BASE 0x40000000
-#define REALVIEW_PBA8_FLASH0_SIZE SZ_64M
-#define REALVIEW_PBA8_FLASH1_BASE 0x44000000
-#define REALVIEW_PBA8_FLASH1_SIZE SZ_64M
-#define REALVIEW_PBA8_ETH_BASE 0x4E000000 /* Ethernet */
-#define REALVIEW_PBA8_USB_BASE 0x4F000000 /* USB */
-#define REALVIEW_PBA8_GIC_DIST_BASE 0x1E001000 /* Generic interrupt controller distributor */
-#define REALVIEW_PBA8_LT_BASE 0xC0000000 /* Logic Tile expansion */
-#define REALVIEW_PBA8_SDRAM6_BASE 0x70000000 /* SDRAM bank 6 256MB */
-#define REALVIEW_PBA8_SDRAM7_BASE 0x80000000 /* SDRAM bank 7 256MB */
-
-#define REALVIEW_PBA8_SYS_PLD_CTRL1 0x74
-
-/*
- * PBA8 PCI regions
- */
-#define REALVIEW_PBA8_PCI_BASE 0x90040000 /* PCI-X Unit base */
-#define REALVIEW_PBA8_PCI_IO_BASE 0x90050000 /* IO Region on AHB */
-#define REALVIEW_PBA8_PCI_MEM_BASE 0xA0000000 /* MEM Region on AHB */
-
-#define REALVIEW_PBA8_PCI_BASE_SIZE 0x10000 /* 16 Kb */
-#define REALVIEW_PBA8_PCI_IO_SIZE 0x1000 /* 4 Kb */
-#define REALVIEW_PBA8_PCI_MEM_SIZE 0x20000000 /* 512 MB */
-
-#endif /* __ASM_ARCH_BOARD_PBA8_H */
diff --git a/arch/arm/mach-realview/board-pbx.h b/arch/arm/mach-realview/board-pbx.h
deleted file mode 100644
index 5cda480b12bb..000000000000
--- a/arch/arm/mach-realview/board-pbx.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2009 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __ASM_ARCH_BOARD_PBX_H
-#define __ASM_ARCH_BOARD_PBX_H
-
-#include "platform.h"
-
-/*
- * Peripheral addresses
- */
-#define REALVIEW_PBX_UART0_BASE 0x10009000 /* UART 0 */
-#define REALVIEW_PBX_UART1_BASE 0x1000A000 /* UART 1 */
-#define REALVIEW_PBX_UART2_BASE 0x1000B000 /* UART 2 */
-#define REALVIEW_PBX_UART3_BASE 0x1000C000 /* UART 3 */
-#define REALVIEW_PBX_SSP_BASE 0x1000D000 /* Synchronous Serial Port */
-#define REALVIEW_PBX_WATCHDOG0_BASE 0x1000F000 /* Watchdog 0 */
-#define REALVIEW_PBX_WATCHDOG_BASE 0x10010000 /* watchdog interface */
-#define REALVIEW_PBX_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */
-#define REALVIEW_PBX_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */
-#define REALVIEW_PBX_GPIO0_BASE 0x10013000 /* GPIO port 0 */
-#define REALVIEW_PBX_RTC_BASE 0x10017000 /* Real Time Clock */
-#define REALVIEW_PBX_TIMER4_5_BASE 0x10018000 /* Timer 4/5 */
-#define REALVIEW_PBX_TIMER6_7_BASE 0x10019000 /* Timer 6/7 */
-#define REALVIEW_PBX_SCTL_BASE 0x1001A000 /* System Controller */
-#define REALVIEW_PBX_CLCD_BASE 0x10020000 /* CLCD */
-#define REALVIEW_PBX_ONB_SRAM_BASE 0x10060000 /* On-board SRAM */
-#define REALVIEW_PBX_DMC_BASE 0x100E0000 /* DMC configuration */
-#define REALVIEW_PBX_SMC_BASE 0x100E1000 /* SMC configuration */
-#define REALVIEW_PBX_CAN_BASE 0x100E2000 /* CAN bus */
-#define REALVIEW_PBX_GIC_CPU_BASE 0x1E000000 /* Generic interrupt controller CPU interface */
-#define REALVIEW_PBX_FLASH0_BASE 0x40000000
-#define REALVIEW_PBX_FLASH0_SIZE SZ_64M
-#define REALVIEW_PBX_FLASH1_BASE 0x44000000
-#define REALVIEW_PBX_FLASH1_SIZE SZ_64M
-#define REALVIEW_PBX_ETH_BASE 0x4E000000 /* Ethernet */
-#define REALVIEW_PBX_USB_BASE 0x4F000000 /* USB */
-#define REALVIEW_PBX_GIC_DIST_BASE 0x1E001000 /* Generic interrupt controller distributor */
-#define REALVIEW_PBX_LT_BASE 0xC0000000 /* Logic Tile expansion */
-#define REALVIEW_PBX_SDRAM6_BASE 0x70000000 /* SDRAM bank 6 256MB */
-#define REALVIEW_PBX_SDRAM7_BASE 0x80000000 /* SDRAM bank 7 256MB */
-
-/*
- * Tile-specific addresses
- */
-#define REALVIEW_PBX_TILE_SCU_BASE 0x1F000000 /* SCU registers */
-#define REALVIEW_PBX_TILE_GIC_CPU_BASE 0x1F000100 /* Private Generic interrupt controller CPU interface */
-#define REALVIEW_PBX_TILE_TWD_BASE 0x1F000600
-#define REALVIEW_PBX_TILE_TWD_PERCPU_BASE 0x1F000700
-#define REALVIEW_PBX_TILE_TWD_SIZE 0x00000100
-#define REALVIEW_PBX_TILE_GIC_DIST_BASE 0x1F001000 /* Private Generic interrupt controller distributor */
-#define REALVIEW_PBX_TILE_L220_BASE 0x1F002000 /* L220 registers */
-
-#define REALVIEW_PBX_SYS_PLD_CTRL1 0x74
-
-/*
- * PBX PCI regions
- */
-#define REALVIEW_PBX_PCI_BASE 0x90040000 /* PCI-X Unit base */
-#define REALVIEW_PBX_PCI_IO_BASE 0x90050000 /* IO Region on AHB */
-#define REALVIEW_PBX_PCI_MEM_BASE 0xA0000000 /* MEM Region on AHB */
-
-#define REALVIEW_PBX_PCI_BASE_SIZE 0x10000 /* 16 Kb */
-#define REALVIEW_PBX_PCI_IO_SIZE 0x1000 /* 4 Kb */
-#define REALVIEW_PBX_PCI_MEM_SIZE 0x20000000 /* 512 MB */
-
-/*
- * Core tile identification (REALVIEW_SYS_PROCID)
- */
-#define REALVIEW_PBX_PROC_MASK 0xFF000000
-#define REALVIEW_PBX_PROC_ARM7TDMI 0x00000000
-#define REALVIEW_PBX_PROC_ARM9 0x02000000
-#define REALVIEW_PBX_PROC_ARM11 0x04000000
-#define REALVIEW_PBX_PROC_ARM11MP 0x06000000
-#define REALVIEW_PBX_PROC_A9MP 0x0C000000
-#define REALVIEW_PBX_PROC_A8 0x0E000000
-
-#define check_pbx_proc(proc_type) \
- ((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_PBX_PROC_MASK) \
- == proc_type)
-
-#ifdef CONFIG_MACH_REALVIEW_PBX
-#define core_tile_pbx11mp() check_pbx_proc(REALVIEW_PBX_PROC_ARM11MP)
-#define core_tile_pbxa9mp() check_pbx_proc(REALVIEW_PBX_PROC_A9MP)
-#define core_tile_pbxa8() check_pbx_proc(REALVIEW_PBX_PROC_A8)
-#else
-#define core_tile_pbx11mp() 0
-#define core_tile_pbxa9mp() 0
-#define core_tile_pbxa8() 0
-#endif
-
-#endif /* __ASM_ARCH_BOARD_PBX_H */
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
deleted file mode 100644
index a0ead0ae23d6..000000000000
--- a/arch/arm/mach-realview/core.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/core.c
- *
- * Copyright (C) 1999 - 2003 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in 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/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/platform_data/video-clcd-versatile.h>
-#include <linux/io.h>
-#include <linux/smsc911x.h>
-#include <linux/smc91x.h>
-#include <linux/ata_platform.h>
-#include <linux/amba/mmci.h>
-#include <linux/gfp.h>
-#include <linux/mtd/physmap.h>
-#include <linux/memblock.h>
-
-#include <clocksource/timer-sp804.h>
-#include "hardware.h"
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/hardware/icst.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/map.h>
-
-#include "platform.h"
-
-#include <plat/sched_clock.h>
-
-#include "core.h"
-
-#define REALVIEW_FLASHCTRL (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET)
-
-static void realview_flash_set_vpp(struct platform_device *pdev, int on)
-{
- u32 val;
-
- val = __raw_readl(REALVIEW_FLASHCTRL);
- if (on)
- val |= REALVIEW_FLASHPROG_FLVPPEN;
- else
- val &= ~REALVIEW_FLASHPROG_FLVPPEN;
- __raw_writel(val, REALVIEW_FLASHCTRL);
-}
-
-static struct physmap_flash_data realview_flash_data = {
- .width = 4,
- .set_vpp = realview_flash_set_vpp,
-};
-
-struct platform_device realview_flash_device = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &realview_flash_data,
- },
-};
-
-int realview_flash_register(struct resource *res, u32 num)
-{
- realview_flash_device.resource = res;
- realview_flash_device.num_resources = num;
- return platform_device_register(&realview_flash_device);
-}
-
-static struct smsc911x_platform_config smsc911x_config = {
- .flags = SMSC911X_USE_32BIT,
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
- .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct smc91x_platdata smc91x_platdata = {
- .flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
- SMC91X_NOWAIT,
-};
-
-static struct platform_device realview_eth_device = {
- .name = "smsc911x",
- .id = 0,
- .num_resources = 2,
-};
-
-int realview_eth_register(const char *name, struct resource *res)
-{
- if (name)
- realview_eth_device.name = name;
- realview_eth_device.resource = res;
- if (strcmp(realview_eth_device.name, "smsc911x") == 0)
- realview_eth_device.dev.platform_data = &smsc911x_config;
- else
- realview_eth_device.dev.platform_data = &smc91x_platdata;
-
- return platform_device_register(&realview_eth_device);
-}
-
-struct platform_device realview_usb_device = {
- .name = "isp1760",
- .num_resources = 2,
-};
-
-int realview_usb_register(struct resource *res)
-{
- realview_usb_device.resource = res;
- return platform_device_register(&realview_usb_device);
-}
-
-static struct pata_platform_info pata_platform_data = {
- .ioport_shift = 1,
-};
-
-static struct resource pata_resources[] = {
- [0] = {
- .start = REALVIEW_CF_BASE,
- .end = REALVIEW_CF_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = REALVIEW_CF_BASE + 0x100,
- .end = REALVIEW_CF_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-struct platform_device realview_cf_device = {
- .name = "pata_platform",
- .id = -1,
- .num_resources = ARRAY_SIZE(pata_resources),
- .resource = pata_resources,
- .dev = {
- .platform_data = &pata_platform_data,
- },
-};
-
-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,
- .flags = IORESOURCE_MEM,
-};
-
-struct platform_device realview_i2c_device = {
- .name = "versatile-i2c",
- .id = 0,
- .num_resources = 1,
- .resource = &realview_i2c_resource,
-};
-
-static struct i2c_board_info realview_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("ds1338", 0xd0 >> 1),
- },
-};
-
-static int __init realview_i2c_init(void)
-{
- return i2c_register_board_info(0, realview_i2c_board_info,
- ARRAY_SIZE(realview_i2c_board_info));
-}
-arch_initcall(realview_i2c_init);
-
-#define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET)
-
-/*
- * This is only used if GPIOLIB support is disabled
- */
-static unsigned int realview_mmc_status(struct device *dev)
-{
- struct amba_device *adev = container_of(dev, struct amba_device, dev);
- u32 mask;
-
- if (machine_is_realview_pb1176()) {
- static bool inserted = false;
-
- /*
- * The PB1176 does not have the status register,
- * assume it is inserted at startup, then invert
- * for each call so card insertion/removal will
- * be detected anyway. This will not be called if
- * GPIO on PL061 is active, which is the proper
- * way to do this on the PB1176.
- */
- inserted = !inserted;
- return inserted ? 0 : 1;
- }
-
- if (adev->res.start == REALVIEW_MMCI0_BASE)
- mask = 1;
- else
- mask = 2;
-
- return readl(REALVIEW_SYSMCI) & mask;
-}
-
-struct mmci_platform_data realview_mmc0_plat_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .status = realview_mmc_status,
- .gpio_wp = 17,
- .gpio_cd = 16,
- .cd_invert = true,
-};
-
-struct mmci_platform_data realview_mmc1_plat_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .status = realview_mmc_status,
- .gpio_wp = 19,
- .gpio_cd = 18,
- .cd_invert = true,
-};
-
-void __init realview_init_early(void)
-{
- void __iomem *sys = __io_address(REALVIEW_SYS_BASE);
-
- versatile_sched_clock_init(sys + REALVIEW_SYS_24MHz_OFFSET, 24000000);
-}
-
-/*
- * CLCD support.
- */
-#define SYS_CLCD_NLCDIOON (1 << 2)
-#define SYS_CLCD_VDDPOSSWITCH (1 << 3)
-#define SYS_CLCD_PWR3V5SWITCH (1 << 4)
-#define SYS_CLCD_ID_MASK (0x1f << 8)
-#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
-#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
-#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
-#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
-#define SYS_CLCD_ID_VGA (0x1f << 8)
-
-/*
- * Disable all display connectors on the interface module.
- */
-static void realview_clcd_disable(struct clcd_fb *fb)
-{
- void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
- u32 val;
-
- val = readl(sys_clcd);
- val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
- writel(val, sys_clcd);
-}
-
-/*
- * Enable the relevant connector on the interface module.
- */
-static void realview_clcd_enable(struct clcd_fb *fb)
-{
- void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
- u32 val;
-
- /*
- * Enable the PSUs
- */
- val = readl(sys_clcd);
- val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
- writel(val, sys_clcd);
-}
-
-/*
- * Detect which LCD panel is connected, and return the appropriate
- * clcd_panel structure. Note: we do not have any information on
- * the required timings for the 8.4in panel, so we presently assume
- * VGA timings.
- */
-static int realview_clcd_setup(struct clcd_fb *fb)
-{
- void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
- const char *panel_name, *vga_panel_name;
- unsigned long framesize;
- u32 val;
-
- if (machine_is_realview_eb()) {
- /* VGA, 16bpp */
- framesize = 640 * 480 * 2;
- vga_panel_name = "VGA";
- } else {
- /* XVGA, 16bpp */
- framesize = 1024 * 768 * 2;
- vga_panel_name = "XVGA";
- }
-
- val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
- if (val == SYS_CLCD_ID_SANYO_3_8)
- panel_name = "Sanyo TM38QV67A02A";
- else if (val == SYS_CLCD_ID_SANYO_2_5)
- panel_name = "Sanyo QVGA Portrait";
- else if (val == SYS_CLCD_ID_EPSON_2_2)
- panel_name = "Epson L2F50113T00";
- else if (val == SYS_CLCD_ID_VGA)
- panel_name = vga_panel_name;
- else {
- pr_err("CLCD: unknown LCD panel ID 0x%08x, using VGA\n", val);
- panel_name = vga_panel_name;
- }
-
- fb->panel = versatile_clcd_get_panel(panel_name);
- if (!fb->panel)
- return -EINVAL;
-
- return versatile_clcd_setup_dma(fb, framesize);
-}
-
-struct clcd_board clcd_plat_data = {
- .name = "RealView",
- .caps = CLCD_CAP_ALL,
- .check = clcdfb_check,
- .decode = clcdfb_decode,
- .disable = realview_clcd_disable,
- .enable = realview_clcd_enable,
- .setup = realview_clcd_setup,
- .mmap = versatile_clcd_mmap_dma,
- .remove = versatile_clcd_remove_dma,
-};
-
-/*
- * Where is the timer (VA)?
- */
-void __iomem *timer0_va_base;
-void __iomem *timer1_va_base;
-void __iomem *timer2_va_base;
-void __iomem *timer3_va_base;
-
-/*
- * Set up the clock source and clock events devices
- */
-void __init realview_timer_init(unsigned int timer_irq)
-{
- u32 val;
-
- /*
- * set clock frequency:
- * REALVIEW_REFCLK is 32KHz
- * REALVIEW_TIMCLK is 1MHz
- */
- val = readl(__io_address(REALVIEW_SCTL_BASE));
- writel((REALVIEW_TIMCLK << REALVIEW_TIMER1_EnSel) |
- (REALVIEW_TIMCLK << REALVIEW_TIMER2_EnSel) |
- (REALVIEW_TIMCLK << REALVIEW_TIMER3_EnSel) |
- (REALVIEW_TIMCLK << REALVIEW_TIMER4_EnSel) | val,
- __io_address(REALVIEW_SCTL_BASE));
-
- /*
- * Initialise to a known state (all timers off)
- */
- sp804_timer_disable(timer0_va_base);
- sp804_timer_disable(timer1_va_base);
- sp804_timer_disable(timer2_va_base);
- sp804_timer_disable(timer3_va_base);
-
- sp804_clocksource_init(timer3_va_base, "timer3");
- sp804_clockevents_init(timer0_va_base, timer_irq, "timer0");
-}
-
-/*
- * Setup the memory banks.
- */
-void realview_fixup(struct tag *tags, char **from)
-{
- /*
- * Most RealView platforms have 512MB contiguous RAM at 0x70000000.
- * Half of this is mirrored at 0.
- */
-#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
- memblock_add(0x70000000, SZ_512M);
-#else
- memblock_add(0, SZ_256M);
-#endif
-}
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
deleted file mode 100644
index 05a995ea16d3..000000000000
--- a/arch/arm/mach-realview/core.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2004 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __ASM_ARCH_REALVIEW_H
-#define __ASM_ARCH_REALVIEW_H
-
-#include <linux/amba/bus.h>
-#include <linux/io.h>
-
-#include <asm/setup.h>
-
-#define APB_DEVICE(name, busid, base, plat) \
-static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
-
-#define AHB_DEVICE(name, busid, base, plat) \
-static AMBA_AHB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
-
-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;
-extern struct clcd_board clcd_plat_data;
-extern void __iomem *timer0_va_base;
-extern void __iomem *timer1_va_base;
-extern void __iomem *timer2_va_base;
-extern void __iomem *timer3_va_base;
-
-extern void realview_timer_init(unsigned int timer_irq);
-extern int realview_flash_register(struct resource *res, u32 num);
-extern int realview_eth_register(const char *name, struct resource *res);
-extern int realview_usb_register(struct resource *res);
-extern void realview_init_early(void);
-extern void realview_fixup(struct tag *tags, char **from);
-
-extern const struct smp_operations realview_smp_ops;
-extern void realview_cpu_die(unsigned int cpu);
-
-#endif
diff --git a/arch/arm/mach-realview/hardware.h b/arch/arm/mach-realview/hardware.h
deleted file mode 100644
index 957a230aadf4..000000000000
--- a/arch/arm/mach-realview/hardware.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file contains the hardware definitions of the RealView boards.
- *
- * Copyright (C) 2003 ARM Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <asm/sizes.h>
-
-/* macro to get at IO space when running virtually */
-#ifdef CONFIG_MMU
-/*
- * Statically mapped addresses:
- *
- * 10xx xxxx -> fbxx xxxx
- * 1exx xxxx -> fdxx xxxx
- * 1fxx xxxx -> fexx xxxx
- */
-#define IO_ADDRESS(x) (((x) & 0x03ffffff) + 0xfb000000)
-#else
-#define IO_ADDRESS(x) (x)
-#endif
-#define __io_address(n) IOMEM(IO_ADDRESS(n))
-
-#endif
diff --git a/arch/arm/mach-realview/hotplug.h b/arch/arm/mach-realview/hotplug.h
new file mode 100644
index 000000000000..eacd7a4dad2f
--- /dev/null
+++ b/arch/arm/mach-realview/hotplug.h
@@ -0,0 +1 @@
+void realview_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-realview/irqs-eb.h b/arch/arm/mach-realview/irqs-eb.h
deleted file mode 100644
index 61e31680a749..000000000000
--- a/arch/arm/mach-realview/irqs-eb.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2007 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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 __MACH_IRQS_EB_H
-#define __MACH_IRQS_EB_H
-
-#define IRQ_LOCALTIMER 29
-#define IRQ_EB_GIC_START 32
-
-/*
- * RealView EB interrupt sources
- */
-#define IRQ_EB_WDOG (IRQ_EB_GIC_START + 0) /* Watchdog timer */
-#define IRQ_EB_SOFT (IRQ_EB_GIC_START + 1) /* Software interrupt */
-#define IRQ_EB_COMMRx (IRQ_EB_GIC_START + 2) /* Debug Comm Rx interrupt */
-#define IRQ_EB_COMMTx (IRQ_EB_GIC_START + 3) /* Debug Comm Tx interrupt */
-#define IRQ_EB_TIMER0_1 (IRQ_EB_GIC_START + 4) /* Timer 0 and 1 */
-#define IRQ_EB_TIMER2_3 (IRQ_EB_GIC_START + 5) /* Timer 2 and 3 */
-#define IRQ_EB_GPIO0 (IRQ_EB_GIC_START + 6) /* GPIO 0 */
-#define IRQ_EB_GPIO1 (IRQ_EB_GIC_START + 7) /* GPIO 1 */
-#define IRQ_EB_GPIO2 (IRQ_EB_GIC_START + 8) /* GPIO 2 */
- /* 9 reserved */
-#define IRQ_EB_RTC (IRQ_EB_GIC_START + 10) /* Real Time Clock */
-#define IRQ_EB_SSP (IRQ_EB_GIC_START + 11) /* Synchronous Serial Port */
-#define IRQ_EB_UART0 (IRQ_EB_GIC_START + 12) /* UART 0 on development chip */
-#define IRQ_EB_UART1 (IRQ_EB_GIC_START + 13) /* UART 1 on development chip */
-#define IRQ_EB_UART2 (IRQ_EB_GIC_START + 14) /* UART 2 on development chip */
-#define IRQ_EB_UART3 (IRQ_EB_GIC_START + 15) /* UART 3 on development chip */
-#define IRQ_EB_SCI (IRQ_EB_GIC_START + 16) /* Smart Card Interface */
-#define IRQ_EB_MMCI0A (IRQ_EB_GIC_START + 17) /* Multimedia Card 0A */
-#define IRQ_EB_MMCI0B (IRQ_EB_GIC_START + 18) /* Multimedia Card 0B */
-#define IRQ_EB_AACI (IRQ_EB_GIC_START + 19) /* Audio Codec */
-#define IRQ_EB_KMI0 (IRQ_EB_GIC_START + 20) /* Keyboard/Mouse port 0 */
-#define IRQ_EB_KMI1 (IRQ_EB_GIC_START + 21) /* Keyboard/Mouse port 1 */
-#define IRQ_EB_CHARLCD (IRQ_EB_GIC_START + 22) /* Character LCD */
-#define IRQ_EB_CLCD (IRQ_EB_GIC_START + 23) /* CLCD controller */
-#define IRQ_EB_DMA (IRQ_EB_GIC_START + 24) /* DMA controller */
-#define IRQ_EB_PWRFAIL (IRQ_EB_GIC_START + 25) /* Power failure */
-#define IRQ_EB_PISMO (IRQ_EB_GIC_START + 26) /* PISMO interface */
-#define IRQ_EB_DoC (IRQ_EB_GIC_START + 27) /* Disk on Chip memory controller */
-#define IRQ_EB_ETH (IRQ_EB_GIC_START + 28) /* Ethernet controller */
-#define IRQ_EB_USB (IRQ_EB_GIC_START + 29) /* USB controller */
-#define IRQ_EB_TSPEN (IRQ_EB_GIC_START + 30) /* Touchscreen pen */
-#define IRQ_EB_TSKPAD (IRQ_EB_GIC_START + 31) /* Touchscreen keypad */
-
-/*
- * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
- */
-#define IRQ_EB11MP_AACI (IRQ_EB_GIC_START + 0)
-#define IRQ_EB11MP_TIMER0_1 (IRQ_EB_GIC_START + 1)
-#define IRQ_EB11MP_TIMER2_3 (IRQ_EB_GIC_START + 2)
-#define IRQ_EB11MP_USB (IRQ_EB_GIC_START + 3)
-#define IRQ_EB11MP_UART0 (IRQ_EB_GIC_START + 4)
-#define IRQ_EB11MP_UART1 (IRQ_EB_GIC_START + 5)
-#define IRQ_EB11MP_RTC (IRQ_EB_GIC_START + 6)
-#define IRQ_EB11MP_KMI0 (IRQ_EB_GIC_START + 7)
-#define IRQ_EB11MP_KMI1 (IRQ_EB_GIC_START + 8)
-#define IRQ_EB11MP_ETH (IRQ_EB_GIC_START + 9)
-#define IRQ_EB11MP_EB_IRQ1 (IRQ_EB_GIC_START + 10) /* main GIC */
-#define IRQ_EB11MP_EB_IRQ2 (IRQ_EB_GIC_START + 11) /* tile GIC */
-#define IRQ_EB11MP_EB_FIQ1 (IRQ_EB_GIC_START + 12) /* main GIC */
-#define IRQ_EB11MP_EB_FIQ2 (IRQ_EB_GIC_START + 13) /* tile GIC */
-#define IRQ_EB11MP_MMCI0A (IRQ_EB_GIC_START + 14)
-#define IRQ_EB11MP_MMCI0B (IRQ_EB_GIC_START + 15)
-
-#define IRQ_EB11MP_PMU_CPU0 (IRQ_EB_GIC_START + 17)
-#define IRQ_EB11MP_PMU_CPU1 (IRQ_EB_GIC_START + 18)
-#define IRQ_EB11MP_PMU_CPU2 (IRQ_EB_GIC_START + 19)
-#define IRQ_EB11MP_PMU_CPU3 (IRQ_EB_GIC_START + 20)
-#define IRQ_EB11MP_PMU_SCU0 (IRQ_EB_GIC_START + 21)
-#define IRQ_EB11MP_PMU_SCU1 (IRQ_EB_GIC_START + 22)
-#define IRQ_EB11MP_PMU_SCU2 (IRQ_EB_GIC_START + 23)
-#define IRQ_EB11MP_PMU_SCU3 (IRQ_EB_GIC_START + 24)
-#define IRQ_EB11MP_PMU_SCU4 (IRQ_EB_GIC_START + 25)
-#define IRQ_EB11MP_PMU_SCU5 (IRQ_EB_GIC_START + 26)
-#define IRQ_EB11MP_PMU_SCU6 (IRQ_EB_GIC_START + 27)
-#define IRQ_EB11MP_PMU_SCU7 (IRQ_EB_GIC_START + 28)
-
-#define IRQ_EB11MP_L220_EVENT (IRQ_EB_GIC_START + 29)
-#define IRQ_EB11MP_L220_SLAVE (IRQ_EB_GIC_START + 30)
-#define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
-
-/*
- * The 11MPcore tile leaves the following unconnected.
- */
-#define IRQ_EB11MP_UART2 0
-#define IRQ_EB11MP_UART3 0
-#define IRQ_EB11MP_CLCD 0
-#define IRQ_EB11MP_DMA 0
-#define IRQ_EB11MP_WDOG 0
-#define IRQ_EB11MP_GPIO0 0
-#define IRQ_EB11MP_GPIO1 0
-#define IRQ_EB11MP_GPIO2 0
-#define IRQ_EB11MP_SCI 0
-#define IRQ_EB11MP_SSP 0
-
-#define NR_GIC_EB11MP 2
-
-#endif /* __MACH_IRQS_EB_H */
diff --git a/arch/arm/mach-realview/irqs-pb1176.h b/arch/arm/mach-realview/irqs-pb1176.h
deleted file mode 100644
index 778edfd430e7..000000000000
--- a/arch/arm/mach-realview/irqs-pb1176.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2008 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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 __MACH_IRQS_PB1176_H
-#define __MACH_IRQS_PB1176_H
-
-#define IRQ_DC1176_GIC_START 32
-#define IRQ_PB1176_GIC_START 64
-
-/*
- * ARM1176 DevChip interrupt sources (primary GIC)
- */
-#define IRQ_DC1176_WATCHDOG (IRQ_DC1176_GIC_START + 0) /* Watchdog timer */
-#define IRQ_DC1176_SOFTINT (IRQ_DC1176_GIC_START + 1) /* Software interrupt */
-#define IRQ_DC1176_COMMRx (IRQ_DC1176_GIC_START + 2) /* Debug Comm Rx interrupt */
-#define IRQ_DC1176_COMMTx (IRQ_DC1176_GIC_START + 3) /* Debug Comm Tx interrupt */
-#define IRQ_DC1176_CORE_PMU (IRQ_DC1176_GIC_START + 7) /* Core PMU interrupt */
-#define IRQ_DC1176_TIMER0 (IRQ_DC1176_GIC_START + 8) /* Timer 0 */
-#define IRQ_DC1176_TIMER1 (IRQ_DC1176_GIC_START + 9) /* Timer 1 */
-#define IRQ_DC1176_TIMER2 (IRQ_DC1176_GIC_START + 10) /* Timer 2 */
-#define IRQ_DC1176_APC (IRQ_DC1176_GIC_START + 11)
-#define IRQ_DC1176_IEC (IRQ_DC1176_GIC_START + 12)
-#define IRQ_DC1176_L2CC (IRQ_DC1176_GIC_START + 13)
-#define IRQ_DC1176_RTC (IRQ_DC1176_GIC_START + 14)
-#define IRQ_DC1176_CLCD (IRQ_DC1176_GIC_START + 15) /* CLCD controller */
-#define IRQ_DC1176_GPIO0 (IRQ_DC1176_GIC_START + 16)
-#define IRQ_DC1176_SSP (IRQ_DC1176_GIC_START + 17) /* SSP port */
-#define IRQ_DC1176_UART0 (IRQ_DC1176_GIC_START + 18) /* UART 0 on development chip */
-#define IRQ_DC1176_UART1 (IRQ_DC1176_GIC_START + 19) /* UART 1 on development chip */
-#define IRQ_DC1176_UART2 (IRQ_DC1176_GIC_START + 20) /* UART 2 on development chip */
-#define IRQ_DC1176_UART3 (IRQ_DC1176_GIC_START + 21) /* UART 3 on development chip */
-
-#define IRQ_DC1176_PB_IRQ2 (IRQ_DC1176_GIC_START + 30) /* tile GIC */
-#define IRQ_DC1176_PB_IRQ1 (IRQ_DC1176_GIC_START + 31) /* main GIC */
-
-/*
- * RealView PB1176 interrupt sources (secondary GIC)
- */
-#define IRQ_PB1176_MMCI0A (IRQ_PB1176_GIC_START + 1) /* Multimedia Card 0A */
-#define IRQ_PB1176_MMCI0B (IRQ_PB1176_GIC_START + 2) /* Multimedia Card 0A */
-#define IRQ_PB1176_KMI0 (IRQ_PB1176_GIC_START + 3) /* Keyboard/Mouse port 0 */
-#define IRQ_PB1176_KMI1 (IRQ_PB1176_GIC_START + 4) /* Keyboard/Mouse port 1 */
-#define IRQ_PB1176_SCI (IRQ_PB1176_GIC_START + 5)
-#define IRQ_PB1176_UART4 (IRQ_PB1176_GIC_START + 6) /* UART 4 on baseboard */
-#define IRQ_PB1176_CHARLCD (IRQ_PB1176_GIC_START + 7) /* Character LCD */
-#define IRQ_PB1176_GPIO1 (IRQ_PB1176_GIC_START + 8)
-#define IRQ_PB1176_GPIO2 (IRQ_PB1176_GIC_START + 9)
-#define IRQ_PB1176_ETH (IRQ_PB1176_GIC_START + 10) /* Ethernet controller */
-#define IRQ_PB1176_USB (IRQ_PB1176_GIC_START + 11) /* USB controller */
-
-#define IRQ_PB1176_PISMO (IRQ_PB1176_GIC_START + 16)
-
-#define IRQ_PB1176_AACI (IRQ_PB1176_GIC_START + 19) /* Audio Codec */
-
-#define IRQ_PB1176_TIMER0_1 (IRQ_PB1176_GIC_START + 22)
-#define IRQ_PB1176_TIMER2_3 (IRQ_PB1176_GIC_START + 23)
-#define IRQ_PB1176_DMAC (IRQ_PB1176_GIC_START + 24) /* DMA controller */
-#define IRQ_PB1176_RTC (IRQ_PB1176_GIC_START + 25) /* Real Time Clock */
-
-#define IRQ_PB1176_SCTL -1
-
-#endif /* __MACH_IRQS_PB1176_H */
diff --git a/arch/arm/mach-realview/irqs-pb11mp.h b/arch/arm/mach-realview/irqs-pb11mp.h
deleted file mode 100644
index 938898a3df9f..000000000000
--- a/arch/arm/mach-realview/irqs-pb11mp.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2008 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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 __MACH_IRQS_PB11MP_H
-#define __MACH_IRQS_PB11MP_H
-
-#define IRQ_LOCALTIMER 29
-#define IRQ_TC11MP_GIC_START 32
-#define IRQ_PB11MP_GIC_START 64
-
-/*
- * ARM11MPCore test chip interrupt sources (primary GIC on the test chip)
- */
-#define IRQ_TC11MP_AACI (IRQ_TC11MP_GIC_START + 0)
-#define IRQ_TC11MP_TIMER0_1 (IRQ_TC11MP_GIC_START + 1)
-#define IRQ_TC11MP_TIMER2_3 (IRQ_TC11MP_GIC_START + 2)
-#define IRQ_TC11MP_USB (IRQ_TC11MP_GIC_START + 3)
-#define IRQ_TC11MP_UART0 (IRQ_TC11MP_GIC_START + 4)
-#define IRQ_TC11MP_UART1 (IRQ_TC11MP_GIC_START + 5)
-#define IRQ_TC11MP_RTC (IRQ_TC11MP_GIC_START + 6)
-#define IRQ_TC11MP_KMI0 (IRQ_TC11MP_GIC_START + 7)
-#define IRQ_TC11MP_KMI1 (IRQ_TC11MP_GIC_START + 8)
-#define IRQ_TC11MP_ETH (IRQ_TC11MP_GIC_START + 9)
-#define IRQ_TC11MP_PB_IRQ1 (IRQ_TC11MP_GIC_START + 10) /* main GIC */
-#define IRQ_TC11MP_PB_IRQ2 (IRQ_TC11MP_GIC_START + 11) /* tile GIC */
-#define IRQ_TC11MP_PB_FIQ1 (IRQ_TC11MP_GIC_START + 12) /* main GIC */
-#define IRQ_TC11MP_PB_FIQ2 (IRQ_TC11MP_GIC_START + 13) /* tile GIC */
-#define IRQ_TC11MP_MMCI0A (IRQ_TC11MP_GIC_START + 14)
-#define IRQ_TC11MP_MMCI0B (IRQ_TC11MP_GIC_START + 15)
-
-#define IRQ_TC11MP_PMU_CPU0 (IRQ_TC11MP_GIC_START + 17)
-#define IRQ_TC11MP_PMU_CPU1 (IRQ_TC11MP_GIC_START + 18)
-#define IRQ_TC11MP_PMU_CPU2 (IRQ_TC11MP_GIC_START + 19)
-#define IRQ_TC11MP_PMU_CPU3 (IRQ_TC11MP_GIC_START + 20)
-#define IRQ_TC11MP_PMU_SCU0 (IRQ_TC11MP_GIC_START + 21)
-#define IRQ_TC11MP_PMU_SCU1 (IRQ_TC11MP_GIC_START + 22)
-#define IRQ_TC11MP_PMU_SCU2 (IRQ_TC11MP_GIC_START + 23)
-#define IRQ_TC11MP_PMU_SCU3 (IRQ_TC11MP_GIC_START + 24)
-#define IRQ_TC11MP_PMU_SCU4 (IRQ_TC11MP_GIC_START + 25)
-#define IRQ_TC11MP_PMU_SCU5 (IRQ_TC11MP_GIC_START + 26)
-#define IRQ_TC11MP_PMU_SCU6 (IRQ_TC11MP_GIC_START + 27)
-#define IRQ_TC11MP_PMU_SCU7 (IRQ_TC11MP_GIC_START + 28)
-
-#define IRQ_TC11MP_L220_EVENT (IRQ_TC11MP_GIC_START + 29)
-#define IRQ_TC11MP_L220_SLAVE (IRQ_TC11MP_GIC_START + 30)
-#define IRQ_TC11MP_L220_DECODE (IRQ_TC11MP_GIC_START + 31)
-
-/*
- * RealView PB11MPCore GIC interrupt sources (secondary GIC on the board)
- */
-#define IRQ_PB11MP_WATCHDOG (IRQ_PB11MP_GIC_START + 0) /* Watchdog timer */
-#define IRQ_PB11MP_SOFT (IRQ_PB11MP_GIC_START + 1) /* Software interrupt */
-#define IRQ_PB11MP_COMMRx (IRQ_PB11MP_GIC_START + 2) /* Debug Comm Rx interrupt */
-#define IRQ_PB11MP_COMMTx (IRQ_PB11MP_GIC_START + 3) /* Debug Comm Tx interrupt */
-#define IRQ_PB11MP_GPIO0 (IRQ_PB11MP_GIC_START + 6) /* GPIO 0 */
-#define IRQ_PB11MP_GPIO1 (IRQ_PB11MP_GIC_START + 7) /* GPIO 1 */
-#define IRQ_PB11MP_GPIO2 (IRQ_PB11MP_GIC_START + 8) /* GPIO 2 */
- /* 9 reserved */
-#define IRQ_PB11MP_RTC_GIC1 (IRQ_PB11MP_GIC_START + 10) /* Real Time Clock */
-#define IRQ_PB11MP_SSP (IRQ_PB11MP_GIC_START + 11) /* Synchronous Serial Port */
-#define IRQ_PB11MP_UART0_GIC1 (IRQ_PB11MP_GIC_START + 12) /* UART 0 on development chip */
-#define IRQ_PB11MP_UART1_GIC1 (IRQ_PB11MP_GIC_START + 13) /* UART 1 on development chip */
-#define IRQ_PB11MP_UART2 (IRQ_PB11MP_GIC_START + 14) /* UART 2 on development chip */
-#define IRQ_PB11MP_UART3 (IRQ_PB11MP_GIC_START + 15) /* UART 3 on development chip */
-#define IRQ_PB11MP_SCI (IRQ_PB11MP_GIC_START + 16) /* Smart Card Interface */
-#define IRQ_PB11MP_MMCI0A_GIC1 (IRQ_PB11MP_GIC_START + 17) /* Multimedia Card 0A */
-#define IRQ_PB11MP_MMCI0B_GIC1 (IRQ_PB11MP_GIC_START + 18) /* Multimedia Card 0B */
-#define IRQ_PB11MP_AACI_GIC1 (IRQ_PB11MP_GIC_START + 19) /* Audio Codec */
-#define IRQ_PB11MP_KMI0_GIC1 (IRQ_PB11MP_GIC_START + 20) /* Keyboard/Mouse port 0 */
-#define IRQ_PB11MP_KMI1_GIC1 (IRQ_PB11MP_GIC_START + 21) /* Keyboard/Mouse port 1 */
-#define IRQ_PB11MP_CHARLCD (IRQ_PB11MP_GIC_START + 22) /* Character LCD */
-#define IRQ_PB11MP_CLCD (IRQ_PB11MP_GIC_START + 23) /* CLCD controller */
-#define IRQ_PB11MP_DMAC (IRQ_PB11MP_GIC_START + 24) /* DMA controller */
-#define IRQ_PB11MP_PWRFAIL (IRQ_PB11MP_GIC_START + 25) /* Power failure */
-#define IRQ_PB11MP_PISMO (IRQ_PB11MP_GIC_START + 26) /* PISMO interface */
-#define IRQ_PB11MP_DoC (IRQ_PB11MP_GIC_START + 27) /* Disk on Chip memory controller */
-#define IRQ_PB11MP_ETH_GIC1 (IRQ_PB11MP_GIC_START + 28) /* Ethernet controller */
-#define IRQ_PB11MP_USB_GIC1 (IRQ_PB11MP_GIC_START + 29) /* USB controller */
-#define IRQ_PB11MP_TSPEN (IRQ_PB11MP_GIC_START + 30) /* Touchscreen pen */
-#define IRQ_PB11MP_TSKPAD (IRQ_PB11MP_GIC_START + 31) /* Touchscreen keypad */
-
-#endif /* __MACH_IRQS_PB11MP_H */
diff --git a/arch/arm/mach-realview/irqs-pba8.h b/arch/arm/mach-realview/irqs-pba8.h
deleted file mode 100644
index 262e321938b8..000000000000
--- a/arch/arm/mach-realview/irqs-pba8.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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 __MACH_IRQS_PBA8_H
-#define __MACH_IRQS_PBA8_H
-
-#define IRQ_PBA8_GIC_START 32
-
-/*
- * PB-A8 on-board gic irq sources
- */
-#define IRQ_PBA8_WATCHDOG (IRQ_PBA8_GIC_START + 0) /* Watchdog timer */
-#define IRQ_PBA8_SOFT (IRQ_PBA8_GIC_START + 1) /* Software interrupt */
-#define IRQ_PBA8_COMMRx (IRQ_PBA8_GIC_START + 2) /* Debug Comm Rx interrupt */
-#define IRQ_PBA8_COMMTx (IRQ_PBA8_GIC_START + 3) /* Debug Comm Tx interrupt */
-#define IRQ_PBA8_TIMER0_1 (IRQ_PBA8_GIC_START + 4) /* Timer 0/1 (default timer) */
-#define IRQ_PBA8_TIMER2_3 (IRQ_PBA8_GIC_START + 5) /* Timer 2/3 */
-#define IRQ_PBA8_GPIO0 (IRQ_PBA8_GIC_START + 6) /* GPIO 0 */
-#define IRQ_PBA8_GPIO1 (IRQ_PBA8_GIC_START + 7) /* GPIO 1 */
-#define IRQ_PBA8_GPIO2 (IRQ_PBA8_GIC_START + 8) /* GPIO 2 */
- /* 9 reserved */
-#define IRQ_PBA8_RTC (IRQ_PBA8_GIC_START + 10) /* Real Time Clock */
-#define IRQ_PBA8_SSP (IRQ_PBA8_GIC_START + 11) /* Synchronous Serial Port */
-#define IRQ_PBA8_UART0 (IRQ_PBA8_GIC_START + 12) /* UART 0 on development chip */
-#define IRQ_PBA8_UART1 (IRQ_PBA8_GIC_START + 13) /* UART 1 on development chip */
-#define IRQ_PBA8_UART2 (IRQ_PBA8_GIC_START + 14) /* UART 2 on development chip */
-#define IRQ_PBA8_UART3 (IRQ_PBA8_GIC_START + 15) /* UART 3 on development chip */
-#define IRQ_PBA8_SCI (IRQ_PBA8_GIC_START + 16) /* Smart Card Interface */
-#define IRQ_PBA8_MMCI0A (IRQ_PBA8_GIC_START + 17) /* Multimedia Card 0A */
-#define IRQ_PBA8_MMCI0B (IRQ_PBA8_GIC_START + 18) /* Multimedia Card 0B */
-#define IRQ_PBA8_AACI (IRQ_PBA8_GIC_START + 19) /* Audio Codec */
-#define IRQ_PBA8_KMI0 (IRQ_PBA8_GIC_START + 20) /* Keyboard/Mouse port 0 */
-#define IRQ_PBA8_KMI1 (IRQ_PBA8_GIC_START + 21) /* Keyboard/Mouse port 1 */
-#define IRQ_PBA8_CHARLCD (IRQ_PBA8_GIC_START + 22) /* Character LCD */
-#define IRQ_PBA8_CLCD (IRQ_PBA8_GIC_START + 23) /* CLCD controller */
-#define IRQ_PBA8_DMAC (IRQ_PBA8_GIC_START + 24) /* DMA controller */
-#define IRQ_PBA8_PWRFAIL (IRQ_PBA8_GIC_START + 25) /* Power failure */
-#define IRQ_PBA8_PISMO (IRQ_PBA8_GIC_START + 26) /* PISMO interface */
-#define IRQ_PBA8_DoC (IRQ_PBA8_GIC_START + 27) /* Disk on Chip memory controller */
-#define IRQ_PBA8_ETH (IRQ_PBA8_GIC_START + 28) /* Ethernet controller */
-#define IRQ_PBA8_USB (IRQ_PBA8_GIC_START + 29) /* USB controller */
-#define IRQ_PBA8_TSPEN (IRQ_PBA8_GIC_START + 30) /* Touchscreen pen */
-#define IRQ_PBA8_TSKPAD (IRQ_PBA8_GIC_START + 31) /* Touchscreen keypad */
-
-#define IRQ_PBA8_PMU (IRQ_PBA8_GIC_START + 47) /* Cortex-A8 PMU */
-
-/* ... */
-#define IRQ_PBA8_PCI0 (IRQ_PBA8_GIC_START + 50)
-#define IRQ_PBA8_PCI1 (IRQ_PBA8_GIC_START + 51)
-#define IRQ_PBA8_PCI2 (IRQ_PBA8_GIC_START + 52)
-#define IRQ_PBA8_PCI3 (IRQ_PBA8_GIC_START + 53)
-
-#define IRQ_PBA8_SMC -1
-#define IRQ_PBA8_SCTL -1
-
-#endif /* __MACH_IRQS_PBA8_H */
diff --git a/arch/arm/mach-realview/irqs-pbx.h b/arch/arm/mach-realview/irqs-pbx.h
deleted file mode 100644
index 4ef0567dec32..000000000000
--- a/arch/arm/mach-realview/irqs-pbx.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2009 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __MACH_IRQS_PBX_H
-#define __MACH_IRQS_PBX_H
-
-#define IRQ_LOCALTIMER 29
-#define IRQ_PBX_GIC_START 32
-
-/*
- * PBX on-board gic irq sources
- */
-#define IRQ_PBX_WATCHDOG (IRQ_PBX_GIC_START + 0) /* Watchdog timer */
-#define IRQ_PBX_SOFT (IRQ_PBX_GIC_START + 1) /* Software interrupt */
-#define IRQ_PBX_COMMRx (IRQ_PBX_GIC_START + 2) /* Debug Comm Rx interrupt */
-#define IRQ_PBX_COMMTx (IRQ_PBX_GIC_START + 3) /* Debug Comm Tx interrupt */
-#define IRQ_PBX_TIMER0_1 (IRQ_PBX_GIC_START + 4) /* Timer 0/1 (default timer) */
-#define IRQ_PBX_TIMER2_3 (IRQ_PBX_GIC_START + 5) /* Timer 2/3 */
-#define IRQ_PBX_GPIO0 (IRQ_PBX_GIC_START + 6) /* GPIO 0 */
-#define IRQ_PBX_GPIO1 (IRQ_PBX_GIC_START + 7) /* GPIO 1 */
-#define IRQ_PBX_GPIO2 (IRQ_PBX_GIC_START + 8) /* GPIO 2 */
- /* 9 reserved */
-#define IRQ_PBX_RTC (IRQ_PBX_GIC_START + 10) /* Real Time Clock */
-#define IRQ_PBX_SSP (IRQ_PBX_GIC_START + 11) /* Synchronous Serial Port */
-#define IRQ_PBX_UART0 (IRQ_PBX_GIC_START + 12) /* UART 0 on development chip */
-#define IRQ_PBX_UART1 (IRQ_PBX_GIC_START + 13) /* UART 1 on development chip */
-#define IRQ_PBX_UART2 (IRQ_PBX_GIC_START + 14) /* UART 2 on development chip */
-#define IRQ_PBX_UART3 (IRQ_PBX_GIC_START + 15) /* UART 3 on development chip */
-#define IRQ_PBX_SCI (IRQ_PBX_GIC_START + 16) /* Smart Card Interface */
-#define IRQ_PBX_MMCI0A (IRQ_PBX_GIC_START + 17) /* Multimedia Card 0A */
-#define IRQ_PBX_MMCI0B (IRQ_PBX_GIC_START + 18) /* Multimedia Card 0B */
-#define IRQ_PBX_AACI (IRQ_PBX_GIC_START + 19) /* Audio Codec */
-#define IRQ_PBX_KMI0 (IRQ_PBX_GIC_START + 20) /* Keyboard/Mouse port 0 */
-#define IRQ_PBX_KMI1 (IRQ_PBX_GIC_START + 21) /* Keyboard/Mouse port 1 */
-#define IRQ_PBX_CHARLCD (IRQ_PBX_GIC_START + 22) /* Character LCD */
-#define IRQ_PBX_CLCD (IRQ_PBX_GIC_START + 23) /* CLCD controller */
-#define IRQ_PBX_DMAC (IRQ_PBX_GIC_START + 24) /* DMA controller */
-#define IRQ_PBX_PWRFAIL (IRQ_PBX_GIC_START + 25) /* Power failure */
-#define IRQ_PBX_PISMO (IRQ_PBX_GIC_START + 26) /* PISMO interface */
-#define IRQ_PBX_DoC (IRQ_PBX_GIC_START + 27) /* Disk on Chip memory controller */
-#define IRQ_PBX_ETH (IRQ_PBX_GIC_START + 28) /* Ethernet controller */
-#define IRQ_PBX_USB (IRQ_PBX_GIC_START + 29) /* USB controller */
-#define IRQ_PBX_TSPEN (IRQ_PBX_GIC_START + 30) /* Touchscreen pen */
-#define IRQ_PBX_TSKPAD (IRQ_PBX_GIC_START + 31) /* Touchscreen keypad */
-
-#define IRQ_PBX_PMU_SCU0 (IRQ_PBX_GIC_START + 32) /* SCU PMU Interrupts (11mp) */
-#define IRQ_PBX_PMU_SCU1 (IRQ_PBX_GIC_START + 33)
-#define IRQ_PBX_PMU_SCU2 (IRQ_PBX_GIC_START + 34)
-#define IRQ_PBX_PMU_SCU3 (IRQ_PBX_GIC_START + 35)
-#define IRQ_PBX_PMU_SCU4 (IRQ_PBX_GIC_START + 36)
-#define IRQ_PBX_PMU_SCU5 (IRQ_PBX_GIC_START + 37)
-#define IRQ_PBX_PMU_SCU6 (IRQ_PBX_GIC_START + 38)
-#define IRQ_PBX_PMU_SCU7 (IRQ_PBX_GIC_START + 39)
-
-#define IRQ_PBX_WATCHDOG1 (IRQ_PBX_GIC_START + 40) /* Watchdog1 timer */
-#define IRQ_PBX_TIMER4_5 (IRQ_PBX_GIC_START + 41) /* Timer 0/1 (default timer) */
-#define IRQ_PBX_TIMER6_7 (IRQ_PBX_GIC_START + 42) /* Timer 2/3 */
-/* ... */
-#define IRQ_PBX_PMU_CPU0 (IRQ_PBX_GIC_START + 44) /* CPU PMU Interrupts */
-#define IRQ_PBX_PMU_CPU1 (IRQ_PBX_GIC_START + 45)
-#define IRQ_PBX_PMU_CPU2 (IRQ_PBX_GIC_START + 46)
-#define IRQ_PBX_PMU_CPU3 (IRQ_PBX_GIC_START + 47)
-
-/* ... */
-#define IRQ_PBX_PCI0 (IRQ_PBX_GIC_START + 50)
-#define IRQ_PBX_PCI1 (IRQ_PBX_GIC_START + 51)
-#define IRQ_PBX_PCI2 (IRQ_PBX_GIC_START + 52)
-#define IRQ_PBX_PCI3 (IRQ_PBX_GIC_START + 53)
-
-#define IRQ_PBX_SMC -1
-#define IRQ_PBX_SCTL -1
-
-#endif /* __MACH_IRQS_PBX_H */
diff --git a/arch/arm/mach-realview/platform.h b/arch/arm/mach-realview/platform.h
deleted file mode 100644
index 11121739d371..000000000000
--- a/arch/arm/mach-realview/platform.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) ARM Limited 2003. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __ASM_ARCH_PLATFORM_H
-#define __ASM_ARCH_PLATFORM_H
-
-/*
- * Memory definitions
- */
-#define REALVIEW_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)...*/
-#define REALVIEW_BOOT_ROM_HI 0x30000000
-#define REALVIEW_BOOT_ROM_BASE REALVIEW_BOOT_ROM_HI /* Normal position */
-#define REALVIEW_BOOT_ROM_SIZE SZ_64M
-
-#define REALVIEW_SSRAM_BASE /* REALVIEW_SSMC_BASE ? */
-#define REALVIEW_SSRAM_SIZE SZ_2M
-
-/*
- * SDRAM
- */
-#define REALVIEW_SDRAM_BASE 0x00000000
-
-/*
- * Logic expansion modules
- *
- */
-
-
-/* ------------------------------------------------------------------------
- * RealView Registers
- * ------------------------------------------------------------------------
- *
- */
-#define REALVIEW_SYS_ID_OFFSET 0x00
-#define REALVIEW_SYS_SW_OFFSET 0x04
-#define REALVIEW_SYS_LED_OFFSET 0x08
-#define REALVIEW_SYS_OSC0_OFFSET 0x0C
-
-#define REALVIEW_SYS_OSC1_OFFSET 0x10
-#define REALVIEW_SYS_OSC2_OFFSET 0x14
-#define REALVIEW_SYS_OSC3_OFFSET 0x18
-#define REALVIEW_SYS_OSC4_OFFSET 0x1C /* OSC1 for RealView/AB */
-
-#define REALVIEW_SYS_LOCK_OFFSET 0x20
-#define REALVIEW_SYS_100HZ_OFFSET 0x24
-#define REALVIEW_SYS_CFGDATA1_OFFSET 0x28
-#define REALVIEW_SYS_CFGDATA2_OFFSET 0x2C
-#define REALVIEW_SYS_FLAGS_OFFSET 0x30
-#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30
-#define REALVIEW_SYS_FLAGSCLR_OFFSET 0x34
-#define REALVIEW_SYS_NVFLAGS_OFFSET 0x38
-#define REALVIEW_SYS_NVFLAGSSET_OFFSET 0x38
-#define REALVIEW_SYS_NVFLAGSCLR_OFFSET 0x3C
-#define REALVIEW_SYS_RESETCTL_OFFSET 0x40
-#define REALVIEW_SYS_PCICTL_OFFSET 0x44
-#define REALVIEW_SYS_MCI_OFFSET 0x48
-#define REALVIEW_SYS_FLASH_OFFSET 0x4C
-#define REALVIEW_SYS_CLCD_OFFSET 0x50
-#define REALVIEW_SYS_CLCDSER_OFFSET 0x54
-#define REALVIEW_SYS_BOOTCS_OFFSET 0x58
-#define REALVIEW_SYS_24MHz_OFFSET 0x5C
-#define REALVIEW_SYS_MISC_OFFSET 0x60
-#define REALVIEW_SYS_IOSEL_OFFSET 0x70
-#define REALVIEW_SYS_PROCID_OFFSET 0x84
-#define REALVIEW_SYS_TEST_OSC0_OFFSET 0xC0
-#define REALVIEW_SYS_TEST_OSC1_OFFSET 0xC4
-#define REALVIEW_SYS_TEST_OSC2_OFFSET 0xC8
-#define REALVIEW_SYS_TEST_OSC3_OFFSET 0xCC
-#define REALVIEW_SYS_TEST_OSC4_OFFSET 0xD0
-
-#define REALVIEW_SYS_BASE 0x10000000
-#define REALVIEW_SYS_ID (REALVIEW_SYS_BASE + REALVIEW_SYS_ID_OFFSET)
-#define REALVIEW_SYS_SW (REALVIEW_SYS_BASE + REALVIEW_SYS_SW_OFFSET)
-#define REALVIEW_SYS_LED (REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET)
-#define REALVIEW_SYS_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC0_OFFSET)
-#define REALVIEW_SYS_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC1_OFFSET)
-
-#define REALVIEW_SYS_LOCK (REALVIEW_SYS_BASE + REALVIEW_SYS_LOCK_OFFSET)
-#define REALVIEW_SYS_100HZ (REALVIEW_SYS_BASE + REALVIEW_SYS_100HZ_OFFSET)
-#define REALVIEW_SYS_CFGDATA1 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA1_OFFSET)
-#define REALVIEW_SYS_CFGDATA2 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA2_OFFSET)
-#define REALVIEW_SYS_FLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGS_OFFSET)
-#define REALVIEW_SYS_FLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSSET_OFFSET)
-#define REALVIEW_SYS_FLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSCLR_OFFSET)
-#define REALVIEW_SYS_NVFLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGS_OFFSET)
-#define REALVIEW_SYS_NVFLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSSET_OFFSET)
-#define REALVIEW_SYS_NVFLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSCLR_OFFSET)
-#define REALVIEW_SYS_RESETCTL (REALVIEW_SYS_BASE + REALVIEW_SYS_RESETCTL_OFFSET)
-#define REALVIEW_SYS_PCICTL (REALVIEW_SYS_BASE + REALVIEW_SYS_PCICTL_OFFSET)
-#define REALVIEW_SYS_MCI (REALVIEW_SYS_BASE + REALVIEW_SYS_MCI_OFFSET)
-#define REALVIEW_SYS_FLASH (REALVIEW_SYS_BASE + REALVIEW_SYS_FLASH_OFFSET)
-#define REALVIEW_SYS_CLCD (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCD_OFFSET)
-#define REALVIEW_SYS_CLCDSER (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCDSER_OFFSET)
-#define REALVIEW_SYS_BOOTCS (REALVIEW_SYS_BASE + REALVIEW_SYS_BOOTCS_OFFSET)
-#define REALVIEW_SYS_24MHz (REALVIEW_SYS_BASE + REALVIEW_SYS_24MHz_OFFSET)
-#define REALVIEW_SYS_MISC (REALVIEW_SYS_BASE + REALVIEW_SYS_MISC_OFFSET)
-#define REALVIEW_SYS_IOSEL (REALVIEW_SYS_BASE + REALVIEW_SYS_IOSEL_OFFSET)
-#define REALVIEW_SYS_PROCID (REALVIEW_SYS_BASE + REALVIEW_SYS_PROCID_OFFSET)
-#define REALVIEW_SYS_TEST_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC0_OFFSET)
-#define REALVIEW_SYS_TEST_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC1_OFFSET)
-#define REALVIEW_SYS_TEST_OSC2 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC2_OFFSET)
-#define REALVIEW_SYS_TEST_OSC3 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC3_OFFSET)
-#define REALVIEW_SYS_TEST_OSC4 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC4_OFFSET)
-
-/* ------------------------------------------------------------------------
- * RealView control registers
- * ------------------------------------------------------------------------
- */
-
-/*
- * REALVIEW_IDFIELD
- *
- * 31:24 = manufacturer (0x41 = ARM)
- * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus)
- * 15:12 = FPGA (0x3 = XVC600 or XVC600E)
- * 11:4 = build value
- * 3:0 = revision number (0x1 = rev B (AHB))
- */
-
-/*
- * REALVIEW_SYS_LOCK
- * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL,
- * SYS_CLD, SYS_BOOTCS
- */
-#define REALVIEW_SYS_LOCK_LOCKED (1 << 16)
-#define REALVIEW_SYS_LOCK_VAL 0xA05F /* Enable write access */
-
-/*
- * REALVIEW_SYS_FLASH
- */
-#define REALVIEW_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */
-
-/*
- * REALVIEW_INTREG
- * - used to acknowledge and control MMCI and UART interrupts
- */
-#define REALVIEW_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */
-#define REALVIEW_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */
-#define REALVIEW_INTREG_CARDIN 0x08 /* MMCI card in detect */
- /* write 1 to acknowledge and clear */
-#define REALVIEW_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */
-#define REALVIEW_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */
-
-/*
- * RealView common peripheral addresses
- */
-#define REALVIEW_SCTL_BASE 0x10001000 /* System controller */
-#define REALVIEW_I2C_BASE 0x10002000 /* I2C control */
-#define REALVIEW_AACI_BASE 0x10004000 /* Audio */
-#define REALVIEW_MMCI0_BASE 0x10005000 /* MMC interface */
-#define REALVIEW_KMI0_BASE 0x10006000 /* KMI interface */
-#define REALVIEW_KMI1_BASE 0x10007000 /* KMI 2nd interface */
-#define REALVIEW_CHAR_LCD_BASE 0x10008000 /* Character LCD */
-#define REALVIEW_SCI_BASE 0x1000E000 /* Smart card controller */
-#define REALVIEW_GPIO1_BASE 0x10014000 /* GPIO port 1 */
-#define REALVIEW_GPIO2_BASE 0x10015000 /* GPIO port 2 */
-#define REALVIEW_DMC_BASE 0x10018000 /* DMC configuration */
-#define REALVIEW_DMAC_BASE 0x10030000 /* DMA controller */
-
-/* PCI space */
-#define REALVIEW_PCI_BASE 0x41000000 /* PCI Interface */
-#define REALVIEW_PCI_CFG_BASE 0x42000000
-#define REALVIEW_PCI_MEM_BASE0 0x44000000
-#define REALVIEW_PCI_MEM_BASE1 0x50000000
-#define REALVIEW_PCI_MEM_BASE2 0x60000000
-/* Sizes of above maps */
-#define REALVIEW_PCI_BASE_SIZE 0x01000000
-#define REALVIEW_PCI_CFG_BASE_SIZE 0x02000000
-#define REALVIEW_PCI_MEM_BASE0_SIZE 0x0c000000 /* 32Mb */
-#define REALVIEW_PCI_MEM_BASE1_SIZE 0x10000000 /* 256Mb */
-#define REALVIEW_PCI_MEM_BASE2_SIZE 0x10000000 /* 256Mb */
-
-#define REALVIEW_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */
-#define REALVIEW_LT_BASE 0x80000000 /* Logic Tile expansion */
-
-/*
- * CompactFlash
- */
-#define REALVIEW_CF_BASE 0x18000000 /* CompactFlash */
-#define REALVIEW_CF_MEM_BASE 0x18003000 /* SMC for CompactFlash */
-
-/*
- * Disk on Chip
- */
-#define REALVIEW_DOC_BASE 0x2C000000
-#define REALVIEW_DOC_SIZE (16 << 20)
-#define REALVIEW_DOC_PAGE_SIZE 512
-#define REALVIEW_DOC_TOTAL_PAGES (DOC_SIZE / PAGE_SIZE)
-
-#define ERASE_UNIT_PAGES 32
-#define START_PAGE 0x80
-
-/*
- * LED settings, bits [7:0]
- */
-#define REALVIEW_SYS_LED0 (1 << 0)
-#define REALVIEW_SYS_LED1 (1 << 1)
-#define REALVIEW_SYS_LED2 (1 << 2)
-#define REALVIEW_SYS_LED3 (1 << 3)
-#define REALVIEW_SYS_LED4 (1 << 4)
-#define REALVIEW_SYS_LED5 (1 << 5)
-#define REALVIEW_SYS_LED6 (1 << 6)
-#define REALVIEW_SYS_LED7 (1 << 7)
-
-#define ALL_LEDS 0xFF
-
-#define LED_BANK REALVIEW_SYS_LED
-
-/*
- * Control registers
- */
-#define REALVIEW_IDFIELD_OFFSET 0x0 /* RealView build information */
-#define REALVIEW_FLASHPROG_OFFSET 0x4 /* Flash devices */
-#define REALVIEW_INTREG_OFFSET 0x8 /* Interrupt control */
-#define REALVIEW_DECODE_OFFSET 0xC /* Fitted logic modules */
-
-/*
- * System controller bit assignment
- */
-#define REALVIEW_REFCLK 0
-#define REALVIEW_TIMCLK 1
-
-#define REALVIEW_TIMER1_EnSel 15
-#define REALVIEW_TIMER2_EnSel 17
-#define REALVIEW_TIMER3_EnSel 19
-#define REALVIEW_TIMER4_EnSel 21
-
-
-#define REALVIEW_CSR_BASE 0x10000000
-#define REALVIEW_CSR_SIZE 0x10000000
-
-#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/arch/arm/mach-realview/platsmp-dt.c b/arch/arm/mach-realview/platsmp-dt.c
index 6964e8876061..70ca99eb52c6 100644
--- a/arch/arm/mach-realview/platsmp-dt.c
+++ b/arch/arm/mach-realview/platsmp-dt.c
@@ -17,8 +17,7 @@
#include <asm/smp_scu.h>
#include <plat/platsmp.h>
-
-#include "core.h"
+#include "hotplug.h"
#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
deleted file mode 100644
index e8ab69c7abfb..000000000000
--- a/arch/arm/mach-realview/platsmp.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/platsmp.c
- *
- * Copyright (C) 2002 ARM Ltd.
- * All 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.
- */
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#include "hardware.h"
-#include <asm/mach-types.h>
-#include <asm/smp_scu.h>
-
-#include "board-eb.h"
-#include "board-pb11mp.h"
-#include "board-pbx.h"
-
-#include <plat/platsmp.h>
-
-#include "core.h"
-
-static void __iomem *scu_base_addr(void)
-{
- if (machine_is_realview_eb_mp())
- return __io_address(REALVIEW_EB11MP_SCU_BASE);
- else if (machine_is_realview_pb11mp())
- return __io_address(REALVIEW_TC11MP_SCU_BASE);
- else if (machine_is_realview_pbx() &&
- (core_tile_pbx11mp() || core_tile_pbxa9mp()))
- return __io_address(REALVIEW_PBX_TILE_SCU_BASE);
- else
- return (void __iomem *)0;
-}
-
-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system.
- */
-static void __init realview_smp_init_cpus(void)
-{
- void __iomem *scu_base = scu_base_addr();
- unsigned int i, ncores;
-
- ncores = scu_base ? scu_get_core_count(scu_base) : 1;
-
- /* sanity check */
- if (ncores > nr_cpu_ids) {
- pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
- ncores, nr_cpu_ids);
- ncores = nr_cpu_ids;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
-}
-
-static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
-{
-
- scu_enable(scu_base_addr());
-
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The BootMonitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- */
- __raw_writel(virt_to_phys(versatile_secondary_startup),
- __io_address(REALVIEW_SYS_FLAGSSET));
-}
-
-const struct smp_operations realview_smp_ops __initconst = {
- .smp_init_cpus = realview_smp_init_cpus,
- .smp_prepare_cpus = realview_smp_prepare_cpus,
- .smp_secondary_init = versatile_secondary_init,
- .smp_boot_secondary = versatile_boot_secondary,
-#ifdef CONFIG_HOTPLUG_CPU
- .cpu_die = realview_cpu_die,
-#endif
-};
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
deleted file mode 100644
index b442fa61e943..000000000000
--- a/arch/arm/mach-realview/realview_eb.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/realview_eb.c
- *
- * Copyright (C) 2004 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in 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/platform_device.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/amba/pl022.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/clk-realview.h>
-#include <linux/reboot.h>
-
-#include "hardware.h"
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <asm/smp_twd.h>
-#include <asm/system_info.h>
-#include <asm/outercache.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include "board-eb.h"
-#include "irqs-eb.h"
-
-#include "core.h"
-
-static struct map_desc realview_eb_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_SYS_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SYS_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_EB_GIC_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_EB_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_EB_TIMER0_1_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB_TIMER0_1_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_EB_TIMER2_3_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB_TIMER2_3_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#ifdef CONFIG_DEBUG_LL
- {
- .virtual = IO_ADDRESS(REALVIEW_EB_UART0_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }
-#endif
-};
-
-static struct map_desc realview_eb11mp_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_EB11MP_PRIV_MEM_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB11MP_PRIV_MEM_BASE),
- .length = REALVIEW_EB11MP_PRIV_MEM_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_EB11MP_L220_BASE),
- .pfn = __phys_to_pfn(REALVIEW_EB11MP_L220_BASE),
- .length = SZ_8K,
- .type = MT_DEVICE,
- }
-};
-
-static void __init realview_eb_map_io(void)
-{
- iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc));
- if (core_tile_eb11mp() || core_tile_a9mp())
- iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc));
-}
-
-static struct pl061_platform_data gpio0_plat_data = {
- .gpio_base = 0,
-};
-
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
-};
-
-static struct pl061_platform_data gpio2_plat_data = {
- .gpio_base = 16,
-};
-
-static struct pl022_ssp_controller ssp0_plat_data = {
- .bus_id = 0,
- .enable_dma = 0,
- .num_chipselect = 1,
-};
-
-/*
- * RealView EB AMBA devices
- */
-
-/*
- * These devices are connected via the core APB bridge
- */
-#define GPIO2_IRQ { IRQ_EB_GPIO2 }
-#define GPIO3_IRQ { IRQ_EB_GPIO3 }
-
-#define AACI_IRQ { IRQ_EB_AACI }
-#define MMCI0_IRQ { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B }
-#define KMI0_IRQ { IRQ_EB_KMI0 }
-#define KMI1_IRQ { IRQ_EB_KMI1 }
-
-/*
- * These devices are connected directly to the multi-layer AHB switch
- */
-#define EB_SMC_IRQ { }
-#define MPMC_IRQ { }
-#define EB_CLCD_IRQ { IRQ_EB_CLCD }
-#define DMAC_IRQ { IRQ_EB_DMA }
-
-/*
- * These devices are connected via the core APB bridge
- */
-#define SCTL_IRQ { }
-#define EB_WATCHDOG_IRQ { IRQ_EB_WDOG }
-#define EB_GPIO0_IRQ { IRQ_EB_GPIO0 }
-#define GPIO1_IRQ { IRQ_EB_GPIO1 }
-#define EB_RTC_IRQ { IRQ_EB_RTC }
-
-/*
- * These devices are connected via the DMA APB bridge
- */
-#define SCI_IRQ { IRQ_EB_SCI }
-#define EB_UART0_IRQ { IRQ_EB_UART0 }
-#define EB_UART1_IRQ { IRQ_EB_UART1 }
-#define EB_UART2_IRQ { IRQ_EB_UART2 }
-#define EB_UART3_IRQ { IRQ_EB_UART3 }
-#define EB_SSP_IRQ { IRQ_EB_SSP }
-
-/* FPGA Primecells */
-APB_DEVICE(aaci, "fpga:aaci", AACI, NULL);
-APB_DEVICE(mmc0, "fpga:mmc0", MMCI0, &realview_mmc0_plat_data);
-APB_DEVICE(kmi0, "fpga:kmi0", KMI0, NULL);
-APB_DEVICE(kmi1, "fpga:kmi1", KMI1, NULL);
-APB_DEVICE(uart3, "fpga:uart3", EB_UART3, NULL);
-
-/* DevChip Primecells */
-AHB_DEVICE(smc, "dev:smc", EB_SMC, NULL);
-AHB_DEVICE(clcd, "dev:clcd", EB_CLCD, &clcd_plat_data);
-AHB_DEVICE(dmac, "dev:dmac", DMAC, NULL);
-AHB_DEVICE(sctl, "dev:sctl", SCTL, NULL);
-APB_DEVICE(wdog, "dev:wdog", EB_WATCHDOG, NULL);
-APB_DEVICE(gpio0, "dev:gpio0", EB_GPIO0, &gpio0_plat_data);
-APB_DEVICE(gpio1, "dev:gpio1", GPIO1, &gpio1_plat_data);
-APB_DEVICE(gpio2, "dev:gpio2", GPIO2, &gpio2_plat_data);
-APB_DEVICE(rtc, "dev:rtc", EB_RTC, NULL);
-APB_DEVICE(sci0, "dev:sci0", SCI, NULL);
-APB_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
-APB_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
-APB_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
-APB_DEVICE(ssp0, "dev:ssp0", EB_SSP, &ssp0_plat_data);
-
-static struct amba_device *amba_devs[] __initdata = {
- &dmac_device,
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &uart3_device,
- &smc_device,
- &clcd_device,
- &sctl_device,
- &wdog_device,
- &gpio0_device,
- &gpio1_device,
- &gpio2_device,
- &rtc_device,
- &sci0_device,
- &ssp0_device,
- &aaci_device,
- &mmc0_device,
- &kmi0_device,
- &kmi1_device,
-};
-
-/*
- * RealView EB platform devices
- */
-static struct resource realview_eb_flash_resource = {
- .start = REALVIEW_EB_FLASH_BASE,
- .end = REALVIEW_EB_FLASH_BASE + REALVIEW_EB_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct resource realview_eb_eth_resources[] = {
- [0] = {
- .start = REALVIEW_EB_ETH_BASE,
- .end = REALVIEW_EB_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EB_ETH,
- .end = IRQ_EB_ETH,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
- },
-};
-
-/*
- * Detect and register the correct Ethernet device. RealView/EB rev D
- * platforms use the newer SMSC LAN9118 Ethernet chip
- */
-static int eth_device_register(void)
-{
- void __iomem *eth_addr = ioremap(REALVIEW_EB_ETH_BASE, SZ_4K);
- const char *name = NULL;
- u32 idrev;
-
- if (!eth_addr)
- return -ENOMEM;
-
- idrev = readl(eth_addr + 0x50);
- if ((idrev & 0xFFFF0000) != 0x01180000)
- /* SMSC LAN9118 not present, use LAN91C111 instead */
- name = "smc91x";
-
- iounmap(eth_addr);
- return realview_eth_register(name, realview_eb_eth_resources);
-}
-
-static struct resource realview_eb_isp1761_resources[] = {
- [0] = {
- .start = REALVIEW_EB_USB_BASE,
- .end = REALVIEW_EB_USB_BASE + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EB_USB,
- .end = IRQ_EB_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource pmu_resources[] = {
- [0] = {
- .start = IRQ_EB11MP_PMU_CPU0,
- .end = IRQ_EB11MP_PMU_CPU0,
- .flags = IORESOURCE_IRQ,
- },
- [1] = {
- .start = IRQ_EB11MP_PMU_CPU1,
- .end = IRQ_EB11MP_PMU_CPU1,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_EB11MP_PMU_CPU2,
- .end = IRQ_EB11MP_PMU_CPU2,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = IRQ_EB11MP_PMU_CPU3,
- .end = IRQ_EB11MP_PMU_CPU3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device pmu_device = {
- .id = -1,
- .num_resources = ARRAY_SIZE(pmu_resources),
- .resource = pmu_resources,
-};
-
-static struct resource char_lcd_resources[] = {
- {
- .start = REALVIEW_CHAR_LCD_BASE,
- .end = (REALVIEW_CHAR_LCD_BASE + SZ_4K - 1),
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_EB_CHARLCD,
- .end = IRQ_EB_CHARLCD,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device char_lcd_device = {
- .name = "arm-charlcd",
- .id = -1,
- .num_resources = ARRAY_SIZE(char_lcd_resources),
- .resource = char_lcd_resources,
-};
-
-static void __init gic_init_irq(void)
-{
- if (core_tile_eb11mp() || core_tile_a9mp()) {
- unsigned int pldctrl;
-
- /* new irq mode */
- writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
- pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1);
- pldctrl |= 0x00800000;
- writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1);
- writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
-
- /* core tile GIC, primary */
- gic_init(0, 29, __io_address(REALVIEW_EB11MP_GIC_DIST_BASE),
- __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
-
-#ifndef CONFIG_REALVIEW_EB_ARM11MP_REVB
- /* board GIC, secondary */
- gic_init(1, 96, __io_address(REALVIEW_EB_GIC_DIST_BASE),
- __io_address(REALVIEW_EB_GIC_CPU_BASE));
- gic_cascade_irq(1, IRQ_EB11MP_EB_IRQ1);
-#endif
- } else {
- /* board GIC, primary */
- gic_init(0, 29, __io_address(REALVIEW_EB_GIC_DIST_BASE),
- __io_address(REALVIEW_EB_GIC_CPU_BASE));
- }
-}
-
-/*
- * Fix up the IRQ numbers for the RealView EB/ARM11MPCore tile
- */
-static void realview_eb11mp_fixup(void)
-{
- /* AMBA devices */
- dmac_device.irq[0] = IRQ_EB11MP_DMA;
- uart0_device.irq[0] = IRQ_EB11MP_UART0;
- uart1_device.irq[0] = IRQ_EB11MP_UART1;
- uart2_device.irq[0] = IRQ_EB11MP_UART2;
- uart3_device.irq[0] = IRQ_EB11MP_UART3;
- clcd_device.irq[0] = IRQ_EB11MP_CLCD;
- wdog_device.irq[0] = IRQ_EB11MP_WDOG;
- gpio0_device.irq[0] = IRQ_EB11MP_GPIO0;
- gpio1_device.irq[0] = IRQ_EB11MP_GPIO1;
- gpio2_device.irq[0] = IRQ_EB11MP_GPIO2;
- rtc_device.irq[0] = IRQ_EB11MP_RTC;
- sci0_device.irq[0] = IRQ_EB11MP_SCI;
- ssp0_device.irq[0] = IRQ_EB11MP_SSP;
- aaci_device.irq[0] = IRQ_EB11MP_AACI;
- mmc0_device.irq[0] = IRQ_EB11MP_MMCI0A;
- mmc0_device.irq[1] = IRQ_EB11MP_MMCI0B;
- kmi0_device.irq[0] = IRQ_EB11MP_KMI0;
- kmi1_device.irq[0] = IRQ_EB11MP_KMI1;
-
- /* platform devices */
- realview_eb_eth_resources[1].start = IRQ_EB11MP_ETH;
- realview_eb_eth_resources[1].end = IRQ_EB11MP_ETH;
- realview_eb_isp1761_resources[1].start = IRQ_EB11MP_USB;
- realview_eb_isp1761_resources[1].end = IRQ_EB11MP_USB;
-}
-
-#ifdef CONFIG_HAVE_ARM_TWD
-static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
- REALVIEW_EB11MP_TWD_BASE,
- IRQ_LOCALTIMER);
-
-static void __init realview_eb_twd_init(void)
-{
- if (core_tile_eb11mp() || core_tile_a9mp()) {
- int err = twd_local_timer_register(&twd_local_timer);
- if (err)
- pr_err("twd_local_timer_register failed %d\n", err);
- }
-}
-#else
-#define realview_eb_twd_init() do { } while(0)
-#endif
-
-static void __init realview_eb_timer_init(void)
-{
- unsigned int timer_irq;
-
- timer0_va_base = __io_address(REALVIEW_EB_TIMER0_1_BASE);
- timer1_va_base = __io_address(REALVIEW_EB_TIMER0_1_BASE) + 0x20;
- timer2_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE);
- timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20;
-
- if (core_tile_eb11mp() || core_tile_a9mp())
- timer_irq = IRQ_EB11MP_TIMER0_1;
- else
- timer_irq = IRQ_EB_TIMER0_1;
-
- realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
- realview_timer_init(timer_irq);
- realview_eb_twd_init();
-}
-
-static void realview_eb_restart(enum reboot_mode mode, const char *cmd)
-{
- void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
- void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
-
- /*
- * To reset, we hit the on-board reset register
- * in the system FPGA
- */
- __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
- if (core_tile_eb11mp())
- __raw_writel(0x0008, reset_ctrl);
- dsb();
-}
-
-static void __init realview_eb_init(void)
-{
- int i;
-
- if (core_tile_eb11mp() || core_tile_a9mp()) {
- realview_eb11mp_fixup();
-
-#ifdef CONFIG_CACHE_L2X0
- /*
- * The PL220 needs to be manually configured as the hardware
- * doesn't report the correct sizes.
- * 1MB (128KB/way), 8-way associativity, event monitor and
- * parity enabled, ignore share bit, no force write allocate
- * Bits: .... ...0 0111 1001 0000 .... .... ....
- */
- l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff);
-
- /*
- * due to a bug in the l220 cache controller, we must not call
- * the sync function. stub it out here instead!
- */
- outer_cache.sync = NULL;
-#endif
- pmu_device.name = core_tile_a9mp() ? "armv7-pmu" : "armv6-pmu";
- platform_device_register(&pmu_device);
- }
-
- 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);
-
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .smp = smp_ops(realview_smp_ops),
- .fixup = realview_fixup,
- .map_io = realview_eb_map_io,
- .init_early = realview_init_early,
- .init_irq = gic_init_irq,
- .init_time = realview_eb_timer_init,
- .init_machine = realview_eb_init,
-#ifdef CONFIG_ZONE_DMA
- .dma_zone_size = SZ_256M,
-#endif
- .restart = realview_eb_restart,
-MACHINE_END
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
deleted file mode 100644
index 537f3878d501..000000000000
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/realview_pb1176.c
- *
- * Copyright (C) 2008 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in 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/platform_device.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/amba/pl022.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/clk-realview.h>
-#include <linux/reboot.h>
-#include <linux/memblock.h>
-
-#include "hardware.h"
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include "board-pb1176.h"
-#include "irqs-pb1176.h"
-
-#include "core.h"
-
-static struct map_desc realview_pb1176_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_SYS_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SYS_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB1176_GIC_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB1176_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB1176_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB1176_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_DC1176_GIC_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_DC1176_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_DC1176_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_DC1176_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB1176_TIMER0_1_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB1176_TIMER0_1_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB1176_TIMER2_3_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB1176_TIMER2_3_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB1176_L220_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB1176_L220_BASE),
- .length = SZ_8K,
- .type = MT_DEVICE,
- },
-#ifdef CONFIG_DEBUG_LL
- {
- .virtual = IO_ADDRESS(REALVIEW_PB1176_UART0_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB1176_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#endif
-};
-
-static void __init realview_pb1176_map_io(void)
-{
- iotable_init(realview_pb1176_io_desc, ARRAY_SIZE(realview_pb1176_io_desc));
-}
-
-static struct pl061_platform_data gpio0_plat_data = {
- .gpio_base = 0,
-};
-
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
-};
-
-static struct pl061_platform_data gpio2_plat_data = {
- .gpio_base = 16,
-};
-
-static struct pl022_ssp_controller ssp0_plat_data = {
- .bus_id = 0,
- .enable_dma = 0,
- .num_chipselect = 1,
-};
-
-/*
- * RealView PB1176 AMBA devices
- */
-#define GPIO2_IRQ { IRQ_PB1176_GPIO2 }
-#define GPIO3_IRQ { IRQ_PB1176_GPIO3 }
-#define AACI_IRQ { IRQ_PB1176_AACI }
-#define MMCI0_IRQ { IRQ_PB1176_MMCI0A, IRQ_PB1176_MMCI0B }
-#define KMI0_IRQ { IRQ_PB1176_KMI0 }
-#define KMI1_IRQ { IRQ_PB1176_KMI1 }
-#define PB1176_SMC_IRQ { }
-#define MPMC_IRQ { }
-#define PB1176_CLCD_IRQ { IRQ_DC1176_CLCD }
-#define SCTL_IRQ { }
-#define PB1176_WATCHDOG_IRQ { IRQ_DC1176_WATCHDOG }
-#define PB1176_GPIO0_IRQ { IRQ_DC1176_GPIO0 }
-#define GPIO1_IRQ { IRQ_PB1176_GPIO1 }
-#define PB1176_RTC_IRQ { IRQ_DC1176_RTC }
-#define SCI_IRQ { IRQ_PB1176_SCI }
-#define PB1176_UART0_IRQ { IRQ_DC1176_UART0 }
-#define PB1176_UART1_IRQ { IRQ_DC1176_UART1 }
-#define PB1176_UART2_IRQ { IRQ_DC1176_UART2 }
-#define PB1176_UART3_IRQ { IRQ_DC1176_UART3 }
-#define PB1176_UART4_IRQ { IRQ_PB1176_UART4 }
-#define PB1176_SSP_IRQ { IRQ_DC1176_SSP }
-
-/* FPGA Primecells */
-APB_DEVICE(aaci, "fpga:aaci", AACI, NULL);
-APB_DEVICE(mmc0, "fpga:mmc0", MMCI0, &realview_mmc0_plat_data);
-APB_DEVICE(kmi0, "fpga:kmi0", KMI0, NULL);
-APB_DEVICE(kmi1, "fpga:kmi1", KMI1, NULL);
-APB_DEVICE(uart4, "fpga:uart4", PB1176_UART4, NULL);
-
-/* DevChip Primecells */
-AHB_DEVICE(smc, "dev:smc", PB1176_SMC, NULL);
-AHB_DEVICE(sctl, "dev:sctl", SCTL, NULL);
-APB_DEVICE(wdog, "dev:wdog", PB1176_WATCHDOG, NULL);
-APB_DEVICE(gpio0, "dev:gpio0", PB1176_GPIO0, &gpio0_plat_data);
-APB_DEVICE(gpio1, "dev:gpio1", GPIO1, &gpio1_plat_data);
-APB_DEVICE(gpio2, "dev:gpio2", GPIO2, &gpio2_plat_data);
-APB_DEVICE(rtc, "dev:rtc", PB1176_RTC, NULL);
-APB_DEVICE(sci0, "dev:sci0", SCI, NULL);
-APB_DEVICE(uart0, "dev:uart0", PB1176_UART0, NULL);
-APB_DEVICE(uart1, "dev:uart1", PB1176_UART1, NULL);
-APB_DEVICE(uart2, "dev:uart2", PB1176_UART2, NULL);
-APB_DEVICE(uart3, "dev:uart3", PB1176_UART3, NULL);
-APB_DEVICE(ssp0, "dev:ssp0", PB1176_SSP, &ssp0_plat_data);
-AHB_DEVICE(clcd, "dev:clcd", PB1176_CLCD, &clcd_plat_data);
-
-static struct amba_device *amba_devs[] __initdata = {
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &uart3_device,
- &uart4_device,
- &smc_device,
- &clcd_device,
- &sctl_device,
- &wdog_device,
- &gpio0_device,
- &gpio1_device,
- &gpio2_device,
- &rtc_device,
- &sci0_device,
- &ssp0_device,
- &aaci_device,
- &mmc0_device,
- &kmi0_device,
- &kmi1_device,
-};
-
-/*
- * RealView PB1176 platform devices
- */
-static struct resource realview_pb1176_flash_resources[] = {
- {
- .start = REALVIEW_PB1176_FLASH_BASE,
- .end = REALVIEW_PB1176_FLASH_BASE + REALVIEW_PB1176_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-#ifdef CONFIG_REALVIEW_PB1176_SECURE_FLASH
- {
- .start = REALVIEW_PB1176_SEC_FLASH_BASE,
- .end = REALVIEW_PB1176_SEC_FLASH_BASE + REALVIEW_PB1176_SEC_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-#endif
-};
-
-static struct physmap_flash_data pb1176_rom_pdata = {
- .probe_type = "map_rom",
- .width = 4,
- .nr_parts = 0,
-};
-
-static struct resource pb1176_rom_resources[] = {
- /*
- * This exposes the PB1176 DevChip ROM as an MTD ROM mapping.
- * The reference manual states that this is actually a pseudo-ROM
- * programmed in NVRAM.
- */
- {
- .start = REALVIEW_DC1176_ROM_BASE,
- .end = REALVIEW_DC1176_ROM_BASE + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device pb1176_rom_device = {
- .name = "physmap-flash",
- .id = -1,
- .num_resources = ARRAY_SIZE(pb1176_rom_resources),
- .resource = pb1176_rom_resources,
- .dev = {
- .platform_data = &pb1176_rom_pdata,
- },
-};
-
-static struct resource realview_pb1176_smsc911x_resources[] = {
- [0] = {
- .start = REALVIEW_PB1176_ETH_BASE,
- .end = REALVIEW_PB1176_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_PB1176_ETH,
- .end = IRQ_PB1176_ETH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource realview_pb1176_isp1761_resources[] = {
- [0] = {
- .start = REALVIEW_PB1176_USB_BASE,
- .end = REALVIEW_PB1176_USB_BASE + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_PB1176_USB,
- .end = IRQ_PB1176_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource pmu_resource = {
- .start = IRQ_DC1176_CORE_PMU,
- .end = IRQ_DC1176_CORE_PMU,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device pmu_device = {
- .name = "armv6-pmu",
- .id = -1,
- .num_resources = 1,
- .resource = &pmu_resource,
-};
-
-static struct resource char_lcd_resources[] = {
- {
- .start = REALVIEW_CHAR_LCD_BASE,
- .end = (REALVIEW_CHAR_LCD_BASE + SZ_4K - 1),
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_PB1176_CHARLCD,
- .end = IRQ_PB1176_CHARLCD,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device char_lcd_device = {
- .name = "arm-charlcd",
- .id = -1,
- .num_resources = ARRAY_SIZE(char_lcd_resources),
- .resource = char_lcd_resources,
-};
-
-static void __init gic_init_irq(void)
-{
- /* ARM1176 DevChip GIC, primary */
- gic_init(0, IRQ_DC1176_GIC_START,
- __io_address(REALVIEW_DC1176_GIC_DIST_BASE),
- __io_address(REALVIEW_DC1176_GIC_CPU_BASE));
-
- /* board GIC, secondary */
- gic_init(1, IRQ_PB1176_GIC_START,
- __io_address(REALVIEW_PB1176_GIC_DIST_BASE),
- __io_address(REALVIEW_PB1176_GIC_CPU_BASE));
- gic_cascade_irq(1, IRQ_DC1176_PB_IRQ1);
-}
-
-static void __init realview_pb1176_timer_init(void)
-{
- timer0_va_base = __io_address(REALVIEW_PB1176_TIMER0_1_BASE);
- timer1_va_base = __io_address(REALVIEW_PB1176_TIMER0_1_BASE) + 0x20;
- timer2_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE);
- timer3_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE) + 0x20;
-
- realview_clk_init(__io_address(REALVIEW_SYS_BASE), true);
- realview_timer_init(IRQ_DC1176_TIMER0);
-}
-
-static void realview_pb1176_restart(enum reboot_mode mode, const char *cmd)
-{
- void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
- void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
- __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
- __raw_writel(REALVIEW_PB1176_SYS_SOFT_RESET, reset_ctrl);
- dsb();
-}
-
-static void realview_pb1176_fixup(struct tag *tags, char **from)
-{
- /*
- * RealView PB1176 only has 128MB of RAM mapped at 0.
- */
- memblock_add(0, SZ_128M);
-}
-
-static void __init realview_pb1176_init(void)
-{
- int i;
-
-#ifdef CONFIG_CACHE_L2X0
- /*
- * The PL220 needs to be manually configured as the hardware
- * doesn't report the correct sizes.
- * 128kB (16kB/way), 8-way associativity, event monitor and
- * parity enabled, ignore share bit, no force write allocate
- * Bits: .... ...0 0111 0011 0000 .... .... ....
- */
- l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff);
-#endif
-
- realview_flash_register(realview_pb1176_flash_resources,
- ARRAY_SIZE(realview_pb1176_flash_resources));
- platform_device_register(&pb1176_rom_device);
- realview_eth_register(NULL, realview_pb1176_smsc911x_resources);
- platform_device_register(&realview_i2c_device);
- 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];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .fixup = realview_pb1176_fixup,
- .map_io = realview_pb1176_map_io,
- .init_early = realview_init_early,
- .init_irq = gic_init_irq,
- .init_time = realview_pb1176_timer_init,
- .init_machine = realview_pb1176_init,
-#ifdef CONFIG_ZONE_DMA
- .dma_zone_size = SZ_256M,
-#endif
- .restart = realview_pb1176_restart,
-MACHINE_END
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
deleted file mode 100644
index a90a0752f157..000000000000
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/realview_pb11mp.c
- *
- * Copyright (C) 2008 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in 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/platform_device.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/amba/pl022.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/clk-realview.h>
-#include <linux/reboot.h>
-
-#include "hardware.h"
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <asm/smp_twd.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-#include <asm/outercache.h>
-
-#include "board-pb11mp.h"
-#include "irqs-pb11mp.h"
-
-#include "core.h"
-
-static struct map_desc realview_pb11mp_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_SYS_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SYS_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB11MP_GIC_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB11MP_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB11MP_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB11MP_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, { /* Maps the SCU, GIC CPU interface, TWD, GIC DIST */
- .virtual = IO_ADDRESS(REALVIEW_TC11MP_PRIV_MEM_BASE),
- .pfn = __phys_to_pfn(REALVIEW_TC11MP_PRIV_MEM_BASE),
- .length = REALVIEW_TC11MP_PRIV_MEM_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB11MP_TIMER0_1_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB11MP_TIMER0_1_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PB11MP_TIMER2_3_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB11MP_TIMER2_3_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_TC11MP_L220_BASE),
- .pfn = __phys_to_pfn(REALVIEW_TC11MP_L220_BASE),
- .length = SZ_8K,
- .type = MT_DEVICE,
- },
-#ifdef CONFIG_DEBUG_LL
- {
- .virtual = IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PB11MP_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#endif
-};
-
-static void __init realview_pb11mp_map_io(void)
-{
- iotable_init(realview_pb11mp_io_desc, ARRAY_SIZE(realview_pb11mp_io_desc));
-}
-
-static struct pl061_platform_data gpio0_plat_data = {
- .gpio_base = 0,
-};
-
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
-};
-
-static struct pl061_platform_data gpio2_plat_data = {
- .gpio_base = 16,
-};
-
-static struct pl022_ssp_controller ssp0_plat_data = {
- .bus_id = 0,
- .enable_dma = 0,
- .num_chipselect = 1,
-};
-
-/*
- * RealView PB11MPCore AMBA devices
- */
-
-#define GPIO2_IRQ { IRQ_PB11MP_GPIO2 }
-#define GPIO3_IRQ { IRQ_PB11MP_GPIO3 }
-#define AACI_IRQ { IRQ_TC11MP_AACI }
-#define MMCI0_IRQ { IRQ_TC11MP_MMCI0A, IRQ_TC11MP_MMCI0B }
-#define KMI0_IRQ { IRQ_TC11MP_KMI0 }
-#define KMI1_IRQ { IRQ_TC11MP_KMI1 }
-#define PB11MP_SMC_IRQ { }
-#define MPMC_IRQ { }
-#define PB11MP_CLCD_IRQ { IRQ_PB11MP_CLCD }
-#define DMAC_IRQ { IRQ_PB11MP_DMAC }
-#define SCTL_IRQ { }
-#define PB11MP_WATCHDOG_IRQ { IRQ_PB11MP_WATCHDOG }
-#define PB11MP_GPIO0_IRQ { IRQ_PB11MP_GPIO0 }
-#define GPIO1_IRQ { IRQ_PB11MP_GPIO1 }
-#define PB11MP_RTC_IRQ { IRQ_TC11MP_RTC }
-#define SCI_IRQ { IRQ_PB11MP_SCI }
-#define PB11MP_UART0_IRQ { IRQ_TC11MP_UART0 }
-#define PB11MP_UART1_IRQ { IRQ_TC11MP_UART1 }
-#define PB11MP_UART2_IRQ { IRQ_PB11MP_UART2 }
-#define PB11MP_UART3_IRQ { IRQ_PB11MP_UART3 }
-#define PB11MP_SSP_IRQ { IRQ_PB11MP_SSP }
-
-/* FPGA Primecells */
-APB_DEVICE(aaci, "fpga:aaci", AACI, NULL);
-APB_DEVICE(mmc0, "fpga:mmc0", MMCI0, &realview_mmc0_plat_data);
-APB_DEVICE(kmi0, "fpga:kmi0", KMI0, NULL);
-APB_DEVICE(kmi1, "fpga:kmi1", KMI1, NULL);
-APB_DEVICE(uart3, "fpga:uart3", PB11MP_UART3, NULL);
-
-/* DevChip Primecells */
-AHB_DEVICE(smc, "dev:smc", PB11MP_SMC, NULL);
-AHB_DEVICE(sctl, "dev:sctl", SCTL, NULL);
-APB_DEVICE(wdog, "dev:wdog", PB11MP_WATCHDOG, NULL);
-APB_DEVICE(gpio0, "dev:gpio0", PB11MP_GPIO0, &gpio0_plat_data);
-APB_DEVICE(gpio1, "dev:gpio1", GPIO1, &gpio1_plat_data);
-APB_DEVICE(gpio2, "dev:gpio2", GPIO2, &gpio2_plat_data);
-APB_DEVICE(rtc, "dev:rtc", PB11MP_RTC, NULL);
-APB_DEVICE(sci0, "dev:sci0", SCI, NULL);
-APB_DEVICE(uart0, "dev:uart0", PB11MP_UART0, NULL);
-APB_DEVICE(uart1, "dev:uart1", PB11MP_UART1, NULL);
-APB_DEVICE(uart2, "dev:uart2", PB11MP_UART2, NULL);
-APB_DEVICE(ssp0, "dev:ssp0", PB11MP_SSP, &ssp0_plat_data);
-
-/* Primecells on the NEC ISSP chip */
-AHB_DEVICE(clcd, "issp:clcd", PB11MP_CLCD, &clcd_plat_data);
-AHB_DEVICE(dmac, "issp:dmac", DMAC, NULL);
-
-static struct amba_device *amba_devs[] __initdata = {
- &dmac_device,
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &uart3_device,
- &smc_device,
- &clcd_device,
- &sctl_device,
- &wdog_device,
- &gpio0_device,
- &gpio1_device,
- &gpio2_device,
- &rtc_device,
- &sci0_device,
- &ssp0_device,
- &aaci_device,
- &mmc0_device,
- &kmi0_device,
- &kmi1_device,
-};
-
-/*
- * RealView PB11MPCore platform devices
- */
-static struct resource realview_pb11mp_flash_resource[] = {
- [0] = {
- .start = REALVIEW_PB11MP_FLASH0_BASE,
- .end = REALVIEW_PB11MP_FLASH0_BASE + REALVIEW_PB11MP_FLASH0_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = REALVIEW_PB11MP_FLASH1_BASE,
- .end = REALVIEW_PB11MP_FLASH1_BASE + REALVIEW_PB11MP_FLASH1_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct resource realview_pb11mp_smsc911x_resources[] = {
- [0] = {
- .start = REALVIEW_PB11MP_ETH_BASE,
- .end = REALVIEW_PB11MP_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_TC11MP_ETH,
- .end = IRQ_TC11MP_ETH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource realview_pb11mp_isp1761_resources[] = {
- [0] = {
- .start = REALVIEW_PB11MP_USB_BASE,
- .end = REALVIEW_PB11MP_USB_BASE + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_TC11MP_USB,
- .end = IRQ_TC11MP_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource pmu_resources[] = {
- [0] = {
- .start = IRQ_TC11MP_PMU_CPU0,
- .end = IRQ_TC11MP_PMU_CPU0,
- .flags = IORESOURCE_IRQ,
- },
- [1] = {
- .start = IRQ_TC11MP_PMU_CPU1,
- .end = IRQ_TC11MP_PMU_CPU1,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_TC11MP_PMU_CPU2,
- .end = IRQ_TC11MP_PMU_CPU2,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = IRQ_TC11MP_PMU_CPU3,
- .end = IRQ_TC11MP_PMU_CPU3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device pmu_device = {
- .name = "armv6-pmu",
- .id = -1,
- .num_resources = ARRAY_SIZE(pmu_resources),
- .resource = pmu_resources,
-};
-
-static void __init gic_init_irq(void)
-{
- unsigned int pldctrl;
-
- /* new irq mode with no DCC */
- writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
- pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_PB11MP_SYS_PLD_CTRL1);
- pldctrl |= 2 << 22;
- writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_PB11MP_SYS_PLD_CTRL1);
- writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
-
- /* ARM11MPCore test chip GIC, primary */
- gic_init(0, 29, __io_address(REALVIEW_TC11MP_GIC_DIST_BASE),
- __io_address(REALVIEW_TC11MP_GIC_CPU_BASE));
-
- /* board GIC, secondary */
- gic_init(1, IRQ_PB11MP_GIC_START,
- __io_address(REALVIEW_PB11MP_GIC_DIST_BASE),
- __io_address(REALVIEW_PB11MP_GIC_CPU_BASE));
- gic_cascade_irq(1, IRQ_TC11MP_PB_IRQ1);
-}
-
-#ifdef CONFIG_HAVE_ARM_TWD
-static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
- REALVIEW_TC11MP_TWD_BASE,
- IRQ_LOCALTIMER);
-
-static void __init realview_pb11mp_twd_init(void)
-{
- int err = twd_local_timer_register(&twd_local_timer);
- if (err)
- pr_err("twd_local_timer_register failed %d\n", err);
-}
-#else
-#define realview_pb11mp_twd_init() do {} while(0)
-#endif
-
-static void __init realview_pb11mp_timer_init(void)
-{
- timer0_va_base = __io_address(REALVIEW_PB11MP_TIMER0_1_BASE);
- timer1_va_base = __io_address(REALVIEW_PB11MP_TIMER0_1_BASE) + 0x20;
- timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
- timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
-
- realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
- realview_timer_init(IRQ_TC11MP_TIMER0_1);
- realview_pb11mp_twd_init();
-}
-
-static void realview_pb11mp_restart(enum reboot_mode mode, const char *cmd)
-{
- void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
- void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
-
- /*
- * To reset, we hit the on-board reset register
- * in the system FPGA
- */
- __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
- __raw_writel(0x0000, reset_ctrl);
- __raw_writel(0x0004, reset_ctrl);
- dsb();
-}
-
-static void __init realview_pb11mp_init(void)
-{
- int i;
-
-#ifdef CONFIG_CACHE_L2X0
- /*
- * The PL220 needs to be manually configured as the hardware
- * doesn't report the correct sizes.
- * 1MB (128KB/way), 8-way associativity, event monitor and
- * parity enabled, ignore share bit, no force write allocate
- * Bits: .... ...0 0111 1001 0000 .... .... ....
- */
- l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff);
- /*
- * due to a bug in the l220 cache controller, we must not call
- * the sync function. stub it out here instead!
- */
- outer_cache.sync = NULL;
-#endif
-
- realview_flash_register(realview_pb11mp_flash_resource,
- ARRAY_SIZE(realview_pb11mp_flash_resource));
- 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);
-
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .smp = smp_ops(realview_smp_ops),
- .fixup = realview_fixup,
- .map_io = realview_pb11mp_map_io,
- .init_early = realview_init_early,
- .init_irq = gic_init_irq,
- .init_time = realview_pb11mp_timer_init,
- .init_machine = realview_pb11mp_init,
-#ifdef CONFIG_ZONE_DMA
- .dma_zone_size = SZ_256M,
-#endif
- .restart = realview_pb11mp_restart,
-MACHINE_END
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
deleted file mode 100644
index ddafb67c2b6f..000000000000
--- a/arch/arm/mach-realview/realview_pba8.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * linux/arch/arm/mach-realview/realview_pba8.c
- *
- * Copyright (C) 2008 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in 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/platform_device.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/amba/pl022.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/clk-realview.h>
-#include <linux/reboot.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include "hardware.h"
-#include "board-pba8.h"
-#include "irqs-pba8.h"
-
-#include "core.h"
-
-static struct map_desc realview_pba8_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_SYS_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SYS_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBA8_GIC_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBA8_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBA8_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBA8_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBA8_TIMER0_1_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBA8_TIMER0_1_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBA8_TIMER2_3_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBA8_TIMER2_3_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#ifdef CONFIG_DEBUG_LL
- {
- .virtual = IO_ADDRESS(REALVIEW_PBA8_UART0_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBA8_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#endif
-};
-
-static void __init realview_pba8_map_io(void)
-{
- iotable_init(realview_pba8_io_desc, ARRAY_SIZE(realview_pba8_io_desc));
-}
-
-static struct pl061_platform_data gpio0_plat_data = {
- .gpio_base = 0,
-};
-
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
-};
-
-static struct pl061_platform_data gpio2_plat_data = {
- .gpio_base = 16,
-};
-
-static struct pl022_ssp_controller ssp0_plat_data = {
- .bus_id = 0,
- .enable_dma = 0,
- .num_chipselect = 1,
-};
-
-/*
- * RealView PBA8Core AMBA devices
- */
-
-#define GPIO2_IRQ { IRQ_PBA8_GPIO2 }
-#define GPIO3_IRQ { IRQ_PBA8_GPIO3 }
-#define AACI_IRQ { IRQ_PBA8_AACI }
-#define MMCI0_IRQ { IRQ_PBA8_MMCI0A, IRQ_PBA8_MMCI0B }
-#define KMI0_IRQ { IRQ_PBA8_KMI0 }
-#define KMI1_IRQ { IRQ_PBA8_KMI1 }
-#define PBA8_SMC_IRQ { }
-#define MPMC_IRQ { }
-#define PBA8_CLCD_IRQ { IRQ_PBA8_CLCD }
-#define DMAC_IRQ { IRQ_PBA8_DMAC }
-#define SCTL_IRQ { }
-#define PBA8_WATCHDOG_IRQ { IRQ_PBA8_WATCHDOG }
-#define PBA8_GPIO0_IRQ { IRQ_PBA8_GPIO0 }
-#define GPIO1_IRQ { IRQ_PBA8_GPIO1 }
-#define PBA8_RTC_IRQ { IRQ_PBA8_RTC }
-#define SCI_IRQ { IRQ_PBA8_SCI }
-#define PBA8_UART0_IRQ { IRQ_PBA8_UART0 }
-#define PBA8_UART1_IRQ { IRQ_PBA8_UART1 }
-#define PBA8_UART2_IRQ { IRQ_PBA8_UART2 }
-#define PBA8_UART3_IRQ { IRQ_PBA8_UART3 }
-#define PBA8_SSP_IRQ { IRQ_PBA8_SSP }
-
-/* FPGA Primecells */
-APB_DEVICE(aaci, "fpga:aaci", AACI, NULL);
-APB_DEVICE(mmc0, "fpga:mmc0", MMCI0, &realview_mmc0_plat_data);
-APB_DEVICE(kmi0, "fpga:kmi0", KMI0, NULL);
-APB_DEVICE(kmi1, "fpga:kmi1", KMI1, NULL);
-APB_DEVICE(uart3, "fpga:uart3", PBA8_UART3, NULL);
-
-/* DevChip Primecells */
-AHB_DEVICE(smc, "dev:smc", PBA8_SMC, NULL);
-AHB_DEVICE(sctl, "dev:sctl", SCTL, NULL);
-APB_DEVICE(wdog, "dev:wdog", PBA8_WATCHDOG, NULL);
-APB_DEVICE(gpio0, "dev:gpio0", PBA8_GPIO0, &gpio0_plat_data);
-APB_DEVICE(gpio1, "dev:gpio1", GPIO1, &gpio1_plat_data);
-APB_DEVICE(gpio2, "dev:gpio2", GPIO2, &gpio2_plat_data);
-APB_DEVICE(rtc, "dev:rtc", PBA8_RTC, NULL);
-APB_DEVICE(sci0, "dev:sci0", SCI, NULL);
-APB_DEVICE(uart0, "dev:uart0", PBA8_UART0, NULL);
-APB_DEVICE(uart1, "dev:uart1", PBA8_UART1, NULL);
-APB_DEVICE(uart2, "dev:uart2", PBA8_UART2, NULL);
-APB_DEVICE(ssp0, "dev:ssp0", PBA8_SSP, &ssp0_plat_data);
-
-/* Primecells on the NEC ISSP chip */
-AHB_DEVICE(clcd, "issp:clcd", PBA8_CLCD, &clcd_plat_data);
-AHB_DEVICE(dmac, "issp:dmac", DMAC, NULL);
-
-static struct amba_device *amba_devs[] __initdata = {
- &dmac_device,
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &uart3_device,
- &smc_device,
- &clcd_device,
- &sctl_device,
- &wdog_device,
- &gpio0_device,
- &gpio1_device,
- &gpio2_device,
- &rtc_device,
- &sci0_device,
- &ssp0_device,
- &aaci_device,
- &mmc0_device,
- &kmi0_device,
- &kmi1_device,
-};
-
-/*
- * RealView PB-A8 platform devices
- */
-static struct resource realview_pba8_flash_resource[] = {
- [0] = {
- .start = REALVIEW_PBA8_FLASH0_BASE,
- .end = REALVIEW_PBA8_FLASH0_BASE + REALVIEW_PBA8_FLASH0_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = REALVIEW_PBA8_FLASH1_BASE,
- .end = REALVIEW_PBA8_FLASH1_BASE + REALVIEW_PBA8_FLASH1_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct resource realview_pba8_smsc911x_resources[] = {
- [0] = {
- .start = REALVIEW_PBA8_ETH_BASE,
- .end = REALVIEW_PBA8_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_PBA8_ETH,
- .end = IRQ_PBA8_ETH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource realview_pba8_isp1761_resources[] = {
- [0] = {
- .start = REALVIEW_PBA8_USB_BASE,
- .end = REALVIEW_PBA8_USB_BASE + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_PBA8_USB,
- .end = IRQ_PBA8_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource pmu_resource = {
- .start = IRQ_PBA8_PMU,
- .end = IRQ_PBA8_PMU,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device pmu_device = {
- .name = "armv7-pmu",
- .id = -1,
- .num_resources = 1,
- .resource = &pmu_resource,
-};
-
-static void __init gic_init_irq(void)
-{
- /* ARM PB-A8 on-board GIC */
- gic_init(0, IRQ_PBA8_GIC_START,
- __io_address(REALVIEW_PBA8_GIC_DIST_BASE),
- __io_address(REALVIEW_PBA8_GIC_CPU_BASE));
-}
-
-static void __init realview_pba8_timer_init(void)
-{
- timer0_va_base = __io_address(REALVIEW_PBA8_TIMER0_1_BASE);
- timer1_va_base = __io_address(REALVIEW_PBA8_TIMER0_1_BASE) + 0x20;
- timer2_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE);
- timer3_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE) + 0x20;
-
- realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
- realview_timer_init(IRQ_PBA8_TIMER0_1);
-}
-
-static void realview_pba8_restart(enum reboot_mode mode, const char *cmd)
-{
- void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
- void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
-
- /*
- * To reset, we hit the on-board reset register
- * in the system FPGA
- */
- __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
- __raw_writel(0x0000, reset_ctrl);
- __raw_writel(0x0004, reset_ctrl);
- dsb();
-}
-
-static void __init realview_pba8_init(void)
-{
- int i;
-
- realview_flash_register(realview_pba8_flash_resource,
- ARRAY_SIZE(realview_pba8_flash_resource));
- 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);
-
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .fixup = realview_fixup,
- .map_io = realview_pba8_map_io,
- .init_early = realview_init_early,
- .init_irq = gic_init_irq,
- .init_time = realview_pba8_timer_init,
- .init_machine = realview_pba8_init,
-#ifdef CONFIG_ZONE_DMA
- .dma_zone_size = SZ_256M,
-#endif
- .restart = realview_pba8_restart,
-MACHINE_END
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
deleted file mode 100644
index be1cec5fe3ad..000000000000
--- a/arch/arm/mach-realview/realview_pbx.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * arch/arm/mach-realview/realview_pbx.c
- *
- * Copyright (C) 2009 ARM Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in 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/platform_device.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/pl061.h>
-#include <linux/amba/mmci.h>
-#include <linux/amba/pl022.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/clk-realview.h>
-#include <linux/reboot.h>
-#include <linux/memblock.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/smp_twd.h>
-#include <asm/pgtable.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include "hardware.h"
-#include "board-pbx.h"
-#include "irqs-pbx.h"
-
-#include "core.h"
-
-static struct map_desc realview_pbx_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_SYS_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SYS_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBX_GIC_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBX_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
- .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBX_TIMER0_1_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_TIMER0_1_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBX_TIMER2_3_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_TIMER2_3_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#ifdef CONFIG_DEBUG_LL
- {
- .virtual = IO_ADDRESS(REALVIEW_PBX_UART0_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- },
-#endif
-};
-
-static struct map_desc realview_local_io_desc[] __initdata = {
- {
- .virtual = IO_ADDRESS(REALVIEW_PBX_TILE_SCU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_TILE_SCU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBX_TILE_GIC_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_TILE_GIC_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_PBX_TILE_L220_BASE),
- .pfn = __phys_to_pfn(REALVIEW_PBX_TILE_L220_BASE),
- .length = SZ_8K,
- .type = MT_DEVICE,
- }
-};
-
-static void __init realview_pbx_map_io(void)
-{
- iotable_init(realview_pbx_io_desc, ARRAY_SIZE(realview_pbx_io_desc));
- if (core_tile_pbx11mp() || core_tile_pbxa9mp())
- iotable_init(realview_local_io_desc, ARRAY_SIZE(realview_local_io_desc));
-}
-
-static struct pl061_platform_data gpio0_plat_data = {
- .gpio_base = 0,
-};
-
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
-};
-
-static struct pl061_platform_data gpio2_plat_data = {
- .gpio_base = 16,
-};
-
-static struct pl022_ssp_controller ssp0_plat_data = {
- .bus_id = 0,
- .enable_dma = 0,
- .num_chipselect = 1,
-};
-
-/*
- * RealView PBXCore AMBA devices
- */
-
-#define GPIO2_IRQ { IRQ_PBX_GPIO2 }
-#define GPIO3_IRQ { IRQ_PBX_GPIO3 }
-#define AACI_IRQ { IRQ_PBX_AACI }
-#define MMCI0_IRQ { IRQ_PBX_MMCI0A, IRQ_PBX_MMCI0B }
-#define KMI0_IRQ { IRQ_PBX_KMI0 }
-#define KMI1_IRQ { IRQ_PBX_KMI1 }
-#define PBX_SMC_IRQ { }
-#define MPMC_IRQ { }
-#define PBX_CLCD_IRQ { IRQ_PBX_CLCD }
-#define DMAC_IRQ { IRQ_PBX_DMAC }
-#define SCTL_IRQ { }
-#define PBX_WATCHDOG_IRQ { IRQ_PBX_WATCHDOG }
-#define PBX_GPIO0_IRQ { IRQ_PBX_GPIO0 }
-#define GPIO1_IRQ { IRQ_PBX_GPIO1 }
-#define PBX_RTC_IRQ { IRQ_PBX_RTC }
-#define SCI_IRQ { IRQ_PBX_SCI }
-#define PBX_UART0_IRQ { IRQ_PBX_UART0 }
-#define PBX_UART1_IRQ { IRQ_PBX_UART1 }
-#define PBX_UART2_IRQ { IRQ_PBX_UART2 }
-#define PBX_UART3_IRQ { IRQ_PBX_UART3 }
-#define PBX_SSP_IRQ { IRQ_PBX_SSP }
-
-/* FPGA Primecells */
-APB_DEVICE(aaci, "fpga:aaci", AACI, NULL);
-APB_DEVICE(mmc0, "fpga:mmc0", MMCI0, &realview_mmc0_plat_data);
-APB_DEVICE(kmi0, "fpga:kmi0", KMI0, NULL);
-APB_DEVICE(kmi1, "fpga:kmi1", KMI1, NULL);
-APB_DEVICE(uart3, "fpga:uart3", PBX_UART3, NULL);
-
-/* DevChip Primecells */
-AHB_DEVICE(smc, "dev:smc", PBX_SMC, NULL);
-AHB_DEVICE(sctl, "dev:sctl", SCTL, NULL);
-APB_DEVICE(wdog, "dev:wdog", PBX_WATCHDOG, NULL);
-APB_DEVICE(gpio0, "dev:gpio0", PBX_GPIO0, &gpio0_plat_data);
-APB_DEVICE(gpio1, "dev:gpio1", GPIO1, &gpio1_plat_data);
-APB_DEVICE(gpio2, "dev:gpio2", GPIO2, &gpio2_plat_data);
-APB_DEVICE(rtc, "dev:rtc", PBX_RTC, NULL);
-APB_DEVICE(sci0, "dev:sci0", SCI, NULL);
-APB_DEVICE(uart0, "dev:uart0", PBX_UART0, NULL);
-APB_DEVICE(uart1, "dev:uart1", PBX_UART1, NULL);
-APB_DEVICE(uart2, "dev:uart2", PBX_UART2, NULL);
-APB_DEVICE(ssp0, "dev:ssp0", PBX_SSP, &ssp0_plat_data);
-
-/* Primecells on the NEC ISSP chip */
-AHB_DEVICE(clcd, "issp:clcd", PBX_CLCD, &clcd_plat_data);
-AHB_DEVICE(dmac, "issp:dmac", DMAC, NULL);
-
-static struct amba_device *amba_devs[] __initdata = {
- &dmac_device,
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &uart3_device,
- &smc_device,
- &clcd_device,
- &sctl_device,
- &wdog_device,
- &gpio0_device,
- &gpio1_device,
- &gpio2_device,
- &rtc_device,
- &sci0_device,
- &ssp0_device,
- &aaci_device,
- &mmc0_device,
- &kmi0_device,
- &kmi1_device,
-};
-
-/*
- * RealView PB-X platform devices
- */
-static struct resource realview_pbx_flash_resources[] = {
- [0] = {
- .start = REALVIEW_PBX_FLASH0_BASE,
- .end = REALVIEW_PBX_FLASH0_BASE + REALVIEW_PBX_FLASH0_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = REALVIEW_PBX_FLASH1_BASE,
- .end = REALVIEW_PBX_FLASH1_BASE + REALVIEW_PBX_FLASH1_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct resource realview_pbx_smsc911x_resources[] = {
- [0] = {
- .start = REALVIEW_PBX_ETH_BASE,
- .end = REALVIEW_PBX_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_PBX_ETH,
- .end = IRQ_PBX_ETH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource realview_pbx_isp1761_resources[] = {
- [0] = {
- .start = REALVIEW_PBX_USB_BASE,
- .end = REALVIEW_PBX_USB_BASE + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_PBX_USB,
- .end = IRQ_PBX_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-#ifdef CONFIG_CACHE_L2X0
-static struct resource pmu_resources[] = {
- [0] = {
- .start = IRQ_PBX_PMU_CPU0,
- .end = IRQ_PBX_PMU_CPU0,
- .flags = IORESOURCE_IRQ,
- },
- [1] = {
- .start = IRQ_PBX_PMU_CPU1,
- .end = IRQ_PBX_PMU_CPU1,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_PBX_PMU_CPU2,
- .end = IRQ_PBX_PMU_CPU2,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = IRQ_PBX_PMU_CPU3,
- .end = IRQ_PBX_PMU_CPU3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device pmu_device = {
- .name = "armv7-pmu",
- .id = -1,
- .num_resources = ARRAY_SIZE(pmu_resources),
- .resource = pmu_resources,
-};
-#endif
-
-static void __init gic_init_irq(void)
-{
- /* ARM PBX on-board GIC */
- if (core_tile_pbx11mp() || core_tile_pbxa9mp()) {
- gic_init(0, 29, __io_address(REALVIEW_PBX_TILE_GIC_DIST_BASE),
- __io_address(REALVIEW_PBX_TILE_GIC_CPU_BASE));
- } else {
- gic_init(0, IRQ_PBX_GIC_START,
- __io_address(REALVIEW_PBX_GIC_DIST_BASE),
- __io_address(REALVIEW_PBX_GIC_CPU_BASE));
- }
-}
-
-#ifdef CONFIG_HAVE_ARM_TWD
-static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
- REALVIEW_PBX_TILE_TWD_BASE,
- IRQ_LOCALTIMER);
-
-static void __init realview_pbx_twd_init(void)
-{
- int err = twd_local_timer_register(&twd_local_timer);
- if (err)
- pr_err("twd_local_timer_register failed %d\n", err);
-}
-#else
-#define realview_pbx_twd_init() do { } while(0)
-#endif
-
-static void __init realview_pbx_timer_init(void)
-{
- timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE);
- timer1_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE) + 0x20;
- timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
- timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
-
- realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
- realview_timer_init(IRQ_PBX_TIMER0_1);
- realview_pbx_twd_init();
-}
-
-static void realview_pbx_fixup(struct tag *tags, char **from)
-{
-#ifdef CONFIG_SPARSEMEM
- /*
- * Memory configuration with SPARSEMEM enabled on RealView PBX (see
- * asm/mach/memory.h for more information).
- */
-
- memblock_add(0, SZ_256M);
- memblock_add(0x20000000, SZ_512M);
- memblock_add(0x80000000, SZ_256M);
-#else
- realview_fixup(tags, from);
-#endif
-}
-
-static void realview_pbx_restart(enum reboot_mode mode, const char *cmd)
-{
- void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
- void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
-
- /*
- * To reset, we hit the on-board reset register
- * in the system FPGA
- */
- __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
- __raw_writel(0x00F0, reset_ctrl);
- __raw_writel(0x00F4, reset_ctrl);
- dsb();
-}
-
-static void __init realview_pbx_init(void)
-{
- int i;
-
-#ifdef CONFIG_CACHE_L2X0
- if (core_tile_pbxa9mp()) {
- void __iomem *l2x0_base =
- __io_address(REALVIEW_PBX_TILE_L220_BASE);
-
- /* set RAM latencies to 1 cycle for eASIC */
- writel(0, l2x0_base + L310_TAG_LATENCY_CTRL);
- writel(0, l2x0_base + L310_DATA_LATENCY_CTRL);
-
- /* 16KB way size, 8-way associativity, parity disabled
- * Bits: .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */
- l2x0_init(l2x0_base, 0x02520000, 0xc0000fff);
- platform_device_register(&pmu_device);
- }
-#endif
-
- realview_flash_register(realview_pbx_flash_resources,
- ARRAY_SIZE(realview_pbx_flash_resources));
- 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++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
-}
-
-MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
- /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
- .atag_offset = 0x100,
- .smp = smp_ops(realview_smp_ops),
- .fixup = realview_pbx_fixup,
- .map_io = realview_pbx_map_io,
- .init_early = realview_init_early,
- .init_irq = gic_init_irq,
- .init_time = realview_pbx_timer_init,
- .init_machine = realview_pbx_init,
-#ifdef CONFIG_ZONE_DMA
- .dma_zone_size = SZ_256M,
-#endif
- .restart = realview_pbx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index bf50328107bd..f6c3f151d0d4 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -21,7 +21,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
+#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -33,6 +33,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_data/dma-s3c24xx.h>
+#include <linux/dmaengine.h>
#include <mach/hardware.h>
#include <mach/regs-clock.h>
@@ -304,6 +305,8 @@ struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {
},
};
+#define s3c24xx_device_dma_mask (*((u64[]) { DMA_BIT_MASK(32) }))
+
#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \
defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
static struct resource s3c2410_dma_resource[] = {
@@ -354,7 +357,9 @@ struct platform_device s3c2410_device_dma = {
.num_resources = ARRAY_SIZE(s3c2410_dma_resource),
.resource = s3c2410_dma_resource,
.dev = {
- .platform_data = &s3c2410_dma_platdata,
+ .dma_mask = &s3c24xx_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &s3c2410_dma_platdata,
},
};
#endif
@@ -395,7 +400,9 @@ struct platform_device s3c2412_device_dma = {
.num_resources = ARRAY_SIZE(s3c2410_dma_resource),
.resource = s3c2410_dma_resource,
.dev = {
- .platform_data = &s3c2412_dma_platdata,
+ .dma_mask = &s3c24xx_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &s3c2412_dma_platdata,
},
};
#endif
@@ -439,10 +446,44 @@ static struct s3c24xx_dma_channel s3c2440_dma_channels[DMACH_MAX] = {
[DMACH_USB_EP4] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 3), },
};
+static const struct dma_slave_map s3c2440_dma_slave_map[] = {
+ /* TODO: DMACH_XD0 */
+ /* TODO: DMACH_XD1 */
+ { "s3c2440-sdi", "rx-tx", (void *)DMACH_SDI },
+ { "s3c2410-spi.0", "rx", (void *)DMACH_SPI0 },
+ { "s3c2410-spi.0", "tx", (void *)DMACH_SPI0 },
+ { "s3c2410-spi.1", "rx", (void *)DMACH_SPI1 },
+ { "s3c2410-spi.1", "tx", (void *)DMACH_SPI1 },
+ { "s3c2440-uart.0", "rx", (void *)DMACH_UART0 },
+ { "s3c2440-uart.0", "tx", (void *)DMACH_UART0 },
+ { "s3c2440-uart.1", "rx", (void *)DMACH_UART1 },
+ { "s3c2440-uart.1", "tx", (void *)DMACH_UART1 },
+ { "s3c2440-uart.2", "rx", (void *)DMACH_UART2 },
+ { "s3c2440-uart.2", "tx", (void *)DMACH_UART2 },
+ { "s3c2440-uart.3", "rx", (void *)DMACH_UART3 },
+ { "s3c2440-uart.3", "tx", (void *)DMACH_UART3 },
+ /* TODO: DMACH_TIMER */
+ { "s3c24xx-iis", "rx", (void *)DMACH_I2S_IN },
+ { "s3c24xx-iis", "tx", (void *)DMACH_I2S_OUT },
+ { "samsung-ac97", "rx", (void *)DMACH_PCM_IN },
+ { "samsung-ac97", "tx", (void *)DMACH_PCM_OUT },
+ { "samsung-ac97", "rx", (void *)DMACH_MIC_IN },
+ { "s3c-hsudc", "rx0", (void *)DMACH_USB_EP1 },
+ { "s3c-hsudc", "rx1", (void *)DMACH_USB_EP2 },
+ { "s3c-hsudc", "rx2", (void *)DMACH_USB_EP3 },
+ { "s3c-hsudc", "rx3", (void *)DMACH_USB_EP4 },
+ { "s3c-hsudc", "tx0", (void *)DMACH_USB_EP1 },
+ { "s3c-hsudc", "tx1", (void *)DMACH_USB_EP2 },
+ { "s3c-hsudc", "tx2", (void *)DMACH_USB_EP3 },
+ { "s3c-hsudc", "tx3", (void *)DMACH_USB_EP4 }
+};
+
static struct s3c24xx_dma_platdata s3c2440_dma_platdata = {
.num_phy_channels = 4,
.channels = s3c2440_dma_channels,
.num_channels = DMACH_MAX,
+ .slave_map = s3c2440_dma_slave_map,
+ .slavecnt = ARRAY_SIZE(s3c2440_dma_slave_map),
};
struct platform_device s3c2440_device_dma = {
@@ -451,7 +492,9 @@ struct platform_device s3c2440_device_dma = {
.num_resources = ARRAY_SIZE(s3c2410_dma_resource),
.resource = s3c2410_dma_resource,
.dev = {
- .platform_data = &s3c2440_dma_platdata,
+ .dma_mask = &s3c24xx_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &s3c2440_dma_platdata,
},
};
#endif
@@ -503,7 +546,9 @@ struct platform_device s3c2443_device_dma = {
.num_resources = ARRAY_SIZE(s3c2443_dma_resource),
.resource = s3c2443_dma_resource,
.dev = {
- .platform_data = &s3c2443_dma_platdata,
+ .dma_mask = &s3c24xx_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &s3c2443_dma_platdata,
},
};
#endif
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index 13999c1c46cf..ec60bd4a1646 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -535,6 +535,7 @@ static struct platform_device *mini2440_devices[] __initdata = {
&mini2440_button_device,
&s3c_device_nand,
&s3c_device_sdi,
+ &s3c2440_device_dma,
&s3c_device_iis,
&uda1340_codec,
&mini2440_audio,
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index 571f95cc5a53..ccc3ab8d58e7 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -393,8 +393,7 @@ static const struct i2c_device_id wlf_gf_module_id[] = {
static struct i2c_driver wlf_gf_module_driver = {
.driver = {
- .name = "wlf-gf-module",
- .owner = THIS_MODULE,
+ .name = "wlf-gf-module"
},
.probe = wlf_gf_module_probe,
.id_table = wlf_gf_module_id,
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index c0b1f5bafae4..0a2ca9be00e6 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/delay.h>
+#include <linux/gpio/machine.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
@@ -217,9 +218,22 @@ static struct platform_device jornada_ssp_device = {
.id = -1,
};
+static struct resource jornada_kbd_resources[] = {
+ DEFINE_RES_IRQ(IRQ_GPIO0),
+};
+
static struct platform_device jornada_kbd_device = {
.name = "jornada720_kbd",
.id = -1,
+ .num_resources = ARRAY_SIZE(jornada_kbd_resources),
+ .resource = jornada_kbd_resources,
+};
+
+static struct gpiod_lookup_table jornada_ts_gpiod_table = {
+ .dev_id = "jornada_ts",
+ .table = {
+ GPIO_LOOKUP("gpio", 9, "penup", GPIO_ACTIVE_HIGH),
+ },
};
static struct platform_device jornada_ts_device = {
@@ -250,6 +264,8 @@ static int __init jornada720_init(void)
GPSR = GPIO_GPIO20; /* restart gpio20 */
udelay(20); /* give it some time to restart */
+ gpiod_add_lookup_table(&jornada_ts_gpiod_table);
+
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 4a48c9f5f725..09817bae4558 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -22,7 +22,6 @@ config ARCH_RCAR_GEN2
select PM_GENERIC_DOMAINS
select RENESAS_IRQC
select SYS_SUPPORTS_SH_CMT
- select PCI_DOMAINS if PCI
config ARCH_RMOBILE
bool
diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c
index 3506327e0bed..78d3e859bd64 100644
--- a/arch/arm/mach-shmobile/setup-r8a7790.c
+++ b/arch/arm/mach-shmobile/setup-r8a7790.c
@@ -28,7 +28,7 @@ static const char * const r8a7790_boards_compat_dt[] __initconst = {
};
DT_MACHINE_START(R8A7790_DT, "Generic R8A7790 (Flattened Device Tree)")
- .smp_init = shmobile_smp_init_fallback_ops,
+ .smp_init = smp_init_ops(shmobile_smp_init_fallback_ops),
.smp = smp_ops(r8a7790_smp_ops),
.init_early = shmobile_init_delay,
.init_time = rcar_gen2_timer_init,
diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c
index 110e8b588e56..26e2d181a190 100644
--- a/arch/arm/mach-shmobile/setup-r8a7791.c
+++ b/arch/arm/mach-shmobile/setup-r8a7791.c
@@ -29,7 +29,7 @@ static const char *const r8a7791_boards_compat_dt[] __initconst = {
};
DT_MACHINE_START(R8A7791_DT, "Generic R8A7791 (Flattened Device Tree)")
- .smp_init = shmobile_smp_init_fallback_ops,
+ .smp_init = smp_init_ops(shmobile_smp_init_fallback_ops),
.smp = smp_ops(r8a7791_smp_ops),
.init_early = shmobile_init_delay,
.init_time = rcar_gen2_timer_init,
diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig
index b7260c2b510c..1b6cae5e78f4 100644
--- a/arch/arm/mach-spear/Kconfig
+++ b/arch/arm/mach-spear/Kconfig
@@ -20,7 +20,6 @@ config ARCH_SPEAR13XX
select HAVE_ARM_TWD if SMP
select PINCTRL
select MFD_SYSCON
- select MIGHT_HAVE_PCI
help
Supports for ARM's SPEAR13XX family
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 096ed216c6d5..b9863f9a35fa 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -32,6 +32,7 @@ config MACH_SUN7I
default ARCH_SUNXI
select ARM_GIC
select ARM_PSCI
+ select ARCH_SUPPORTS_BIG_ENDIAN
select HAVE_ARM_ARCH_TIMER
select SUN5I_HSTIMER
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 95dca8c2c9ed..2e2bde271205 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -22,6 +22,7 @@ static const char * const sunxi_board_dt_compat[] = {
"allwinner,sun5i-a10s",
"allwinner,sun5i-a13",
"allwinner,sun5i-r8",
+ "nextthing,gr8",
NULL,
};
diff --git a/arch/arm/mach-uniphier/Makefile b/arch/arm/mach-uniphier/Makefile
index 396afe109e67..6bea3d3a2dd7 100644
--- a/arch/arm/mach-uniphier/Makefile
+++ b/arch/arm/mach-uniphier/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj- += dummy.o
diff --git a/arch/arm/mach-uniphier/headsmp.S b/arch/arm/mach-uniphier/headsmp.S
deleted file mode 100644
index c819dff84546..000000000000
--- a/arch/arm/mach-uniphier/headsmp.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <asm/cp15.h>
-
-ENTRY(uniphier_smp_trampoline)
-ARM_BE8(setend be) @ ensure we are in BE8 mode
- mrc p15, 0, r0, c0, c0, 5 @ MPIDR (Multiprocessor Affinity Reg)
- and r2, r0, #0x3 @ CPU ID
- ldr r1, uniphier_smp_trampoline_jump
- ldr r3, uniphier_smp_trampoline_poll_addr
- mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
- orr r0, r0, #CR_I @ Enable ICache
- bic r0, r0, #(CR_C | CR_M) @ Disable MMU and Dcache
- mcr p15, 0, r0, c1, c0, 0
- b 1f @ cache the following 5 instructions
-0: wfe
-1: ldr r0, [r3]
- cmp r0, r2
- bxeq r1 @ branch to secondary_startup
- b 0b
- .globl uniphier_smp_trampoline_jump
-uniphier_smp_trampoline_jump:
- .word 0 @ set virt_to_phys(secondary_startup)
- .globl uniphier_smp_trampoline_poll_addr
-uniphier_smp_trampoline_poll_addr:
- .word 0 @ set CPU ID to be kicked to this reg
- .globl uniphier_smp_trampoline_end
-uniphier_smp_trampoline_end:
-ENDPROC(uniphier_smp_trampoline)
diff --git a/arch/arm/mach-uniphier/platsmp.c b/arch/arm/mach-uniphier/platsmp.c
deleted file mode 100644
index 9978c41128f6..000000000000
--- a/arch/arm/mach-uniphier/platsmp.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.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.
- */
-
-#define pr_fmt(fmt) "uniphier: " fmt
-
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/sizes.h>
-#include <asm/cacheflush.h>
-#include <asm/hardware/cache-uniphier.h>
-#include <asm/pgtable.h>
-#include <asm/smp.h>
-#include <asm/smp_scu.h>
-
-/*
- * The secondary CPUs check this register from the boot ROM for the jump
- * destination. After that, it can be reused as a scratch register.
- */
-#define UNIPHIER_SMPCTRL_ROM_RSV2 0x208
-
-static void __iomem *uniphier_smp_rom_boot_rsv2;
-static unsigned int uniphier_smp_max_cpus;
-
-extern char uniphier_smp_trampoline;
-extern char uniphier_smp_trampoline_jump;
-extern char uniphier_smp_trampoline_poll_addr;
-extern char uniphier_smp_trampoline_end;
-
-/*
- * Copy trampoline code to the tail of the 1st section of the page table used
- * in the boot ROM. This area is directly accessible by the secondary CPUs
- * for all the UniPhier SoCs.
- */
-static const phys_addr_t uniphier_smp_trampoline_dest_end = SECTION_SIZE;
-static phys_addr_t uniphier_smp_trampoline_dest;
-
-static int __init uniphier_smp_copy_trampoline(phys_addr_t poll_addr)
-{
- size_t trmp_size;
- static void __iomem *trmp_base;
-
- if (!uniphier_cache_l2_is_enabled()) {
- pr_warn("outer cache is needed for SMP, but not enabled\n");
- return -ENODEV;
- }
-
- uniphier_cache_l2_set_locked_ways(1);
-
- outer_flush_all();
-
- trmp_size = &uniphier_smp_trampoline_end - &uniphier_smp_trampoline;
- uniphier_smp_trampoline_dest = uniphier_smp_trampoline_dest_end -
- trmp_size;
-
- uniphier_cache_l2_touch_range(uniphier_smp_trampoline_dest,
- uniphier_smp_trampoline_dest_end);
-
- trmp_base = ioremap_cache(uniphier_smp_trampoline_dest, trmp_size);
- if (!trmp_base) {
- pr_err("failed to map trampoline destination area\n");
- return -ENOMEM;
- }
-
- memcpy(trmp_base, &uniphier_smp_trampoline, trmp_size);
-
- writel(virt_to_phys(secondary_startup),
- trmp_base + (&uniphier_smp_trampoline_jump -
- &uniphier_smp_trampoline));
-
- writel(poll_addr, trmp_base + (&uniphier_smp_trampoline_poll_addr -
- &uniphier_smp_trampoline));
-
- flush_cache_all(); /* flush out trampoline code to outer cache */
-
- iounmap(trmp_base);
-
- return 0;
-}
-
-static int __init uniphier_smp_prepare_trampoline(unsigned int max_cpus)
-{
- struct device_node *np;
- struct resource res;
- phys_addr_t rom_rsv2_phys;
- int ret;
-
- np = of_find_compatible_node(NULL, NULL, "socionext,uniphier-smpctrl");
- ret = of_address_to_resource(np, 0, &res);
- of_node_put(np);
- if (ret) {
- pr_err("failed to get resource of SMP control\n");
- return ret;
- }
-
- rom_rsv2_phys = res.start + UNIPHIER_SMPCTRL_ROM_RSV2;
-
- ret = uniphier_smp_copy_trampoline(rom_rsv2_phys);
- if (ret)
- return ret;
-
- uniphier_smp_rom_boot_rsv2 = ioremap(rom_rsv2_phys, SZ_4);
- if (!uniphier_smp_rom_boot_rsv2) {
- pr_err("failed to map ROM_BOOT_RSV2 register\n");
- return -ENOMEM;
- }
-
- writel(uniphier_smp_trampoline_dest, uniphier_smp_rom_boot_rsv2);
- asm("sev"); /* Bring up all secondary CPUs to the trampoline code */
-
- uniphier_smp_max_cpus = max_cpus; /* save for later use */
-
- return 0;
-}
-
-static void __init uniphier_smp_unprepare_trampoline(void)
-{
- iounmap(uniphier_smp_rom_boot_rsv2);
-
- if (uniphier_smp_trampoline_dest)
- outer_inv_range(uniphier_smp_trampoline_dest,
- uniphier_smp_trampoline_dest_end);
-
- uniphier_cache_l2_set_locked_ways(0);
-}
-
-static int __init uniphier_smp_enable_scu(void)
-{
- unsigned long scu_base_phys = 0;
- void __iomem *scu_base;
-
- if (scu_a9_has_base())
- scu_base_phys = scu_a9_get_base();
-
- if (!scu_base_phys) {
- pr_err("failed to get scu base\n");
- return -ENODEV;
- }
-
- scu_base = ioremap(scu_base_phys, SZ_128);
- if (!scu_base) {
- pr_err("failed to map scu base\n");
- return -ENOMEM;
- }
-
- scu_enable(scu_base);
- iounmap(scu_base);
-
- return 0;
-}
-
-static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
-{
- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
- int ret;
-
- ret = uniphier_smp_prepare_trampoline(max_cpus);
- if (ret)
- goto err;
-
- ret = uniphier_smp_enable_scu();
- if (ret)
- goto err;
-
- return;
-err:
- pr_warn("disabling SMP\n");
- init_cpu_present(&only_cpu_0);
- uniphier_smp_unprepare_trampoline();
-}
-
-static int __init uniphier_smp_boot_secondary(unsigned int cpu,
- struct task_struct *idle)
-{
- if (WARN_ON_ONCE(!uniphier_smp_rom_boot_rsv2))
- return -EFAULT;
-
- writel(cpu, uniphier_smp_rom_boot_rsv2);
- readl(uniphier_smp_rom_boot_rsv2); /* relax */
-
- asm("sev"); /* wake up secondary CPUs sleeping in the trampoline */
-
- if (cpu == uniphier_smp_max_cpus - 1) {
- /* clean up resources if this is the last CPU */
- uniphier_smp_unprepare_trampoline();
- }
-
- return 0;
-}
-
-static const struct smp_operations uniphier_smp_ops __initconst = {
- .smp_prepare_cpus = uniphier_smp_prepare_cpus,
- .smp_boot_secondary = uniphier_smp_boot_secondary,
-};
-CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
- &uniphier_smp_ops);
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig
index b0cc26284fc9..c257d40ca51d 100644
--- a/arch/arm/mach-versatile/Kconfig
+++ b/arch/arm/mach-versatile/Kconfig
@@ -9,7 +9,6 @@ config ARCH_VERSATILE
select CPU_ARM926T
select ICST
select MFD_SYSCON
- select MIGHT_HAVE_PCI
select PLAT_VERSATILE
select POWER_RESET
select POWER_RESET_VERSATILE
diff --git a/arch/arm/mm/cache-uniphier.c b/arch/arm/mm/cache-uniphier.c
index c8e2f4947223..dfe97b409916 100644
--- a/arch/arm/mm/cache-uniphier.c
+++ b/arch/arm/mm/cache-uniphier.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.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
@@ -43,27 +44,15 @@
#define UNIPHIER_SSCOPE_CM_SYNC 0x8 /* sync (drain bufs) */
#define UNIPHIER_SSCOPE_CM_FLUSH_PREFETCH 0x9 /* flush p-fetch buf */
#define UNIPHIER_SSCOQM 0x248 /* Cache Operation Queue Mode */
-#define UNIPHIER_SSCOQM_TID_MASK (0x3 << 21)
-#define UNIPHIER_SSCOQM_TID_LRU_DATA (0x0 << 21)
-#define UNIPHIER_SSCOQM_TID_LRU_INST (0x1 << 21)
-#define UNIPHIER_SSCOQM_TID_WAY (0x2 << 21)
#define UNIPHIER_SSCOQM_S_MASK (0x3 << 17)
#define UNIPHIER_SSCOQM_S_RANGE (0x0 << 17)
#define UNIPHIER_SSCOQM_S_ALL (0x1 << 17)
-#define UNIPHIER_SSCOQM_S_WAY (0x2 << 17)
#define UNIPHIER_SSCOQM_CE BIT(15) /* notify completion */
#define UNIPHIER_SSCOQM_CM_INV 0x0 /* invalidate */
#define UNIPHIER_SSCOQM_CM_CLEAN 0x1 /* clean */
#define UNIPHIER_SSCOQM_CM_FLUSH 0x2 /* flush */
-#define UNIPHIER_SSCOQM_CM_PREFETCH 0x3 /* prefetch to cache */
-#define UNIPHIER_SSCOQM_CM_PREFETCH_BUF 0x4 /* prefetch to pf-buf */
-#define UNIPHIER_SSCOQM_CM_TOUCH 0x5 /* touch */
-#define UNIPHIER_SSCOQM_CM_TOUCH_ZERO 0x6 /* touch to zero */
-#define UNIPHIER_SSCOQM_CM_TOUCH_DIRTY 0x7 /* touch with dirty */
#define UNIPHIER_SSCOQAD 0x24c /* Cache Operation Queue Address */
#define UNIPHIER_SSCOQSZ 0x250 /* Cache Operation Queue Size */
-#define UNIPHIER_SSCOQMASK 0x254 /* Cache Operation Queue Address Mask */
-#define UNIPHIER_SSCOQWN 0x258 /* Cache Operation Queue Way Number */
#define UNIPHIER_SSCOPPQSEF 0x25c /* Cache Operation Queue Set Complete*/
#define UNIPHIER_SSCOPPQSEF_FE BIT(1)
#define UNIPHIER_SSCOPPQSEF_OE BIT(0)
@@ -72,9 +61,6 @@
#define UNIPHIER_SSCOLPQS_EST BIT(1)
#define UNIPHIER_SSCOLPQS_QST BIT(0)
-/* Is the touch/pre-fetch destination specified by ways? */
-#define UNIPHIER_SSCOQM_TID_IS_WAY(op) \
- ((op & UNIPHIER_SSCOQM_TID_MASK) == UNIPHIER_SSCOQM_TID_WAY)
/* Is the operation region specified by address range? */
#define UNIPHIER_SSCOQM_S_IS_RANGE(op) \
((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
@@ -178,11 +164,6 @@ static void __uniphier_cache_maint_common(struct uniphier_cache_data *data,
writel_relaxed(start, data->op_base + UNIPHIER_SSCOQAD);
writel_relaxed(size, data->op_base + UNIPHIER_SSCOQSZ);
}
-
- /* set target ways if needed */
- if (unlikely(UNIPHIER_SSCOQM_TID_IS_WAY(operation)))
- writel_relaxed(data->way_locked_mask,
- data->op_base + UNIPHIER_SSCOQWN);
} while (unlikely(readl_relaxed(data->op_base + UNIPHIER_SSCOPPQSEF) &
(UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
@@ -338,46 +319,8 @@ static void uniphier_cache_sync(void)
__uniphier_cache_sync(data);
}
-int __init uniphier_cache_l2_is_enabled(void)
-{
- struct uniphier_cache_data *data;
-
- data = list_first_entry_or_null(&uniphier_cache_list,
- struct uniphier_cache_data, list);
- if (!data)
- return 0;
-
- return !!(readl_relaxed(data->ctrl_base + UNIPHIER_SSCC) &
- UNIPHIER_SSCC_ON);
-}
-
-void __init uniphier_cache_l2_touch_range(unsigned long start,
- unsigned long end)
-{
- struct uniphier_cache_data *data;
-
- data = list_first_entry_or_null(&uniphier_cache_list,
- struct uniphier_cache_data, list);
- if (data)
- __uniphier_cache_maint_range(data, start, end,
- UNIPHIER_SSCOQM_TID_WAY |
- UNIPHIER_SSCOQM_CM_TOUCH);
-}
-
-void __init uniphier_cache_l2_set_locked_ways(u32 way_mask)
-{
- struct uniphier_cache_data *data;
-
- data = list_first_entry_or_null(&uniphier_cache_list,
- struct uniphier_cache_data, list);
- if (data)
- __uniphier_cache_set_locked_ways(data, way_mask);
-}
-
static const struct of_device_id uniphier_cache_match[] __initconst = {
- {
- .compatible = "socionext,uniphier-system-cache",
- },
+ { .compatible = "socionext,uniphier-system-cache" },
{ /* sentinel */ }
};
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index a2302aba5df2..ab4f74536057 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2014,6 +2014,63 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
__free_iova(mapping, iova, len);
}
+/**
+ * arm_iommu_map_resource - map a device resource for DMA
+ * @dev: valid struct device pointer
+ * @phys_addr: physical address of resource
+ * @size: size of resource to map
+ * @dir: DMA transfer direction
+ */
+static dma_addr_t arm_iommu_map_resource(struct device *dev,
+ phys_addr_t phys_addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+ dma_addr_t dma_addr;
+ int ret, prot;
+ phys_addr_t addr = phys_addr & PAGE_MASK;
+ unsigned int offset = phys_addr & ~PAGE_MASK;
+ size_t len = PAGE_ALIGN(size + offset);
+
+ dma_addr = __alloc_iova(mapping, len);
+ if (dma_addr == DMA_ERROR_CODE)
+ return dma_addr;
+
+ prot = __dma_direction_to_prot(dir) | IOMMU_MMIO;
+
+ ret = iommu_map(mapping->domain, dma_addr, addr, len, prot);
+ if (ret < 0)
+ goto fail;
+
+ return dma_addr + offset;
+fail:
+ __free_iova(mapping, dma_addr, len);
+ return DMA_ERROR_CODE;
+}
+
+/**
+ * arm_iommu_unmap_resource - unmap a device DMA resource
+ * @dev: valid struct device pointer
+ * @dma_handle: DMA address to resource
+ * @size: size of resource to map
+ * @dir: DMA transfer direction
+ */
+static void arm_iommu_unmap_resource(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+ dma_addr_t iova = dma_handle & PAGE_MASK;
+ unsigned int offset = dma_handle & ~PAGE_MASK;
+ size_t len = PAGE_ALIGN(size + offset);
+
+ if (!iova)
+ return;
+
+ iommu_unmap(mapping->domain, iova, len);
+ __free_iova(mapping, iova, len);
+}
+
static void arm_iommu_sync_single_for_cpu(struct device *dev,
dma_addr_t handle, size_t size, enum dma_data_direction dir)
{
@@ -2057,6 +2114,9 @@ struct dma_map_ops iommu_ops = {
.unmap_sg = arm_iommu_unmap_sg,
.sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu,
.sync_sg_for_device = arm_iommu_sync_sg_for_device,
+
+ .map_resource = arm_iommu_map_resource,
+ .unmap_resource = arm_iommu_unmap_resource,
};
struct dma_map_ops iommu_coherent_ops = {
@@ -2070,6 +2130,9 @@ struct dma_map_ops iommu_coherent_ops = {
.map_sg = arm_coherent_iommu_map_sg,
.unmap_sg = arm_coherent_iommu_unmap_sg,
+
+ .map_resource = arm_iommu_map_resource,
+ .unmap_resource = arm_iommu_unmap_resource,
};
/**
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index 78c8bf4043c0..272f49b2c68f 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -52,21 +52,27 @@ void __init orion_clkdev_init(struct clk *tclk)
static void fill_resources(struct platform_device *device,
struct resource *resources,
resource_size_t mapbase,
- resource_size_t size,
- unsigned int irq)
+ resource_size_t size)
{
device->resource = resources;
device->num_resources = 1;
resources[0].flags = IORESOURCE_MEM;
resources[0].start = mapbase;
resources[0].end = mapbase + size;
+}
- if (irq != NO_IRQ) {
- device->num_resources++;
- resources[1].flags = IORESOURCE_IRQ;
- resources[1].start = irq;
- resources[1].end = irq;
- }
+static void fill_resources_irq(struct platform_device *device,
+ struct resource *resources,
+ resource_size_t mapbase,
+ resource_size_t size,
+ unsigned int irq)
+{
+ fill_resources(device, resources, mapbase, size);
+
+ device->num_resources++;
+ resources[1].flags = IORESOURCE_IRQ;
+ resources[1].start = irq;
+ resources[1].end = irq;
}
/*****************************************************************************
@@ -93,7 +99,7 @@ static void __init uart_complete(
data->uartclk = uart_get_clk_rate(clk);
orion_uart->dev.platform_data = data;
- fill_resources(orion_uart, resources, mapbase, 0xff, irq);
+ fill_resources_irq(orion_uart, resources, mapbase, 0xff, irq);
platform_device_register(orion_uart);
}
@@ -305,8 +311,8 @@ void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
unsigned int tx_csum_limit)
{
fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
- fill_resources(&orion_ge_mvmdio, orion_ge_mvmdio_resources,
+ mapbase + 0x2000, SZ_16K - 1);
+ fill_resources_irq(&orion_ge_mvmdio, orion_ge_mvmdio_resources,
mapbase + 0x2004, 0x84 - 1, irq_err);
orion_ge00_shared_data.tx_csum_limit = tx_csum_limit;
ge_complete(&orion_ge00_shared_data,
@@ -354,11 +360,10 @@ static struct platform_device orion_ge01 = {
void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
unsigned long irq,
- unsigned long irq_err,
unsigned int tx_csum_limit)
{
fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
+ mapbase + 0x2000, SZ_16K - 1);
orion_ge01_shared_data.tx_csum_limit = tx_csum_limit;
ge_complete(&orion_ge01_shared_data,
orion_ge01_resources, irq, &orion_ge01_shared,
@@ -404,11 +409,10 @@ static struct platform_device orion_ge10 = {
void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
- unsigned long irq,
- unsigned long irq_err)
+ unsigned long irq)
{
fill_resources(&orion_ge10_shared, orion_ge10_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
+ mapbase + 0x2000, SZ_16K - 1);
ge_complete(&orion_ge10_shared_data,
orion_ge10_resources, irq, &orion_ge10_shared,
NULL,
@@ -453,11 +457,10 @@ static struct platform_device orion_ge11 = {
void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
- unsigned long irq,
- unsigned long irq_err)
+ unsigned long irq)
{
fill_resources(&orion_ge11_shared, orion_ge11_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
+ mapbase + 0x2000, SZ_16K - 1);
ge_complete(&orion_ge11_shared_data,
orion_ge11_resources, irq, &orion_ge11_shared,
NULL,
@@ -467,37 +470,15 @@ void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
/*****************************************************************************
* Ethernet switch
****************************************************************************/
-static struct resource orion_switch_resources[] = {
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion_switch_device = {
- .name = "dsa",
- .id = 0,
- .num_resources = 0,
- .resource = orion_switch_resources,
-};
-
-void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq)
+void __init orion_ge00_switch_init(struct dsa_platform_data *d)
{
int i;
- if (irq != NO_IRQ) {
- orion_switch_resources[0].start = irq;
- orion_switch_resources[0].end = irq;
- orion_switch_device.num_resources = 1;
- }
-
d->netdev = &orion_ge00.dev;
for (i = 0; i < d->nr_chips; i++)
d->chip[i].host_dev = &orion_ge_mvmdio.dev;
- orion_switch_device.dev.platform_data = d;
- platform_device_register(&orion_switch_device);
+ platform_device_register_data(NULL, "dsa", 0, d, sizeof(d));
}
/*****************************************************************************
@@ -538,7 +519,7 @@ void __init orion_i2c_init(unsigned long mapbase,
unsigned long freq_m)
{
orion_i2c_pdata.freq_m = freq_m;
- fill_resources(&orion_i2c, orion_i2c_resources, mapbase,
+ fill_resources_irq(&orion_i2c, orion_i2c_resources, mapbase,
SZ_32 - 1, irq);
platform_device_register(&orion_i2c);
}
@@ -548,7 +529,7 @@ void __init orion_i2c_1_init(unsigned long mapbase,
unsigned long freq_m)
{
orion_i2c_1_pdata.freq_m = freq_m;
- fill_resources(&orion_i2c_1, orion_i2c_1_resources, mapbase,
+ fill_resources_irq(&orion_i2c_1, orion_i2c_1_resources, mapbase,
SZ_32 - 1, irq);
platform_device_register(&orion_i2c_1);
}
@@ -576,14 +557,14 @@ static struct platform_device orion_spi_1 = {
void __init orion_spi_init(unsigned long mapbase)
{
fill_resources(&orion_spi, &orion_spi_resources,
- mapbase, SZ_512 - 1, NO_IRQ);
+ mapbase, SZ_512 - 1);
platform_device_register(&orion_spi);
}
void __init orion_spi_1_init(unsigned long mapbase)
{
fill_resources(&orion_spi_1, &orion_spi_1_resources,
- mapbase, SZ_512 - 1, NO_IRQ);
+ mapbase, SZ_512 - 1);
platform_device_register(&orion_spi_1);
}
@@ -741,7 +722,7 @@ void __init orion_ehci_init(unsigned long mapbase,
enum orion_ehci_phy_ver phy_version)
{
orion_ehci_data.phy_version = phy_version;
- fill_resources(&orion_ehci, orion_ehci_resources, mapbase, SZ_4K - 1,
+ fill_resources_irq(&orion_ehci, orion_ehci_resources, mapbase, SZ_4K - 1,
irq);
platform_device_register(&orion_ehci);
@@ -765,7 +746,7 @@ static struct platform_device orion_ehci_1 = {
void __init orion_ehci_1_init(unsigned long mapbase,
unsigned long irq)
{
- fill_resources(&orion_ehci_1, orion_ehci_1_resources,
+ fill_resources_irq(&orion_ehci_1, orion_ehci_1_resources,
mapbase, SZ_4K - 1, irq);
platform_device_register(&orion_ehci_1);
@@ -789,7 +770,7 @@ static struct platform_device orion_ehci_2 = {
void __init orion_ehci_2_init(unsigned long mapbase,
unsigned long irq)
{
- fill_resources(&orion_ehci_2, orion_ehci_2_resources,
+ fill_resources_irq(&orion_ehci_2, orion_ehci_2_resources,
mapbase, SZ_4K - 1, irq);
platform_device_register(&orion_ehci_2);
@@ -819,7 +800,7 @@ void __init orion_sata_init(struct mv_sata_platform_data *sata_data,
unsigned long irq)
{
orion_sata.dev.platform_data = sata_data;
- fill_resources(&orion_sata, orion_sata_resources,
+ fill_resources_irq(&orion_sata, orion_sata_resources,
mapbase, 0x5000 - 1, irq);
platform_device_register(&orion_sata);
@@ -849,7 +830,7 @@ void __init orion_crypto_init(unsigned long mapbase,
unsigned long sram_size,
unsigned long irq)
{
- fill_resources(&orion_crypto, orion_crypto_resources,
+ fill_resources_irq(&orion_crypto, orion_crypto_resources,
mapbase, 0xffff, irq);
orion_crypto.num_resources = 3;
orion_crypto_resources[2].start = srambase;
diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h
index 9e6d76ad48a9..9347f3c58a6d 100644
--- a/arch/arm/plat-orion/include/plat/common.h
+++ b/arch/arm/plat-orion/include/plat/common.h
@@ -47,21 +47,17 @@ void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
unsigned long irq,
- unsigned long irq_err,
unsigned int tx_csum_limit);
void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
- unsigned long irq,
- unsigned long irq_err);
+ unsigned long irq);
void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
- unsigned long irq,
- unsigned long irq_err);
+ unsigned long irq);
-void __init orion_ge00_switch_init(struct dsa_platform_data *d,
- int irq);
+void __init orion_ge00_switch_init(struct dsa_platform_data *d);
void __init orion_i2c_init(unsigned long mapbase,
unsigned long irq,
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 557b134db772..2f06a2e8b1dd 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -3,8 +3,6 @@
#
ccflags-$(CONFIG_ARCH_MMP) := -I$(srctree)/$(src)/include
-obj-$(CONFIG_ARCH_PXA) := dma.o
-
obj-$(CONFIG_PXA3xx) += mfp.o
obj-$(CONFIG_ARCH_MMP) += mfp.o
diff --git a/arch/arm/plat-pxa/dma.c b/arch/arm/plat-pxa/dma.c
deleted file mode 100644
index de2b061889ec..000000000000
--- a/arch/arm/plat-pxa/dma.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * linux/arch/arm/plat-pxa/dma.c
- *
- * PXA DMA registration and IRQ dispatching
- *
- * Author: Nicolas Pitre
- * Created: Nov 15, 2001
- * Copyright: MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/irq.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-#define DMA_DEBUG_NAME "pxa_dma"
-#define DMA_MAX_REQUESTERS 64
-
-struct dma_channel {
- char *name;
- pxa_dma_prio prio;
- void (*irq_handler)(int, void *);
- void *data;
- spinlock_t lock;
-};
-
-static struct dma_channel *dma_channels;
-static int num_dma_channels;
-
-/*
- * Debug fs
- */
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/seq_file.h>
-
-static struct dentry *dbgfs_root, *dbgfs_state, **dbgfs_chan;
-
-static int dbg_show_requester_chan(struct seq_file *s, void *p)
-{
- int chan = (int)s->private;
- int i;
- u32 drcmr;
-
- seq_printf(s, "DMA channel %d requesters list :\n", chan);
- for (i = 0; i < DMA_MAX_REQUESTERS; i++) {
- drcmr = DRCMR(i);
- if ((drcmr & DRCMR_CHLNUM) == chan)
- seq_printf(s, "\tRequester %d (MAPVLD=%d)\n",
- i, !!(drcmr & DRCMR_MAPVLD));
- }
-
- return 0;
-}
-
-static inline int dbg_burst_from_dcmd(u32 dcmd)
-{
- int burst = (dcmd >> 16) & 0x3;
-
- return burst ? 4 << burst : 0;
-}
-
-static int is_phys_valid(unsigned long addr)
-{
- return pfn_valid(__phys_to_pfn(addr));
-}
-
-#define DCSR_STR(flag) (dcsr & DCSR_##flag ? #flag" " : "")
-#define DCMD_STR(flag) (dcmd & DCMD_##flag ? #flag" " : "")
-
-static int dbg_show_descriptors(struct seq_file *s, void *p)
-{
- int chan = (int)s->private;
- int i, max_show = 20, burst, width;
- u32 dcmd;
- unsigned long phys_desc;
- struct pxa_dma_desc *desc;
- unsigned long flags;
-
- spin_lock_irqsave(&dma_channels[chan].lock, flags);
- phys_desc = DDADR(chan);
-
- seq_printf(s, "DMA channel %d descriptors :\n", chan);
- seq_printf(s, "[%03d] First descriptor unknown\n", 0);
- for (i = 1; i < max_show && is_phys_valid(phys_desc); i++) {
- desc = phys_to_virt(phys_desc);
- dcmd = desc->dcmd;
- burst = dbg_burst_from_dcmd(dcmd);
- width = (1 << ((dcmd >> 14) & 0x3)) >> 1;
-
- seq_printf(s, "[%03d] Desc at %08lx(virt %p)\n",
- i, phys_desc, desc);
- seq_printf(s, "\tDDADR = %08x\n", desc->ddadr);
- seq_printf(s, "\tDSADR = %08x\n", desc->dsadr);
- seq_printf(s, "\tDTADR = %08x\n", desc->dtadr);
- seq_printf(s, "\tDCMD = %08x (%s%s%s%s%s%s%sburst=%d width=%d len=%d)\n",
- dcmd,
- DCMD_STR(INCSRCADDR), DCMD_STR(INCTRGADDR),
- DCMD_STR(FLOWSRC), DCMD_STR(FLOWTRG),
- DCMD_STR(STARTIRQEN), DCMD_STR(ENDIRQEN),
- DCMD_STR(ENDIAN), burst, width,
- dcmd & DCMD_LENGTH);
- phys_desc = desc->ddadr;
- }
- if (i == max_show)
- seq_printf(s, "[%03d] Desc at %08lx ... max display reached\n",
- i, phys_desc);
- else
- seq_printf(s, "[%03d] Desc at %08lx is %s\n",
- i, phys_desc, phys_desc == DDADR_STOP ?
- "DDADR_STOP" : "invalid");
-
- spin_unlock_irqrestore(&dma_channels[chan].lock, flags);
-
- return 0;
-}
-
-static int dbg_show_chan_state(struct seq_file *s, void *p)
-{
- int chan = (int)s->private;
- u32 dcsr, dcmd;
- int burst, width;
- static char *str_prio[] = { "high", "normal", "low" };
-
- dcsr = DCSR(chan);
- dcmd = DCMD(chan);
- burst = dbg_burst_from_dcmd(dcmd);
- width = (1 << ((dcmd >> 14) & 0x3)) >> 1;
-
- seq_printf(s, "DMA channel %d\n", chan);
- seq_printf(s, "\tPriority : %s\n", str_prio[dma_channels[chan].prio]);
- seq_printf(s, "\tUnaligned transfer bit: %s\n",
- DALGN & (1 << chan) ? "yes" : "no");
- seq_printf(s, "\tDCSR = %08x (%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
- dcsr, DCSR_STR(RUN), DCSR_STR(NODESC),
- DCSR_STR(STOPIRQEN), DCSR_STR(EORIRQEN),
- DCSR_STR(EORJMPEN), DCSR_STR(EORSTOPEN),
- DCSR_STR(SETCMPST), DCSR_STR(CLRCMPST),
- DCSR_STR(CMPST), DCSR_STR(EORINTR), DCSR_STR(REQPEND),
- DCSR_STR(STOPSTATE), DCSR_STR(ENDINTR),
- DCSR_STR(STARTINTR), DCSR_STR(BUSERR));
-
- seq_printf(s, "\tDCMD = %08x (%s%s%s%s%s%s%sburst=%d width=%d len=%d)\n",
- dcmd,
- DCMD_STR(INCSRCADDR), DCMD_STR(INCTRGADDR),
- DCMD_STR(FLOWSRC), DCMD_STR(FLOWTRG),
- DCMD_STR(STARTIRQEN), DCMD_STR(ENDIRQEN),
- DCMD_STR(ENDIAN), burst, width, dcmd & DCMD_LENGTH);
- seq_printf(s, "\tDSADR = %08x\n", DSADR(chan));
- seq_printf(s, "\tDTADR = %08x\n", DTADR(chan));
- seq_printf(s, "\tDDADR = %08x\n", DDADR(chan));
-
- return 0;
-}
-
-static int dbg_show_state(struct seq_file *s, void *p)
-{
- /* basic device status */
- seq_puts(s, "DMA engine status\n");
- seq_printf(s, "\tChannel number: %d\n", num_dma_channels);
-
- return 0;
-}
-
-#define DBGFS_FUNC_DECL(name) \
-static int dbg_open_##name(struct inode *inode, struct file *file) \
-{ \
- return single_open(file, dbg_show_##name, inode->i_private); \
-} \
-static const struct file_operations dbg_fops_##name = { \
- .owner = THIS_MODULE, \
- .open = dbg_open_##name, \
- .llseek = seq_lseek, \
- .read = seq_read, \
- .release = single_release, \
-}
-
-DBGFS_FUNC_DECL(state);
-DBGFS_FUNC_DECL(chan_state);
-DBGFS_FUNC_DECL(descriptors);
-DBGFS_FUNC_DECL(requester_chan);
-
-static struct dentry *pxa_dma_dbg_alloc_chan(int ch, struct dentry *chandir)
-{
- char chan_name[11];
- struct dentry *chan, *chan_state = NULL, *chan_descr = NULL;
- struct dentry *chan_reqs = NULL;
- void *dt;
-
- scnprintf(chan_name, sizeof(chan_name), "%d", ch);
- chan = debugfs_create_dir(chan_name, chandir);
- dt = (void *)ch;
-
- if (chan)
- chan_state = debugfs_create_file("state", 0400, chan, dt,
- &dbg_fops_chan_state);
- if (chan_state)
- chan_descr = debugfs_create_file("descriptors", 0400, chan, dt,
- &dbg_fops_descriptors);
- if (chan_descr)
- chan_reqs = debugfs_create_file("requesters", 0400, chan, dt,
- &dbg_fops_requester_chan);
- if (!chan_reqs)
- goto err_state;
-
- return chan;
-
-err_state:
- debugfs_remove_recursive(chan);
- return NULL;
-}
-
-static void pxa_dma_init_debugfs(void)
-{
- int i;
- struct dentry *chandir;
-
- dbgfs_root = debugfs_create_dir(DMA_DEBUG_NAME, NULL);
- if (IS_ERR(dbgfs_root) || !dbgfs_root)
- goto err_root;
-
- dbgfs_state = debugfs_create_file("state", 0400, dbgfs_root, NULL,
- &dbg_fops_state);
- if (!dbgfs_state)
- goto err_state;
-
- dbgfs_chan = kmalloc(sizeof(*dbgfs_state) * num_dma_channels,
- GFP_KERNEL);
- if (!dbgfs_chan)
- goto err_alloc;
-
- chandir = debugfs_create_dir("channels", dbgfs_root);
- if (!chandir)
- goto err_chandir;
-
- for (i = 0; i < num_dma_channels; i++) {
- dbgfs_chan[i] = pxa_dma_dbg_alloc_chan(i, chandir);
- if (!dbgfs_chan[i])
- goto err_chans;
- }
-
- return;
-err_chans:
-err_chandir:
- kfree(dbgfs_chan);
-err_alloc:
-err_state:
- debugfs_remove_recursive(dbgfs_root);
-err_root:
- pr_err("pxa_dma: debugfs is not available\n");
-}
-
-static void __exit pxa_dma_cleanup_debugfs(void)
-{
- debugfs_remove_recursive(dbgfs_root);
-}
-#else
-static inline void pxa_dma_init_debugfs(void) {}
-static inline void pxa_dma_cleanup_debugfs(void) {}
-#endif
-
-int pxa_request_dma (char *name, pxa_dma_prio prio,
- void (*irq_handler)(int, void *),
- void *data)
-{
- unsigned long flags;
- int i, found = 0;
-
- /* basic sanity checks */
- if (!name || !irq_handler)
- return -EINVAL;
-
- local_irq_save(flags);
-
- do {
- /* try grabbing a DMA channel with the requested priority */
- for (i = 0; i < num_dma_channels; i++) {
- if ((dma_channels[i].prio == prio) &&
- !dma_channels[i].name &&
- !pxad_toggle_reserved_channel(i)) {
- found = 1;
- break;
- }
- }
- /* if requested prio group is full, try a hier priority */
- } while (!found && prio--);
-
- if (found) {
- DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
- dma_channels[i].name = name;
- dma_channels[i].irq_handler = irq_handler;
- dma_channels[i].data = data;
- } else {
- printk (KERN_WARNING "No more available DMA channels for %s\n", name);
- i = -ENODEV;
- }
-
- local_irq_restore(flags);
- return i;
-}
-EXPORT_SYMBOL(pxa_request_dma);
-
-void pxa_free_dma (int dma_ch)
-{
- unsigned long flags;
-
- if (!dma_channels[dma_ch].name) {
- printk (KERN_CRIT
- "%s: trying to free channel %d which is already freed\n",
- __func__, dma_ch);
- return;
- }
-
- local_irq_save(flags);
- DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
- dma_channels[dma_ch].name = NULL;
- pxad_toggle_reserved_channel(dma_ch);
- local_irq_restore(flags);
-}
-EXPORT_SYMBOL(pxa_free_dma);
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
- int i, dint = DINT, done = 0;
- struct dma_channel *channel;
-
- while (dint) {
- i = __ffs(dint);
- dint &= (dint - 1);
- channel = &dma_channels[i];
- if (channel->name && channel->irq_handler) {
- channel->irq_handler(i, channel->data);
- done++;
- }
- }
- if (done)
- return IRQ_HANDLED;
- else
- return IRQ_NONE;
-}
-
-int __init pxa_init_dma(int irq, int num_ch)
-{
- int i, ret;
-
- dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL);
- if (dma_channels == NULL)
- return -ENOMEM;
-
- /* dma channel priorities on pxa2xx processors:
- * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH
- * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM
- * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW
- */
- for (i = 0; i < num_ch; i++) {
- DCSR(i) = 0;
- dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW);
- spin_lock_init(&dma_channels[i].lock);
- }
-
- ret = request_irq(irq, dma_irq_handler, IRQF_SHARED, "DMA",
- dma_channels);
- if (ret) {
- printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n");
- kfree(dma_channels);
- return ret;
- }
- num_dma_channels = num_ch;
-
- pxa_dma_init_debugfs();
-
- return 0;
-}
diff --git a/arch/arm/plat-pxa/include/plat/dma.h b/arch/arm/plat-pxa/include/plat/dma.h
deleted file mode 100644
index ceba3e4184fc..000000000000
--- a/arch/arm/plat-pxa/include/plat/dma.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef __PLAT_DMA_H
-#define __PLAT_DMA_H
-
-#define DMAC_REG(x) (*((volatile u32 *)(DMAC_REGS_VIRT + (x))))
-
-#define DCSR(n) DMAC_REG((n) << 2)
-#define DALGN DMAC_REG(0x00a0) /* DMA Alignment Register */
-#define DINT DMAC_REG(0x00f0) /* DMA Interrupt Register */
-#define DDADR(n) DMAC_REG(0x0200 + ((n) << 4))
-#define DSADR(n) DMAC_REG(0x0204 + ((n) << 4))
-#define DTADR(n) DMAC_REG(0x0208 + ((n) << 4))
-#define DCMD(n) DMAC_REG(0x020c + ((n) << 4))
-#define DRCMR(n) DMAC_REG((((n) < 64) ? 0x0100 : 0x1100) + \
- (((n) & 0x3f) << 2))
-
-#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */
-#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */
-#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */
-#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */
-#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */
-#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */
-#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */
-#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */
-
-#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */
-#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */
-#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */
-#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */
-#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */
-#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */
-#define DCSR_EORINTR (1 << 9) /* The end of Receive */
-
-#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */
-#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */
-
-#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */
-#define DDADR_STOP (1 << 0) /* Stop (read / write) */
-
-#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */
-#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */
-#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */
-#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */
-#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */
-#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */
-#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */
-#define DCMD_BURST8 (1 << 16) /* 8 byte burst */
-#define DCMD_BURST16 (2 << 16) /* 16 byte burst */
-#define DCMD_BURST32 (3 << 16) /* 32 byte burst */
-#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */
-#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */
-#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */
-#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
-
-/*
- * Descriptor structure for PXA's DMA engine
- * Note: this structure must always be aligned to a 16-byte boundary.
- */
-
-typedef struct pxa_dma_desc {
- volatile u32 ddadr; /* Points to the next descriptor + flags */
- volatile u32 dsadr; /* DSADR value for the current transfer */
- volatile u32 dtadr; /* DTADR value for the current transfer */
- volatile u32 dcmd; /* DCMD value for the current transfer */
-} pxa_dma_desc;
-
-typedef enum {
- DMA_PRIO_HIGH = 0,
- DMA_PRIO_MEDIUM = 1,
- DMA_PRIO_LOW = 2
-} pxa_dma_prio;
-
-/*
- * DMA registration
- */
-
-int __init pxa_init_dma(int irq, int num_ch);
-
-int pxa_request_dma (char *name,
- pxa_dma_prio prio,
- void (*irq_handler)(int, void *),
- void *data);
-
-void pxa_free_dma (int dma_ch);
-
-/*
- * Cooperation with pxa_dma + dmaengine while there remains at least one pxa
- * driver not converted to dmaengine.
- */
-#if defined(CONFIG_PXA_DMA)
-extern int pxad_toggle_reserved_channel(int legacy_channel);
-#else
-static inline int pxad_toggle_reserved_channel(int legacy_channel)
-{
- return 0;
-}
-#endif
-
-extern void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors);
-
-#endif /* __PLAT_DMA_H */
diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h
index b63aeebb93f3..0fe2828f9354 100644
--- a/arch/arm/plat-samsung/include/plat/map-s5p.h
+++ b/arch/arm/plat-samsung/include/plat/map-s5p.h
@@ -14,10 +14,6 @@
#define __ASM_PLAT_MAP_S5P_H __FILE__
#define S5P_VA_CHIPID S3C_ADDR(0x02000000)
-#define S5P_VA_CMU S3C_ADDR(0x02100000)
-
-#define S5P_VA_DMC0 S3C_ADDR(0x02440000)
-#define S5P_VA_DMC1 S3C_ADDR(0x02480000)
#define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000)
#define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x))
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 01600401a53e..30398dbc940a 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -8,9 +8,9 @@ config ARM64
select ARCH_CLOCKSOURCE_DATA
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
+ select ARCH_HAS_GIGANTIC_PAGE
select ARCH_HAS_KCOV
select ARCH_HAS_SG_CHAIN
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index b6b36570b1c0..cfbdf02ef566 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -3,6 +3,8 @@ menu "Platform selection"
config ARCH_SUNXI
bool "Allwinner sunxi 64-bit SoC Family"
select GENERIC_IRQ_CHIP
+ select PINCTRL
+ select PINCTRL_SUN50I_A64
help
This enables support for Allwinner sunxi based SoCs like the A64.
@@ -42,6 +44,13 @@ config ARCH_BERLIN
help
This enables support for Marvell Berlin SoC Family
+config ARCH_BRCMSTB
+ bool "Broadcom Set-Top-Box SoCs"
+ select BRCMSTB_L2_IRQ
+ select GENERIC_IRQ_CHIP
+ help
+ This enables support for Broadcom's ARMv8 Set Top Box SoCs
+
config ARCH_EXYNOS
bool "ARMv8 based Samsung Exynos SoC family"
select COMMON_CLK_SAMSUNG
@@ -68,6 +77,7 @@ config ARCH_HISI
bool "Hisilicon SoC Family"
select ARM_TIMER_SP804
select HISILICON_IRQ_MBIGEN if PCI
+ select PINCTRL
help
This enables support for Hisilicon ARMv8 SoC family
@@ -162,6 +172,8 @@ config ARCH_TEGRA
select GENERIC_CLOCKEVENTS
select GPIOLIB
select PINCTRL
+ select PM
+ select PM_GENERIC_DOMAINS
select RESET_CONTROLLER
help
This enables support for the NVIDIA Tegra SoC family.
@@ -205,6 +217,11 @@ config ARCH_XGENE
help
This enables support for AppliedMicro X-Gene SOC Family
+config ARCH_ZX
+ bool "ZTE ZX SoC Family"
+ help
+ This enables support for ZTE ZX SoC Family
+
config ARCH_ZYNQMP
bool "Xilinx ZynqMP Family"
help
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 6e199c903676..6684f97c2722 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -19,6 +19,7 @@ dts-dirs += socionext
dts-dirs += sprd
dts-dirs += xilinx
dts-dirs += lg
+dts-dirs += zte
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index 90a84c514d3d..e6e3491d48a5 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -87,3 +87,14 @@
pinctrl-names = "default";
};
+&ir {
+ status = "okay";
+ pinctrl-0 = <&remote_input_ao_pins>;
+ pinctrl-names = "default";
+};
+
+&i2c_A {
+ status = "okay";
+ pinctrl-0 = <&i2c_a_pins>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts
index 62979076e250..03e3d76626dd 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts
@@ -50,3 +50,9 @@
compatible = "amlogic,p200", "amlogic,meson-gxbb";
model = "Amlogic Meson GXBB P200 Development Board";
};
+
+&i2c_B {
+ status = "okay";
+ pinctrl-0 = <&i2c_b_pins>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index f4f30f674b4c..06a34dc6002f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -57,6 +57,19 @@
device_type = "memory";
reg = <0x0 0x0 0x0 0x40000000>;
};
+
+ usb_pwr: regulator-usb-pwrs {
+ compatible = "regulator-fixed";
+
+ regulator-name = "USB_PWR";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ /* signal name in schematic: USB_PWR_EN */
+ gpio = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
/* This UART is brought out to the DB9 connector */
@@ -72,3 +85,25 @@
pinctrl-names = "default";
};
+&ir {
+ status = "okay";
+ pinctrl-0 = <&remote_input_ao_pins>;
+ pinctrl-names = "default";
+};
+
+&usb0_phy {
+ status = "okay";
+ phy-supply = <&usb_pwr>;
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
index 54bb7c739089..73f159370188 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
@@ -52,6 +52,19 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ usb_vbus: regulator-usb0-vbus {
+ compatible = "regulator-fixed";
+
+ regulator-name = "USB0_VBUS";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ gpio = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
};
&uart_AO {
@@ -60,3 +73,32 @@
pinctrl-names = "default";
};
+
+&ir {
+ status = "okay";
+ pinctrl-0 = <&remote_input_ao_pins>;
+ pinctrl-names = "default";
+};
+
+&ethmac {
+ status = "okay";
+ pinctrl-0 = <&eth_pins>;
+ pinctrl-names = "default";
+};
+
+&usb0_phy {
+ status = "okay";
+ phy-supply = <&usb_vbus>;
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index bf6c8d051002..610e0e1c3cee 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -45,6 +45,9 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/meson-gxbb-gpio.h>
#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
+#include <dt-bindings/clock/gxbb-clkc.h>
+#include <dt-bindings/clock/gxbb-aoclkc.h>
+#include <dt-bindings/reset/gxbb-aoclkc.h>
/ {
compatible = "amlogic,meson-gxbb";
@@ -99,6 +102,30 @@
method = "smc";
};
+ firmware {
+ sm: secure-monitor {
+ compatible = "amlogic,meson-gxbb-sm";
+ };
+ };
+
+ efuse: efuse {
+ compatible = "amlogic,meson-gxbb-efuse";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sn: sn@14 {
+ reg = <0x14 0x10>;
+ };
+
+ eth_mac: eth_mac@34 {
+ reg = <0x34 0x10>;
+ };
+
+ bid: bid@46 {
+ reg = <0x46 0x30>;
+ };
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13
@@ -124,6 +151,25 @@
#size-cells = <2>;
ranges;
+ usb0_phy: phy@c0000000 {
+ compatible = "amlogic,meson-gxbb-usb2-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0xc0000000 0x0 0x20>;
+ resets = <&reset RESET_USB_OTG>;
+ clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
+ clock-names = "usb_general", "usb";
+ status = "disabled";
+ };
+
+ usb1_phy: phy@c0000020 {
+ compatible = "amlogic,meson-gxbb-usb2-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0xc0000020 0x0 0x20>;
+ clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1>;
+ clock-names = "usb_general", "usb";
+ status = "disabled";
+ };
+
cbus: cbus@c1100000 {
compatible = "simple-bus";
reg = <0x0 0xc1100000 0x0 0x100000>;
@@ -153,6 +199,27 @@
status = "disabled";
};
+ pwm_ab: pwm@8550 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x08550 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_cd: pwm@8650 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x08650 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pwm_ef: pwm@86c0 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x086c0 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
uart_C: serial@8700 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x8700 0x0 0x14>;
@@ -160,6 +227,51 @@
clocks = <&xtal>;
status = "disabled";
};
+
+ watchdog@98d0 {
+ compatible = "amlogic,meson-gxbb-wdt";
+ reg = <0x0 0x098d0 0x0 0x10>;
+ clocks = <&xtal>;
+ };
+
+ spifc: spi@8c80 {
+ compatible = "amlogic,meson-gxbb-spifc";
+ reg = <0x0 0x08c80 0x0 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clkc CLKID_SPI>;
+ status = "disabled";
+ };
+
+ i2c_A: i2c@8500 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x08500 0x0 0x20>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c_B: i2c@87c0 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x087c0 0x0 0x20>;
+ interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c_C: i2c@87e0 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x087e0 0x0 0x20>;
+ interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
gic: interrupt-controller@c4301000 {
@@ -203,6 +315,56 @@
function = "uart_ao";
};
};
+
+ remote_input_ao_pins: remote_input_ao {
+ mux {
+ groups = "remote_input_ao";
+ function = "remote_input_ao";
+ };
+ };
+
+ i2c_ao_pins: i2c_ao {
+ mux {
+ groups = "i2c_sck_ao",
+ "i2c_sda_ao";
+ function = "i2c_ao";
+ };
+ };
+
+ pwm_ao_a_3_pins: pwm_ao_a_3 {
+ mux {
+ groups = "pwm_ao_a_3";
+ function = "pwm_ao_a_3";
+ };
+ };
+
+ pwm_ao_a_6_pins: pwm_ao_a_6 {
+ mux {
+ groups = "pwm_ao_a_6";
+ function = "pwm_ao_a_6";
+ };
+ };
+
+ pwm_ao_a_12_pins: pwm_ao_a_12 {
+ mux {
+ groups = "pwm_ao_a_12";
+ function = "pwm_ao_a_12";
+ };
+ };
+
+ pwm_ao_b_pins: pwm_ao_b {
+ mux {
+ groups = "pwm_ao_b";
+ function = "pwm_ao_b";
+ };
+ };
+ };
+
+ clkc_AO: clock-controller@040 {
+ compatible = "amlogic,gxbb-aoclkc";
+ reg = <0x0 0x00040 0x0 0x4>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
};
uart_AO: serial@4c0 {
@@ -212,6 +374,30 @@
clocks = <&xtal>;
status = "disabled";
};
+
+ ir: ir@580 {
+ compatible = "amlogic,meson-gxbb-ir";
+ reg = <0x0 0x00580 0x0 0x40>;
+ interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>;
+ status = "disabled";
+ };
+
+ pwm_ab_AO: pwm@550 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x0 0x0550 0x0 0x10>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ i2c_AO: i2c@500 {
+ compatible = "amlogic,meson-gxbb-i2c";
+ reg = <0x0 0x500 0x0 0x20>;
+ interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc CLKID_AO_I2C>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
periphs: periphs@c8834000 {
@@ -251,6 +437,16 @@
};
};
+ nor_pins: nor {
+ mux {
+ groups = "nor_d",
+ "nor_q",
+ "nor_c",
+ "nor_cs";
+ function = "nor";
+ };
+ };
+
sdcard_pins: sdcard {
mux {
groups = "sdcard_d0",
@@ -263,6 +459,25 @@
};
};
+ sdio_pins: sdio {
+ mux {
+ groups = "sdio_d0",
+ "sdio_d1",
+ "sdio_d2",
+ "sdio_d3",
+ "sdio_cmd",
+ "sdio_clk";
+ function = "sdio";
+ };
+ };
+
+ sdio_irq_pins: sdio_irq {
+ mux {
+ groups = "sdio_irq";
+ function = "sdio";
+ };
+ };
+
uart_a_pins: uart_a {
mux {
groups = "uart_tx_a",
@@ -287,6 +502,30 @@
};
};
+ i2c_a_pins: i2c_a {
+ mux {
+ groups = "i2c_sck_a",
+ "i2c_sda_a";
+ function = "i2c_a";
+ };
+ };
+
+ i2c_b_pins: i2c_b {
+ mux {
+ groups = "i2c_sck_b",
+ "i2c_sda_b";
+ function = "i2c_b";
+ };
+ };
+
+ i2c_c_pins: i2c_c {
+ mux {
+ groups = "i2c_sck_c",
+ "i2c_sda_c";
+ function = "i2c_c";
+ };
+ };
+
eth_pins: eth_c {
mux {
groups = "eth_mdio",
@@ -306,6 +545,55 @@
function = "eth";
};
};
+
+ pwm_a_x_pins: pwm_a_x {
+ mux {
+ groups = "pwm_a_x";
+ function = "pwm_a_x";
+ };
+ };
+
+ pwm_a_y_pins: pwm_a_y {
+ mux {
+ groups = "pwm_a_y";
+ function = "pwm_a_y";
+ };
+ };
+
+ pwm_b_pins: pwm_b {
+ mux {
+ groups = "pwm_b";
+ function = "pwm_b";
+ };
+ };
+
+ pwm_d_pins: pwm_d {
+ mux {
+ groups = "pwm_d";
+ function = "pwm_d";
+ };
+ };
+
+ pwm_e_pins: pwm_e {
+ mux {
+ groups = "pwm_e";
+ function = "pwm_e";
+ };
+ };
+
+ pwm_f_x_pins: pwm_f_x {
+ mux {
+ groups = "pwm_f_x";
+ function = "pwm_f_x";
+ };
+ };
+
+ pwm_f_y_pins: pwm_f_y {
+ mux {
+ groups = "pwm_f_y";
+ function = "pwm_f_y";
+ };
+ };
};
};
@@ -321,6 +609,15 @@
#clock-cells = <1>;
reg = <0x0 0x0 0x0 0x3db>;
};
+
+ mailbox: mailbox@404 {
+ compatible = "amlogic,meson-gxbb-mhu";
+ reg = <0 0x404 0 0x4c>;
+ interrupts = <0 208 IRQ_TYPE_EDGE_RISING>,
+ <0 209 IRQ_TYPE_EDGE_RISING>,
+ <0 210 IRQ_TYPE_EDGE_RISING>;
+ #mbox-cells = <1>;
+ };
};
apb: apb@d0000000 {
@@ -331,14 +628,40 @@
ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>;
};
+ usb0: usb@c9000000 {
+ compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
+ reg = <0x0 0xc9000000 0x0 0x40000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB0_DDR_BRIDGE>;
+ clock-names = "otg";
+ phys = <&usb0_phy>;
+ phy-names = "usb2-phy";
+ dr_mode = "host";
+ status = "disabled";
+ };
+
+ usb1: usb@c9100000 {
+ compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
+ reg = <0x0 0xc9100000 0x0 0x40000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
+ clock-names = "otg";
+ phys = <&usb1_phy>;
+ phy-names = "usb2-phy";
+ dr_mode = "host";
+ status = "disabled";
+ };
+
ethmac: ethernet@c9410000 {
- compatible = "amlogic,meson6-dwmac", "snps,dwmac";
+ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac";
reg = <0x0 0xc9410000 0x0 0x10000
0x0 0xc8834540 0x0 0x4>;
interrupts = <0 8 1>;
interrupt-names = "macirq";
- clocks = <&xtal>;
- clock-names = "stmmaceth";
+ clocks = <&clkc CLKID_ETH>,
+ <&clkc CLKID_FCLK_DIV2>,
+ <&clkc CLKID_MPLL2>;
+ clock-names = "stmmaceth", "clkin0", "clkin1";
phy-mode = "rgmii";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
index 1425ed41620c..72720e9132a1 100644
--- a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
@@ -26,6 +26,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_0>;
+ #clock-cells = <1>;
+ clocks = <&pmd0clk 0>;
};
cpu@001 {
device_type = "cpu";
@@ -34,6 +36,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_0>;
+ #clock-cells = <1>;
+ clocks = <&pmd0clk 0>;
};
cpu@100 {
device_type = "cpu";
@@ -42,6 +46,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_1>;
+ #clock-cells = <1>;
+ clocks = <&pmd1clk 0>;
};
cpu@101 {
device_type = "cpu";
@@ -50,6 +56,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_1>;
+ #clock-cells = <1>;
+ clocks = <&pmd1clk 0>;
};
cpu@200 {
device_type = "cpu";
@@ -58,6 +66,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_2>;
+ #clock-cells = <1>;
+ clocks = <&pmd2clk 0>;
};
cpu@201 {
device_type = "cpu";
@@ -66,6 +76,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_2>;
+ #clock-cells = <1>;
+ clocks = <&pmd2clk 0>;
};
cpu@300 {
device_type = "cpu";
@@ -74,6 +86,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_3>;
+ #clock-cells = <1>;
+ clocks = <&pmd3clk 0>;
};
cpu@301 {
device_type = "cpu";
@@ -82,6 +96,8 @@
enable-method = "spin-table";
cpu-release-addr = <0x1 0x0000fff8>;
next-level-cache = <&xgene_L2_3>;
+ #clock-cells = <1>;
+ clocks = <&pmd3clk 0>;
};
xgene_L2_0: l2-cache-0 {
compatible = "cache";
@@ -223,6 +239,46 @@
clock-output-names = "refclk";
};
+ pmdpll: pmdpll@170000f0 {
+ compatible = "apm,xgene-pcppll-v2-clock";
+ #clock-cells = <1>;
+ clocks = <&refclk 0>;
+ reg = <0x0 0x170000f0 0x0 0x10>;
+ clock-output-names = "pmdpll";
+ };
+
+ pmd0clk: pmd0clk@7e200200 {
+ compatible = "apm,xgene-pmd-clock";
+ #clock-cells = <1>;
+ clocks = <&pmdpll 0>;
+ reg = <0x0 0x7e200200 0x0 0x10>;
+ clock-output-names = "pmd0clk";
+ };
+
+ pmd1clk: pmd1clk@7e200210 {
+ compatible = "apm,xgene-pmd-clock";
+ #clock-cells = <1>;
+ clocks = <&pmdpll 0>;
+ reg = <0x0 0x7e200210 0x0 0x10>;
+ clock-output-names = "pmd1clk";
+ };
+
+ pmd2clk: pmd2clk@7e200220 {
+ compatible = "apm,xgene-pmd-clock";
+ #clock-cells = <1>;
+ clocks = <&pmdpll 0>;
+ reg = <0x0 0x7e200220 0x0 0x10>;
+ clock-output-names = "pmd2clk";
+ };
+
+ pmd3clk: pmd3clk@7e200230 {
+ compatible = "apm,xgene-pmd-clock";
+ #clock-cells = <1>;
+ clocks = <&pmdpll 0>;
+ reg = <0x0 0x7e200230 0x0 0x10>;
+ clock-output-names = "pmd3clk";
+ };
+
socpll: socpll@17000120 {
compatible = "apm,xgene-socpll-v2-clock";
#clock-cells = <1>;
@@ -453,6 +509,64 @@
};
};
+ pmu: pmu@78810000 {
+ compatible = "apm,xgene-pmu-v2";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ regmap-csw = <&csw>;
+ regmap-mcba = <&mcba>;
+ regmap-mcbb = <&mcbb>;
+ reg = <0x0 0x78810000 0x0 0x1000>;
+ interrupts = <0x0 0x22 0x4>;
+
+ pmul3c@7e610000 {
+ compatible = "apm,xgene-pmu-l3c";
+ reg = <0x0 0x7e610000 0x0 0x1000>;
+ };
+
+ pmuiob@7e940000 {
+ compatible = "apm,xgene-pmu-iob";
+ reg = <0x0 0x7e940000 0x0 0x1000>;
+ };
+
+ pmucmcb@7e710000 {
+ compatible = "apm,xgene-pmu-mcb";
+ reg = <0x0 0x7e710000 0x0 0x1000>;
+ enable-bit-index = <0>;
+ };
+
+ pmucmcb@7e730000 {
+ compatible = "apm,xgene-pmu-mcb";
+ reg = <0x0 0x7e730000 0x0 0x1000>;
+ enable-bit-index = <1>;
+ };
+
+ pmucmc@7e810000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e810000 0x0 0x1000>;
+ enable-bit-index = <0>;
+ };
+
+ pmucmc@7e850000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e850000 0x0 0x1000>;
+ enable-bit-index = <1>;
+ };
+
+ pmucmc@7e890000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e890000 0x0 0x1000>;
+ enable-bit-index = <2>;
+ };
+
+ pmucmc@7e8d0000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e8d0000 0x0 0x1000>;
+ enable-bit-index = <3>;
+ };
+ };
+
mailbox: mailbox@10540000 {
compatible = "apm,xgene-slimpro-mbox";
reg = <0x0 0x10540000 0x0 0x8000>;
@@ -472,6 +586,11 @@
mboxes = <&mailbox 0>;
};
+ hwmonslimpro {
+ compatible = "apm,xgene-slimpro-hwmon";
+ mboxes = <&mailbox 7>;
+ };
+
serial0: serial@10600000 {
device_type = "serial";
compatible = "ns16550";
@@ -508,10 +627,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x10 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x11 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x12 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x13 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x10 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x11 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x12 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x13 0x4>;
dma-coherent;
clocks = <&pcie0clk 0>;
msi-parent = <&v2m0>;
@@ -533,10 +652,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x16 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x17 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x18 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x19 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x16 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x17 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x18 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x19 0x4>;
dma-coherent;
clocks = <&pcie1clk 0>;
msi-parent = <&v2m0>;
diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi
index 31ea70a5a3ff..63be8e51eaa8 100644
--- a/arch/arm64/boot/dts/apm/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi
@@ -553,6 +553,64 @@
};
};
+ pmu: pmu@78810000 {
+ compatible = "apm,xgene-pmu-v2";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ regmap-csw = <&csw>;
+ regmap-mcba = <&mcba>;
+ regmap-mcbb = <&mcbb>;
+ reg = <0x0 0x78810000 0x0 0x1000>;
+ interrupts = <0x0 0x22 0x4>;
+
+ pmul3c@7e610000 {
+ compatible = "apm,xgene-pmu-l3c";
+ reg = <0x0 0x7e610000 0x0 0x1000>;
+ };
+
+ pmuiob@7e940000 {
+ compatible = "apm,xgene-pmu-iob";
+ reg = <0x0 0x7e940000 0x0 0x1000>;
+ };
+
+ pmucmcb@7e710000 {
+ compatible = "apm,xgene-pmu-mcb";
+ reg = <0x0 0x7e710000 0x0 0x1000>;
+ enable-bit-index = <0>;
+ };
+
+ pmucmcb@7e730000 {
+ compatible = "apm,xgene-pmu-mcb";
+ reg = <0x0 0x7e730000 0x0 0x1000>;
+ enable-bit-index = <1>;
+ };
+
+ pmucmc@7e810000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e810000 0x0 0x1000>;
+ enable-bit-index = <0>;
+ };
+
+ pmucmc@7e850000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e850000 0x0 0x1000>;
+ enable-bit-index = <1>;
+ };
+
+ pmucmc@7e890000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e890000 0x0 0x1000>;
+ enable-bit-index = <2>;
+ };
+
+ pmucmc@7e8d0000 {
+ compatible = "apm,xgene-pmu-mc";
+ reg = <0x0 0x7e8d0000 0x0 0x1000>;
+ enable-bit-index = <3>;
+ };
+ };
+
pcie0: pcie@1f2b0000 {
status = "disabled";
device_type = "pci";
@@ -569,10 +627,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x4>;
dma-coherent;
clocks = <&pcie0clk 0>;
msi-parent = <&msi>;
@@ -594,10 +652,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x4>;
dma-coherent;
clocks = <&pcie1clk 0>;
msi-parent = <&msi>;
@@ -619,10 +677,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x4>;
dma-coherent;
clocks = <&pcie2clk 0>;
msi-parent = <&msi>;
@@ -644,10 +702,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x4>;
dma-coherent;
clocks = <&pcie3clk 0>;
msi-parent = <&msi>;
@@ -669,10 +727,10 @@
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
- interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
- 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
- 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
- 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x4
+ 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x4
+ 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x4
+ 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x4>;
dma-coherent;
clocks = <&pcie4clk 0>;
msi-parent = <&msi>;
@@ -697,6 +755,11 @@
mboxes = <&mailbox 0>;
};
+ hwmonslimpro {
+ compatible = "apm,xgene-slimpro-hwmon";
+ mboxes = <&mailbox 7>;
+ };
+
serial0: serial@1c020000 {
status = "disabled";
device_type = "serial";
diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi
index d4a12fad8afd..d95dc408629a 100644
--- a/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@ -299,6 +299,14 @@
};
};
+ pwm: pwm@66010000 {
+ compatible = "brcm,iproc-pwm";
+ reg = <0x66010000 0x28>;
+ clocks = <&osc>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
mdio_mux_iproc: mdio-mux@6602023c {
compatible = "brcm,mdio-mux-iproc";
reg = <0x6602023c 0x14>;
diff --git a/arch/arm64/boot/dts/exynos/exynos7.dtsi b/arch/arm64/boot/dts/exynos/exynos7.dtsi
index 162831546e18..6328a66ed97e 100644
--- a/arch/arm64/boot/dts/exynos/exynos7.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos7.dtsi
@@ -10,6 +10,7 @@
*/
#include <dt-bindings/clock/exynos7-clk.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
compatible = "samsung,exynos7";
@@ -473,10 +474,14 @@
timer {
compatible = "arm,armv8-timer";
- interrupts = <1 13 0xff08>,
- <1 14 0xff08>,
- <1 11 0xff08>,
- <1 10 0xff08>;
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
};
pmu_system_controller: system-controller@105c0000 {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
index 9d3e9fe1c87c..dd9e91941df4 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
@@ -56,12 +56,14 @@
gpio1 = &gpio2;
gpio2 = &gpio3;
gpio3 = &gpio4;
- serial0 = &lpuart0;
- serial1 = &lpuart1;
- serial2 = &lpuart2;
- serial3 = &lpuart3;
- serial4 = &lpuart4;
- serial5 = &lpuart5;
+ serial0 = &duart0;
+ serial1 = &duart1;
+ serial2 = &duart2;
+ serial3 = &duart3;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
};
};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
index 40846319be69..d2313e05fd22 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
@@ -52,6 +52,14 @@
aliases {
crypto = &crypto;
+ serial0 = &duart0;
+ serial1 = &duart1;
+ serial2 = &duart2;
+ serial3 = &duart3;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
};
};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index a67e210e2019..58635f7f4668 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -247,6 +247,13 @@
bus-width = <4>;
};
+ ddr: memory-controller@1080000 {
+ compatible = "fsl,qoriq-memory-controller";
+ reg = <0x0 0x1080000 0x0 0x1000>;
+ interrupts = <0 144 0x4>;
+ big-endian;
+ };
+
dspi0: dspi@2100000 {
compatible = "fsl,ls1043a-dspi", "fsl,ls1021a-v1.0-dspi";
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
index e8801faca996..b0dd010979e7 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
@@ -57,6 +57,9 @@
serial1 = &serial1;
};
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
};
&esdhc {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
index e127f0baab19..ad0ebb8a1949 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
@@ -56,6 +56,10 @@
serial0 = &serial0;
serial1 = &serial1;
};
+
+ chosen {
+ stdout-path = "serial1:115200n8";
+ };
};
&esdhc {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
index e3b6034ea5d9..d1059765dfee 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
@@ -588,6 +588,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
+ dma-coherent;
num-lanes = <4>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -612,6 +613,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
+ dma-coherent;
num-lanes = <4>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -636,6 +638,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
+ dma-coherent;
num-lanes = <8>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -660,6 +663,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
+ dma-coherent;
num-lanes = <4>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -715,4 +719,18 @@
interrupts = <0 12 4>;
};
};
+
+ ddr1: memory-controller@1080000 {
+ compatible = "fsl,qoriq-memory-controller";
+ reg = <0x0 0x1080000 0x0 0x1000>;
+ interrupts = <0 17 0x4>;
+ little-endian;
+ };
+
+ ddr2: memory-controller@1090000 {
+ compatible = "fsl,qoriq-memory-controller";
+ reg = <0x0 0x1090000 0x0 0x1000>;
+ interrupts = <0 18 0x4>;
+ little-endian;
+ };
};
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
index 593c7e43de79..dba3c131c62c 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -29,16 +29,56 @@
* Reserve below regions from memory node:
*
* 0x05e0,0000 - 0x05ef,ffff: MCU firmware runtime using
+ * 0x05f0,1000 - 0x05f0,1fff: Reboot reason
* 0x06df,f000 - 0x06df,ffff: Mailbox message data
* 0x0740,f000 - 0x0740,ffff: MCU firmware section
+ * 0x21f0,0000 - 0x21ff,ffff: pstore/ramoops buffer
* 0x3e00,0000 - 0x3fff,ffff: OP-TEE
*/
memory@0 {
device_type = "memory";
reg = <0x00000000 0x00000000 0x00000000 0x05e00000>,
- <0x00000000 0x05f00000 0x00000000 0x00eff000>,
+ <0x00000000 0x05f00000 0x00000000 0x00001000>,
+ <0x00000000 0x05f02000 0x00000000 0x00efd000>,
<0x00000000 0x06e00000 0x00000000 0x0060f000>,
- <0x00000000 0x07410000 0x00000000 0x36bf0000>;
+ <0x00000000 0x07410000 0x00000000 0x1aaf0000>,
+ <0x00000000 0x22000000 0x00000000 0x1c000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ramoops@0x21f00000 {
+ compatible = "ramoops";
+ reg = <0x0 0x21f00000 0x0 0x00100000>;
+ record-size = <0x00020000>;
+ console-size = <0x00020000>;
+ ftrace-size = <0x00020000>;
+ };
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x00000000 0x08000000>;
+ linux,cma-default;
+ };
+ };
+
+ reboot-mode-syscon@5f01000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x0 0x05f01000 0x0 0x00001000>;
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x0>;
+
+ mode-normal = <0x77665501>;
+ mode-bootloader = <0x77665500>;
+ mode-recovery = <0x77665502>;
+ };
};
soc {
@@ -55,6 +95,8 @@
};
uart1: uart@f7111000 {
+ assigned-clocks = <&sys_ctrl HI6220_UART1_SRC>;
+ assigned-clock-rates = <150000000>;
status = "ok";
};
@@ -372,3 +414,43 @@
&uart3 {
label = "LS-UART1";
};
+
+&ade {
+ status = "ok";
+};
+
+&dsi {
+ status = "ok";
+
+ ports {
+ /* 1 for output port */
+ port@1 {
+ reg = <1>;
+
+ dsi_out0: endpoint@0 {
+ remote-endpoint = <&adv7533_in>;
+ };
+ };
+ };
+};
+
+&i2c2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "ok";
+
+ adv7533: adv7533@39 {
+ compatible = "adi,adv7533";
+ reg = <0x39>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <1 2>;
+ pd-gpio = <&gpio0 4 0>;
+ adi,dsi-lanes = <4>;
+
+ port {
+ adv7533_in: endpoint {
+ remote-endpoint = <&dsi_out0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 4f270410a5cb..17839db585d5 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -262,6 +262,11 @@
#clock-cells = <1>;
};
+ medianoc_ade: medianoc_ade@f4520000 {
+ compatible = "syscon";
+ reg = <0x0 0xf4520000 0x0 0x4000>;
+ };
+
stub_clock: stub_clock {
compatible = "hisilicon,hi6220-stub-clk";
hisilicon,hi6220-clk-sram = <&sram>;
@@ -766,6 +771,7 @@
interrupts = <0x0 0x48 0x4>;
clocks = <&sys_ctrl 2>, <&sys_ctrl 1>;
clock-names = "ciu", "biu";
+ resets = <&sys_ctrl PERIPH_RSTDIS0_MMC0>;
bus-width = <0x8>;
vmmc-supply = <&ldo19>;
pinctrl-names = "default";
@@ -779,12 +785,16 @@
card-detect-delay = <200>;
hisilicon,peripheral-syscon = <&ao_ctrl>;
cap-sd-highspeed;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
reg = <0x0 0xf723e000 0x0 0x1000>;
interrupts = <0x0 0x49 0x4>;
#address-cells = <0x1>;
#size-cells = <0x0>;
clocks = <&sys_ctrl 4>, <&sys_ctrl 3>;
clock-names = "ciu", "biu";
+ resets = <&sys_ctrl PERIPH_RSTDIS0_MMC1>;
vqmmc-supply = <&ldo7>;
vmmc-supply = <&ldo10>;
bus-width = <0x4>;
@@ -802,6 +812,7 @@
interrupts = <0x0 0x4a 0x4>;
clocks = <&sys_ctrl HI6220_MMC2_CIUCLK>, <&sys_ctrl HI6220_MMC2_CLK>;
clock-names = "ciu", "biu";
+ resets = <&sys_ctrl PERIPH_RSTDIS0_MMC2>;
bus-width = <0x4>;
broken-cd;
pinctrl-names = "default", "idle";
@@ -850,5 +861,55 @@
};
};
};
+
+ ade: ade@f4100000 {
+ compatible = "hisilicon,hi6220-ade";
+ reg = <0x0 0xf4100000 0x0 0x7800>;
+ reg-names = "ade_base";
+ hisilicon,noc-syscon = <&medianoc_ade>;
+ resets = <&media_ctrl MEDIA_ADE>;
+ interrupts = <0 115 4>; /* ldi interrupt */
+
+ clocks = <&media_ctrl HI6220_ADE_CORE>,
+ <&media_ctrl HI6220_CODEC_JPEG>,
+ <&media_ctrl HI6220_ADE_PIX_SRC>;
+ /*clock name*/
+ clock-names = "clk_ade_core",
+ "clk_codec_jpeg",
+ "clk_ade_pix";
+
+ assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
+ <&media_ctrl HI6220_CODEC_JPEG>;
+ assigned-clock-rates = <360000000>, <288000000>;
+ dma-coherent;
+ status = "disabled";
+
+ port {
+ ade_out: endpoint {
+ remote-endpoint = <&dsi_in>;
+ };
+ };
+ };
+
+ dsi: dsi@f4107800 {
+ compatible = "hisilicon,hi6220-dsi";
+ reg = <0x0 0xf4107800 0x0 0x100>;
+ clocks = <&media_ctrl HI6220_DSI_PCLK>;
+ clock-names = "pclk";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* 0 for input port */
+ port@0 {
+ reg = <0>;
+ dsi_in: endpoint {
+ remote-endpoint = <&ade_out>;
+ };
+ };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
index bf322ed038b8..4b472a302cd8 100644
--- a/arch/arm64/boot/dts/hisilicon/hip05.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
@@ -300,11 +300,6 @@
clock-frequency = <200000000>;
};
- peri_c_subctrl: syscon@80000000 {
- compatible = "hisilicon,hip05-perisubc", "syscon";
- reg = < 0x0 0x80000000 0x0 0x10000>;
- };
-
uart0: uart@80300000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x80300000 0x0 0x10000>;
diff --git a/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi b/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi
deleted file mode 100644
index b6a130c2e5a4..000000000000
--- a/arch/arm64/boot/dts/hisilicon/hip05_hns.dtsi
+++ /dev/null
@@ -1,180 +0,0 @@
-soc0: soc@000000000 {
- #address-cells = <2>;
- #size-cells = <2>;
- device_type = "soc";
- compatible = "simple-bus";
- ranges = <0x0 0x0 0x0 0x0 0x1 0x0>;
- chip-id = <0>;
-
- soc0_mdio0: mdio@803c0000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "hisilicon,hns-mdio";
- reg = <0x0 0x803c0000 0x0 0x10000>;
- subctrl-vbase = <&peri_c_subctrl>;
-
- soc0_phy0: ethernet-phy@0 {
- reg = <0x0>;
- compatible = "ethernet-phy-ieee802.3-c22";
- };
- soc0_phy1: ethernet-phy@1 {
- reg = <0x1>;
- compatible = "ethernet-phy-ieee802.3-c22";
- };
- };
-
- dsaf0: dsa@c7000000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "hisilicon,hns-dsaf-v1";
- mode = "6port-16rss";
- interrupt-parent = <&mbigen_dsa>;
-
- reg = <0x0 0xc5000000 0x0 0x890000
- 0x0 0xc7000000 0x0 0x60000
- >;
-
- reg-names = "ppe-base","dsaf-base";
- subctrl-syscon = <&dsaf_subctrl>;
- reset-field-offset = <0>;
- interrupts = <
- /* [14] ge fifo err 8 / xge 6**/
- 149 0x4 150 0x4 151 0x4 152 0x4
- 153 0x4 154 0x4 26 0x4 27 0x4
- 155 0x4 156 0x4 157 0x4 158 0x4 159 0x4 160 0x4
- /* [12] rcb com 4*3**/
- 0x6 0x4 0x7 0x4 0x8 0x4 0x9 0x4
- 16 0x4 17 0x4 18 0x4 19 0x4
- 22 0x4 23 0x4 24 0x4 25 0x4
- /* [8] ppe tnl 0-7***/
- 0x0 0x4 0x1 0x4 0x2 0x4 0x3 0x4
- 0x4 0x4 0x5 0x4 12 0x4 13 0x4
- /* [21] dsaf event int 3+18**/
- 128 0x4 129 0x4 130 0x4
- 0x83 0x4 0x84 0x4 0x85 0x4 0x86 0x4 0x87 0x4 0x88 0x4
- 0x89 0x4 0x8a 0x4 0x8b 0x4 0x8c 0x4 0x8d 0x4 0x8e 0x4
- 0x8f 0x4 0x90 0x4 0x91 0x4 0x92 0x4 0x93 0x4 0x94 0x4
- /* [4] debug rcb 2*2*/
- 0xe 0x1 0xf 0x1 0x14 0x1 0x15 0x1
- /* [256] sevice rcb 2*128*/
- 0x180 0x1 0x181 0x1 0x182 0x1 0x183 0x1
- 0x184 0x1 0x185 0x1 0x186 0x1 0x187 0x1
- 0x188 0x1 0x189 0x1 0x18a 0x1 0x18b 0x1
- 0x18c 0x1 0x18d 0x1 0x18e 0x1 0x18f 0x1
- 0x190 0x1 0x191 0x1 0x192 0x1 0x193 0x1
- 0x194 0x1 0x195 0x1 0x196 0x1 0x197 0x1
- 0x198 0x1 0x199 0x1 0x19a 0x1 0x19b 0x1
- 0x19c 0x1 0x19d 0x1 0x19e 0x1 0x19f 0x1
- 0x1a0 0x1 0x1a1 0x1 0x1a2 0x1 0x1a3 0x1
- 0x1a4 0x1 0x1a5 0x1 0x1a6 0x1 0x1a7 0x1
- 0x1a8 0x1 0x1a9 0x1 0x1aa 0x1 0x1ab 0x1
- 0x1ac 0x1 0x1ad 0x1 0x1ae 0x1 0x1af 0x1
- 0x1b0 0x1 0x1b1 0x1 0x1b2 0x1 0x1b3 0x1
- 0x1b4 0x1 0x1b5 0x1 0x1b6 0x1 0x1b7 0x1
- 0x1b8 0x1 0x1b9 0x1 0x1ba 0x1 0x1bb 0x1
- 0x1bc 0x1 0x1bd 0x1 0x1be 0x1 0x1bf 0x1
- 0x1c0 0x1 0x1c1 0x1 0x1c2 0x1 0x1c3 0x1
- 0x1c4 0x1 0x1c5 0x1 0x1c6 0x1 0x1c7 0x1
- 0x1c8 0x1 0x1c9 0x1 0x1ca 0x1 0x1cb 0x1
- 0x1cc 0x1 0x1cd 0x1 0x1ce 0x1 0x1cf 0x1
- 0x1d0 0x1 0x1d1 0x1 0x1d2 0x1 0x1d3 0x1
- 0x1d4 0x1 0x1d5 0x1 0x1d6 0x1 0x1d7 0x1
- 0x1d8 0x1 0x1d9 0x1 0x1da 0x1 0x1db 0x1
- 0x1dc 0x1 0x1dd 0x1 0x1de 0x1 0x1df 0x1
- 0x1e0 0x1 0x1e1 0x1 0x1e2 0x1 0x1e3 0x1
- 0x1e4 0x1 0x1e5 0x1 0x1e6 0x1 0x1e7 0x1
- 0x1e8 0x1 0x1e9 0x1 0x1ea 0x1 0x1eb 0x1
- 0x1ec 0x1 0x1ed 0x1 0x1ee 0x1 0x1ef 0x1
- 0x1f0 0x1 0x1f1 0x1 0x1f2 0x1 0x1f3 0x1
- 0x1f4 0x1 0x1f5 0x1 0x1f6 0x1 0x1f7 0x1
- 0x1f8 0x1 0x1f9 0x1 0x1fa 0x1 0x1fb 0x1
- 0x1fc 0x1 0x1fd 0x1 0x1fe 0x1 0x1ff 0x1
- 0x200 0x1 0x201 0x1 0x202 0x1 0x203 0x1
- 0x204 0x1 0x205 0x1 0x206 0x1 0x207 0x1
- 0x208 0x1 0x209 0x1 0x20a 0x1 0x20b 0x1
- 0x20c 0x1 0x20d 0x1 0x20e 0x1 0x20f 0x1
- 0x210 0x1 0x211 0x1 0x212 0x1 0x213 0x1
- 0x214 0x1 0x215 0x1 0x216 0x1 0x217 0x1
- 0x218 0x1 0x219 0x1 0x21a 0x1 0x21b 0x1
- 0x21c 0x1 0x21d 0x1 0x21e 0x1 0x21f 0x1
- 0x220 0x1 0x221 0x1 0x222 0x1 0x223 0x1
- 0x224 0x1 0x225 0x1 0x226 0x1 0x227 0x1
- 0x228 0x1 0x229 0x1 0x22a 0x1 0x22b 0x1
- 0x22c 0x1 0x22d 0x1 0x22e 0x1 0x22f 0x1
- 0x230 0x1 0x231 0x1 0x232 0x1 0x233 0x1
- 0x234 0x1 0x235 0x1 0x236 0x1 0x237 0x1
- 0x238 0x1 0x239 0x1 0x23a 0x1 0x23b 0x1
- 0x23c 0x1 0x23d 0x1 0x23e 0x1 0x23f 0x1
- 0x240 0x1 0x241 0x1 0x242 0x1 0x243 0x1
- 0x244 0x1 0x245 0x1 0x246 0x1 0x247 0x1
- 0x248 0x1 0x249 0x1 0x24a 0x1 0x24b 0x1
- 0x24c 0x1 0x24d 0x1 0x24e 0x1 0x24f 0x1
- 0x250 0x1 0x251 0x1 0x252 0x1 0x253 0x1
- 0x254 0x1 0x255 0x1 0x256 0x1 0x257 0x1
- 0x258 0x1 0x259 0x1 0x25a 0x1 0x25b 0x1
- 0x25c 0x1 0x25d 0x1 0x25e 0x1 0x25f 0x1
- 0x260 0x1 0x261 0x1 0x262 0x1 0x263 0x1
- 0x264 0x1 0x265 0x1 0x266 0x1 0x267 0x1
- 0x268 0x1 0x269 0x1 0x26a 0x1 0x26b 0x1
- 0x26c 0x1 0x26d 0x1 0x26e 0x1 0x26f 0x1
- 0x270 0x1 0x271 0x1 0x272 0x1 0x273 0x1
- 0x274 0x1 0x275 0x1 0x276 0x1 0x277 0x1
- 0x278 0x1 0x279 0x1 0x27a 0x1 0x27b 0x1
- 0x27c 0x1 0x27d 0x1 0x27e 0x1 0x27f 0x1>;
- buf-size = <4096>;
- desc-num = <1024>;
- dma-coherent;
-
- port@0 {
- reg = <0>;
- serdes-syscon = <&serdes_ctrl0>;
- };
- port@1 {
- reg = <1>;
- serdes-syscon = <&serdes_ctrl0>;
- };
- port@4 {
- reg = <4>;
- phy-handle = <&soc0_phy0>;
- serdes-syscon = <&serdes_ctrl1>;
- };
- port@5 {
- reg = <5>;
- phy-handle = <&soc0_phy1>;
- serdes-syscon = <&serdes_ctrl1>;
- };
- };
-
- eth0: ethernet@0{
- compatible = "hisilicon,hns-nic-v1";
- ae-handle = <&dsaf0>;
- port-idx-in-ae = <0>;
- local-mac-address = [00 00 00 01 00 58];
- status = "disabled";
- dma-coherent;
- };
- eth1: ethernet@1{
- compatible = "hisilicon,hns-nic-v1";
- ae-handle = <&dsaf0>;
- port-idx-in-ae = <1>;
- local-mac-address = [00 00 00 01 00 59];
- status = "disabled";
- dma-coherent;
- };
- eth2: ethernet@4{
- compatible = "hisilicon,hns-nic-v1";
- ae-handle = <&dsaf0>;
- port-idx-in-ae = <4>;
- local-mac-address = [00 00 00 01 00 5a];
- status = "disabled";
- dma-coherent;
- };
- eth3: ethernet@5{
- compatible = "hisilicon,hns-nic-v1";
- ae-handle = <&dsaf0>;
- port-idx-in-ae = <5>;
- local-mac-address = [00 00 00 01 00 5b];
- status = "disabled";
- dma-coherent;
- };
-};
diff --git a/arch/arm64/boot/dts/hisilicon/hip06-d03.dts b/arch/arm64/boot/dts/hisilicon/hip06-d03.dts
index f3e5323e430b..f54b28359607 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06-d03.dts
+++ b/arch/arm64/boot/dts/hisilicon/hip06-d03.dts
@@ -25,6 +25,34 @@
chosen { };
};
+&eth0 {
+ status = "ok";
+};
+
+&eth1 {
+ status = "ok";
+};
+
+&eth2 {
+ status = "ok";
+};
+
+&eth3 {
+ status = "ok";
+};
+
+&sas0 {
+ status = "ok";
+};
+
+&sas1 {
+ status = "ok";
+};
+
+&sas2 {
+ status = "ok";
+};
+
&usb_ohci {
status = "ok";
};
diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
index 5927bc472f1b..b548763366dd 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
@@ -277,6 +277,39 @@
#interrupt-cells = <2>;
num-pins = <2>;
};
+
+ mbigen_sas1: intc_sas1 {
+ msi-parent = <&its_dsa 0x40000>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-pins = <128>;
+ };
+
+ mbigen_sas2: intc_sas2 {
+ msi-parent = <&its_dsa 0x40040>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-pins = <128>;
+ };
+ };
+
+ mbigen_dsa@c0080000 {
+ compatible = "hisilicon,mbigen-v2";
+ reg = <0x0 0xc0080000 0x0 0x10000>;
+
+ mbigen_dsaf0: intc_dsaf0 {
+ msi-parent = <&its_dsa 0x40800>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-pins = <409>;
+ };
+
+ mbigen_sas0: intc-sas0 {
+ msi-parent = <&its_dsa 0x40900>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-pins = <128>;
+ };
};
soc {
@@ -302,6 +335,338 @@
dma-coherent;
status = "disabled";
};
+
+ peri_c_subctrl: sub_ctrl_c@60000000 {
+ compatible = "hisilicon,peri-subctrl","syscon";
+ reg = <0 0x60000000 0x0 0x10000>;
+ };
+
+ dsa_subctrl: dsa_subctrl@c0000000 {
+ compatible = "hisilicon,dsa-subctrl", "syscon";
+ reg = <0x0 0xc0000000 0x0 0x10000>;
+ };
+
+ pcie_subctl: pcie_subctl@a0000000 {
+ compatible = "hisilicon,pcie-sas-subctrl", "syscon";
+ reg = <0x0 0xa0000000 0x0 0x10000>;
+ };
+
+ serdes_ctrl: sds_ctrl@c2200000 {
+ compatible = "syscon";
+ reg = <0 0xc2200000 0x0 0x80000>;
+ };
+
+ mdio@603c0000 {
+ compatible = "hisilicon,hns-mdio";
+ reg = <0x0 0x603c0000 0x0 0x1000>;
+ subctrl-vbase = <&peri_c_subctrl 0x338 0xa38 0x531c 0x5a1c>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+
+ phy1: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+ };
+
+ dsaf0: dsa@c7000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "hisilicon,hns-dsaf-v2";
+ mode = "6port-16rss";
+ reg = <0x0 0xc5000000 0x0 0x890000
+ 0x0 0xc7000000 0x0 0x600000>;
+ reg-names = "ppe-base", "dsaf-base";
+ interrupt-parent = <&mbigen_dsaf0>;
+ subctrl-syscon = <&dsa_subctrl>;
+ reset-field-offset = <0>;
+ interrupts =
+ <576 1>, <577 1>, <578 1>, <579 1>, <580 1>,
+ <581 1>, <582 1>, <583 1>, <584 1>, <585 1>,
+ <586 1>, <587 1>, <588 1>, <589 1>, <590 1>,
+ <591 1>, <592 1>, <593 1>, <594 1>, <595 1>,
+ <596 1>, <597 1>, <598 1>, <599 1>, <600 1>,
+ <960 1>, <961 1>, <962 1>, <963 1>, <964 1>,
+ <965 1>, <966 1>, <967 1>, <968 1>, <969 1>,
+ <970 1>, <971 1>, <972 1>, <973 1>, <974 1>,
+ <975 1>, <976 1>, <977 1>, <978 1>, <979 1>,
+ <980 1>, <981 1>, <982 1>, <983 1>, <984 1>,
+ <985 1>, <986 1>, <987 1>, <988 1>, <989 1>,
+ <990 1>, <991 1>, <992 1>, <993 1>, <994 1>,
+ <995 1>, <996 1>, <997 1>, <998 1>, <999 1>,
+ <1000 1>, <1001 1>, <1002 1>, <1003 1>, <1004 1>,
+ <1005 1>, <1006 1>, <1007 1>, <1008 1>, <1009 1>,
+ <1010 1>, <1011 1>, <1012 1>, <1013 1>, <1014 1>,
+ <1015 1>, <1016 1>, <1017 1>, <1018 1>, <1019 1>,
+ <1020 1>, <1021 1>, <1022 1>, <1023 1>, <1024 1>,
+ <1025 1>, <1026 1>, <1027 1>, <1028 1>, <1029 1>,
+ <1030 1>, <1031 1>, <1032 1>, <1033 1>, <1034 1>,
+ <1035 1>, <1036 1>, <1037 1>, <1038 1>, <1039 1>,
+ <1040 1>, <1041 1>, <1042 1>, <1043 1>, <1044 1>,
+ <1045 1>, <1046 1>, <1047 1>, <1048 1>, <1049 1>,
+ <1050 1>, <1051 1>, <1052 1>, <1053 1>, <1054 1>,
+ <1055 1>, <1056 1>, <1057 1>, <1058 1>, <1059 1>,
+ <1060 1>, <1061 1>, <1062 1>, <1063 1>, <1064 1>,
+ <1065 1>, <1066 1>, <1067 1>, <1068 1>, <1069 1>,
+ <1070 1>, <1071 1>, <1072 1>, <1073 1>, <1074 1>,
+ <1075 1>, <1076 1>, <1077 1>, <1078 1>, <1079 1>,
+ <1080 1>, <1081 1>, <1082 1>, <1083 1>, <1084 1>,
+ <1085 1>, <1086 1>, <1087 1>, <1088 1>, <1089 1>,
+ <1090 1>, <1091 1>, <1092 1>, <1093 1>, <1094 1>,
+ <1095 1>, <1096 1>, <1097 1>, <1098 1>, <1099 1>,
+ <1100 1>, <1101 1>, <1102 1>, <1103 1>, <1104 1>,
+ <1105 1>, <1106 1>, <1107 1>, <1108 1>, <1109 1>,
+ <1110 1>, <1111 1>, <1112 1>, <1113 1>, <1114 1>,
+ <1115 1>, <1116 1>, <1117 1>, <1118 1>, <1119 1>,
+ <1120 1>, <1121 1>, <1122 1>, <1123 1>, <1124 1>,
+ <1125 1>, <1126 1>, <1127 1>, <1128 1>, <1129 1>,
+ <1130 1>, <1131 1>, <1132 1>, <1133 1>, <1134 1>,
+ <1135 1>, <1136 1>, <1137 1>, <1138 1>, <1139 1>,
+ <1140 1>, <1141 1>, <1142 1>, <1143 1>, <1144 1>,
+ <1145 1>, <1146 1>, <1147 1>, <1148 1>, <1149 1>,
+ <1150 1>, <1151 1>, <1152 1>, <1153 1>, <1154 1>,
+ <1155 1>, <1156 1>, <1157 1>, <1158 1>, <1159 1>,
+ <1160 1>, <1161 1>, <1162 1>, <1163 1>, <1164 1>,
+ <1165 1>, <1166 1>, <1167 1>, <1168 1>, <1169 1>,
+ <1170 1>, <1171 1>, <1172 1>, <1173 1>, <1174 1>,
+ <1175 1>, <1176 1>, <1177 1>, <1178 1>, <1179 1>,
+ <1180 1>, <1181 1>, <1182 1>, <1183 1>, <1184 1>,
+ <1185 1>, <1186 1>, <1187 1>, <1188 1>, <1189 1>,
+ <1190 1>, <1191 1>, <1192 1>, <1193 1>, <1194 1>,
+ <1195 1>, <1196 1>, <1197 1>, <1198 1>, <1199 1>,
+ <1200 1>, <1201 1>, <1202 1>, <1203 1>, <1204 1>,
+ <1205 1>, <1206 1>, <1207 1>, <1208 1>, <1209 1>,
+ <1210 1>, <1211 1>, <1212 1>, <1213 1>, <1214 1>,
+ <1215 1>, <1216 1>, <1217 1>, <1218 1>, <1219 1>,
+ <1220 1>, <1221 1>, <1222 1>, <1223 1>, <1224 1>,
+ <1225 1>, <1226 1>, <1227 1>, <1228 1>, <1229 1>,
+ <1230 1>, <1231 1>, <1232 1>, <1233 1>, <1234 1>,
+ <1235 1>, <1236 1>, <1237 1>, <1238 1>, <1239 1>,
+ <1240 1>, <1241 1>, <1242 1>, <1243 1>, <1244 1>,
+ <1245 1>, <1246 1>, <1247 1>, <1248 1>, <1249 1>,
+ <1250 1>, <1251 1>, <1252 1>, <1253 1>, <1254 1>,
+ <1255 1>, <1256 1>, <1257 1>, <1258 1>, <1259 1>,
+ <1260 1>, <1261 1>, <1262 1>, <1263 1>, <1264 1>,
+ <1265 1>, <1266 1>, <1267 1>, <1268 1>, <1269 1>,
+ <1270 1>, <1271 1>, <1272 1>, <1273 1>, <1274 1>,
+ <1275 1>, <1276 1>, <1277 1>, <1278 1>, <1279 1>,
+ <1280 1>, <1281 1>, <1282 1>, <1283 1>, <1284 1>,
+ <1285 1>, <1286 1>, <1287 1>, <1288 1>, <1289 1>,
+ <1290 1>, <1291 1>, <1292 1>, <1293 1>, <1294 1>,
+ <1295 1>, <1296 1>, <1297 1>, <1298 1>, <1299 1>,
+ <1300 1>, <1301 1>, <1302 1>, <1303 1>, <1304 1>,
+ <1305 1>, <1306 1>, <1307 1>, <1308 1>, <1309 1>,
+ <1310 1>, <1311 1>, <1312 1>, <1313 1>, <1314 1>,
+ <1315 1>, <1316 1>, <1317 1>, <1318 1>, <1319 1>,
+ <1320 1>, <1321 1>, <1322 1>, <1323 1>, <1324 1>,
+ <1325 1>, <1326 1>, <1327 1>, <1328 1>, <1329 1>,
+ <1330 1>, <1331 1>, <1332 1>, <1333 1>, <1334 1>,
+ <1335 1>, <1336 1>, <1337 1>, <1338 1>, <1339 1>,
+ <1340 1>, <1341 1>, <1342 1>, <1343 1>;
+
+ desc-num = <0x400>;
+ buf-size = <0x1000>;
+ dma-coherent;
+
+ port@0 {
+ reg = <0>;
+ serdes-syscon = <&serdes_ctrl>;
+ port-rst-offset = <0>;
+ port-mode-offset = <0>;
+ media-type = "fiber";
+ };
+
+ port@1 {
+ reg = <1>;
+ serdes-syscon= <&serdes_ctrl>;
+ port-rst-offset = <1>;
+ port-mode-offset = <1>;
+ media-type = "fiber";
+ };
+
+ port@4 {
+ reg = <4>;
+ phy-handle = <&phy0>;
+ serdes-syscon= <&serdes_ctrl>;
+ port-rst-offset = <4>;
+ port-mode-offset = <2>;
+ media-type = "copper";
+ };
+
+ port@5 {
+ reg = <5>;
+ phy-handle = <&phy1>;
+ serdes-syscon= <&serdes_ctrl>;
+ port-rst-offset = <5>;
+ port-mode-offset = <3>;
+ media-type = "copper";
+ };
+ };
+
+ eth0: ethernet@4{
+ compatible = "hisilicon,hns-nic-v2";
+ ae-handle = <&dsaf0>;
+ port-idx-in-ae = <4>;
+ local-mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ dma-coherent;
+ };
+
+ eth1: ethernet@5{
+ compatible = "hisilicon,hns-nic-v2";
+ ae-handle = <&dsaf0>;
+ port-idx-in-ae = <5>;
+ local-mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ dma-coherent;
+ };
+
+ eth2: ethernet@0{
+ compatible = "hisilicon,hns-nic-v2";
+ ae-handle = <&dsaf0>;
+ port-idx-in-ae = <0>;
+ local-mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ dma-coherent;
+ };
+
+ eth3: ethernet@1{
+ compatible = "hisilicon,hns-nic-v2";
+ ae-handle = <&dsaf0>;
+ port-idx-in-ae = <1>;
+ local-mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ dma-coherent;
+ };
+
+ sas0: sas@c3000000 {
+ compatible = "hisilicon,hip06-sas-v2";
+ reg = <0 0xc3000000 0 0x10000>;
+ sas-addr = [50 01 88 20 16 00 00 00];
+ hisilicon,sas-syscon = <&dsa_subctrl>;
+ ctrl-reset-reg = <0xa60>;
+ ctrl-reset-sts-reg = <0x5a30>;
+ ctrl-clock-ena-reg = <0x338>;
+ queue-count = <16>;
+ phy-count = <8>;
+ dma-coherent;
+ interrupt-parent = <&mbigen_sas0>;
+ interrupts = <64 4>,<65 4>,<66 4>,<67 4>,<68 4>,
+ <69 4>,<70 4>,<71 4>,<72 4>,<73 4>,
+ <75 4>,<76 4>,<77 4>,<78 4>,<79 4>,
+ <80 4>,<81 4>,<82 4>,<83 4>,<84 4>,
+ <85 4>,<86 4>,<87 4>,<88 4>,<89 4>,
+ <90 4>,<91 4>,<92 4>,<93 4>,<94 4>,
+ <95 4>,<96 4>,<97 4>,<98 4>,<99 4>,
+ <100 4>,<101 4>,<102 4>,<103 4>,<104 4>,
+ <105 4>,<106 4>,<107 4>,<108 4>,<109 4>,
+ <110 4>,<111 4>,<112 4>,<113 4>,<114 4>,
+ <115 4>,<116 4>,<117 4>,<118 4>,<119 4>,
+ <120 4>,<121 4>,<122 4>,<123 4>,<124 4>,
+ <125 4>,<126 4>,<127 4>,<128 4>,<129 4>,
+ <130 4>,<131 4>,<132 4>,<133 4>,<134 4>,
+ <135 4>,<136 4>,<137 4>,<138 4>,<139 4>,
+ <140 4>,<141 4>,<142 4>,<143 4>,<144 4>,
+ <145 4>,<146 4>,<147 4>,<148 4>,<149 4>,
+ <150 4>,<151 4>,<152 4>,<153 4>,<154 4>,
+ <155 4>,<156 4>,<157 4>,<158 4>,<159 4>,
+ <160 4>,<601 1>,<602 1>,<603 1>,<604 1>,
+ <605 1>,<606 1>,<607 1>,<608 1>,<609 1>,
+ <610 1>,<611 1>,<612 1>,<613 1>,<614 1>,
+ <615 1>,<616 1>,<617 1>,<618 1>,<619 1>,
+ <620 1>,<621 1>,<622 1>,<623 1>,<624 1>,
+ <625 1>,<626 1>,<627 1>,<628 1>,<629 1>,
+ <630 1>,<631 1>,<632 1>;
+ status = "disabled";
+ };
+
+ sas1: sas@a2000000 {
+ compatible = "hisilicon,hip06-sas-v2";
+ reg = <0 0xa2000000 0 0x10000>;
+ sas-addr = [50 01 88 20 16 00 00 00];
+ hisilicon,sas-syscon = <&pcie_subctl>;
+ am-max-trans;
+ ctrl-reset-reg = <0xa18>;
+ ctrl-reset-sts-reg = <0x5a0c>;
+ ctrl-clock-ena-reg = <0x318>;
+ queue-count = <16>;
+ phy-count = <8>;
+ dma-coherent;
+ interrupt-parent = <&mbigen_sas1>;
+ interrupts = <64 4>,<65 4>,<66 4>,<67 4>,<68 4>,
+ <69 4>,<70 4>,<71 4>,<72 4>,<73 4>,
+ <74 4>,<75 4>,<76 4>,<77 4>,<78 4>,
+ <79 4>,<80 4>,<81 4>,<82 4>,<83 4>,
+ <84 4>,<85 4>,<86 4>,<87 4>,<88 4>,
+ <89 4>,<90 4>,<91 4>,<92 4>,<93 4>,
+ <94 4>,<95 4>,<96 4>,<97 4>,<98 4>,
+ <99 4>,<100 4>,<101 4>,<102 4>,<103 4>,
+ <104 4>,<105 4>,<106 4>,<107 4>,<108 4>,
+ <109 4>,<110 4>,<111 4>,<112 4>,<113 4>,
+ <114 4>,<115 4>,<116 4>,<117 4>,<118 4>,
+ <119 4>,<120 4>,<121 4>,<122 4>,<123 4>,
+ <124 4>,<125 4>,<126 4>,<127 4>,<128 4>,
+ <129 4>,<130 4>,<131 4>,<132 4>,<133 4>,
+ <134 4>,<135 4>,<136 4>,<137 4>,<138 4>,
+ <139 4>,<140 4>,<141 4>,<142 4>,<143 4>,
+ <144 4>,<145 4>,<146 4>,<147 4>,<148 4>,
+ <149 4>,<150 4>,<151 4>,<152 4>,<153 4>,
+ <154 4>,<155 4>,<156 4>,<157 4>,<158 4>,
+ <159 4>,<576 1>,<577 1>,<578 1>,<579 1>,
+ <580 1>,<581 1>,<582 1>,<583 1>,<584 1>,
+ <585 1>,<586 1>,<587 1>,<588 1>,<589 1>,
+ <590 1>,<591 1>,<592 1>,<593 1>,<594 1>,
+ <595 1>,<596 1>,<597 1>,<598 1>,<599 1>,
+ <600 1>,<601 1>,<602 1>,<603 1>,<604 1>,
+ <605 1>,<606 1>,<607 1>;
+ status = "disabled";
+ };
+
+ sas2: sas@a3000000 {
+ compatible = "hisilicon,hip06-sas-v2";
+ reg = <0 0xa3000000 0 0x10000>;
+ sas-addr = [50 01 88 20 16 00 00 00];
+ hisilicon,sas-syscon = <&pcie_subctl>;
+ ctrl-reset-reg = <0xae0>;
+ ctrl-reset-sts-reg = <0x5a70>;
+ ctrl-clock-ena-reg = <0x3a8>;
+ queue-count = <16>;
+ phy-count = <9>;
+ dma-coherent;
+ interrupt-parent = <&mbigen_sas2>;
+ interrupts = <192 4>,<193 4>,<194 4>,<195 4>,<196 4>,
+ <197 4>,<198 4>,<199 4>,<200 4>,<201 4>,
+ <202 4>,<203 4>,<204 4>,<205 4>,<206 4>,
+ <207 4>,<208 4>,<209 4>,<210 4>,<211 4>,
+ <212 4>,<213 4>,<214 4>,<215 4>,<216 4>,
+ <217 4>,<218 4>,<219 4>,<220 4>,<221 4>,
+ <222 4>,<223 4>,<224 4>,<225 4>,<226 4>,
+ <227 4>,<228 4>,<229 4>,<230 4>,<231 4>,
+ <232 4>,<233 4>,<234 4>,<235 4>,<236 4>,
+ <237 4>,<238 4>,<239 4>,<240 4>,<241 4>,
+ <242 4>,<243 4>,<244 4>,<245 4>,<246 4>,
+ <247 4>,<248 4>,<249 4>,<250 4>,<251 4>,
+ <252 4>,<253 4>,<254 4>,<255 4>,<256 4>,
+ <257 4>,<258 4>,<259 4>,<260 4>,<261 4>,
+ <262 4>,<263 4>,<264 4>,<265 4>,<266 4>,
+ <267 4>,<268 4>,<269 4>,<270 4>,<271 4>,
+ <272 4>,<273 4>,<274 4>,<275 4>,<276 4>,
+ <277 4>,<278 4>,<279 4>,<280 4>,<281 4>,
+ <282 4>,<283 4>,<284 4>,<285 4>,<286 4>,
+ <287 4>,<608 1>,<609 1>,<610 1>,<611 1>,
+ <612 1>,<613 1>,<614 1>,<615 1>,<616 1>,
+ <617 1>,<618 1>,<619 1>,<620 1>,<621 1>,
+ <622 1>,<623 1>,<624 1>,<625 1>,<626 1>,
+ <627 1>,<628 1>,<629 1>,<630 1>,<631 1>,
+ <632 1>,<633 1>,<634 1>,<635 1>,<636 1>,
+ <637 1>,<638 1>,<639 1>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm64/boot/dts/marvell/Makefile b/arch/arm64/boot/dts/marvell/Makefile
index 308468d377d0..cf3953124cef 100644
--- a/arch/arm64/boot/dts/marvell/Makefile
+++ b/arch/arm64/boot/dts/marvell/Makefile
@@ -5,6 +5,7 @@ dtb-$(CONFIG_ARCH_BERLIN) += berlin4ct-stb.dtb
# Mvebu SoC Family
dtb-$(CONFIG_ARCH_MVEBU) += armada-3720-db.dtb
dtb-$(CONFIG_ARCH_MVEBU) += armada-7040-db.dtb
+dtb-$(CONFIG_ARCH_MVEBU) += armada-8040-db.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/marvell/armada-8020.dtsi b/arch/arm64/boot/dts/marvell/armada-8020.dtsi
index 3753c1c6d54d..048e5cf5160e 100644
--- a/arch/arm64/boot/dts/marvell/armada-8020.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-8020.dtsi
@@ -47,6 +47,7 @@
#include "armada-ap806-dual.dtsi"
#include "armada-cp110-master.dtsi"
+#include "armada-cp110-slave.dtsi"
/ {
model = "Marvell Armada 8020";
diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
new file mode 100644
index 000000000000..6e6f182fb297
--- /dev/null
+++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 Marvell Technology Group Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/*
+ * Device Tree file for Marvell Armada 8040 Development board platform
+ */
+
+#include "armada-8040.dtsi"
+
+/ {
+ model = "Marvell Armada 8040 DB board";
+ compatible = "marvell,armada8040-db", "marvell,armada8040",
+ "marvell,armada-ap806-quad", "marvell,armada-ap806";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@00000000 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+};
+
+&i2c0 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+&spi0 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0 0x200000>;
+ };
+ partition@400000 {
+ label = "Filesystem";
+ reg = <0x200000 0xce0000>;
+ };
+ };
+ };
+};
+
+/* Accessible over the mini-USB CON9 connector on the main board */
+&uart0 {
+ status = "okay";
+};
+
+
+/* CON5 on CP0 expansion */
+&cpm_pcie2 {
+ status = "okay";
+};
+
+&cpm_i2c0 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+/* CON4 on CP0 expansion */
+&cpm_sata0 {
+ status = "okay";
+};
+
+/* CON9 on CP0 expansion */
+&cpm_usb3_0 {
+ status = "okay";
+};
+
+/* CON10 on CP0 expansion */
+&cpm_usb3_1 {
+ status = "okay";
+};
+
+/* CON5 on CP1 expansion */
+&cps_pcie2 {
+ status = "okay";
+};
+
+&cps_i2c0 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+/* CON4 on CP1 expansion */
+&cps_sata0 {
+ status = "okay";
+};
+
+/* CON9 on CP1 expansion */
+&cps_usb3_0 {
+ status = "okay";
+};
+
+/* CON10 on CP1 expansion */
+&cps_usb3_1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-8040.dtsi b/arch/arm64/boot/dts/marvell/armada-8040.dtsi
index 8bd0d8f8ad4c..9c1b28c47683 100644
--- a/arch/arm64/boot/dts/marvell/armada-8040.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-8040.dtsi
@@ -47,6 +47,7 @@
#include "armada-ap806-quad.dtsi"
#include "armada-cp110-master.dtsi"
+#include "armada-cp110-slave.dtsi"
/ {
model = "Marvell Armada 8040";
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
index c2a6745f168c..7b6136182ad0 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
@@ -128,6 +128,12 @@
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
+ pmu {
+ compatible = "arm,cortex-a72-pmu";
+ interrupt-parent = <&pic>;
+ interrupts = <17>;
+ };
+
odmi: odmi@300000 {
compatible = "marvell,odmi-controller";
interrupt-controller;
@@ -140,6 +146,14 @@
marvell,spi-base = <128>, <136>, <144>, <152>;
};
+ pic: interrupt-controller@3f0100 {
+ compatible = "marvell,armada-8k-pic";
+ reg = <0x3f0100 0x10>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
xor@400000 {
compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
reg = <0x400000 0x1000>,
diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
index da31bbbbb59e..e5e3ed678b6f 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
@@ -176,6 +176,7 @@
#interrupt-cells = <1>;
device_type = "pci";
dma-coherent;
+ msi-parent = <&gic_v2m0>;
bus-range = <0 0xff>;
ranges =
@@ -201,6 +202,7 @@
#interrupt-cells = <1>;
device_type = "pci";
dma-coherent;
+ msi-parent = <&gic_v2m0>;
bus-range = <0 0xff>;
ranges =
@@ -227,6 +229,7 @@
#interrupt-cells = <1>;
device_type = "pci";
dma-coherent;
+ msi-parent = <&gic_v2m0>;
bus-range = <0 0xff>;
ranges =
diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
new file mode 100644
index 000000000000..842fb333285c
--- /dev/null
+++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2016 Marvell Technology Group Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/*
+ * Device Tree file for Marvell Armada CP110 Slave.
+ */
+
+/ {
+ cp110-slave {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "simple-bus";
+ interrupt-parent = <&gic>;
+ ranges;
+
+ config-space {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&gic>;
+ ranges = <0x0 0x0 0xf4000000 0x2000000>;
+
+ cps_syscon0: system-controller@440000 {
+ compatible = "marvell,cp110-system-controller0",
+ "syscon";
+ reg = <0x440000 0x1000>;
+ #clock-cells = <2>;
+ core-clock-output-names =
+ "cps-apll", "cps-ppv2-core", "cps-eip",
+ "cps-core", "cps-nand-core";
+ gate-clock-output-names =
+ "cps-audio", "cps-communit", "cps-nand",
+ "cps-ppv2", "cps-sdio", "cps-mg-domain",
+ "cps-mg-core", "cps-xor1", "cps-xor0",
+ "cps-gop-dp", "none", "cps-pcie_x10",
+ "cps-pcie_x11", "cps-pcie_x4", "cps-pcie-xor",
+ "cps-sata", "cps-sata-usb", "cps-main",
+ "cps-sd-mmc", "none", "none",
+ "cps-slow-io", "cps-usb3h0", "cps-usb3h1",
+ "cps-usb3dev", "cps-eip150", "cps-eip197";
+ };
+
+ cps_sata0: sata@540000 {
+ compatible = "marvell,armada-8k-ahci";
+ reg = <0x540000 0x30000>;
+ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cps_syscon0 1 15>;
+ status = "disabled";
+ };
+
+ cps_usb3_0: usb3@500000 {
+ compatible = "marvell,armada-8k-xhci",
+ "generic-xhci";
+ reg = <0x500000 0x4000>;
+ dma-coherent;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cps_syscon0 1 22>;
+ status = "disabled";
+ };
+
+ cps_usb3_1: usb3@510000 {
+ compatible = "marvell,armada-8k-xhci",
+ "generic-xhci";
+ reg = <0x510000 0x4000>;
+ dma-coherent;
+ interrupts = <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cps_syscon0 1 23>;
+ status = "disabled";
+ };
+
+ cps_xor0: xor@6a0000 {
+ compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+ reg = <0x6a0000 0x1000>,
+ <0x6b0000 0x1000>;
+ dma-coherent;
+ msi-parent = <&gic_v2m0>;
+ clocks = <&cps_syscon0 1 8>;
+ };
+
+ cps_xor1: xor@6c0000 {
+ compatible = "marvell,armada-7k-xor", "marvell,xor-v2";
+ reg = <0x6c0000 0x1000>,
+ <0x6d0000 0x1000>;
+ dma-coherent;
+ msi-parent = <&gic_v2m0>;
+ clocks = <&cps_syscon0 1 7>;
+ };
+
+ cps_spi0: spi@700600 {
+ compatible = "marvell,armada-380-spi";
+ reg = <0x700600 0x50>;
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ cell-index = <1>;
+ clocks = <&cps_syscon0 0 3>;
+ status = "disabled";
+ };
+
+ cps_spi1: spi@700680 {
+ compatible = "marvell,armada-380-spi";
+ reg = <0x700680 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <2>;
+ clocks = <&cps_syscon0 1 21>;
+ status = "disabled";
+ };
+
+ cps_i2c0: i2c@701000 {
+ compatible = "marvell,mv78230-i2c";
+ reg = <0x701000 0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cps_syscon0 1 21>;
+ status = "disabled";
+ };
+
+ cps_i2c1: i2c@701100 {
+ compatible = "marvell,mv78230-i2c";
+ reg = <0x701100 0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cps_syscon0 1 21>;
+ status = "disabled";
+ };
+ };
+
+ cps_pcie0: pcie@f4600000 {
+ compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+ reg = <0 0xf4600000 0 0x10000>,
+ <0 0xfaf00000 0 0x80000>;
+ reg-names = "ctrl", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ dma-coherent;
+ msi-parent = <&gic_v2m0>;
+
+ bus-range = <0 0xff>;
+ ranges =
+ /* downstream I/O */
+ <0x81000000 0 0xfd000000 0 0xfd000000 0 0x10000
+ /* non-prefetchable memory */
+ 0x82000000 0 0xfa000000 0 0xfa000000 0 0xf00000>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
+ num-lanes = <1>;
+ clocks = <&cps_syscon0 1 13>;
+ status = "disabled";
+ };
+
+ cps_pcie1: pcie@f4620000 {
+ compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+ reg = <0 0xf4620000 0 0x10000>,
+ <0 0xfbf00000 0 0x80000>;
+ reg-names = "ctrl", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ dma-coherent;
+ msi-parent = <&gic_v2m0>;
+
+ bus-range = <0 0xff>;
+ ranges =
+ /* downstream I/O */
+ <0x81000000 0 0xfd010000 0 0xfd010000 0 0x10000
+ /* non-prefetchable memory */
+ 0x82000000 0 0xfb000000 0 0xfb000000 0 0xf00000>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>;
+
+ num-lanes = <1>;
+ clocks = <&cps_syscon0 1 11>;
+ status = "disabled";
+ };
+
+ cps_pcie2: pcie@f4640000 {
+ compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
+ reg = <0 0xf4640000 0 0x10000>,
+ <0 0xfcf00000 0 0x80000>;
+ reg-names = "ctrl", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ dma-coherent;
+ msi-parent = <&gic_v2m0>;
+
+ bus-range = <0 0xff>;
+ ranges =
+ /* downstream I/O */
+ <0x81000000 0 0xfd020000 0 0xfd020000 0 0x10000
+ /* non-prefetchable memory */
+ 0x82000000 0 0xfc000000 0 0xfc000000 0 0xf00000>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>;
+
+ num-lanes = <1>;
+ clocks = <&cps_syscon0 1 12>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/marvell/berlin4ct.dtsi b/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
index 099ad93bb49b..85c23facb9fe 100644
--- a/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
+++ b/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
@@ -68,6 +68,7 @@
device_type = "cpu";
reg = <0x0>;
enable-method = "psci";
+ next-level-cache = <&l2>;
cpu-idle-states = <&CPU_SLEEP_0>;
};
@@ -76,6 +77,7 @@
device_type = "cpu";
reg = <0x1>;
enable-method = "psci";
+ next-level-cache = <&l2>;
cpu-idle-states = <&CPU_SLEEP_0>;
};
@@ -84,6 +86,7 @@
device_type = "cpu";
reg = <0x2>;
enable-method = "psci";
+ next-level-cache = <&l2>;
cpu-idle-states = <&CPU_SLEEP_0>;
};
@@ -92,9 +95,14 @@
device_type = "cpu";
reg = <0x3>;
enable-method = "psci";
+ next-level-cache = <&l2>;
cpu-idle-states = <&CPU_SLEEP_0>;
};
+ l2: cache {
+ compatible = "cache";
+ };
+
idle-states {
entry-method = "psci";
CPU_SLEEP_0: cpu-sleep-0 {
@@ -115,7 +123,7 @@
};
pmu {
- compatible = "arm,armv8-pmuv3";
+ compatible = "arm,cortex-a53-pmu", "arm,armv8-pmuv3";
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
@@ -279,7 +287,6 @@
reg = <0x4000 0x100>;
clocks = <&osc>;
interrupts = <1>;
- status = "disabled";
};
wdt2: watchdog@5000 {
@@ -287,7 +294,6 @@
reg = <0x5000 0x100>;
clocks = <&osc>;
interrupts = <2>;
- status = "disabled";
};
sm_gpio0: gpio@8000 {
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 7453a47b3047..2a7f731c7759 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -42,6 +42,44 @@
gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
+
+ connector {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+ type = "d";
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&hdmi0_out>;
+ };
+ };
+ };
+};
+
+&cec {
+ status = "okay";
+};
+
+&dpi0 {
+ status = "okay";
+};
+
+&hdmi_phy {
+ status = "okay";
+};
+
+&hdmi0 {
+ status = "okay";
+
+ ports {
+ port@1 {
+ reg = <1>;
+
+ hdmi0_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+ };
};
&i2c1 {
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 10f638f4e7d8..1c71e256601d 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -254,6 +254,16 @@
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ hdmi_pin: xxx {
+
+ /*hdmi htplg pin*/
+ pins1 {
+ pinmux = <MT8173_PIN_21_HTPLG__FUNC_HTPLG>;
+ input-enable;
+ bias-pull-down;
+ };
+ };
+
i2c0_pins_a: i2c0 {
pins1 {
pinmux = <MT8173_PIN_45_SDA0__FUNC_SDA0>,
@@ -341,6 +351,14 @@
clock-names = "spi", "wrap";
};
+ cec: cec@10013000 {
+ compatible = "mediatek,mt8173-cec";
+ reg = <0 0x10013000 0 0xbc>;
+ interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_CEC>;
+ status = "disabled";
+ };
+
vpu: vpu@10020000 {
compatible = "mediatek,mt8173-vpu";
reg = <0 0x10020000 0 0x30000>,
@@ -383,6 +401,19 @@
#clock-cells = <1>;
};
+ hdmi_phy: hdmi-phy@10209100 {
+ compatible = "mediatek,mt8173-hdmi-phy";
+ reg = <0 0x10209100 0 0x24>;
+ clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>;
+ clock-names = "pll_ref";
+ clock-output-names = "hdmitx_dig_cts";
+ mediatek,ibias = <0xa>;
+ mediatek,ibias_up = <0x1c>;
+ #clock-cells = <0>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
mipi_tx0: mipi-dphy@10215000 {
compatible = "mediatek,mt8173-mipi-tx";
reg = <0 0x10215000 0 0x1000>;
@@ -577,6 +608,14 @@
status = "disabled";
};
+ hdmiddc0: i2c@11012000 {
+ compatible = "mediatek,mt8173-hdmi-ddc";
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>;
+ reg = <0 0x11012000 0 0x1C>;
+ clocks = <&pericfg CLK_PERI_I2C5>;
+ clock-names = "ddc-i2c";
+ };
+
i2c6: i2c@11013000 {
compatible = "mediatek,mt8173-i2c";
reg = <0 0x11013000 0 0x70>,
@@ -885,6 +924,12 @@
<&apmixedsys CLK_APMIXED_TVDPLL>;
clock-names = "pixel", "engine", "pll";
status = "disabled";
+
+ port {
+ dpi0_out: endpoint {
+ remote-endpoint = <&hdmi0_in>;
+ };
+ };
};
pwm0: pwm@1401e000 {
@@ -942,6 +987,38 @@
clocks = <&mmsys CLK_MM_DISP_OD>;
};
+ hdmi0: hdmi@14025000 {
+ compatible = "mediatek,mt8173-hdmi";
+ reg = <0 0x14025000 0 0x400>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&mmsys CLK_MM_HDMI_PIXEL>,
+ <&mmsys CLK_MM_HDMI_PLLCK>,
+ <&mmsys CLK_MM_HDMI_AUDIO>,
+ <&mmsys CLK_MM_HDMI_SPDIF>;
+ clock-names = "pixel", "pll", "bclk", "spdif";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pin>;
+ phys = <&hdmi_phy>;
+ phy-names = "hdmi";
+ mediatek,syscon-hdmi = <&mmsys 0x900>;
+ assigned-clocks = <&topckgen CLK_TOP_HDMI_SEL>;
+ assigned-clock-parents = <&hdmi_phy>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi0_in: endpoint {
+ remote-endpoint = <&dpi0_out>;
+ };
+ };
+ };
+ };
+
larb4: larb@14027000 {
compatible = "mediatek,mt8173-smi-larb";
reg = <0 0x14027000 0 0x1000>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
index 431266a48e9c..c2becb603e11 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
@@ -27,6 +27,12 @@
reg = <0x0 0x80000000 0x0 0xc0000000>;
};
+ host1x@50000000 {
+ dpaux: dpaux@545c0000 {
+ status = "okay";
+ };
+ };
+
pinmux: pinmux@700008d4 {
pinctrl-names = "boot";
pinctrl-0 = <&state_boot>;
@@ -1556,6 +1562,46 @@
};
};
+ i2c@7000d100 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ nau8825@1a {
+ compatible = "nuvoton,nau8825";
+ reg = <0x1a>;
+ interrupt-parent = <&gpio>;
+ interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
+ clock-names = "mclk";
+
+ nuvoton,jkdet-enable;
+ nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
+ nuvoton,vref-impedance = <2>;
+ nuvoton,micbias-voltage = <6>;
+ nuvoton,sar-threshold-num = <4>;
+ nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
+ nuvoton,sar-hysteresis = <1>;
+ nuvoton,sar-voltage = <0>;
+ nuvoton,sar-compare-time = <0>;
+ nuvoton,sar-sampling-time = <0>;
+ nuvoton,short-key-debounce = <2>;
+ nuvoton,jack-insert-debounce = <7>;
+ nuvoton,jack-eject-debounce = <7>;
+ status = "okay";
+ };
+
+ audio-codec@2d {
+ compatible = "realtek,rt5677";
+ reg = <0x2d>;
+ interrupt-parent = <&gpio>;
+ interrupts = <TEGRA_GPIO(X, 0) IRQ_TYPE_LEVEL_HIGH>;
+ realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ status = "okay";
+ };
+ };
+
pmc@7000e400 {
nvidia,invert-interrupt;
nvidia,suspend-mode = <0>;
@@ -1568,12 +1614,81 @@
status = "okay";
};
+ usb@70090000 {
+ phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
+ <&{/padctl@7009f000/pads/pcie/lanes/pcie-6}>;
+ phy-names = "usb2-0", "usb3-0";
+
+ dvddio-pex-supply = <&avddio_1v05>;
+ hvddio-pex-supply = <&pp1800>;
+ avdd-usb-supply = <&pp3300>;
+ avdd-pll-utmip-supply = <&pp1800>;
+ avdd-pll-uerefe-supply = <&pp1050_avdd>;
+ dvdd-pex-pll-supply = <&avddio_1v05>;
+ hvdd-pex-pll-e-supply = <&pp1800>;
+
+ status = "okay";
+ };
+
+ padctl@7009f000 {
+ status = "okay";
+
+ pads {
+ usb2 {
+ status = "okay";
+
+ lanes {
+ usb2-0 {
+ nvidia,function = "xusb";
+ status = "okay";
+ };
+ };
+ };
+
+ pcie {
+ status = "okay";
+
+ lanes {
+ pcie-6 {
+ nvidia,function = "usb3-ss";
+ status = "okay";
+ };
+ };
+ };
+ };
+
+ ports {
+ usb2-0 {
+ status = "okay";
+ vbus-supply = <&usbc_vbus>;
+ mode = "otg";
+ };
+
+ usb3-0 {
+ nvidia,usb2-companion = <0>;
+ status = "okay";
+ };
+ };
+ };
+
sdhci@700b0600 {
bus-width = <8>;
non-removable;
status = "okay";
};
+ aconnect@702c0000 {
+ status = "okay";
+
+ dma@702e2000 {
+ status = "okay";
+ };
+
+ agic@702f9000 {
+ status = "okay";
+ };
+ };
+
clocks {
compatible = "simple-bus";
#address-cells = <1>;
@@ -1646,6 +1761,11 @@
};
};
+ max98357a {
+ compatible = "maxim,max98357a";
+ status = "okay";
+ };
+
psci {
compatible = "arm,psci-1.0";
method = "smc";
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index c4cfdcf60d26..f6739797150a 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -34,6 +34,7 @@
clock-names = "dpaux", "parent";
resets = <&tegra_car 207>;
reset-names = "dpaux";
+ power-domains = <&pd_sor>;
status = "disabled";
state_dpaux1_aux: pinmux-aux {
@@ -108,6 +109,7 @@
clock-names = "dsi", "lp", "parent";
resets = <&tegra_car 48>;
reset-names = "dsi";
+ power-domains = <&pd_sor>;
nvidia,mipi-calibrate = <&mipi 0x0c0>; /* DSIA & DSIB pads */
status = "disabled";
@@ -137,6 +139,7 @@
clock-names = "dsi", "lp", "parent";
resets = <&tegra_car 82>;
reset-names = "dsi";
+ power-domains = <&pd_sor>;
nvidia,mipi-calibrate = <&mipi 0x300>; /* DSIC & DSID pads */
status = "disabled";
@@ -178,6 +181,7 @@
pinctrl-1 = <&state_dpaux_i2c>;
pinctrl-2 = <&state_dpaux_off>;
pinctrl-names = "aux", "i2c", "off";
+ power-domains = <&pd_sor>;
status = "disabled";
};
@@ -197,6 +201,7 @@
pinctrl-1 = <&state_dpaux1_i2c>;
pinctrl-2 = <&state_dpaux1_off>;
pinctrl-names = "aux", "i2c", "off";
+ power-domains = <&pd_sor>;
status = "disabled";
};
@@ -209,6 +214,7 @@
clock-names = "dpaux", "parent";
resets = <&tegra_car 181>;
reset-names = "dpaux";
+ power-domains = <&pd_sor>;
status = "disabled";
state_dpaux_aux: pinmux-aux {
@@ -325,7 +331,7 @@
};
gpio: gpio@6000d000 {
- compatible = "nvidia,tegra210-gpio", "nvidia,tegra124-gpio", "nvidia,tegra30-gpio";
+ compatible = "nvidia,tegra210-gpio", "nvidia,tegra30-gpio";
reg = <0x0 0x6000d000 0x0 0x1000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
@@ -648,27 +654,41 @@
#power-domain-cells = <0>;
};
+ pd_sor: sor {
+ clocks = <&tegra_car TEGRA210_CLK_SOR0>,
+ <&tegra_car TEGRA210_CLK_SOR1>,
+ <&tegra_car TEGRA210_CLK_CSI>,
+ <&tegra_car TEGRA210_CLK_DSIA>,
+ <&tegra_car TEGRA210_CLK_DSIB>,
+ <&tegra_car TEGRA210_CLK_DPAUX>,
+ <&tegra_car TEGRA210_CLK_DPAUX1>,
+ <&tegra_car TEGRA210_CLK_MIPI_CAL>;
+ resets = <&tegra_car TEGRA210_CLK_SOR0>,
+ <&tegra_car TEGRA210_CLK_SOR1>,
+ <&tegra_car TEGRA210_CLK_CSI>,
+ <&tegra_car TEGRA210_CLK_DSIA>,
+ <&tegra_car TEGRA210_CLK_DSIB>,
+ <&tegra_car TEGRA210_CLK_DPAUX>,
+ <&tegra_car TEGRA210_CLK_DPAUX1>,
+ <&tegra_car TEGRA210_CLK_MIPI_CAL>;
+ #power-domain-cells = <0>;
+ };
+
pd_xusbss: xusba {
clocks = <&tegra_car TEGRA210_CLK_XUSB_SS>;
- clock-names = "xusb-ss";
resets = <&tegra_car TEGRA210_CLK_XUSB_SS>;
- reset-names = "xusb-ss";
#power-domain-cells = <0>;
};
pd_xusbdev: xusbb {
clocks = <&tegra_car TEGRA210_CLK_XUSB_DEV>;
- clock-names = "xusb-dev";
resets = <&tegra_car 95>;
- reset-names = "xusb-dev";
#power-domain-cells = <0>;
};
pd_xusbhost: xusbc {
clocks = <&tegra_car TEGRA210_CLK_XUSB_HOST>;
- clock-names = "xusb-host";
resets = <&tegra_car TEGRA210_CLK_XUSB_HOST>;
- reset-names = "xusb-host";
#power-domain-cells = <0>;
};
};
@@ -948,6 +968,7 @@
reg = <0x0 0x700e3000 0x0 0x100>;
clocks = <&tegra_car TEGRA210_CLK_MIPI_CAL>;
clock-names = "mipi-cal";
+ power-domains = <&pd_sor>;
#nvidia,mipi-calibrate-cells = <1>;
};
@@ -961,6 +982,50 @@
#size-cells = <1>;
ranges = <0x702c0000 0x0 0x702c0000 0x00040000>;
status = "disabled";
+
+ adma: dma@702e2000 {
+ compatible = "nvidia,tegra210-adma";
+ reg = <0x702e2000 0x2000>;
+ interrupt-parent = <&agic>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+ clock-names = "d_audio";
+ status = "disabled";
+ };
+
+ agic: agic@702f9000 {
+ compatible = "nvidia,tegra210-agic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x702f9000 0x2000>,
+ <0x702fa000 0x2000>;
+ interrupts = <GIC_SPI 102 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ clocks = <&tegra_car TEGRA210_CLK_APE>;
+ clock-names = "clk";
+ status = "disabled";
+ };
};
spi@70410000 {
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index fa1f661ccccf..5dd05de5619b 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -1,5 +1,6 @@
dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb msm8916-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb
+dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
index ee828a8a8236..e1e6c6b5c489 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
@@ -24,4 +24,52 @@
bias-pull-up;
};
};
+
+ adv7533_int_active: adv533_int_active {
+ pinmux {
+ function = "gpio";
+ pins = "gpio31";
+ };
+ pinconf {
+ pins = "gpio31";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ adv7533_int_suspend: adv7533_int_suspend {
+ pinmux {
+ function = "gpio";
+ pins = "gpio31";
+ };
+ pinconf {
+ pins = "gpio31";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ adv7533_switch_active: adv7533_switch_active {
+ pinmux {
+ function = "gpio";
+ pins = "gpio32";
+ };
+ pinconf {
+ pins = "gpio32";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ adv7533_switch_suspend: adv7533_switch_suspend {
+ pinmux {
+ function = "gpio";
+ pins = "gpio32";
+ };
+ pinconf {
+ pins = "gpio32";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
index 18639bc0a506..bb062b547110 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -63,6 +63,47 @@
/* On High speed expansion */
label = "HS-I2C2";
status = "okay";
+
+ adv_bridge: bridge@39 {
+ status = "okay";
+
+ compatible = "adi,adv7533";
+ reg = <0x39>;
+
+ interrupt-parent = <&msmgpio>;
+ interrupts = <31 2>;
+
+ adi,dsi-lanes = <4>;
+
+ pd-gpios = <&msmgpio 32 0>;
+
+ avdd-supply = <&pm8916_l6>;
+ v1p2-supply = <&pm8916_l6>;
+ v3p3-supply = <&pm8916_l17>;
+
+ pinctrl-names = "default","sleep";
+ pinctrl-0 = <&adv7533_int_active &adv7533_switch_active>;
+ pinctrl-1 = <&adv7533_int_suspend &adv7533_switch_suspend>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7533_in: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ adv7533_out: endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
};
i2c@78ba000 {
@@ -180,6 +221,36 @@
lpass@07708000 {
status = "okay";
};
+
+ mdss@1a00000 {
+ status = "okay";
+
+ mdp@1a01000 {
+ status = "okay";
+ };
+
+ dsi@1a98000 {
+ status = "okay";
+
+ vdda-supply = <&pm8916_l2>;
+ vddio-supply = <&pm8916_l6>;
+
+ ports {
+ port@1 {
+ endpoint {
+ remote-endpoint = <&adv7533_in>;
+ data-lanes = <0 1 2 3>;
+ };
+ };
+ };
+ };
+
+ dsi-phy@1a98300 {
+ status = "okay";
+
+ vddio-supply = <&pm8916_l6>;
+ };
+ };
};
usb2513 {
@@ -194,6 +265,17 @@
pinctrl-names = "default";
pinctrl-0 = <&usb_id_default>;
};
+
+ hdmi-out {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con: endpoint {
+ remote-endpoint = <&adv7533_out>;
+ };
+ };
+ };
};
&smd_rpm_regulators {
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
new file mode 100644
index 000000000000..24552f19b3fa
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2016, 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.
+ */
+&msmgpio {
+ sdc2_cd_on: sdc2_cd_on {
+ mux {
+ pins = "gpio38";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio38";
+ bias-pull-up; /* pull up */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc2_cd_off: sdc2_cd_off {
+ mux {
+ pins = "gpio38";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio38";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+};
diff --git a/arch/arm/mach-qcom/board.c b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
index d8060dfd1a21..230e9c8484ac 100644
--- a/arch/arm/mach-qcom/board.c
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
@@ -1,4 +1,5 @@
-/* Copyright (c) 2010-2014 The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2014-2016, 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
@@ -10,22 +11,11 @@
* GNU General Public License for more details.
*/
-#include <linux/init.h>
+/dts-v1/;
-#include <asm/mach/arch.h>
+#include "apq8096-db820c.dtsi"
-static const char * const qcom_dt_match[] __initconst = {
- "qcom,apq8064",
- "qcom,apq8074-dragonboard",
- "qcom,apq8084",
- "qcom,ipq8062",
- "qcom,ipq8064",
- "qcom,msm8660-surf",
- "qcom,msm8960-cdp",
- "qcom,mdm9615",
- NULL
+/ {
+ model = "Qualcomm Technologies, Inc. DB820c";
+ compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc";
};
-
-DT_MACHINE_START(QCOM_DT, "Qualcomm (Flattened Device Tree)")
- .dt_compat = qcom_dt_match,
-MACHINE_END
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
new file mode 100644
index 000000000000..afb218cffc60
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8996.dtsi"
+#include "apq8096-db820c-pins.dtsi"
+
+/ {
+ aliases {
+ serial0 = &blsp2_uart1;
+ serial1 = &blsp2_uart2;
+ i2c0 = &blsp1_i2c2;
+ i2c1 = &blsp2_i2c1;
+ i2c2 = &blsp2_i2c0;
+ spi0 = &blsp1_spi0;
+ spi1 = &blsp2_spi5;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ soc {
+ serial@75b0000 {
+ label = "LS-UART1";
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp2_uart1_2pins_default>;
+ pinctrl-1 = <&blsp2_uart1_2pins_sleep>;
+ };
+
+ serial@75b1000 {
+ label = "LS-UART0";
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp2_uart2_4pins_default>;
+ pinctrl-1 = <&blsp2_uart2_4pins_sleep>;
+ };
+
+ i2c@07577000 {
+ /* On Low speed expansion */
+ label = "LS-I2C0";
+ status = "okay";
+ };
+
+ i2c@075b6000 {
+ /* On Low speed expansion */
+ label = "LS-I2C1";
+ status = "okay";
+ };
+
+ spi@07575000 {
+ /* On Low speed expansion */
+ label = "LS-SPI0";
+ status = "okay";
+ };
+
+ i2c@075b5000 {
+ /* On High speed expansion */
+ label = "HS-I2C2";
+ status = "okay";
+ };
+
+ spi@075ba000{
+ /* On High speed expansion */
+ label = "HS-SPI1";
+ status = "okay";
+ };
+
+ sdhci@74a4900 {
+ /* External SD card */
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+ cd-gpios = <&msmgpio 38 0x1>;
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 11bdc24cfc74..466ca5705c99 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -86,6 +86,11 @@
reg = <0x0 0x89300000 0x0 0x600000>;
no-map;
};
+
+ mba_mem: mba@8ea00000 {
+ no-map;
+ reg = <0 0x8ea00000 0 0x100000>;
+ };
};
cpus {
@@ -155,6 +160,49 @@
interrupts = <GIC_PPI 7 GIC_CPU_MASK_SIMPLE(4)>;
};
+ thermal-zones {
+ cpu-thermal0 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 4>;
+
+ trips {
+ cpu_alert0: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit0: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal1 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens 3>;
+
+ trips {
+ cpu_alert1: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ cpu_crit1: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -187,10 +235,11 @@
};
firmware {
- scm {
+ scm: scm {
compatible = "qcom,scm";
clocks = <&gcc GCC_CRYPTO_CLK>, <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_AHB_CLK>;
clock-names = "core", "bus", "iface";
+ #reset-cells = <1>;
};
};
@@ -228,6 +277,11 @@
reg = <0x1905000 0x20000>;
};
+ tcsr: syscon@1937000 {
+ compatible = "qcom,tcsr-msm8916", "syscon";
+ reg = <0x1937000 0x30000>;
+ };
+
tcsr_mutex: hwlock {
compatible = "qcom,tcsr-mutex";
syscon = <&tcsr_mutex_regs 0 0x1000>;
@@ -483,7 +537,7 @@
compatible = "qcom,ci-hdrc";
reg = <0x78d9000 0x400>;
dr_mode = "peripheral";
- interrupts = <GIC_SPI 134 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
usb-phy = <&usb_otg>;
status = "disabled";
};
@@ -491,7 +545,7 @@
usb_host: ehci@78d9000 {
compatible = "qcom,ehci-host";
reg = <0x78d9000 0x400>;
- interrupts = <GIC_SPI 134 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
usb-phy = <&usb_otg>;
status = "disabled";
};
@@ -499,8 +553,8 @@
usb_otg: phy@78d9000 {
compatible = "qcom,usb-otg-snps";
reg = <0x78d9000 0x400>;
- interrupts = <GIC_SPI 134 IRQ_TYPE_EDGE_BOTH>,
- <GIC_SPI 140 IRQ_TYPE_EDGE_RISING>;
+ interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
qcom,vdd-levels = <500000 1000000 1320000>;
qcom,phy-init-sequence = <0x44 0x6B 0x24 0x13>;
@@ -594,7 +648,7 @@
<0x200a000 0x002100>;
reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
interrupt-names = "periph_irq";
- interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
qcom,ee = <0>;
qcom,channel = <0>;
#address-cells = <2>;
@@ -609,6 +663,144 @@
clocks = <&gcc GCC_PRNG_AHB_CLK>;
clock-names = "core";
};
+
+ qfprom: qfprom@5c000 {
+ compatible = "qcom,qfprom";
+ reg = <0x5c000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ tsens_caldata: caldata@d0 {
+ reg = <0xd0 0x8>;
+ };
+ tsens_calsel: calsel@ec {
+ reg = <0xec 0x4>;
+ };
+ };
+
+ tsens: thermal-sensor@4a8000 {
+ compatible = "qcom,msm8916-tsens";
+ reg = <0x4a8000 0x2000>;
+ nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+ nvmem-cell-names = "calib", "calib_sel";
+ #thermal-sensor-cells = <1>;
+ };
+
+ mdss: mdss@1a00000 {
+ compatible = "qcom,mdss";
+ reg = <0x1a00000 0x1000>,
+ <0x1ac8000 0x3000>;
+ reg-names = "mdss_phys", "vbif_phys";
+
+ power-domains = <&gcc MDSS_GDSC>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>;
+ clock-names = "iface_clk",
+ "bus_clk",
+ "vsync_clk";
+
+ interrupts = <0 72 0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ mdp: mdp@1a01000 {
+ compatible = "qcom,mdp5";
+ reg = <0x1a01000 0x90000>;
+ reg-names = "mdp_phys";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0 0>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_VSYNC_CLK>;
+ clock-names = "iface_clk",
+ "bus_clk",
+ "core_clk",
+ "vsync_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ mdp5_intf1_out: endpoint {
+ remote-endpoint = <&dsi0_in>;
+ };
+ };
+ };
+ };
+
+ dsi0: dsi@1a98000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ reg = <0x1a98000 0x25c>;
+ reg-names = "dsi_ctrl";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <4 0>;
+
+ assigned-clocks = <&gcc BYTE0_CLK_SRC>,
+ <&gcc PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&dsi_phy0 0>,
+ <&dsi_phy0 1>;
+
+ clocks = <&gcc GCC_MDSS_MDP_CLK>,
+ <&gcc GCC_MDSS_AHB_CLK>,
+ <&gcc GCC_MDSS_AXI_CLK>,
+ <&gcc GCC_MDSS_BYTE0_CLK>,
+ <&gcc GCC_MDSS_PCLK0_CLK>,
+ <&gcc GCC_MDSS_ESC0_CLK>;
+ clock-names = "mdp_core_clk",
+ "iface_clk",
+ "bus_clk",
+ "byte_clk",
+ "pixel_clk",
+ "core_clk";
+ phys = <&dsi_phy0>;
+ phy-names = "dsi-phy";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ dsi0_in: endpoint {
+ remote-endpoint = <&mdp5_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ };
+ };
+ };
+ };
+
+ dsi_phy0: dsi-phy@1a98300 {
+ compatible = "qcom,dsi-phy-28nm-lp";
+ reg = <0x1a98300 0xd4>,
+ <0x1a98500 0x280>,
+ <0x1a98780 0x30>;
+ reg-names = "dsi_pll",
+ "dsi_phy",
+ "dsi_phy_regulator";
+
+ #clock-cells = <1>;
+
+ clocks = <&gcc GCC_MDSS_AHB_CLK>;
+ clock-names = "iface_clk";
+ };
+ };
};
smd {
@@ -657,6 +849,88 @@
};
};
};
+
+ hexagon-smp2p {
+ compatible = "qcom,smp2p";
+ qcom,smem = <435>, <428>;
+
+ interrupts = <0 27 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,ipc = <&apcs 8 14>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <1>;
+
+ hexagon_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+
+ #qcom,smem-state-cells = <1>;
+ };
+
+ hexagon_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ wcnss-smp2p {
+ compatible = "qcom,smp2p";
+ qcom,smem = <451>, <431>;
+
+ interrupts = <0 143 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,ipc = <&apcs 8 18>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <4>;
+
+ wcnss_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+
+ #qcom,smem-state-cells = <1>;
+ };
+
+ wcnss_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smsm {
+ compatible = "qcom,smsm";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ipc-1 = <&apcs 0 13>;
+ qcom,ipc-6 = <&apcs 0 19>;
+
+ apps_smsm: apps@0 {
+ reg = <0>;
+
+ #qcom,smem-state-cells = <1>;
+ };
+
+ hexagon_smsm: hexagon@1 {
+ reg = <1>;
+ interrupts = <0 26 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ wcnss_smsm: wcnss@6 {
+ reg = <6>;
+ interrupts = <0 144 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
};
#include "msm8916-pins.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 55ec3e8326b7..338f82a7fdc7 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -97,6 +97,92 @@
};
};
+ thermal-zones {
+ cpu-thermal0 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens0 3>;
+
+ trips {
+ cpu_alert0: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit0: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal1 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens0 5>;
+
+ trips {
+ cpu_alert1: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit1: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal2 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens0 8>;
+
+ trips {
+ cpu_alert2: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit2: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ cpu-thermal3 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens0 10>;
+
+ trips {
+ cpu_alert3: trip0 {
+ temperature = <75000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit3: trip1 {
+ temperature = <110000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -181,6 +267,12 @@
status = "disabled";
};
+ tsens0: thermal-sensor@4a8000 {
+ compatible = "qcom,msm8996-tsens";
+ reg = <0x4a8000 0x2000>;
+ #thermal-sensor-cells = <1>;
+ };
+
blsp2_uart1: serial@75b0000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x75b0000 0x1000>;
@@ -339,7 +431,7 @@
<0x400a000 0x002100>;
reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
interrupt-names = "periph_irq";
- interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
+ interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>;
qcom,ee = <0>;
qcom,channel = <0>;
#address-cells = <2>;
diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
index 17139f7003a6..eb72830ec9eb 100644
--- a/arch/arm64/boot/dts/renesas/Makefile
+++ b/arch/arm64/boot/dts/renesas/Makefile
@@ -1,4 +1,4 @@
-dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x.dtb
+dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x.dtb r8a7795-h3ulcb.dtb
dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-x.dtb
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts
new file mode 100644
index 000000000000..bcb11a868343
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb.dts
@@ -0,0 +1,328 @@
+/*
+ * Device Tree Source for the H3ULCB board
+ *
+ * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2016 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 "r8a7795.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Renesas H3ULCB board based on r8a7795";
+ compatible = "renesas,h3ulcb", "renesas,r8a7795";
+
+ aliases {
+ serial0 = &scif2;
+ ethernet0 = &avb;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@48000000 {
+ device_type = "memory";
+ /* first 128MB is reserved for secure area. */
+ reg = <0x0 0x48000000 0x0 0x38000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led5 {
+ gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
+ };
+ led6 {
+ gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ keyboard {
+ compatible = "gpio-keys";
+
+ key-1 {
+ linux,code = <KEY_1>;
+ label = "SW3";
+ wakeup-source;
+ debounce-interval = <20>;
+ gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ x12_clk: x12 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
+
+ vcc_sdhi0: regulator-vcc-sdhi0 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI0 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ vccq_sdhi0: regulator-vccq-sdhi0 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI0 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
+
+ audio_clkout: audio-clkout {
+ /*
+ * This is same as <&rcar_sound 0>
+ * but needed to avoid cs2000/rcar_sound probe dead-lock
+ */
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <11289600>;
+ };
+
+ rsnd_ak4613: sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcpu>;
+ simple-audio-card,frame-master = <&sndcpu>;
+
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4613>;
+ };
+ };
+};
+
+&extal_clk {
+ clock-frequency = <16666666>;
+};
+
+&extalr_clk {
+ clock-frequency = <32768>;
+};
+
+&pfc {
+ pinctrl-0 = <&scif_clk_pins>;
+ pinctrl-names = "default";
+
+ scif2_pins: scif2 {
+ groups = "scif2_data_a";
+ function = "scif2";
+ };
+
+ scif_clk_pins: scif_clk {
+ groups = "scif_clk_a";
+ function = "scif_clk";
+ };
+
+ i2c2_pins: i2c2 {
+ groups = "i2c2_a";
+ function = "i2c2";
+ };
+
+ avb_pins: avb {
+ groups = "avb_mdc";
+ function = "avb";
+ };
+
+ sdhi0_pins_3v3: sd0_3v3 {
+ groups = "sdhi0_data4", "sdhi0_ctrl";
+ function = "sdhi0";
+ power-source = <3300>;
+ };
+
+ sdhi0_pins_1v8: sd0_1v8 {
+ groups = "sdhi0_data4", "sdhi0_ctrl";
+ function = "sdhi0";
+ power-source = <1800>;
+ };
+
+ sound_pins: sound {
+ groups = "ssi01239_ctrl", "ssi0_data", "ssi1_data_a";
+ function = "ssi";
+ };
+
+ sound_clk_pins: sound-clk {
+ groups = "audio_clk_a_a", "audio_clk_b_a", "audio_clk_c_a",
+ "audio_clkout_a", "audio_clkout3_a";
+ function = "audio_clk";
+ };
+
+ usb1_pins: usb1 {
+ groups = "usb1";
+ function = "usb1";
+ };
+};
+
+&scif2 {
+ pinctrl-0 = <&scif2_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&scif_clk {
+ clock-frequency = <14745600>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ clock-frequency = <100000>;
+
+ ak4613: codec@10 {
+ compatible = "asahi-kasei,ak4613";
+ #sound-dai-cells = <0>;
+ reg = <0x10>;
+ clocks = <&rcar_sound 3>;
+
+ asahi-kasei,in1-single-end;
+ asahi-kasei,in2-single-end;
+ asahi-kasei,out1-single-end;
+ asahi-kasei,out2-single-end;
+ asahi-kasei,out3-single-end;
+ asahi-kasei,out4-single-end;
+ asahi-kasei,out5-single-end;
+ asahi-kasei,out6-single-end;
+ };
+
+ cs2000: clk-multiplier@4f {
+ #clock-cells = <0>;
+ compatible = "cirrus,cs2000-cp";
+ reg = <0x4f>;
+ clocks = <&audio_clkout>, <&x12_clk>;
+ clock-names = "clk_in", "ref_clk";
+
+ assigned-clocks = <&cs2000>;
+ assigned-clock-rates = <24576000>; /* 1/1 divide */
+ };
+};
+
+&rcar_sound {
+ pinctrl-0 = <&sound_pins &sound_clk_pins>;
+ pinctrl-names = "default";
+
+ /* Single DAI */
+ #sound-dai-cells = <0>;
+
+ /* audio_clkout0/1/2/3 */
+ #clock-cells = <1>;
+ clock-frequency = <11289600>;
+
+ status = "okay";
+
+ /* update <audio_clk_b> to <cs2000> */
+ clocks = <&cpg CPG_MOD 1005>,
+ <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+ <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+ <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+ <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+ <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+ <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+ <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+ <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+ <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+ <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+ <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+ <&audio_clk_a>, <&cs2000>,
+ <&audio_clk_c>,
+ <&cpg CPG_CORE R8A7795_CLK_S0D4>;
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0 &src0 &dvc0>;
+ capture = <&ssi1 &src1 &dvc1>;
+ };
+ };
+};
+
+&sdhi0 {
+ pinctrl-0 = <&sdhi0_pins_3v3>;
+ pinctrl-1 = <&sdhi0_pins_1v8>;
+ pinctrl-names = "default", "state_uhs";
+
+ vmmc-supply = <&vcc_sdhi0>;
+ vqmmc-supply = <&vccq_sdhi0>;
+ cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
+ bus-width = <4>;
+ sd-uhs-sdr50;
+ status = "okay";
+};
+
+&ssi1 {
+ shared-pin;
+};
+
+&wdt0 {
+ timeout-sec = <60>;
+ status = "okay";
+};
+
+&audio_clk_a {
+ clock-frequency = <22579200>;
+};
+
+&avb {
+ pinctrl-0 = <&avb_pins>;
+ pinctrl-names = "default";
+ renesas,no-ether-link;
+ phy-handle = <&phy0>;
+ status = "okay";
+
+ phy0: ethernet-phy@0 {
+ rxc-skew-ps = <900>;
+ rxdv-skew-ps = <0>;
+ rxd0-skew-ps = <0>;
+ rxd1-skew-ps = <0>;
+ rxd2-skew-ps = <0>;
+ rxd3-skew-ps = <0>;
+ txc-skew-ps = <900>;
+ txen-skew-ps = <0>;
+ txd0-skew-ps = <0>;
+ txd1-skew-ps = <0>;
+ txd2-skew-ps = <0>;
+ txd3-skew-ps = <0>;
+ reg = <0>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&usb2_phy1 {
+ pinctrl-0 = <&usb1_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
index 98f02631a0f0..b1eab6876f8c 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
@@ -110,6 +110,17 @@
1800000 0>;
};
+ vbus0_usb2: regulator-vbus0-usb2 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "USB20_VBUS0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ gpio = <&gpio6 16 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
audio_clkout: audio_clkout {
/*
* This is same as <&rcar_sound 0>
@@ -135,6 +146,52 @@
sound-dai = <&ak4613>;
};
};
+
+ vga-encoder {
+ compatible = "adi,adv7123";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7123_in: endpoint {
+ remote-endpoint = <&du_out_rgb>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ adv7123_out: endpoint {
+ remote-endpoint = <&vga_in>;
+ };
+ };
+ };
+ };
+
+ vga {
+ compatible = "vga-connector";
+
+ port {
+ vga_in: endpoint {
+ remote-endpoint = <&adv7123_out>;
+ };
+ };
+ };
+};
+
+&du {
+ pinctrl-0 = <&du_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ ports {
+ port@0 {
+ endpoint {
+ remote-endpoint = <&adv7123_in>;
+ };
+ };
+ };
};
&extal_clk {
@@ -172,6 +229,11 @@
function = "avb";
};
+ du_pins: du {
+ groups = "du_rgb888", "du_sync", "du_oddf", "du_clk_out_0";
+ function = "du";
+ };
+
sdhi0_pins: sd0 {
groups = "sdhi0_data4", "sdhi0_ctrl";
function = "sdhi0";
@@ -193,6 +255,11 @@
function = "audio_clk";
};
+ usb0_pins: usb0 {
+ groups = "usb0";
+ function = "usb0";
+ };
+
usb1_pins: usb1 {
groups = "usb1";
function = "usb1";
@@ -369,6 +436,14 @@
status = "okay";
};
+&usb2_phy0 {
+ pinctrl-0 = <&usb0_pins>;
+ pinctrl-names = "default";
+
+ vbus-supply = <&vbus0_usb2>;
+ status = "okay";
+};
+
&usb2_phy1 {
pinctrl-0 = <&usb1_pins>;
pinctrl-names = "default";
@@ -383,6 +458,10 @@
status = "okay";
};
+&ehci0 {
+ status = "okay";
+};
+
&ehci1 {
status = "okay";
};
@@ -391,6 +470,10 @@
status = "okay";
};
+&ohci0 {
+ status = "okay";
+};
+
&ohci1 {
status = "okay";
};
@@ -399,6 +482,10 @@
status = "okay";
};
+&hsusb {
+ status = "okay";
+};
+
&pcie_bus_clk {
clock-frequency = <100000000>;
status = "okay";
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
index b902356873c2..8c15040f2540 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -328,7 +328,8 @@
};
audma0: dma-controller@ec700000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7795",
+ "renesas,rcar-dmac";
reg = <0 0xec700000 0 0x10000>;
interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
@@ -360,7 +361,8 @@
};
audma1: dma-controller@ec720000 {
- compatible = "renesas,rcar-dmac";
+ compatible = "renesas,dmac-r8a7795",
+ "renesas,rcar-dmac";
reg = <0 0xec720000 0 0x10000>;
interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
@@ -1098,6 +1100,7 @@
reg = <0 0xee100000 0 0x2000>;
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 314>;
+ max-frequency = <200000000>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
status = "disabled";
};
@@ -1107,6 +1110,7 @@
reg = <0 0xee120000 0 0x2000>;
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 313>;
+ max-frequency = <200000000>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
status = "disabled";
};
@@ -1116,8 +1120,8 @@
reg = <0 0xee140000 0 0x2000>;
interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 312>;
+ max-frequency = <200000000>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
- cap-mmc-highspeed;
status = "disabled";
};
@@ -1126,8 +1130,8 @@
reg = <0 0xee160000 0 0x2000>;
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 311>;
+ max-frequency = <200000000>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
- cap-mmc-highspeed;
status = "disabled";
};
@@ -1224,6 +1228,23 @@
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
status = "disabled";
};
+
+ hsusb: usb@e6590000 {
+ compatible = "renesas,usbhs-r8a7795",
+ "renesas,rcar-gen3-usbhs";
+ reg = <0 0xe6590000 0 0x100>;
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 704>;
+ dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+ <&usb_dmac1 0>, <&usb_dmac1 1>;
+ dma-names = "ch0", "ch1", "ch2", "ch3";
+ renesas,buswait = <11>;
+ phys = <&usb2_phy0>;
+ phy-names = "usb";
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
+
pciec0: pcie@fe000000 {
compatible = "renesas,pcie-r8a7795";
reg = <0 0xfe000000 0 0x80000>;
@@ -1273,5 +1294,252 @@
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
status = "disabled";
};
+
+ vspbc: vsp@fe920000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfe920000 0 0x8000>;
+ interrupts = <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 624>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+
+ renesas,fcp = <&fcpvb1>;
+ };
+
+ fcpvb1: fcp@fe92f000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfe92f000 0 0x200>;
+ clocks = <&cpg CPG_MOD 606>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ fcpf0: fcp@fe950000 {
+ compatible = "renesas,r8a7795-fcpf", "renesas,fcpf";
+ reg = <0 0xfe950000 0 0x200>;
+ clocks = <&cpg CPG_MOD 615>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ fcpf1: fcp@fe951000 {
+ compatible = "renesas,r8a7795-fcpf", "renesas,fcpf";
+ reg = <0 0xfe951000 0 0x200>;
+ clocks = <&cpg CPG_MOD 614>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ fcpf2: fcp@fe952000 {
+ compatible = "renesas,r8a7795-fcpf", "renesas,fcpf";
+ reg = <0 0xfe952000 0 0x200>;
+ clocks = <&cpg CPG_MOD 613>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ vspbd: vsp@fe960000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfe960000 0 0x8000>;
+ interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 626>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+
+ renesas,fcp = <&fcpvb0>;
+ };
+
+ fcpvb0: fcp@fe96f000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfe96f000 0 0x200>;
+ clocks = <&cpg CPG_MOD 607>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ vspi0: vsp@fe9a0000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfe9a0000 0 0x8000>;
+ interrupts = <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 631>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+
+ renesas,fcp = <&fcpvi0>;
+ };
+
+ fcpvi0: fcp@fe9af000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfe9af000 0 0x200>;
+ clocks = <&cpg CPG_MOD 611>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ vspi1: vsp@fe9b0000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfe9b0000 0 0x8000>;
+ interrupts = <GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 630>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+
+ renesas,fcp = <&fcpvi1>;
+ };
+
+ fcpvi1: fcp@fe9bf000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfe9bf000 0 0x200>;
+ clocks = <&cpg CPG_MOD 610>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ vspi2: vsp@fe9c0000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfe9c0000 0 0x8000>;
+ interrupts = <GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 629>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+
+ renesas,fcp = <&fcpvi2>;
+ };
+
+ fcpvi2: fcp@fe9cf000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfe9cf000 0 0x200>;
+ clocks = <&cpg CPG_MOD 609>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ };
+
+ vspd0: vsp@fea20000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfea20000 0 0x4000>;
+ interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 623>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+
+ renesas,fcp = <&fcpvd0>;
+ };
+
+ fcpvd0: fcp@fea27000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfea27000 0 0x200>;
+ clocks = <&cpg CPG_MOD 603>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+ };
+
+ vspd1: vsp@fea28000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfea28000 0 0x4000>;
+ interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 622>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+
+ renesas,fcp = <&fcpvd1>;
+ };
+
+ fcpvd1: fcp@fea2f000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfea2f000 0 0x200>;
+ clocks = <&cpg CPG_MOD 602>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+ };
+
+ vspd2: vsp@fea30000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfea30000 0 0x4000>;
+ interrupts = <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 621>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+
+ renesas,fcp = <&fcpvd2>;
+ };
+
+ fcpvd2: fcp@fea37000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfea37000 0 0x200>;
+ clocks = <&cpg CPG_MOD 601>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+ };
+
+ vspd3: vsp@fea38000 {
+ compatible = "renesas,vsp2";
+ reg = <0 0xfea38000 0 0x4000>;
+ interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 620>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+
+ renesas,fcp = <&fcpvd3>;
+ };
+
+ fcpvd3: fcp@fea3f000 {
+ compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
+ reg = <0 0xfea3f000 0 0x200>;
+ clocks = <&cpg CPG_MOD 600>;
+ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+ };
+
+ fdp1@fe940000 {
+ compatible = "renesas,fdp1";
+ reg = <0 0xfe940000 0 0x2400>;
+ interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 119>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ renesas,fcp = <&fcpf0>;
+ };
+
+ fdp1@fe944000 {
+ compatible = "renesas,fdp1";
+ reg = <0 0xfe944000 0 0x2400>;
+ interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 118>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ renesas,fcp = <&fcpf1>;
+ };
+
+ fdp1@fe948000 {
+ compatible = "renesas,fdp1";
+ reg = <0 0xfe948000 0 0x2400>;
+ interrupts = <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 117>;
+ power-domains = <&sysc R8A7795_PD_A3VP>;
+ renesas,fcp = <&fcpf2>;
+ };
+
+ du: display@feb00000 {
+ compatible = "renesas,du-r8a7795";
+ reg = <0 0xfeb00000 0 0x80000>,
+ <0 0xfeb90000 0 0x14>;
+ reg-names = "du", "lvds.0";
+ interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 724>,
+ <&cpg CPG_MOD 723>,
+ <&cpg CPG_MOD 722>,
+ <&cpg CPG_MOD 721>,
+ <&cpg CPG_MOD 727>;
+ clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0";
+ status = "disabled";
+
+ vsps = <&vspd0 &vspd1 &vspd2 &vspd3>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_hdmi0: endpoint {
+ };
+ };
+ port@2 {
+ reg = <2>;
+ du_out_hdmi1: endpoint {
+ };
+ };
+ port@3 {
+ reg = <3>;
+ du_out_lvds0: endpoint {
+ };
+ };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
index e72be3856d79..13db7d61c26c 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
@@ -31,11 +31,27 @@
};
};
+&pfc {
+ pinctrl-0 = <&scif_clk_pins>;
+ pinctrl-names = "default";
+
+ scif2_pins: scif2 {
+ groups = "scif2_data_a";
+ function = "scif2";
+ };
+ scif_clk_pins: scif_clk {
+ groups = "scif_clk_a";
+ function = "scif_clk";
+ };
+};
+
&extal_clk {
clock-frequency = <16666666>;
};
&scif2 {
+ pinctrl-0 = <&scif2_pins>;
+ pinctrl-names = "default";
status = "okay";
};
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
index 1edf82440d78..9217da983525 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
@@ -107,6 +107,123 @@
status = "disabled";
};
+ gpio0: gpio@e6050000 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6050000 0 0x50>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 0 16>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 912>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio1: gpio@e6051000 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6051000 0 0x50>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 32 29>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 911>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio2: gpio@e6052000 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6052000 0 0x50>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 64 15>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 910>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio3: gpio@e6053000 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6053000 0 0x50>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 96 16>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 909>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio4: gpio@e6054000 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6054000 0 0x50>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 128 18>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 908>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio5: gpio@e6055000 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055000 0 0x50>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 160 26>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 907>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio6: gpio@e6055400 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055400 0 0x50>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 192 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 906>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ gpio7: gpio@e6055800 {
+ compatible = "renesas,gpio-r8a7796",
+ "renesas,gpio-rcar";
+ reg = <0 0xe6055800 0 0x50>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 224 4>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&cpg CPG_MOD 905>;
+ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
+ };
+
+ pfc: pin-controller@e6060000 {
+ compatible = "renesas,pfc-r8a7796";
+ reg = <0 0xe6060000 0 0x50c>;
+ };
+
cpg: clock-controller@e6150000 {
compatible = "renesas,r8a7796-cpg-mssr";
reg = <0 0xe6150000 0 0x1000>;
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 7037a161b6ef..87669f656454 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -1,5 +1,6 @@
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-geekbox.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
new file mode 100644
index 000000000000..5797933ef80e
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2016 Matthias Brugger <mbrugger@suse.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include "rk3368.dtsi"
+
+/ {
+ model = "Rockchip Orion R68";
+ compatible = "tronsmart,orion-r68-meta", "rockchip,rk3368";
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+
+ emmc_pwrseq: emmc-pwrseq {
+ compatible = "mmc-pwrseq-emmc";
+ pinctrl-0 = <&emmc_reset>;
+ pinctrl-names = "default";
+ reset-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+ };
+
+ ext_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <125000000>;
+ clock-output-names = "ext_gmac";
+ };
+
+ keys: gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_key>;
+
+ power {
+ wakeup-source;
+ gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
+ label = "GPIO Power";
+ linux,code = <KEY_POWER>;
+ };
+ };
+
+ leds: gpio-leds {
+ compatible = "gpio-leds";
+
+ red {
+ gpios = <&gpio3 29 GPIO_ACTIVE_HIGH>;
+ label = "orion:red:led";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_ctl>;
+ default-state = "on";
+ };
+
+ blue {
+ gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ label = "orion:blue:led";
+ pinctrl-names = "default";
+ pinctrl-0 = <&stby_pwren>;
+ default-state = "off";
+ };
+ };
+
+ vcc_18: vcc18-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ /* supplies both host and otg */
+ vcc_host: vcc-host-regulator {
+ compatible = "regulator-fixed";
+ gpio = <&gpio0 4 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&host_vbus_drv>;
+ regulator-name = "vcc_host";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vcc_io: vcc-io-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_io";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vcc_lan: vcc-lan-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_lan";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_sd: vcc-sd-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sd";
+ gpio = <&gpio3 11 GPIO_ACTIVE_LOW>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_sys: vcc-sys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vccio_sd: vcc-io-sd-regulator {
+ compatible = "regulator-fixed";
+ regulator-name= "vccio_sd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_io>;
+ };
+
+ vccio_wl: vccio-wl-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vccio_wl";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_io>;
+ };
+
+ vdd_10: vdd-10-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+};
+
+&emmc {
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&emmc_pwrseq>;
+ mmc-hs200-1_2v;
+ mmc-hs200-1_8v;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+ status = "okay";
+};
+
+&gmac {
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&ext_gmac>;
+ clock_in_out = "input";
+ phy-supply = <&vcc_lan>;
+ phy-mode = "rgmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins>;
+ snps,reset-gpio = <&gpio3 12 0>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 1000000>;
+ tx_delay = <0x30>;
+ rx_delay = <0x10>;
+ status = "ok";
+};
+
+&i2c0 {
+ status = "okay";
+
+ vdd_cpu: syr827@40 {
+ compatible = "silergy,syr827";
+ reg = <0x40>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-name = "vdd_cpu";
+ regulator-enable-ramp-delay = <300>;
+ regulator-min-microvolt = <712500>;
+ regulator-max-microvolt = <1500000>;
+ regulator-ramp-delay = <8000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ hym8563: hym8563@51 {
+ compatible = "haoyu,hym8563";
+ reg = <0x51>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "xin32k";
+ /* rtc_int is not connected */
+ };
+};
+
+&pinctrl {
+ pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
+ bias-disable;
+ drive-strength = <8>;
+ };
+
+ pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma {
+ bias-pull-up;
+ drive-strength = <8>;
+ };
+
+ emmc {
+ emmc_bus8: emmc-bus8 {
+ rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 19 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 20 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 21 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 22 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 23 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 24 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
+ <1 25 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+ };
+
+ emmc-clk {
+ rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+ };
+
+ emmc-cmd {
+ rockchip,pins = <1 26 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+ };
+
+ emmc_reset: emmc-reset {
+ rockchip,pins = <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ keys {
+ pwr_key: pwr-key {
+ rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+
+ leds {
+ stby_pwren: stby-pwren {
+ rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ led_ctl: led-ctl {
+ rockchip,pins = <3 29 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ sdmmc {
+ sdmmc_clk: sdmmc-clk {
+ rockchip,pins = <2 9 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+ };
+
+ sdmmc_cmd: sdmmc-cmd {
+ rockchip,pins = <2 10 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+ };
+
+ sdmmc_cd: sdmmc-cd {
+ rockchip,pins = <2 11 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+ };
+
+ sdmmc_bus1: sdmmc-bus1 {
+ rockchip,pins = <2 5 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+ };
+
+ sdmmc_bus4: sdmmc-bus4 {
+ rockchip,pins = <2 5 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
+ <2 6 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
+ <2 7 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
+ <2 8 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+ };
+ };
+
+ usb {
+ host_vbus_drv: host-vbus-drv {
+ rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&saradc {
+ vref-supply = <&vcc_18>;
+ status = "okay";
+};
+
+&sdmmc {
+ bus-width = <4>;
+ clock-frequency = <50000000>;
+ clock-freq-min-max = <400000 50000000>;
+ cap-sd-highspeed;
+ card-detect-delay = <200>;
+ keep-power-in-suspend;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_xfer>;
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
index 82a32e5591e2..eed1ef6669ff 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
@@ -248,7 +248,6 @@
&sdio0 {
assigned-clocks = <&cru SCLK_SDIO0>;
assigned-clock-parents = <&cru PLL_CPLL>;
- broken-cd;
bus-width = <4>;
cap-sd-highspeed;
cap-sdio-irq;
diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index 4f44d1191bfd..0fcb2147c9f9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -45,6 +45,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,boot-mode.h>
#include <dt-bindings/thermal/thermal.h>
/ {
@@ -641,6 +642,15 @@
compatible = "rockchip,rk3368-pmu-io-voltage-domain";
status = "disabled";
};
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x200>;
+ mode-normal = <BOOT_NORMAL>;
+ mode-recovery = <BOOT_RECOVERY>;
+ mode-bootloader = <BOOT_FASTBOOT>;
+ mode-loader = <BOOT_BL_DOWNLOAD>;
+ };
};
cru: clock-controller@ff760000 {
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index d33aa06d46f5..8e82497925fe 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -49,6 +49,13 @@
compatible = "rockchip,rk3399-evb", "rockchip,rk3399",
"google,rk3399evb-rev2";
+ clkin_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "clkin_gmac";
+ #clock-cells = <0>;
+ };
+
vdd_center: vdd-center {
compatible = "pwm-regulator";
pwms = <&pwm3 0 25000 0>;
@@ -69,18 +76,61 @@
regulator-max-microvolt = <3300000>;
};
+ vcc5v0_sys: vcc5v0-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ vcc5v0_host: vcc5v0-host-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_host_en>;
+ regulator-name = "vcc5v0_host";
+ vin-supply = <&vcc5v0_sys>;
+ };
+
vcc_phy: vcc-phy-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc_phy";
regulator-always-on;
regulator-boot-on;
};
+
+ vcc_phy: vcc-phy-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_phy";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
};
&emmc_phy {
status = "okay";
};
+&gmac {
+ assigned-clocks = <&cru SCLK_RMII_SRC>;
+ assigned-clock-parents = <&clkin_gmac>;
+ clock_in_out = "input";
+ phy-supply = <&vcc_phy>;
+ phy-mode = "rgmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins>;
+ snps,reset-gpio = <&gpio3 15 GPIO_ACTIVE_LOW>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 50000>;
+ tx_delay = <0x28>;
+ rx_delay = <0x11>;
+ status = "okay";
+};
+
&pwm0 {
status = "okay";
};
@@ -101,6 +151,36 @@
status = "okay";
};
+&pcie_phy {
+ status = "disabled";
+};
+
+&pcie0 {
+ ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
+ num-lanes = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_clkreqn>;
+ status = "disabled";
+};
+
+&u2phy0 {
+ status = "okay";
+};
+
+&u2phy0_host {
+ phy-supply = <&vcc5v0_host>;
+ status = "okay";
+};
+
+&u2phy1 {
+ status = "okay";
+};
+
+&u2phy1_host {
+ phy-supply = <&vcc5v0_host>;
+ status = "okay";
+};
+
&uart2 {
status = "okay";
};
@@ -133,4 +213,11 @@
<1 18 RK_FUNC_GPIO &pcfg_pull_down>;
};
};
+
+ usb2 {
+ vcc5v0_host_en: vcc5v0-host-en {
+ rockchip,pins =
+ <4 25 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index a6dd623a8845..b65c193dc64e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -45,6 +45,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/power/rk3399-power.h>
#include <dt-bindings/thermal/thermal.h>
/ {
@@ -152,6 +153,16 @@
};
};
+ pmu_a53 {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster0>;
+ };
+
+ pmu_a72 {
+ compatible = "arm,cortex-a72-pmu";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster1>;
+ };
+
psci {
compatible = "arm,psci-1.0";
method = "smc";
@@ -159,10 +170,10 @@
timer {
compatible = "arm,armv8-timer";
- interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
- <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
- <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
- <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW 0>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>;
};
xin24m: xin24m {
@@ -181,8 +192,8 @@
dmac_bus: dma-controller@ff6d0000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0xff6d0000 0x0 0x4000>;
- interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH 0>;
#dma-cells = <1>;
clocks = <&cru ACLK_DMAC0_PERILP>;
clock-names = "apb_pclk";
@@ -191,19 +202,39 @@
dmac_peri: dma-controller@ff6e0000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0xff6e0000 0x0 0x4000>;
- interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH 0>;
#dma-cells = <1>;
clocks = <&cru ACLK_DMAC1_PERILP>;
clock-names = "apb_pclk";
};
};
+ gmac: ethernet@fe300000 {
+ compatible = "rockchip,rk3399-gmac";
+ reg = <0x0 0xfe300000 0x0 0x10000>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "macirq";
+ clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_RX>,
+ <&cru SCLK_MAC_TX>, <&cru SCLK_MACREF>,
+ <&cru SCLK_MACREF_OUT>, <&cru ACLK_GMAC>,
+ <&cru PCLK_GMAC>;
+ clock-names = "stmmaceth", "mac_clk_rx",
+ "mac_clk_tx", "clk_mac_ref",
+ "clk_mac_refout", "aclk_mac",
+ "pclk_mac";
+ power-domains = <&power RK3399_PD_GMAC>;
+ resets = <&cru SRST_A_GMAC>;
+ reset-names = "stmmaceth";
+ rockchip,grf = <&grf>;
+ status = "disabled";
+ };
+
sdio0: dwmmc@fe310000 {
compatible = "rockchip,rk3399-dw-mshc",
"rockchip,rk3288-dw-mshc";
reg = <0x0 0xfe310000 0x0 0x4000>;
- interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH 0>;
clock-freq-min-max = <400000 150000000>;
clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
<&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
@@ -216,7 +247,7 @@
compatible = "rockchip,rk3399-dw-mshc",
"rockchip,rk3288-dw-mshc";
reg = <0x0 0xfe320000 0x0 0x4000>;
- interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH 0>;
clock-freq-min-max = <400000 150000000>;
clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
<&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
@@ -228,7 +259,7 @@
sdhci: sdhci@fe330000 {
compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
reg = <0x0 0xfe330000 0x0 0x10000>;
- interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH 0>;
arasan,soc-ctl-syscon = <&grf>;
assigned-clocks = <&cru SCLK_EMMC>;
assigned-clock-rates = <200000000>;
@@ -241,19 +272,60 @@
status = "disabled";
};
+ pcie0: pcie@f8000000 {
+ compatible = "rockchip,rk3399-pcie";
+ reg = <0x0 0xf8000000 0x0 0x2000000>,
+ <0x0 0xfd000000 0x0 0x1000000>;
+ reg-names = "axi-base", "apb-base";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ bus-range = <0x0 0x1>;
+ clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
+ <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>;
+ clock-names = "aclk", "aclk-perf",
+ "hclk", "pm";
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "sys", "legacy", "client";
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie0_intc 0>,
+ <0 0 0 2 &pcie0_intc 1>,
+ <0 0 0 3 &pcie0_intc 2>,
+ <0 0 0 4 &pcie0_intc 3>;
+ msi-map = <0x0 &its 0x0 0x1000>;
+ phys = <&pcie_phy>;
+ phy-names = "pcie-phy";
+ ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x600000
+ 0x81000000 0x0 0xfa600000 0x0 0xfa600000 0x0 0x100000>;
+ resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
+ <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
+ reset-names = "core", "mgmt", "mgmt-sticky", "pipe";
+ status = "disabled";
+
+ pcie0_intc: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+
usb_host0_ehci: usb@fe380000 {
compatible = "generic-ehci";
reg = <0x0 0xfe380000 0x0 0x20000>;
- interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
clock-names = "hclk_host0", "hclk_host0_arb";
+ phys = <&u2phy0_host>;
+ phy-names = "usb";
status = "disabled";
};
usb_host0_ohci: usb@fe3a0000 {
compatible = "generic-ohci";
reg = <0x0 0xfe3a0000 0x0 0x20000>;
- interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
clock-names = "hclk_host0", "hclk_host0_arb";
status = "disabled";
@@ -262,16 +334,18 @@
usb_host1_ehci: usb@fe3c0000 {
compatible = "generic-ehci";
reg = <0x0 0xfe3c0000 0x0 0x20000>;
- interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
clock-names = "hclk_host1", "hclk_host1_arb";
+ phys = <&u2phy1_host>;
+ phy-names = "usb";
status = "disabled";
};
usb_host1_ohci: usb@fe3e0000 {
compatible = "generic-ohci";
reg = <0x0 0xfe3e0000 0x0 0x20000>;
- interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
clock-names = "hclk_host1", "hclk_host1_arb";
status = "disabled";
@@ -279,7 +353,7 @@
gic: interrupt-controller@fee00000 {
compatible = "arm,gic-v3";
- #interrupt-cells = <3>;
+ #interrupt-cells = <4>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
@@ -290,12 +364,34 @@
<0x0 0xfff00000 0 0x10000>, /* GICC */
<0x0 0xfff10000 0 0x10000>, /* GICH */
<0x0 0xfff20000 0 0x10000>; /* GICV */
- interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH 0>;
its: interrupt-controller@fee20000 {
compatible = "arm,gic-v3-its";
msi-controller;
reg = <0x0 0xfee20000 0x0 0x20000>;
};
+
+ ppi-partitions {
+ ppi_cluster0: interrupt-partition-0 {
+ affinity = <&cpu_l0 &cpu_l1 &cpu_l2 &cpu_l3>;
+ };
+
+ ppi_cluster1: interrupt-partition-1 {
+ affinity = <&cpu_b0 &cpu_b1>;
+ };
+ };
+ };
+
+ saradc: saradc@ff100000 {
+ compatible = "rockchip,rk3399-saradc";
+ reg = <0x0 0xff100000 0x0 0x100>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH 0>;
+ #io-channel-cells = <1>;
+ clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
+ clock-names = "saradc", "apb_pclk";
+ resets = <&cru SRST_P_SARADC>;
+ reset-names = "saradc-apb";
+ status = "disabled";
};
i2c1: i2c@ff110000 {
@@ -305,7 +401,7 @@
assigned-clock-rates = <200000000>;
clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c1_xfer>;
#address-cells = <1>;
@@ -320,7 +416,7 @@
assigned-clock-rates = <200000000>;
clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c2_xfer>;
#address-cells = <1>;
@@ -335,7 +431,7 @@
assigned-clock-rates = <200000000>;
clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c3_xfer>;
#address-cells = <1>;
@@ -350,7 +446,7 @@
assigned-clock-rates = <200000000>;
clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c5_xfer>;
#address-cells = <1>;
@@ -365,7 +461,7 @@
assigned-clock-rates = <200000000>;
clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c6_xfer>;
#address-cells = <1>;
@@ -380,7 +476,7 @@
assigned-clock-rates = <200000000>;
clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c7_xfer>;
#address-cells = <1>;
@@ -393,7 +489,7 @@
reg = <0x0 0xff180000 0x0 0x100>;
clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
clock-names = "baudclk", "apb_pclk";
- interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
@@ -406,7 +502,7 @@
reg = <0x0 0xff190000 0x0 0x100>;
clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
clock-names = "baudclk", "apb_pclk";
- interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
@@ -419,7 +515,7 @@
reg = <0x0 0xff1a0000 0x0 0x100>;
clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
clock-names = "baudclk", "apb_pclk";
- interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
@@ -432,7 +528,7 @@
reg = <0x0 0xff1b0000 0x0 0x100>;
clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
clock-names = "baudclk", "apb_pclk";
- interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
@@ -445,7 +541,7 @@
reg = <0x0 0xff1c0000 0x0 0x1000>;
clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
clock-names = "spiclk", "apb_pclk";
- interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&spi0_clk &spi0_tx &spi0_rx &spi0_cs0>;
#address-cells = <1>;
@@ -458,7 +554,7 @@
reg = <0x0 0xff1d0000 0x0 0x1000>;
clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
clock-names = "spiclk", "apb_pclk";
- interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&spi1_clk &spi1_tx &spi1_rx &spi1_cs0>;
#address-cells = <1>;
@@ -471,7 +567,7 @@
reg = <0x0 0xff1e0000 0x0 0x1000>;
clocks = <&cru SCLK_SPI2>, <&cru PCLK_SPI2>;
clock-names = "spiclk", "apb_pclk";
- interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&spi2_clk &spi2_tx &spi2_rx &spi2_cs0>;
#address-cells = <1>;
@@ -484,7 +580,7 @@
reg = <0x0 0xff1f0000 0x0 0x1000>;
clocks = <&cru SCLK_SPI4>, <&cru PCLK_SPI4>;
clock-names = "spiclk", "apb_pclk";
- interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&spi4_clk &spi4_tx &spi4_rx &spi4_cs0>;
#address-cells = <1>;
@@ -497,7 +593,7 @@
reg = <0x0 0xff200000 0x0 0x1000>;
clocks = <&cru SCLK_SPI5>, <&cru PCLK_SPI5>;
clock-names = "spiclk", "apb_pclk";
- interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&spi5_clk &spi5_tx &spi5_rx &spi5_cs0>;
#address-cells = <1>;
@@ -577,7 +673,7 @@
tsadc: tsadc@ff260000 {
compatible = "rockchip,rk3399-tsadc";
reg = <0x0 0xff260000 0x0 0x100>;
- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH 0>;
assigned-clocks = <&cru SCLK_TSADC>;
assigned-clock-rates = <750000>;
clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
@@ -594,6 +690,203 @@
status = "disabled";
};
+ qos_gmac: qos@ffa5c000 {
+ compatible = "syscon";
+ reg = <0x0 0xffa5c000 0x0 0x20>;
+ };
+
+ qos_hdcp: qos@ffa90000 {
+ compatible = "syscon";
+ reg = <0x0 0xffa90000 0x0 0x20>;
+ };
+
+ qos_iep: qos@ffa98000 {
+ compatible = "syscon";
+ reg = <0x0 0xffa98000 0x0 0x20>;
+ };
+
+ qos_isp0_m0: qos@ffaa0000 {
+ compatible = "syscon";
+ reg = <0x0 0xffaa0000 0x0 0x20>;
+ };
+
+ qos_isp0_m1: qos@ffaa0080 {
+ compatible = "syscon";
+ reg = <0x0 0xffaa0080 0x0 0x20>;
+ };
+
+ qos_isp1_m0: qos@ffaa8000 {
+ compatible = "syscon";
+ reg = <0x0 0xffaa8000 0x0 0x20>;
+ };
+
+ qos_isp1_m1: qos@ffaa8080 {
+ compatible = "syscon";
+ reg = <0x0 0xffaa8080 0x0 0x20>;
+ };
+
+ qos_rga_r: qos@ffab0000 {
+ compatible = "syscon";
+ reg = <0x0 0xffab0000 0x0 0x20>;
+ };
+
+ qos_rga_w: qos@ffab0080 {
+ compatible = "syscon";
+ reg = <0x0 0xffab0080 0x0 0x20>;
+ };
+
+ qos_video_m0: qos@ffab8000 {
+ compatible = "syscon";
+ reg = <0x0 0xffab8000 0x0 0x20>;
+ };
+
+ qos_video_m1_r: qos@ffac0000 {
+ compatible = "syscon";
+ reg = <0x0 0xffac0000 0x0 0x20>;
+ };
+
+ qos_video_m1_w: qos@ffac0080 {
+ compatible = "syscon";
+ reg = <0x0 0xffac0080 0x0 0x20>;
+ };
+
+ qos_vop_big_r: qos@ffac8000 {
+ compatible = "syscon";
+ reg = <0x0 0xffac8000 0x0 0x20>;
+ };
+
+ qos_vop_big_w: qos@ffac8080 {
+ compatible = "syscon";
+ reg = <0x0 0xffac8080 0x0 0x20>;
+ };
+
+ qos_vop_little: qos@ffad0000 {
+ compatible = "syscon";
+ reg = <0x0 0xffad0000 0x0 0x20>;
+ };
+
+ qos_gpu: qos@ffae0000 {
+ compatible = "syscon";
+ reg = <0x0 0xffae0000 0x0 0x20>;
+ };
+
+ pmu: power-management@ff310000 {
+ compatible = "rockchip,rk3399-pmu", "syscon", "simple-mfd";
+ reg = <0x0 0xff310000 0x0 0x1000>;
+
+ /*
+ * Note: RK3399 supports 6 voltage domains including VD_CORE_L,
+ * VD_CORE_B, VD_CENTER, VD_GPU, VD_LOGIC and VD_PMU.
+ * Some of the power domains are grouped together for every
+ * voltage domain.
+ * The detail contents as below.
+ */
+ power: power-controller {
+ compatible = "rockchip,rk3399-power-controller";
+ #power-domain-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* These power domains are grouped by VD_CENTER */
+ pd_iep@RK3399_PD_IEP {
+ reg = <RK3399_PD_IEP>;
+ clocks = <&cru ACLK_IEP>,
+ <&cru HCLK_IEP>;
+ pm_qos = <&qos_iep>;
+ };
+ pd_rga@RK3399_PD_RGA {
+ reg = <RK3399_PD_RGA>;
+ clocks = <&cru ACLK_RGA>,
+ <&cru HCLK_RGA>;
+ pm_qos = <&qos_rga_r>,
+ <&qos_rga_w>;
+ };
+ pd_vcodec@RK3399_PD_VCODEC {
+ reg = <RK3399_PD_VCODEC>;
+ clocks = <&cru ACLK_VCODEC>,
+ <&cru HCLK_VCODEC>;
+ pm_qos = <&qos_video_m0>;
+ };
+ pd_vdu@RK3399_PD_VDU {
+ reg = <RK3399_PD_VDU>;
+ clocks = <&cru ACLK_VDU>,
+ <&cru HCLK_VDU>;
+ pm_qos = <&qos_video_m1_r>,
+ <&qos_video_m1_w>;
+ };
+
+ /* These power domains are grouped by VD_GPU */
+ pd_gpu@RK3399_PD_GPU {
+ reg = <RK3399_PD_GPU>;
+ clocks = <&cru ACLK_GPU>;
+ pm_qos = <&qos_gpu>;
+ };
+
+ /* These power domains are grouped by VD_LOGIC */
+ pd_gmac@RK3399_PD_GMAC {
+ reg = <RK3399_PD_GMAC>;
+ clocks = <&cru ACLK_GMAC>;
+ pm_qos = <&qos_gmac>;
+ };
+ pd_vio@RK3399_PD_VIO {
+ reg = <RK3399_PD_VIO>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pd_hdcp@RK3399_PD_HDCP {
+ reg = <RK3399_PD_HDCP>;
+ clocks = <&cru ACLK_HDCP>,
+ <&cru HCLK_HDCP>,
+ <&cru PCLK_HDCP>;
+ pm_qos = <&qos_hdcp>;
+ };
+ pd_isp0@RK3399_PD_ISP0 {
+ reg = <RK3399_PD_ISP0>;
+ clocks = <&cru ACLK_ISP0>,
+ <&cru HCLK_ISP0>;
+ pm_qos = <&qos_isp0_m0>,
+ <&qos_isp0_m1>;
+ };
+ pd_isp1@RK3399_PD_ISP1 {
+ reg = <RK3399_PD_ISP1>;
+ clocks = <&cru ACLK_ISP1>,
+ <&cru HCLK_ISP1>;
+ pm_qos = <&qos_isp1_m0>,
+ <&qos_isp1_m1>;
+ };
+ pd_tcpc0@RK3399_PD_TCPC0 {
+ reg = <RK3399_PD_TCPD0>;
+ clocks = <&cru SCLK_UPHY0_TCPDCORE>,
+ <&cru SCLK_UPHY0_TCPDPHY_REF>;
+ };
+ pd_tcpc1@RK3399_PD_TCPC1 {
+ reg = <RK3399_PD_TCPD1>;
+ clocks = <&cru SCLK_UPHY1_TCPDCORE>,
+ <&cru SCLK_UPHY1_TCPDPHY_REF>;
+ };
+ pd_vo@RK3399_PD_VO {
+ reg = <RK3399_PD_VO>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pd_vopb@RK3399_PD_VOPB {
+ reg = <RK3399_PD_VOPB>;
+ clocks = <&cru ACLK_VOP0>,
+ <&cru HCLK_VOP0>;
+ pm_qos = <&qos_vop_big_r>,
+ <&qos_vop_big_w>;
+ };
+ pd_vopl@RK3399_PD_VOPL {
+ reg = <RK3399_PD_VOPL>;
+ clocks = <&cru ACLK_VOP1>,
+ <&cru HCLK_VOP1>;
+ pm_qos = <&qos_vop_little>;
+ };
+ };
+ };
+ };
+ };
+
pmugrf: syscon@ff320000 {
compatible = "rockchip,rk3399-pmugrf", "syscon", "simple-mfd";
reg = <0x0 0xff320000 0x0 0x1000>;
@@ -611,7 +904,7 @@
reg = <0x0 0xff350000 0x0 0x1000>;
clocks = <&pmucru SCLK_SPI3_PMU>, <&pmucru PCLK_SPI3_PMU>;
clock-names = "spiclk", "apb_pclk";
- interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&spi3_clk &spi3_tx &spi3_rx &spi3_cs0>;
#address-cells = <1>;
@@ -624,7 +917,7 @@
reg = <0x0 0xff370000 0x0 0x100>;
clocks = <&pmucru SCLK_UART4_PMU>, <&pmucru PCLK_UART4_PMU>;
clock-names = "baudclk", "apb_pclk";
- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
@@ -639,7 +932,7 @@
assigned-clock-rates = <200000000>;
clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c0_xfer>;
#address-cells = <1>;
@@ -654,7 +947,7 @@
assigned-clock-rates = <200000000>;
clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c4_xfer>;
#address-cells = <1>;
@@ -669,7 +962,7 @@
assigned-clock-rates = <200000000>;
clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;
clock-names = "i2c", "pclk";
- interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH 0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c8_xfer>;
#address-cells = <1>;
@@ -721,6 +1014,35 @@
status = "disabled";
};
+ efuse0: efuse@ff690000 {
+ compatible = "rockchip,rk3399-efuse";
+ reg = <0x0 0xff690000 0x0 0x80>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&cru PCLK_EFUSE1024NS>;
+ clock-names = "pclk_efuse";
+
+ /* Data cells */
+ cpub_leakage: cpu-leakage@17 {
+ reg = <0x17 0x1>;
+ };
+ gpu_leakage: gpu-leakage@18 {
+ reg = <0x18 0x1>;
+ };
+ center_leakage: center-leakage@19 {
+ reg = <0x19 0x1>;
+ };
+ cpul_leakage: cpu-leakage@1a {
+ reg = <0x1a 0x1>;
+ };
+ logic_leakage: logic-leakage@1b {
+ reg = <0x1b 0x1>;
+ };
+ wafer_info: wafer-info@1c {
+ reg = <0x1c 0x1>;
+ };
+ };
+
pmucru: pmu-clock-controller@ff750000 {
compatible = "rockchip,rk3399-pmucru";
reg = <0x0 0xff750000 0x0 0x1000>;
@@ -741,7 +1063,7 @@
<&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>,
<&cru PCLK_PERIHP>,
<&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>,
- <&cru PCLK_PERILP0>,
+ <&cru PCLK_PERILP0>, <&cru ACLK_CCI>,
<&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>;
assigned-clock-rates =
<594000000>, <800000000>,
@@ -749,7 +1071,7 @@
<150000000>, <75000000>,
<37500000>,
<100000000>, <100000000>,
- <50000000>,
+ <50000000>, <600000000>,
<100000000>, <50000000>;
};
@@ -764,6 +1086,40 @@
status = "disabled";
};
+ u2phy0: usb2-phy@e450 {
+ compatible = "rockchip,rk3399-usb2phy";
+ reg = <0xe450 0x10>;
+ clocks = <&cru SCLK_USB2PHY0_REF>;
+ clock-names = "phyclk";
+ #clock-cells = <0>;
+ clock-output-names = "clk_usbphy0_480m";
+ status = "disabled";
+
+ u2phy0_host: host-port {
+ #phy-cells = <0>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "linestate";
+ status = "disabled";
+ };
+ };
+
+ u2phy1: usb2-phy@e460 {
+ compatible = "rockchip,rk3399-usb2phy";
+ reg = <0xe460 0x10>;
+ clocks = <&cru SCLK_USB2PHY1_REF>;
+ clock-names = "phyclk";
+ #clock-cells = <0>;
+ clock-output-names = "clk_usbphy1_480m";
+ status = "disabled";
+
+ u2phy1_host: host-port {
+ #phy-cells = <0>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "linestate";
+ status = "disabled";
+ };
+ };
+
emmc_phy: phy@f780 {
compatible = "rockchip,rk3399-emmc-phy";
reg = <0xf780 0x24>;
@@ -772,19 +1128,85 @@
#phy-cells = <0>;
status = "disabled";
};
+
+ pcie_phy: pcie-phy {
+ compatible = "rockchip,rk3399-pcie-phy";
+ clocks = <&cru SCLK_PCIEPHY_REF>;
+ clock-names = "refclk";
+ #phy-cells = <0>;
+ resets = <&cru SRST_PCIEPHY>;
+ reset-names = "phy";
+ status = "disabled";
+ };
};
- watchdog@ff840000 {
+ tcphy0: phy@ff7c0000 {
+ compatible = "rockchip,rk3399-typec-phy";
+ reg = <0x0 0xff7c0000 0x0 0x40000>;
+ clocks = <&cru SCLK_UPHY0_TCPDCORE>,
+ <&cru SCLK_UPHY0_TCPDPHY_REF>;
+ clock-names = "tcpdcore", "tcpdphy-ref";
+ assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>;
+ assigned-clock-rates = <50000000>;
+ resets = <&cru SRST_UPHY0>,
+ <&cru SRST_UPHY0_PIPE_L00>,
+ <&cru SRST_P_UPHY0_TCPHY>;
+ reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
+ rockchip,grf = <&grf>;
+ rockchip,typec-conn-dir = <0xe580 0 16>;
+ rockchip,usb3tousb2-en = <0xe580 3 19>;
+ rockchip,external-psm = <0xe588 14 30>;
+ rockchip,pipe-status = <0xe5c0 0 0>;
+ status = "disabled";
+
+ tcphy0_dp: dp-port {
+ #phy-cells = <0>;
+ };
+
+ tcphy0_usb3: usb3-port {
+ #phy-cells = <0>;
+ };
+ };
+
+ tcphy1: phy@ff800000 {
+ compatible = "rockchip,rk3399-typec-phy";
+ reg = <0x0 0xff800000 0x0 0x40000>;
+ clocks = <&cru SCLK_UPHY1_TCPDCORE>,
+ <&cru SCLK_UPHY1_TCPDPHY_REF>;
+ clock-names = "tcpdcore", "tcpdphy-ref";
+ assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>;
+ assigned-clock-rates = <50000000>;
+ resets = <&cru SRST_UPHY1>,
+ <&cru SRST_UPHY1_PIPE_L00>,
+ <&cru SRST_P_UPHY1_TCPHY>;
+ reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
+ rockchip,grf = <&grf>;
+ rockchip,typec-conn-dir = <0xe58c 0 16>;
+ rockchip,usb3tousb2-en = <0xe58c 3 19>;
+ rockchip,external-psm = <0xe594 14 30>;
+ rockchip,pipe-status = <0xe5c0 16 16>;
+ status = "disabled";
+
+ tcphy1_dp: dp-port {
+ #phy-cells = <0>;
+ };
+
+ tcphy1_usb3: usb3-port {
+ #phy-cells = <0>;
+ };
+ };
+
+ watchdog@ff848000 {
compatible = "snps,dw-wdt";
- reg = <0x0 0xff840000 0x0 0x100>;
+ reg = <0x0 0xff848000 0x0 0x100>;
clocks = <&cru PCLK_WDT>;
- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH 0>;
};
rktimer: rktimer@ff850000 {
compatible = "rockchip,rk3399-timer";
reg = <0x0 0xff850000 0x0 0x1000>;
- interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER00>;
clock-names = "pclk", "timer";
};
@@ -792,7 +1214,7 @@
spdif: spdif@ff870000 {
compatible = "rockchip,rk3399-spdif";
reg = <0x0 0xff870000 0x0 0x1000>;
- interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH 0>;
dmas = <&dmac_bus 7>;
dma-names = "tx";
clock-names = "mclk", "hclk";
@@ -806,7 +1228,7 @@
compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
reg = <0x0 0xff880000 0x0 0x1000>;
rockchip,grf = <&grf>;
- interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH 0>;
dmas = <&dmac_bus 0>, <&dmac_bus 1>;
dma-names = "tx", "rx";
clock-names = "i2s_clk", "i2s_hclk";
@@ -819,7 +1241,7 @@
i2s1: i2s@ff890000 {
compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
reg = <0x0 0xff890000 0x0 0x1000>;
- interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH 0>;
dmas = <&dmac_bus 2>, <&dmac_bus 3>;
dma-names = "tx", "rx";
clock-names = "i2s_clk", "i2s_hclk";
@@ -832,7 +1254,7 @@
i2s2: i2s@ff8a0000 {
compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
reg = <0x0 0xff8a0000 0x0 0x1000>;
- interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH 0>;
dmas = <&dmac_bus 4>, <&dmac_bus 5>;
dma-names = "tx", "rx";
clock-names = "i2s_clk", "i2s_hclk";
@@ -852,7 +1274,7 @@
compatible = "rockchip,gpio-bank";
reg = <0x0 0xff720000 0x0 0x100>;
clocks = <&pmucru PCLK_GPIO0_PMU>;
- interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH 0>;
gpio-controller;
#gpio-cells = <0x2>;
@@ -865,7 +1287,7 @@
compatible = "rockchip,gpio-bank";
reg = <0x0 0xff730000 0x0 0x100>;
clocks = <&pmucru PCLK_GPIO1_PMU>;
- interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH 0>;
gpio-controller;
#gpio-cells = <0x2>;
@@ -878,7 +1300,7 @@
compatible = "rockchip,gpio-bank";
reg = <0x0 0xff780000 0x0 0x100>;
clocks = <&cru PCLK_GPIO2>;
- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH 0>;
gpio-controller;
#gpio-cells = <0x2>;
@@ -891,7 +1313,7 @@
compatible = "rockchip,gpio-bank";
reg = <0x0 0xff788000 0x0 0x100>;
clocks = <&cru PCLK_GPIO3>;
- interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH 0>;
gpio-controller;
#gpio-cells = <0x2>;
@@ -904,7 +1326,7 @@
compatible = "rockchip,gpio-bank";
reg = <0x0 0xff790000 0x0 0x100>;
clocks = <&cru PCLK_GPIO4>;
- interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH 0>;
gpio-controller;
#gpio-cells = <0x2>;
@@ -955,6 +1377,72 @@
drive-strength = <13>;
};
+ clock {
+ clk_32k: clk-32k {
+ rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ gmac {
+ rgmii_pins: rgmii-pins {
+ rockchip,pins =
+ /* mac_txclk */
+ <3 17 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_rxclk */
+ <3 14 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_mdio */
+ <3 13 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_txen */
+ <3 12 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_clk */
+ <3 11 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxdv */
+ <3 9 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_mdc */
+ <3 8 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxd1 */
+ <3 7 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxd0 */
+ <3 6 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_txd1 */
+ <3 5 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_txd0 */
+ <3 4 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_rxd3 */
+ <3 3 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxd2 */
+ <3 2 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_txd3 */
+ <3 1 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_txd2 */
+ <3 0 RK_FUNC_1 &pcfg_pull_none_13ma>;
+ };
+
+ rmii_pins: rmii-pins {
+ rockchip,pins =
+ /* mac_mdio */
+ <3 13 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_txen */
+ <3 12 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_clk */
+ <3 11 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxer */
+ <3 10 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxdv */
+ <3 9 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_mdc */
+ <3 8 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxd1 */
+ <3 7 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_rxd0 */
+ <3 6 RK_FUNC_1 &pcfg_pull_none>,
+ /* mac_txd1 */
+ <3 5 RK_FUNC_1 &pcfg_pull_none_13ma>,
+ /* mac_txd0 */
+ <3 4 RK_FUNC_1 &pcfg_pull_none_13ma>;
+ };
+ };
+
i2c0 {
i2c0_xfer: i2c0-xfer {
rockchip,pins =
@@ -1326,5 +1814,18 @@
<1 14 RK_FUNC_1 &pcfg_pull_none>;
};
};
+
+ pcie {
+ pcie_clkreqn: pci-clkreqn {
+ rockchip,pins =
+ <2 26 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ pcie_clkreqnb: pci-clkreqnb {
+ rockchip,pins =
+ <4 24 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
};
};
diff --git a/arch/arm64/boot/dts/socionext/Makefile b/arch/arm64/boot/dts/socionext/Makefile
index 299b67ec4d44..5538598b302c 100644
--- a/arch/arm64/boot/dts/socionext/Makefile
+++ b/arch/arm64/boot/dts/socionext/Makefile
@@ -1,4 +1,6 @@
-dtb-$(CONFIG_ARCH_UNIPHIER) += uniphier-ph1-ld20-ref.dtb
+dtb-$(CONFIG_ARCH_UNIPHIER) += \
+ uniphier-ld11-ref.dtb \
+ uniphier-ld20-ref.dtb
always := $(dtb-y)
clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts
new file mode 100644
index 000000000000..7168cf818ad8
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld11-ref.dts
@@ -0,0 +1,100 @@
+/*
+ * Device Tree Source for UniPhier LD11 Reference Board
+ *
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+/include/ "uniphier-ld11.dtsi"
+/include/ "uniphier-ref-daughter.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier LD11 Reference Board";
+ compatible = "socionext,uniphier-ld11-ref", "socionext,uniphier-ld11";
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x80000000 0 0x40000000>;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ serial3 = &serial3;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ };
+};
+
+&ethsc {
+ interrupts = <0 48 4>;
+};
+
+&serial0 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
+
+&usb2 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
new file mode 100644
index 000000000000..3eb4c42ce7b9
--- /dev/null
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
@@ -0,0 +1,338 @@
+/*
+ * Device Tree Source for UniPhier LD11 SoC
+ *
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; 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 file is distributed in 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.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/memreserve/ 0x80000000 0x00000008; /* cpu-release-addr */
+
+/ {
+ compatible = "socionext,uniphier-ld11";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ };
+ };
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0 0x000>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0x80000000>;
+ };
+
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0 0x001>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0 0x80000000>;
+ };
+ };
+
+ clocks {
+ refclk: ref {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 4>,
+ <1 14 4>,
+ <1 11 4>,
+ <1 10 4>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+
+ serial0: serial@54006800 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006800 0x40>;
+ interrupts = <0 33 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ clocks = <&peri_clk 0>;
+ };
+
+ serial1: serial@54006900 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006900 0x40>;
+ interrupts = <0 35 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ clocks = <&peri_clk 1>;
+ };
+
+ serial2: serial@54006a00 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006a00 0x40>;
+ interrupts = <0 37 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ clocks = <&peri_clk 2>;
+ };
+
+ serial3: serial@54006b00 {
+ compatible = "socionext,uniphier-uart";
+ status = "disabled";
+ reg = <0x54006b00 0x40>;
+ interrupts = <0 177 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ clocks = <&peri_clk 3>;
+ };
+
+ i2c0: i2c@58780000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58780000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ clocks = <&peri_clk 4>;
+ clock-frequency = <100000>;
+ };
+
+ i2c1: i2c@58781000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58781000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 42 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ clocks = <&peri_clk 5>;
+ clock-frequency = <100000>;
+ };
+
+ i2c2: i2c@58782000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58782000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 43 4>;
+ clocks = <&peri_clk 6>;
+ clock-frequency = <400000>;
+ };
+
+ i2c3: i2c@58783000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58783000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 44 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clocks = <&peri_clk 7>;
+ clock-frequency = <100000>;
+ };
+
+ i2c4: i2c@58784000 {
+ compatible = "socionext,uniphier-fi2c";
+ status = "disabled";
+ reg = <0x58784000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 45 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ clocks = <&peri_clk 8>;
+ clock-frequency = <100000>;
+ };
+
+ i2c5: i2c@58785000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58785000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 25 4>;
+ clocks = <&peri_clk 9>;
+ clock-frequency = <400000>;
+ };
+
+ system_bus: system-bus@58c00000 {
+ compatible = "socionext,uniphier-system-bus";
+ status = "disabled";
+ reg = <0x58c00000 0x400>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_system_bus>;
+ };
+
+ smpctrl@59800000 {
+ compatible = "socionext,uniphier-smpctrl";
+ reg = <0x59801000 0x400>;
+ };
+
+ perictrl@59820000 {
+ compatible = "socionext,uniphier-perictrl",
+ "simple-mfd", "syscon";
+ reg = <0x59820000 0x200>;
+
+ peri_clk: clock {
+ compatible = "socionext,uniphier-ld11-peri-clock";
+ #clock-cells = <1>;
+ };
+
+ peri_rst: reset {
+ compatible = "socionext,uniphier-ld11-peri-reset";
+ #reset-cells = <1>;
+ };
+ };
+
+ usb0: usb@5a800100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a800100 0x100>;
+ interrupts = <0 243 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb0>;
+ clocks = <&mio_clk 7>, <&mio_clk 8>, <&mio_clk 12>;
+ resets = <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>, <&sys_rst 8>;
+ };
+
+ usb1: usb@5a810100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a810100 0x100>;
+ interrupts = <0 244 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb1>;
+ clocks = <&mio_clk 7>, <&mio_clk 9>, <&mio_clk 13>;
+ resets = <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>, <&sys_rst 8>;
+ };
+
+ usb2: usb@5a820100 {
+ compatible = "socionext,uniphier-ehci", "generic-ehci";
+ status = "disabled";
+ reg = <0x5a820100 0x100>;
+ interrupts = <0 245 4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2>;
+ clocks = <&mio_clk 7>, <&mio_clk 10>, <&mio_clk 14>;
+ resets = <&mio_rst 7>, <&mio_rst 10>, <&mio_rst 14>, <&sys_rst 8>;
+ };
+
+ mioctrl@5b3e0000 {
+ compatible = "socionext,uniphier-mioctrl",
+ "simple-mfd", "syscon";
+ reg = <0x5b3e0000 0x800>;
+
+ mio_clk: clock {
+ compatible = "socionext,uniphier-ld11-mio-clock";
+ #clock-cells = <1>;
+ };
+
+ mio_rst: reset {
+ compatible = "socionext,uniphier-ld11-mio-reset";
+ #reset-cells = <1>;
+ resets = <&sys_rst 7>;
+ };
+ };
+
+ soc-glue@5f800000 {
+ compatible = "socionext,uniphier-soc-glue",
+ "simple-mfd", "syscon";
+ reg = <0x5f800000 0x2000>;
+
+ pinctrl: pinctrl {
+ compatible = "socionext,uniphier-ld11-pinctrl";
+ };
+ };
+
+ gic: interrupt-controller@5fe00000 {
+ compatible = "arm,gic-v3";
+ reg = <0x5fe00000 0x10000>, /* GICD */
+ <0x5fe40000 0x80000>; /* GICR */
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupts = <1 9 4>;
+ };
+
+ sysctrl@61840000 {
+ compatible = "socionext,uniphier-ld11-sysctrl",
+ "simple-mfd", "syscon";
+ reg = <0x61840000 0x4000>;
+
+ sys_clk: clock {
+ compatible = "socionext,uniphier-ld11-clock";
+ #clock-cells = <1>;
+ };
+
+ sys_rst: reset {
+ compatible = "socionext,uniphier-ld11-reset";
+ #reset-cells = <1>;
+ };
+ };
+ };
+};
+
+/include/ "uniphier-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20-ref.dts b/arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts
index 2adad8c8cd27..609162a1a322 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20-ref.dts
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld20-ref.dts
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-LD20 Reference Board
+ * Device Tree Source for UniPhier LD20 Reference Board
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -43,13 +44,13 @@
*/
/dts-v1/;
-/include/ "uniphier-ph1-ld20.dtsi"
+/include/ "uniphier-ld20.dtsi"
/include/ "uniphier-ref-daughter.dtsi"
/include/ "uniphier-support-card.dtsi"
/ {
- model = "UniPhier PH1-LD20 Reference Board";
- compatible = "socionext,ph1-ld20-ref", "socionext,ph1-ld20";
+ model = "UniPhier LD20 Reference Board";
+ compatible = "socionext,uniphier-ld20-ref", "socionext,uniphier-ld20";
memory {
device_type = "memory";
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
index d73bdc8c9115..08fd7cf7769c 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ph1-ld20.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
@@ -1,7 +1,8 @@
/*
- * Device Tree Source for UniPhier PH1-LD20 SoC
+ * Device Tree Source for UniPhier LD20 SoC
*
- * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2015-2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
@@ -45,7 +46,7 @@
/memreserve/ 0x80000000 0x00000008; /* cpu-release-addr */
/ {
- compatible = "socionext,ph1-ld20";
+ compatible = "socionext,uniphier-ld20";
#address-cells = <2>;
#size-cells = <2>;
interrupt-parent = <&gic>;
@@ -113,18 +114,6 @@
#clock-cells = <0>;
clock-frequency = <25000000>;
};
-
- uart_clk: uart_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <58820000>;
- };
-
- i2c_clk: i2c_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <50000000>;
- };
};
timer {
@@ -148,7 +137,7 @@
interrupts = <0 33 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart0>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 0>;
};
serial1: serial@54006900 {
@@ -158,7 +147,7 @@
interrupts = <0 35 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 1>;
};
serial2: serial@54006a00 {
@@ -168,7 +157,7 @@
interrupts = <0 37 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 2>;
};
serial3: serial@54006b00 {
@@ -178,7 +167,7 @@
interrupts = <0 177 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart3>;
- clocks = <&uart_clk>;
+ clocks = <&peri_clk 3>;
};
i2c0: i2c@58780000 {
@@ -190,7 +179,7 @@
interrupts = <0 41 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 4>;
clock-frequency = <100000>;
};
@@ -203,7 +192,7 @@
interrupts = <0 42 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 5>;
clock-frequency = <100000>;
};
@@ -213,7 +202,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 43 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 6>;
clock-frequency = <400000>;
};
@@ -226,7 +215,7 @@
interrupts = <0 44 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 7>;
clock-frequency = <100000>;
};
@@ -239,7 +228,7 @@
interrupts = <0 45 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 8>;
clock-frequency = <100000>;
};
@@ -249,7 +238,7 @@
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 25 4>;
- clocks = <&i2c_clk>;
+ clocks = <&peri_clk 9>;
clock-frequency = <400000>;
};
@@ -259,6 +248,8 @@
reg = <0x58c00000 0x400>;
#address-cells = <2>;
#size-cells = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_system_bus>;
};
smpctrl@59800000 {
@@ -266,12 +257,45 @@
reg = <0x59801000 0x400>;
};
+ mioctrl@59810000 {
+ compatible = "socionext,uniphier-mioctrl",
+ "simple-mfd", "syscon";
+ reg = <0x59810000 0x800>;
+
+ mio_clk: clock {
+ compatible = "socionext,uniphier-ld20-mio-clock";
+ #clock-cells = <1>;
+ };
+
+ mio_rst: reset {
+ compatible = "socionext,uniphier-ld20-mio-reset";
+ #reset-cells = <1>;
+ };
+ };
+
+ perictrl@59820000 {
+ compatible = "socionext,uniphier-perictrl",
+ "simple-mfd", "syscon";
+ reg = <0x59820000 0x200>;
+
+ peri_clk: clock {
+ compatible = "socionext,uniphier-ld20-peri-clock";
+ #clock-cells = <1>;
+ };
+
+ peri_rst: reset {
+ compatible = "socionext,uniphier-ld20-peri-reset";
+ #reset-cells = <1>;
+ };
+ };
+
soc-glue@5f800000 {
- compatible = "simple-mfd", "syscon";
+ compatible = "socionext,uniphier-soc-glue",
+ "simple-mfd", "syscon";
reg = <0x5f800000 0x2000>;
pinctrl: pinctrl {
- compatible = "socionext,uniphier-ld20-pinctrl";
+ compatible = "socionext,uniphier-ld20-pinctrl";
};
};
@@ -283,6 +307,22 @@
#interrupt-cells = <3>;
interrupts = <1 9 4>;
};
+
+ sysctrl@61840000 {
+ compatible = "socionext,uniphier-sysctrl",
+ "simple-mfd", "syscon";
+ reg = <0x61840000 0x4000>;
+
+ sys_clk: clock {
+ compatible = "socionext,uniphier-ld20-clock";
+ #clock-cells = <1>;
+ };
+
+ sys_rst: reset {
+ compatible = "socionext,uniphier-ld20-reset";
+ #reset-cells = <1>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
index acb0527fdc4a..358089687a69 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
@@ -29,7 +29,7 @@
memory {
device_type = "memory";
- reg = <0x0 0x0 0x40000000>;
+ reg = <0x0 0x0 0x0 0x40000000>;
};
};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
index 3e2e51fbd2bc..68a908334c7b 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
@@ -14,7 +14,7 @@
/ {
compatible = "xlnx,zynqmp";
#address-cells = <2>;
- #size-cells = <1>;
+ #size-cells = <2>;
cpus {
#address-cells = <1>;
@@ -51,6 +51,7 @@
pmu {
compatible = "arm,armv8-pmuv3";
+ interrupt-parent = <&gic>;
interrupts = <0 143 4>,
<0 144 4>,
<0 145 4>,
@@ -75,15 +76,15 @@
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
- ranges;
+ ranges = <0 0 0 0 0xffffffff>;
gic: interrupt-controller@f9010000 {
compatible = "arm,gic-400", "arm,cortex-a15-gic";
#interrupt-cells = <3>;
reg = <0x0 0xf9010000 0x10000>,
- <0x0 0xf902f000 0x2000>,
+ <0x0 0xf9020000 0x20000>,
<0x0 0xf9040000 0x20000>,
- <0x0 0xf906f000 0x2000>;
+ <0x0 0xf9060000 0x20000>;
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <1 9 0xf04>;
@@ -93,14 +94,14 @@
amba: amba {
compatible = "simple-bus";
#address-cells = <2>;
- #size-cells = <1>;
+ #size-cells = <2>;
ranges;
can0: can@ff060000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clock-names = "can_clk", "pclk";
- reg = <0x0 0xff060000 0x1000>;
+ reg = <0x0 0xff060000 0x0 0x1000>;
interrupts = <0 23 4>;
interrupt-parent = <&gic>;
tx-fifo-depth = <0x40>;
@@ -111,7 +112,7 @@
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clock-names = "can_clk", "pclk";
- reg = <0x0 0xff070000 0x1000>;
+ reg = <0x0 0xff070000 0x0 0x1000>;
interrupts = <0 24 4>;
interrupt-parent = <&gic>;
tx-fifo-depth = <0x40>;
@@ -123,7 +124,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 57 4>, <0 57 4>;
- reg = <0x0 0xff0b0000 0x1000>;
+ reg = <0x0 0xff0b0000 0x0 0x1000>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
@@ -134,7 +135,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 59 4>, <0 59 4>;
- reg = <0x0 0xff0c0000 0x1000>;
+ reg = <0x0 0xff0c0000 0x0 0x1000>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
@@ -145,7 +146,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 61 4>, <0 61 4>;
- reg = <0x0 0xff0d0000 0x1000>;
+ reg = <0x0 0xff0d0000 0x0 0x1000>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
@@ -156,7 +157,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 63 4>, <0 63 4>;
- reg = <0x0 0xff0e0000 0x1000>;
+ reg = <0x0 0xff0e0000 0x0 0x1000>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
@@ -170,7 +171,7 @@
interrupts = <0 16 4>;
interrupt-controller;
#interrupt-cells = <2>;
- reg = <0x0 0xff0a0000 0x1000>;
+ reg = <0x0 0xff0a0000 0x0 0x1000>;
};
i2c0: i2c@ff020000 {
@@ -178,7 +179,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 17 4>;
- reg = <0x0 0xff020000 0x1000>;
+ reg = <0x0 0xff020000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
@@ -188,15 +189,54 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 18 4>;
- reg = <0x0 0xff030000 0x1000>;
+ reg = <0x0 0xff030000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
+ pcie: pcie@fd0e0000 {
+ compatible = "xlnx,nwl-pcie-2.11";
+ status = "disabled";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ msi-controller;
+ device_type = "pci";
+ interrupt-parent = <&gic>;
+ interrupts = <0 118 4>,
+ <0 117 4>,
+ <0 116 4>,
+ <0 115 4>, /* MSI_1 [63...32] */
+ <0 114 4>; /* MSI_0 [31...0] */
+ interrupt-names = "misc", "dummy", "intx",
+ "msi1", "msi0";
+ msi-parent = <&pcie>;
+ reg = <0x0 0xfd0e0000 0x0 0x1000>,
+ <0x0 0xfd480000 0x0 0x1000>,
+ <0x80 0x00000000 0x0 0x1000000>;
+ reg-names = "breg", "pcireg", "cfg";
+ ranges = <0x02000000 0x00000000 0xe0000000 0x00000000
+ 0xe0000000 0x00000000 0x10000000
+ /* non-prefetchable memory */
+ 0x43000000 0x00000006 0x00000000 0x00000006
+ 0x00000000 0x00000002 0x00000000>;
+ /* prefetchable memory */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc 0x1>,
+ <0x0 0x0 0x0 0x2 &pcie_intc 0x2>,
+ <0x0 0x0 0x0 0x3 &pcie_intc 0x3>,
+ <0x0 0x0 0x0 0x4 &pcie_intc 0x4>;
+ pcie_intc: legacy-interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+
sata: ahci@fd0c0000 {
compatible = "ceva,ahci-1v84";
status = "disabled";
- reg = <0x0 0xfd0c0000 0x2000>;
+ reg = <0x0 0xfd0c0000 0x0 0x2000>;
interrupt-parent = <&gic>;
interrupts = <0 133 4>;
};
@@ -206,7 +246,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 48 4>;
- reg = <0x0 0xff160000 0x1000>;
+ reg = <0x0 0xff160000 0x0 0x1000>;
clock-names = "clk_xin", "clk_ahb";
};
@@ -215,13 +255,13 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 49 4>;
- reg = <0x0 0xff170000 0x1000>;
+ reg = <0x0 0xff170000 0x0 0x1000>;
clock-names = "clk_xin", "clk_ahb";
};
smmu: smmu@fd800000 {
compatible = "arm,mmu-500";
- reg = <0x0 0xfd800000 0x20000>;
+ reg = <0x0 0xfd800000 0x0 0x20000>;
#global-interrupts = <1>;
interrupt-parent = <&gic>;
interrupts = <0 157 4>,
@@ -236,7 +276,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 19 4>;
- reg = <0x0 0xff040000 0x1000>;
+ reg = <0x0 0xff040000 0x0 0x1000>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
@@ -247,7 +287,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 20 4>;
- reg = <0x0 0xff050000 0x1000>;
+ reg = <0x0 0xff050000 0x0 0x1000>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
@@ -258,7 +298,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 36 4>, <0 37 4>, <0 38 4>;
- reg = <0x0 0xff110000 0x1000>;
+ reg = <0x0 0xff110000 0x0 0x1000>;
timer-width = <32>;
};
@@ -267,7 +307,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 39 4>, <0 40 4>, <0 41 4>;
- reg = <0x0 0xff120000 0x1000>;
+ reg = <0x0 0xff120000 0x0 0x1000>;
timer-width = <32>;
};
@@ -276,7 +316,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 42 4>, <0 43 4>, <0 44 4>;
- reg = <0x0 0xff130000 0x1000>;
+ reg = <0x0 0xff130000 0x0 0x1000>;
timer-width = <32>;
};
@@ -285,7 +325,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 45 4>, <0 46 4>, <0 47 4>;
- reg = <0x0 0xff140000 0x1000>;
+ reg = <0x0 0xff140000 0x0 0x1000>;
timer-width = <32>;
};
@@ -294,7 +334,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 21 4>;
- reg = <0x0 0xff000000 0x1000>;
+ reg = <0x0 0xff000000 0x0 0x1000>;
clock-names = "uart_clk", "pclk";
};
@@ -303,7 +343,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 22 4>;
- reg = <0x0 0xff010000 0x1000>;
+ reg = <0x0 0xff010000 0x0 0x1000>;
clock-names = "uart_clk", "pclk";
};
@@ -312,7 +352,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 65 4>;
- reg = <0x0 0xfe200000 0x40000>;
+ reg = <0x0 0xfe200000 0x0 0x40000>;
clock-names = "clk_xin", "clk_ahb";
};
@@ -321,7 +361,7 @@
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 70 4>;
- reg = <0x0 0xfe300000 0x40000>;
+ reg = <0x0 0xfe300000 0x0 0x40000>;
clock-names = "clk_xin", "clk_ahb";
};
@@ -329,8 +369,8 @@
compatible = "cdns,wdt-r1p2";
status = "disabled";
interrupt-parent = <&gic>;
- interrupts = <0 52 1>;
- reg = <0x0 0xfd4d0000 0x1000>;
+ interrupts = <0 113 1>;
+ reg = <0x0 0xfd4d0000 0x0 0x1000>;
timeout-sec = <10>;
};
};
diff --git a/arch/arm64/boot/dts/zte/Makefile b/arch/arm64/boot/dts/zte/Makefile
new file mode 100644
index 000000000000..667806620f59
--- /dev/null
+++ b/arch/arm64/boot/dts/zte/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_ZX) += zx296718-evb.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/zte/zx296718-evb.dts b/arch/arm64/boot/dts/zte/zx296718-evb.dts
new file mode 100644
index 000000000000..e164ff6de5fc
--- /dev/null
+++ b/arch/arm64/boot/dts/zte/zx296718-evb.dts
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 ZTE Corporation.
+ * Copyright 2016 Linaro Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
+ */
+
+/dts-v1/;
+#include "zx296718.dtsi"
+
+/ {
+ model = "ZTE zx296718 evaluation board";
+ compatible = "zte,zx296718-evb", "zte,zx296718";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@40000000 {
+ device_type = "memory";
+ reg = <0x40000000 0x40000000>;
+ };
+
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/zte/zx296718.dtsi b/arch/arm64/boot/dts/zte/zx296718.dtsi
new file mode 100644
index 000000000000..a223066f24ce
--- /dev/null
+++ b/arch/arm64/boot/dts/zte/zx296718.dtsi
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2016 ZTE Corporation.
+ * Copyright 2016 Linaro Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ compatible = "zte,zx296718";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ core2 {
+ cpu = <&cpu2>;
+ };
+ core3 {
+ cpu = <&cpu3>;
+ };
+ };
+ };
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ };
+
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x1>;
+ enable-method = "psci";
+ };
+
+ cpu2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x2>;
+ enable-method = "psci";
+ };
+
+ cpu3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x3>;
+ enable-method = "psci";
+ };
+ };
+
+ clk24k: clk-24k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000>;
+ clock-output-names = "rtcclk";
+ };
+
+ osc32k: clk-osc32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32000>;
+ clock-output-names = "osc32k";
+ };
+
+ osc12m: clk-osc12m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ clock-output-names = "osc12m";
+ };
+
+ osc24m: clk-osc24m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24m";
+ };
+
+ osc25m: clk-osc25m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ clock-output-names = "osc25m";
+ };
+
+ osc60m: clk-osc60m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <60000000>;
+ clock-output-names = "osc60m";
+ };
+
+ osc99m: clk-osc99m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <99000000>;
+ clock-output-names = "osc99m";
+ };
+
+ osc125m: clk-osc125m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <125000000>;
+ clock-output-names = "osc125m";
+ };
+
+ osc198m: clk-osc198m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <198000000>;
+ clock-output-names = "osc198m";
+ };
+
+ pll_audio: clk-pll-884m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <884000000>;
+ clock-output-names = "pll_audio";
+ };
+
+ pll_ddr: clk-pll-932m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <932000000>;
+ clock-output-names = "pll_ddr";
+ };
+
+ pll_hsic: clk-pll-960m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <960000000>;
+ clock-output-names = "pll_hsic";
+ };
+
+ pll_mac: clk-pll-1000m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000000>;
+ clock-output-names = "pll_mac";
+ };
+
+ pll_vga: clk-pll-1073m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1073000000>;
+ clock-output-names = "pll_vga";
+ };
+
+ pll_mm0: clk-pll-1188m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1188000000>;
+ clock-output-names = "pll_mm0";
+ };
+
+ pll_mm1: clk-pll-1296m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1296000000>;
+ clock-output-names = "pll_mm1";
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gic: interrupt-controller@2a00000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ #redistributor-regions = <6>;
+ redistributor-stride = <0x0 0x40000>;
+ interrupt-controller;
+ reg = <0x02a00000 0x10000>,
+ <0x02b00000 0x20000>,
+ <0x02b20000 0x20000>,
+ <0x02b40000 0x20000>,
+ <0x02b60000 0x20000>,
+ <0x02b80000 0x20000>,
+ <0x02ba0000 0x20000>;
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+
+ aon_sysctrl: aon-sysctrl@116000 {
+ compatible = "zte,zx296718-aon-sysctrl", "syscon";
+ reg = <0x116000 0x1000>;
+ };
+
+ uart0: uart@11f000 {
+ compatible = "arm,pl011", "arm,primecell";
+ arm,primecell-periphid = <0x001feffe>;
+ reg = <0x11f000 0x1000>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24m>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ dma: dma-controller@1460000 {
+ compatible = "zte,zx296702-dma";
+ reg = <0x01460000 0x1000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24m>;
+ clock-names = "dmaclk";
+ #dma-cells = <1>;
+ dma-channels = <32>;
+ dma-requests = <32>;
+ };
+
+ sysctrl: sysctrl@1463000 {
+ compatible = "zte,zx296718-sysctrl", "syscon";
+ reg = <0x1463000 0x1000>;
+ };
+ };
+};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index eadf4855ad2d..dab2cb0c1f1c 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -57,10 +57,12 @@ CONFIG_ARCH_UNIPHIER=y
CONFIG_ARCH_VEXPRESS=y
CONFIG_ARCH_VULCAN=y
CONFIG_ARCH_XGENE=y
+CONFIG_ARCH_ZX=y
CONFIG_ARCH_ZYNQMP=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_PCI_IOV=y
+CONFIG_PCI_AARDVARK=y
CONFIG_PCIE_RCAR=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_PCI_XGENE=y
@@ -82,6 +84,7 @@ CONFIG_COMPAT=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_CPUIDLE=y
CONFIG_CPU_FREQ=y
+CONFIG_CPUFREQ_DT=y
CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
CONFIG_ARM_SCPI_CPUFREQ=y
CONFIG_NET=y
@@ -120,6 +123,14 @@ CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
CONFIG_BPF_JIT=y
+CONFIG_BT=m
+CONFIG_BT_HIDP=m
+# CONFIG_BT_HS is not set
+# CONFIG_BT_LE is not set
+CONFIG_BT_LEDS=y
+# CONFIG_BT_DEBUGFS is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_LL=y
CONFIG_CFG80211=m
CONFIG_MAC80211=m
CONFIG_MAC80211_LEDS=y
@@ -139,7 +150,8 @@ CONFIG_VIRTIO_BLK=y
CONFIG_SRAM=y
# CONFIG_SCSI_PROC_FS is not set
CONFIG_BLK_DEV_SD=y
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_HISI_SAS=y
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_AHCI_PLATFORM=y
@@ -160,6 +172,8 @@ CONFIG_VIRTIO_NET=y
CONFIG_AMD_XGBE=y
CONFIG_NET_XGENE=y
CONFIG_MACB=y
+CONFIG_HNS_DSAF=y
+CONFIG_HNS_ENET=y
CONFIG_E1000E=y
CONFIG_IGB=y
CONFIG_IGBVF=y
@@ -186,6 +200,7 @@ CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PM8941_PWRKEY=y
+CONFIG_INPUT_HISI_POWERKEY=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_AMBAKMI=y
CONFIG_LEGACY_PTY_COUNT=16
@@ -211,12 +226,12 @@ CONFIG_SERIAL_XILINX_PS_UART=y
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
CONFIG_SERIAL_MVEBU_UART=y
CONFIG_VIRTIO_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_IMX=y
+CONFIG_I2C_MESON=y
CONFIG_I2C_MV64XXX=y
CONFIG_I2C_QUP=y
CONFIG_I2C_TEGRA=y
@@ -224,6 +239,7 @@ CONFIG_I2C_UNIPHIER_F=y
CONFIG_I2C_RCAR=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SPI=y
+CONFIG_SPI_MESON_SPIFC=m
CONFIG_SPI_ORION=y
CONFIG_SPI_PL022=y
CONFIG_SPI_QUP=y
@@ -234,6 +250,7 @@ CONFIG_PINCTRL_SINGLE=y
CONFIG_PINCTRL_MAX77620=y
CONFIG_PINCTRL_MSM8916=y
CONFIG_PINCTRL_MSM8996=y
+CONFIG_PINCTRL_QDF2XXX=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_DWAPB=y
@@ -252,10 +269,14 @@ CONFIG_SENSORS_INA2XX=m
CONFIG_SENSORS_ARM_SCPI=y
CONFIG_THERMAL=y
CONFIG_THERMAL_EMULATION=y
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
+CONFIG_CPU_THERMAL=y
CONFIG_EXYNOS_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_RENESAS_WDT=y
CONFIG_S3C2410_WATCHDOG=y
+CONFIG_MESON_GXBB_WATCHDOG=m
+CONFIG_MESON_WATCHDOG=m
CONFIG_MFD_MAX77620=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_SEC_CORE=y
@@ -264,6 +285,7 @@ CONFIG_REGULATOR=y
CONFIG_MFD_CROS_EC=y
CONFIG_MFD_CROS_EC_I2C=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_HI655X=y
CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_PWM=y
@@ -274,6 +296,8 @@ CONFIG_DRM=m
CONFIG_DRM_NOUVEAU=m
CONFIG_DRM_TEGRA=m
CONFIG_DRM_PANEL_SIMPLE=m
+CONFIG_DRM_I2C_ADV7511=m
+CONFIG_DRM_HISI_KIRIN=m
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
CONFIG_BACKLIGHT_GENERIC=m
@@ -291,6 +315,7 @@ CONFIG_SND_SOC_AK4613=y
CONFIG_USB=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PLATFORM=y
CONFIG_USB_XHCI_RCAR=y
CONFIG_USB_EHCI_EXYNOS=y
CONFIG_USB_XHCI_TEGRA=y
@@ -300,6 +325,7 @@ CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_EXYNOS=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_RENESAS_USBHS=m
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC2=y
CONFIG_USB_DWC3=y
@@ -311,15 +337,18 @@ CONFIG_USB_HSIC_USB3503=y
CONFIG_USB_MSM_OTG=y
CONFIG_USB_ULPI=y
CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=m
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ACPI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_OF_ESDHC=y
CONFIG_MMC_SDHCI_TEGRA=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MMC_SPI=y
+CONFIG_MMC_SDHI=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_EXYNOS=y
CONFIG_MMC_DW_K3=y
@@ -345,6 +374,8 @@ CONFIG_DMADEVICES=y
CONFIG_PL330_DMA=y
CONFIG_TEGRA20_APB_DMA=y
CONFIG_QCOM_BAM_DMA=y
+CONFIG_QCOM_HIDMA_MGMT=y
+CONFIG_QCOM_HIDMA=y
CONFIG_RCAR_DMAC=y
CONFIG_VFIO=y
CONFIG_VFIO_PCI=y
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 5ce9b2929e0d..1105aab1e6d6 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -122,6 +122,7 @@ SECTIONS
ENTRY_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
HYPERVISOR_TEXT
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 682b2478691a..eb4a3fcfbaff 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -11,7 +11,8 @@
#include <linux/init.h>
#include <linux/kallsyms.h>
#include <linux/kdebug.h>
-#include <linux/module.h>
+#include <linux/extable.h>
+#include <linux/module.h> /* print_modules */
#include <linux/notifier.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index a4589176bed5..17f2730eb497 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -52,6 +52,7 @@ SECTIONS
KPROBES_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index a4b7edac8f10..b3977e9208a3 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -10,7 +10,7 @@
*/
#include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/extable.h>
#include <linux/pagemap.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index d920b959ff3a..68069a120055 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -33,6 +33,7 @@ SECTIONS
#ifndef CONFIG_SCHEDULE_L1
SCHED_TEXT
#endif
+ CPUIDLE_TEXT
LOCK_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
diff --git a/arch/c6x/kernel/vmlinux.lds.S b/arch/c6x/kernel/vmlinux.lds.S
index 50bc10f97bcb..a1a5c166bc9b 100644
--- a/arch/c6x/kernel/vmlinux.lds.S
+++ b/arch/c6x/kernel/vmlinux.lds.S
@@ -70,6 +70,7 @@ SECTIONS
_stext = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index deba2662b9f3..71b758dc3a96 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -30,7 +30,7 @@ config GENERIC_CALIBRATE_DELAY
default y
config NO_IOPORT_MAP
- def_bool y
+ def_bool y if !PCI
config FORCE_MAX_ZONEORDER
int
diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c
index bdc25aa43468..28292da49664 100644
--- a/arch/cris/arch-v10/drivers/axisflashmap.c
+++ b/arch/cris/arch-v10/drivers/axisflashmap.c
@@ -177,15 +177,6 @@ static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
},
};
-#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
-/* Main flash device */
-static struct mtd_partition main_partition = {
- .name = "main",
- .size = 0,
- .offset = 0
-};
-#endif
-
/*
* Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
* chips in that order (because the amd_flash-driver is faster).
@@ -369,16 +360,6 @@ static int __init init_axis_flash(void)
pidx++;
}
-#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
- if (mymtd) {
- main_partition.size = mymtd->size;
- err = mtd_device_register(mymtd, &main_partition, 1);
- if (err)
- panic("axisflashmap: Could not initialize "
- "partition for whole main mtd device!\n");
- }
-#endif
-
if (mymtd) {
if (use_default_ptable) {
printk(KERN_INFO " Using default partition table.\n");
diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c
index f679a19dfeb8..c903a9e53a47 100644
--- a/arch/cris/arch-v10/drivers/eeprom.c
+++ b/arch/cris/arch-v10/drivers/eeprom.c
@@ -395,7 +395,7 @@ static int eeprom_open(struct inode * inode, struct file * file)
static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
{
/*
- * orig 0: position from begning of eeprom
+ * orig 0: position from beginning of eeprom
* orig 1: relative from current position
* orig 2: position from last eeprom address
*/
diff --git a/arch/cris/arch-v10/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S
index e541d3d8f922..93310124333f 100644
--- a/arch/cris/arch-v10/lib/dram_init.S
+++ b/arch/cris/arch-v10/lib/dram_init.S
@@ -3,7 +3,7 @@
* This file is intended to be included from other assembler files
*
* Note: This file may not modify r9 because r9 is used to carry
- * information from the decompresser to the kernel
+ * information from the decompressor to the kernel
*
* Copyright (C) 2000-2012 Axis Communications AB
*
diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c
index 2081d8b45f06..b5698c876fcc 100644
--- a/arch/cris/arch-v32/drivers/cryptocop.c
+++ b/arch/cris/arch-v32/drivers/cryptocop.c
@@ -1210,7 +1210,7 @@ static int cryptocop_setup_dma_list(struct cryptocop_operation *operation, struc
assert(active_count >= eop_needed_count);
assert((eop_needed_count == 0) || (eop_needed_count == 1));
if (eop_needed_count) {
- /* This means that the bulk operation (cipeher/m2m) is terminated. */
+ /* This means that the bulk operation (cipher/m2m) is terminated. */
if (active_count > 1) {
/* Use zero length EOP descriptor. */
struct cryptocop_dma_desc *ed = alloc_cdesc(alloc_flag);
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 64a5fb93767d..212266a2c5d9 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -1,6 +1,6 @@
#include <linux/pci.h>
#include <linux/kernel.h>
-#include <arch/hwregs/intr_vect.h>
+#include <hwregs/intr_vect.h>
void pcibios_fixup_bus(struct pci_bus *b)
{
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c
index e989cee77414..ef515af1a377 100644
--- a/arch/cris/arch-v32/drivers/sync_serial.c
+++ b/arch/cris/arch-v32/drivers/sync_serial.c
@@ -1627,6 +1627,12 @@ static int __init etrax_sync_serial_init(void)
/* Create a sysfs class for syncser */
syncser_class = class_create(THIS_MODULE, "syncser_class");
+ if (IS_ERR(syncser_class)) {
+ pr_err("Failed to create a sysfs class for syncser\n");
+ unregister_chrdev_region(syncser_first, minor_count);
+ cdev_del(syncser_cdev);
+ return -1;
+ }
/* Initialize Ports */
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c
index 5c84dbb99f30..eb4e0ff36295 100644
--- a/arch/cris/arch-v32/kernel/fasttimer.c
+++ b/arch/cris/arch-v32/kernel/fasttimer.c
@@ -318,11 +318,13 @@ timer_trig_interrupt(int irq, void *dev_id)
static void timer_trig_handler(struct work_struct *work)
{
- reg_timer_rw_ack_intr ack_intr = { 0 };
- reg_timer_rw_intr_mask intr_mask;
- reg_timer_rw_trig_cfg trig_cfg = { 0 };
- struct fast_timer *t;
- unsigned long flags;
+ reg_timer_rw_ack_intr ack_intr = { 0 };
+ reg_timer_rw_intr_mask intr_mask;
+ reg_timer_rw_trig_cfg trig_cfg = { 0 };
+ struct fast_timer *t;
+ fast_timer_function_type *f;
+ unsigned long d;
+ unsigned long flags;
/* We keep interrupts disabled not only when we modify the
* fast timer list, but any time we hold a reference to a
@@ -350,9 +352,6 @@ static void timer_trig_handler(struct work_struct *work)
fast_timer_running = 0;
fast_timer_ints++;
- fast_timer_function_type *f;
- unsigned long d;
-
t = fast_timer_list;
while (t) {
struct fasttime_t tv;
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index 6de8db67cb09..b07da4b695aa 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -471,9 +471,8 @@ init_IRQ(void)
irq_set_default_host(domain);
of_node_put(np);
- for (i = FIRST_IRQ, j = 0; j < NBR_INTR_VECT; i++, j++) {
+ for (i = FIRST_IRQ, j = 0; j < NBR_INTR_VECT && j < MACH_IRQS; i++, j++)
set_exception_vector(i, interrupt[j]);
- }
/* Mark Timer and IPI IRQs as CPU local */
irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
diff --git a/arch/cris/arch-v32/mach-a3/dma.c b/arch/cris/arch-v32/mach-a3/dma.c
index 47c64bf40eae..11f417f4da98 100644
--- a/arch/cris/arch-v32/mach-a3/dma.c
+++ b/arch/cris/arch-v32/mach-a3/dma.c
@@ -41,7 +41,6 @@ int crisv32_request_dma(unsigned int dmanr, const char *device_id,
if (options & DMA_PANIC_ON_ERROR)
panic("request_dma error!");
- spin_unlock_irqrestore(&dma_lock, flags);
return -EBUSY;
}
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
diff --git a/arch/cris/arch-v32/mach-a3/dram_init.S b/arch/cris/arch-v32/mach-a3/dram_init.S
index 5c4f24dce94c..7dc26bdb26b5 100644
--- a/arch/cris/arch-v32/mach-a3/dram_init.S
+++ b/arch/cris/arch-v32/mach-a3/dram_init.S
@@ -3,7 +3,7 @@
* This file is intended to be included from other assembler files
*
* Note: This file may not modify r8 or r9 because they are used to
- * carry information from the decompresser to the kernel
+ * carry information from the decompressor to the kernel
*
* Copyright (C) 2005-2007 Axis Communications AB
*
diff --git a/arch/cris/arch-v32/mach-fs/dma.c b/arch/cris/arch-v32/mach-fs/dma.c
index fc6416a671ea..7c93679c02ad 100644
--- a/arch/cris/arch-v32/mach-fs/dma.c
+++ b/arch/cris/arch-v32/mach-fs/dma.c
@@ -43,7 +43,6 @@ int crisv32_request_dma(unsigned int dmanr, const char *device_id,
}
if (options & DMA_PANIC_ON_ERROR)
panic("request_dma error!");
- spin_unlock_irqrestore(&dma_lock, flags);
return -EBUSY;
}
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
diff --git a/arch/cris/arch-v32/mach-fs/dram_init.S b/arch/cris/arch-v32/mach-fs/dram_init.S
index d3ce2eb04cb1..2ed51e247e8f 100644
--- a/arch/cris/arch-v32/mach-fs/dram_init.S
+++ b/arch/cris/arch-v32/mach-fs/dram_init.S
@@ -3,7 +3,7 @@
* This file is intended to be included from other assembler files
*
* Note: This file may not modify r8 or r9 because they are used to
- * carry information from the decompresser to the kernel
+ * carry information from the decompressor to the kernel
*
* Copyright (C) 2000-2007 Axis Communications AB
*
diff --git a/arch/cris/arch-v32/mm/intmem.c b/arch/cris/arch-v32/mm/intmem.c
index 9ef56092a4c5..c80728401487 100644
--- a/arch/cris/arch-v32/mm/intmem.c
+++ b/arch/cris/arch-v32/mm/intmem.c
@@ -113,14 +113,14 @@ void crisv32_intmem_free(void* addr)
allocation->status = STATUS_FREE;
/* Join with prev and/or next if also free */
- if ((prev != &intmem_allocations) &&
+ if ((&prev->entry != &intmem_allocations) &&
(prev->status == STATUS_FREE)) {
prev->size += allocation->size;
list_del(&allocation->entry);
kfree(allocation);
allocation = prev;
}
- if ((next != &intmem_allocations) &&
+ if ((&next->entry != &intmem_allocations) &&
(next->status == STATUS_FREE)) {
allocation->size += next->size;
list_del(&next->entry);
@@ -145,5 +145,12 @@ unsigned long crisv32_intmem_virt_to_phys(void* addr)
(unsigned long)intmem_virtual + MEM_INTMEM_START +
RESERVED_SIZE);
}
-device_initcall(crisv32_intmem_init);
+
+static int __init crisv32_intmem_setup(void)
+{
+ crisv32_intmem_init();
+
+ return 0;
+}
+device_initcall(crisv32_intmem_setup);
diff --git a/arch/cris/configs/artpec_3_defconfig b/arch/cris/configs/artpec_3_defconfig
index 70e497e0b03e..d31851f29db8 100644
--- a/arch/cris/configs/artpec_3_defconfig
+++ b/arch/cris/configs/artpec_3_defconfig
@@ -25,7 +25,6 @@ CONFIG_MTD_RAM=y
CONFIG_MTD_MTDRAM=y
CONFIG_MTDRAM_TOTAL_SIZE=0
CONFIG_MTDRAM_ERASE_SIZE=64
-CONFIG_MTDRAM_ABS_POS=0x0
CONFIG_BLK_DEV_RAM=y
CONFIG_NETDEVICES=y
# CONFIG_INPUT is not set
diff --git a/arch/cris/configs/dev88_defconfig b/arch/cris/configs/dev88_defconfig
new file mode 100644
index 000000000000..beff4ee6edb3
--- /dev/null
+++ b/arch/cris/configs/dev88_defconfig
@@ -0,0 +1,48 @@
+CONFIG_BUILTIN_DTB="dev88"
+# CONFIG_SWAP is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ETRAX_FAST_TIMER=y
+CONFIG_ETRAXFS=y
+CONFIG_ETRAX_DRAM_SIZE=32
+CONFIG_ETRAX_FLASH1_SIZE=4
+CONFIG_ETRAX_MEM_GRP1_CONFIG=0x40688
+CONFIG_ETRAX_MEM_GRP3_CONFIG=0x3
+CONFIG_ETRAX_MEM_GRP4_CONFIG=0x10040
+CONFIG_ETRAX_SDRAM_GRP0_CONFIG=0x958
+CONFIG_ETRAX_SDRAM_TIMING=0x824a
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_ETRAX_ETHERNET=y
+CONFIG_ETRAX_AXISFLASHMAP=y
+CONFIG_DEVTMPFS=y
+CONFIG_MTD_RAM=y
+CONFIG_MTDRAM_TOTAL_SIZE=0
+CONFIG_MTDRAM_ERASE_SIZE=64
+CONFIG_BLK_DEV_RAM=y
+CONFIG_NETDEVICES=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_ETRAXFS=y
+CONFIG_SERIAL_ETRAXFS_CONSOLE=y
+CONFIG_GPIO_ETRAXFS=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
diff --git a/arch/cris/configs/etrax-100lx_v2_defconfig b/arch/cris/configs/etrax-100lx_v2_defconfig
index a85aabf92be5..d90ac95c1e44 100644
--- a/arch/cris/configs/etrax-100lx_v2_defconfig
+++ b/arch/cris/configs/etrax-100lx_v2_defconfig
@@ -28,7 +28,6 @@ CONFIG_MTD_RAM=y
CONFIG_MTD_MTDRAM=y
CONFIG_MTDRAM_TOTAL_SIZE=0
CONFIG_MTDRAM_ERASE_SIZE=64
-CONFIG_MTDRAM_ABS_POS=0x0
CONFIG_BLK_DEV_RAM=y
CONFIG_NETDEVICES=y
# CONFIG_INPUT is not set
diff --git a/arch/cris/configs/etraxfs_defconfig b/arch/cris/configs/etraxfs_defconfig
index 91232680d6c8..f714e9dfef9b 100644
--- a/arch/cris/configs/etraxfs_defconfig
+++ b/arch/cris/configs/etraxfs_defconfig
@@ -25,7 +25,6 @@ CONFIG_MTD_RAM=y
CONFIG_MTD_MTDRAM=y
CONFIG_MTDRAM_TOTAL_SIZE=0
CONFIG_MTDRAM_ERASE_SIZE=64
-CONFIG_MTDRAM_ABS_POS=0x0
CONFIG_BLK_DEV_RAM=y
CONFIG_NETDEVICES=y
# CONFIG_INPUT is not set
diff --git a/arch/cris/include/arch-v32/arch/cryptocop.h b/arch/cris/include/arch-v32/arch/cryptocop.h
index 716e434e9269..a56ac61a9931 100644
--- a/arch/cris/include/arch-v32/arch/cryptocop.h
+++ b/arch/cris/include/arch-v32/arch/cryptocop.h
@@ -81,7 +81,7 @@ struct cryptocop_tfrm_cfg {
unsigned int flags; /* DECRYPT, ENCRYPT, EXPLICIT_IV */
- /* CBC initialisation vector for cihers. */
+ /* CBC initialisation vector for ciphers. */
u8 iv[CRYPTOCOP_MAX_IV_LENGTH];
/* The position in output where to write the transform output. The order
diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h
index cce8664d5dd6..fe0b2a0ae03b 100644
--- a/arch/cris/include/asm/io.h
+++ b/arch/cris/include/asm/io.h
@@ -8,34 +8,6 @@
#include <asm-generic/iomap.h>
#include <linux/kernel.h>
-struct cris_io_operations
-{
- u32 (*read_mem)(void *addr, int size);
- void (*write_mem)(u32 val, int size, void *addr);
- u32 (*read_io)(u32 port, void *addr, int size, int count);
- void (*write_io)(u32 port, void *addr, int size, int count);
-};
-
-#ifdef CONFIG_PCI
-extern struct cris_io_operations *cris_iops;
-#else
-#define cris_iops ((struct cris_io_operations*)NULL)
-#endif
-
-/*
- * Change virtual addresses to physical addresses and vv.
- */
-
-static inline unsigned long virt_to_phys(volatile void * address)
-{
- return __pa(address);
-}
-
-static inline void * phys_to_virt(unsigned long address)
-{
- return __va(address);
-}
-
extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
extern void __iomem * __ioremap_prot(unsigned long phys_addr, unsigned long size, pgprot_t prot);
@@ -48,147 +20,6 @@ extern void iounmap(volatile void * __iomem addr);
extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
-/*
- * IO bus memory addresses are also 1:1 with the physical address
- */
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the CRIS architecture, we just read/write the
- * memory location directly.
- */
-#ifdef CONFIG_PCI
-#define PCI_SPACE(x) ((((unsigned)(x)) & 0x10000000) == 0x10000000)
-#else
-#define PCI_SPACE(x) 0
-#endif
-static inline unsigned char readb(const volatile void __iomem *addr)
-{
- if (PCI_SPACE(addr) && cris_iops)
- return cris_iops->read_mem((void*)addr, 1);
- else
- return *(volatile unsigned char __force *) addr;
-}
-static inline unsigned short readw(const volatile void __iomem *addr)
-{
- if (PCI_SPACE(addr) && cris_iops)
- return cris_iops->read_mem((void*)addr, 2);
- else
- return *(volatile unsigned short __force *) addr;
-}
-static inline unsigned int readl(const volatile void __iomem *addr)
-{
- if (PCI_SPACE(addr) && cris_iops)
- return cris_iops->read_mem((void*)addr, 4);
- else
- return *(volatile unsigned int __force *) addr;
-}
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-#define __raw_readb readb
-#define __raw_readw readw
-#define __raw_readl readl
-
-static inline void writeb(unsigned char b, volatile void __iomem *addr)
-{
- if (PCI_SPACE(addr) && cris_iops)
- cris_iops->write_mem(b, 1, (void*)addr);
- else
- *(volatile unsigned char __force *) addr = b;
-}
-static inline void writew(unsigned short b, volatile void __iomem *addr)
-{
- if (PCI_SPACE(addr) && cris_iops)
- cris_iops->write_mem(b, 2, (void*)addr);
- else
- *(volatile unsigned short __force *) addr = b;
-}
-static inline void writel(unsigned int b, volatile void __iomem *addr)
-{
- if (PCI_SPACE(addr) && cris_iops)
- cris_iops->write_mem(b, 4, (void*)addr);
- else
- *(volatile unsigned int __force *) addr = b;
-}
-#define writeb_relaxed(b, addr) writeb(b, addr)
-#define writew_relaxed(b, addr) writew(b, addr)
-#define writel_relaxed(b, addr) writel(b, addr)
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-
-#define mmiowb()
-
-#define memset_io(a,b,c) memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
-
-
-/* I/O port access. Normally there is no I/O space on CRIS but when
- * Cardbus/PCI is enabled the request is passed through the bridge.
- */
-
-#define IO_SPACE_LIMIT 0xffff
-#define inb(port) (cris_iops ? cris_iops->read_io(port,NULL,1,1) : 0)
-#define inw(port) (cris_iops ? cris_iops->read_io(port,NULL,2,1) : 0)
-#define inl(port) (cris_iops ? cris_iops->read_io(port,NULL,4,1) : 0)
-#define insb(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,1,count) : 0)
-#define insw(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,2,count) : 0)
-#define insl(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,4,count) : 0)
-static inline void outb(unsigned char data, unsigned int port)
-{
- if (cris_iops)
- cris_iops->write_io(port, (void *) &data, 1, 1);
-}
-static inline void outw(unsigned short data, unsigned int port)
-{
- if (cris_iops)
- cris_iops->write_io(port, (void *) &data, 2, 1);
-}
-static inline void outl(unsigned int data, unsigned int port)
-{
- if (cris_iops)
- cris_iops->write_io(port, (void *) &data, 4, 1);
-}
-static inline void outsb(unsigned int port, const void *addr,
- unsigned long count)
-{
- if (cris_iops)
- cris_iops->write_io(port, (void *)addr, 1, count);
-}
-static inline void outsw(unsigned int port, const void *addr,
- unsigned long count)
-{
- if (cris_iops)
- cris_iops->write_io(port, (void *)addr, 2, count);
-}
-static inline void outsl(unsigned int port, const void *addr,
- unsigned long count)
-{
- if (cris_iops)
- cris_iops->write_io(port, (void *)addr, 4, count);
-}
-
-#define inb_p(port) inb(port)
-#define inw_p(port) inw(port)
-#define inl_p(port) inl(port)
-#define outb_p(val, port) outb((val), (port))
-#define outw_p(val, port) outw((val), (port))
-#define outl_p(val, port) outl((val), (port))
-
-/*
- * 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
+#include <asm-generic/io.h>
#endif
diff --git a/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h b/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h
index 5517f04153a4..c4b6b0e9b1da 100644
--- a/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h
+++ b/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h
@@ -61,7 +61,7 @@
#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_)
#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH)
-/*--- Obsolete. Kept for backw compatibility. ---*/
+/*--- Obsolete. Kept for backward compatibility. ---*/
/* Reads (or writes) a byte/uword/udword from the specified mode
register. */
#define IO_RD(reg) (*(volatile u32*)(reg))
diff --git a/arch/cris/kernel/vmlinux.lds.S b/arch/cris/kernel/vmlinux.lds.S
index 7552c2557506..979586261520 100644
--- a/arch/cris/kernel/vmlinux.lds.S
+++ b/arch/cris/kernel/vmlinux.lds.S
@@ -43,6 +43,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.text.__*)
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 112ef26c7f2e..94183d3639ef 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -6,7 +6,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/extable.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <arch/system.h>
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 7e958d829ec9..aa6e573d57da 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -63,6 +63,7 @@ SECTIONS
*(.text..tlbmiss)
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
#ifdef CONFIG_DEBUG_INFO
INIT_TEXT
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index cb5dfb02c88d..7f11da1b895e 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -29,6 +29,7 @@ SECTIONS
_stext = . ;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
#if defined(CONFIG_ROMKERNEL)
*(.int_redirect)
diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S
index 5f268c1071b3..ec87e67feb19 100644
--- a/arch/hexagon/kernel/vmlinux.lds.S
+++ b/arch/hexagon/kernel/vmlinux.lds.S
@@ -50,6 +50,7 @@ SECTIONS
_text = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.fixup)
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h
index f565ad376142..65d4bb2b6685 100644
--- a/arch/ia64/include/asm/atomic.h
+++ b/arch/ia64/include/asm/atomic.h
@@ -269,6 +269,22 @@ static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
+{
+ long c, old, dec;
+ c = atomic64_read(v);
+ for (;;) {
+ dec = c - 1;
+ if (unlikely(dec < 0))
+ break;
+ old = atomic64_cmpxchg((v), c, dec);
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return dec;
+}
+
/*
* Atomically add I to V and return TRUE if the resulting value is
* negative.
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index dc506b05ffbd..f89d20c97412 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -46,6 +46,7 @@ SECTIONS {
__end_ivt_text = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.gnu.linkonce.t*)
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 018e4a711d79..ad1fe56455aa 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -31,6 +31,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds
index 06a763f49fd3..d2c8abf1c8c4 100644
--- a/arch/m68k/kernel/vmlinux-nommu.lds
+++ b/arch/m68k/kernel/vmlinux-nommu.lds
@@ -45,6 +45,7 @@ SECTIONS {
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
. = ALIGN(16);
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index d0993594f558..5b5ce1e4d1ed 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -16,6 +16,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index 8080469ee6c1..fe5ea1974b16 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -16,6 +16,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
diff --git a/arch/metag/kernel/vmlinux.lds.S b/arch/metag/kernel/vmlinux.lds.S
index 150ace92c7ad..e6c700eaf207 100644
--- a/arch/metag/kernel/vmlinux.lds.S
+++ b/arch/metag/kernel/vmlinux.lds.S
@@ -21,6 +21,7 @@ SECTIONS
.text : {
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index 0a47f0410554..289d0e7f3e3a 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -33,6 +33,7 @@ SECTIONS {
EXIT_TEXT
EXIT_CALL
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 81556b843a8e..7f696f97f9dd 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -632,10 +632,10 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
}
}
-/* Decide whether to display the domain number in /proc */
+/* Display the domain number in /proc */
int pci_proc_domain(struct pci_bus *bus)
{
- return 0;
+ return pci_domain_nr(bus);
}
/* This header fixup will do the resource fixup for all devices as they are
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 212ff92920d2..1a322c807f22 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -30,7 +30,6 @@ config MIPS
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
select RTC_LIB if !MACH_LOONGSON64
select GENERIC_ATOMIC64 if !64BIT
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select HAVE_DMA_CONTIGUOUS
select HAVE_DMA_API_DEBUG
select GENERIC_IRQ_PROBE
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h
index 15e0fecbc300..6bf10e796553 100644
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -51,7 +51,8 @@ extern int cp0_fdc_irq;
extern int get_c0_fdc_int(void);
-void arch_trigger_all_cpu_backtrace(bool);
-#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
+ bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
#endif /* _ASM_IRQ_H */
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 70128d3f770a..9e9e94415d08 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -673,8 +673,6 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
struct file;
pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot);
-int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
- unsigned long size, pgprot_t *vma_prot);
#endif
/*
diff --git a/arch/mips/include/asm/uprobes.h b/arch/mips/include/asm/uprobes.h
index 70a4a2f173ff..b86d1ae07125 100644
--- a/arch/mips/include/asm/uprobes.h
+++ b/arch/mips/include/asm/uprobes.h
@@ -42,16 +42,4 @@ struct arch_uprobe_task {
unsigned long saved_trap_nr;
};
-extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup,
- struct mm_struct *mm, unsigned long addr);
-extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
-extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
-extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
-extern int arch_uprobe_exception_notify(struct notifier_block *self,
- unsigned long val, void *data);
-extern void arch_uprobe_abort_xol(struct arch_uprobe *aup,
- struct pt_regs *regs);
-extern unsigned long arch_uretprobe_hijack_return_addr(
- unsigned long trampoline_vaddr, struct pt_regs *regs);
-
#endif /* __ASM_UPROBES_H */
diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h
index ccdcfcbb24aa..655e2fb5395b 100644
--- a/arch/mips/include/uapi/asm/mman.h
+++ b/arch/mips/include/uapi/asm/mman.h
@@ -105,4 +105,9 @@
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
#endif /* _ASM_MMAN_H */
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index d2d061520a23..9514e5f2209f 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -569,9 +569,16 @@ static void arch_dump_stack(void *info)
dump_stack();
}
-void arch_trigger_all_cpu_backtrace(bool include_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
{
- smp_call_function(arch_dump_stack, NULL, 1);
+ long this_cpu = get_cpu();
+
+ if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
+ dump_stack();
+
+ smp_call_function_many(mask, arch_dump_stack, NULL, 1);
+
+ put_cpu();
}
int mips_get_process_fp_mode(struct task_struct *task)
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index a82c178d0bb9..d5de67591735 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -55,6 +55,7 @@ SECTIONS
.text : {
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/mn10300/kernel/vmlinux.lds.S b/arch/mn10300/kernel/vmlinux.lds.S
index 13c4814c29f8..2d5f1c3f1afb 100644
--- a/arch/mn10300/kernel/vmlinux.lds.S
+++ b/arch/mn10300/kernel/vmlinux.lds.S
@@ -30,6 +30,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.fixup)
diff --git a/arch/nios2/include/asm/cpuinfo.h b/arch/nios2/include/asm/cpuinfo.h
index e88fcae464d9..348bb228fec9 100644
--- a/arch/nios2/include/asm/cpuinfo.h
+++ b/arch/nios2/include/asm/cpuinfo.h
@@ -25,10 +25,10 @@ struct cpuinfo {
/* Core CPU configuration */
char cpu_impl[12];
u32 cpu_clock_freq;
- u32 mmu;
- u32 has_div;
- u32 has_mul;
- u32 has_mulx;
+ bool mmu;
+ bool has_div;
+ bool has_mul;
+ bool has_mulx;
/* CPU caches */
u32 icache_line_size;
diff --git a/arch/nios2/kernel/cpuinfo.c b/arch/nios2/kernel/cpuinfo.c
index 1d96de0bd4aa..1cccc36877bc 100644
--- a/arch/nios2/kernel/cpuinfo.c
+++ b/arch/nios2/kernel/cpuinfo.c
@@ -41,11 +41,6 @@ static inline u32 fcpu(struct device_node *cpu, const char *n)
return val;
}
-static inline u32 fcpu_has(struct device_node *cpu, const char *n)
-{
- return of_get_property(cpu, n, NULL) ? 1 : 0;
-}
-
void __init setup_cpuinfo(void)
{
struct device_node *cpu;
@@ -56,7 +51,7 @@ void __init setup_cpuinfo(void)
if (!cpu)
panic("%s: No CPU found in devicetree!\n", __func__);
- if (!fcpu_has(cpu, "altr,has-initda"))
+ if (!of_property_read_bool(cpu, "altr,has-initda"))
panic("initda instruction is unimplemented. Please update your "
"hardware system to have more than 4-byte line data "
"cache\n");
@@ -69,10 +64,10 @@ void __init setup_cpuinfo(void)
else
strcpy(cpuinfo.cpu_impl, "<unknown>");
- cpuinfo.has_div = fcpu_has(cpu, "altr,has-div");
- cpuinfo.has_mul = fcpu_has(cpu, "altr,has-mul");
- cpuinfo.has_mulx = fcpu_has(cpu, "altr,has-mulx");
- cpuinfo.mmu = fcpu_has(cpu, "altr,has-mmu");
+ cpuinfo.has_div = of_property_read_bool(cpu, "altr,has-div");
+ cpuinfo.has_mul = of_property_read_bool(cpu, "altr,has-mul");
+ cpuinfo.has_mulx = of_property_read_bool(cpu, "altr,has-mulx");
+ cpuinfo.mmu = of_property_read_bool(cpu, "altr,has-mmu");
if (IS_ENABLED(CONFIG_NIOS2_HW_DIV_SUPPORT) && !cpuinfo.has_div)
err_cpu("DIV");
diff --git a/arch/nios2/kernel/vmlinux.lds.S b/arch/nios2/kernel/vmlinux.lds.S
index e23e89539967..6a8045bb1a77 100644
--- a/arch/nios2/kernel/vmlinux.lds.S
+++ b/arch/nios2/kernel/vmlinux.lds.S
@@ -37,6 +37,7 @@ SECTIONS
.text : {
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S
index d936de4c07ca..d68b9ede8423 100644
--- a/arch/openrisc/kernel/vmlinux.lds.S
+++ b/arch/openrisc/kernel/vmlinux.lds.S
@@ -47,6 +47,7 @@ SECTIONS
_stext = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index af12c2db9bb8..71c4a3aa3752 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -10,12 +10,12 @@ config PARISC
select RTC_CLASS
select RTC_DRV_GENERIC
select INIT_ALL_POSSIBLE
+ select HAVE_MEMBLOCK
+ select NO_BOOTMEM
select BUG
select BUILDTIME_EXTABLE_SORT
select HAVE_PERF_EVENTS
select GENERIC_ATOMIC64 if !64BIT
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
- select BROKEN_RODATA
select GENERIC_IRQ_PROBE
select GENERIC_PCI_IOMAP
select ARCH_HAVE_NMI_SAFE_CMPXCHG
@@ -24,6 +24,7 @@ config PARISC
select SYSCTL_ARCH_UNALIGN_ALLOW
select SYSCTL_EXCEPTION_TRACE
select HAVE_MOD_ARCH_SPECIFIC
+ select HAVE_ARCH_HARDENED_USERCOPY
select VIRT_TO_BUS
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS
diff --git a/arch/parisc/include/asm/dwarf.h b/arch/parisc/include/asm/dwarf.h
new file mode 100644
index 000000000000..8fe7d6b2cc42
--- /dev/null
+++ b/arch/parisc/include/asm/dwarf.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 Helge Deller <deller@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_PARISC_DWARF_H
+#define _ASM_PARISC_DWARF_H
+
+#ifdef __ASSEMBLY__
+
+#define CFI_STARTPROC .cfi_startproc
+#define CFI_ENDPROC .cfi_endproc
+#define CFI_DEF_CFA .cfi_def_cfa
+#define CFI_REGISTER .cfi_register
+#define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_UNDEFINED .cfi_undefined
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_PARISC_DWARF_H */
diff --git a/arch/parisc/include/asm/linkage.h b/arch/parisc/include/asm/linkage.h
index 0b19a7242d0c..67e6b433d399 100644
--- a/arch/parisc/include/asm/linkage.h
+++ b/arch/parisc/include/asm/linkage.h
@@ -1,6 +1,8 @@
#ifndef __ASM_PARISC_LINKAGE_H
#define __ASM_PARISC_LINKAGE_H
+#include <asm/dwarf.h>
+
#ifndef __ALIGN
#define __ALIGN .align 4
#define __ALIGN_STR ".align 4"
@@ -10,6 +12,8 @@
* In parisc assembly a semicolon marks a comment while a
* exclamation mark is used to separate independent lines.
*/
+#define ASM_NL !
+
#ifdef __ASSEMBLY__
#define ENTRY(name) \
@@ -26,6 +30,14 @@ name:
END(name)
#endif
+#define ENTRY_CFI(name) \
+ ENTRY(name) ASM_NL\
+ CFI_STARTPROC
+
+#define ENDPROC_CFI(name) \
+ ENDPROC(name) ASM_NL\
+ CFI_ENDPROC
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_PARISC_LINKAGE_H */
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 291cee28ccb6..e44bdb9078a5 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -83,7 +83,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
/* This is the size of the initially mapped kernel memory */
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) || defined(CONFIG_SMP)
#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */
#else
#define KERNEL_INITIAL_ORDER 24 /* 1<<24 = 16MB */
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index 482847865dac..9a2aee1b90fc 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -11,6 +11,7 @@
#include <linux/bug.h>
#include <linux/string.h>
+#include <linux/thread_info.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -201,10 +202,12 @@ extern long lstrnlen_user(const char __user *, long);
#define clear_user lclear_user
#define __clear_user lclear_user
-unsigned long copy_to_user(void __user *dst, const void *src, unsigned long len);
-#define __copy_to_user copy_to_user
-unsigned long __copy_from_user(void *dst, const void __user *src, unsigned long len);
-unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned long len);
+unsigned long __must_check __copy_to_user(void __user *dst, const void *src,
+ unsigned long len);
+unsigned long __must_check __copy_from_user(void *dst, const void __user *src,
+ unsigned long len);
+unsigned long copy_in_user(void __user *dst, const void __user *src,
+ unsigned long len);
#define __copy_in_user copy_in_user
#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user
@@ -217,23 +220,40 @@ static inline void copy_user_overflow(int size, unsigned long count)
WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
}
-static inline unsigned long __must_check copy_from_user(void *to,
- const void __user *from,
- unsigned long n)
+static __always_inline unsigned long __must_check
+copy_from_user(void *to, const void __user *from, unsigned long n)
{
- int sz = __compiletime_object_size(to);
- unsigned long ret = n;
+ int sz = __compiletime_object_size(to);
+ unsigned long ret = n;
- if (likely(sz == -1 || sz >= n))
- ret = __copy_from_user(to, from, n);
- else if (!__builtin_constant_p(n))
+ if (likely(sz < 0 || sz >= n)) {
+ check_object_size(to, n, false);
+ ret = __copy_from_user(to, from, n);
+ } else if (!__builtin_constant_p(n))
copy_user_overflow(sz, n);
else
- __bad_copy_user();
+ __bad_copy_user();
if (unlikely(ret))
memset(to + (n - ret), 0, ret);
- return ret;
+
+ return ret;
+}
+
+static __always_inline unsigned long __must_check
+copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ int sz = __compiletime_object_size(from);
+
+ if (likely(sz < 0 || sz >= n)) {
+ check_object_size(from, n, true);
+ n = __copy_to_user(to, from, n);
+ } else if (!__builtin_constant_p(n))
+ copy_user_overflow(sz, n);
+ else
+ __bad_copy_user();
+
+ return n;
}
struct pt_regs;
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
index f3db7d8eb0c2..5979745815a5 100644
--- a/arch/parisc/include/uapi/asm/mman.h
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -75,4 +75,9 @@
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
#endif /* __PARISC_MMAN_H__ */
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 67001277256c..629eb464d5ba 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -345,7 +345,7 @@ void flush_dcache_page(struct page *page)
!= (addr & (SHM_COLOUR - 1))) {
__flush_cache_page(mpnt, addr, page_to_phys(page));
if (old_addr)
- printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+ printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %pD\n", old_addr, addr, mpnt->vm_file);
old_addr = addr;
}
}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index baa3d9d6e971..4fcff2dcc9c3 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -766,7 +766,7 @@ ENTRY(end_fault_vector)
* copy_thread moved args into task save area.
*/
-ENTRY(ret_from_kernel_thread)
+ENTRY_CFI(ret_from_kernel_thread)
/* Call schedule_tail first though */
BL schedule_tail, %r2
@@ -782,7 +782,7 @@ ENTRY(ret_from_kernel_thread)
copy %r31, %r2
b finish_child_return
nop
-ENDPROC(ret_from_kernel_thread)
+ENDPROC_CFI(ret_from_kernel_thread)
/*
@@ -790,7 +790,7 @@ ENDPROC(ret_from_kernel_thread)
* struct task_struct *next)
*
* switch kernel stacks and return prev */
-ENTRY(_switch_to)
+ENTRY_CFI(_switch_to)
STREG %r2, -RP_OFFSET(%r30)
callee_save_float
@@ -815,7 +815,7 @@ _switch_to_ret:
LDREG -RP_OFFSET(%r30), %r2
bv %r0(%r2)
copy %r26, %r28
-ENDPROC(_switch_to)
+ENDPROC_CFI(_switch_to)
/*
* Common rfi return path for interruptions, kernel execve, and
@@ -833,7 +833,7 @@ ENDPROC(_switch_to)
.align PAGE_SIZE
-ENTRY(syscall_exit_rfi)
+ENTRY_CFI(syscall_exit_rfi)
mfctl %cr30,%r16
LDREG TI_TASK(%r16), %r16 /* thread_info -> task_struct */
ldo TASK_REGS(%r16),%r16
@@ -1037,12 +1037,12 @@ intr_extint:
b do_cpu_irq_mask
ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
-ENDPROC(syscall_exit_rfi)
+ENDPROC_CFI(syscall_exit_rfi)
/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
-ENTRY(intr_save) /* for os_hpmc */
+ENTRY_CFI(intr_save) /* for os_hpmc */
mfsp %sr7,%r16
cmpib,COND(=),n 0,%r16,1f
get_stack_use_cr30
@@ -1117,7 +1117,7 @@ skip_save_ior:
b handle_interruption
ldo R%intr_check_sig(%r2), %r2
-ENDPROC(intr_save)
+ENDPROC_CFI(intr_save)
/*
@@ -1720,7 +1720,7 @@ dtlb_fault:
.endm
.macro fork_like name
-ENTRY(sys_\name\()_wrapper)
+ENTRY_CFI(sys_\name\()_wrapper)
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
ldo TASK_REGS(%r1),%r1
reg_save %r1
@@ -1728,7 +1728,7 @@ ENTRY(sys_\name\()_wrapper)
ldil L%sys_\name, %r31
be R%sys_\name(%sr4,%r31)
STREG %r28, PT_CR27(%r1)
-ENDPROC(sys_\name\()_wrapper)
+ENDPROC_CFI(sys_\name\()_wrapper)
.endm
fork_like clone
@@ -1736,7 +1736,7 @@ fork_like fork
fork_like vfork
/* Set the return value for the child */
-ENTRY(child_return)
+ENTRY_CFI(child_return)
BL schedule_tail, %r2
nop
finish_child_return:
@@ -1748,9 +1748,9 @@ finish_child_return:
reg_restore %r1
b syscall_exit
copy %r0,%r28
-ENDPROC(child_return)
+ENDPROC_CFI(child_return)
-ENTRY(sys_rt_sigreturn_wrapper)
+ENTRY_CFI(sys_rt_sigreturn_wrapper)
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
ldo TASK_REGS(%r26),%r26 /* get pt regs */
/* Don't save regs, we are going to restore them from sigcontext. */
@@ -1778,9 +1778,9 @@ ENTRY(sys_rt_sigreturn_wrapper)
*/
bv %r0(%r2)
LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
-ENDPROC(sys_rt_sigreturn_wrapper)
+ENDPROC_CFI(sys_rt_sigreturn_wrapper)
-ENTRY(syscall_exit)
+ENTRY_CFI(syscall_exit)
/* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
* via syscall_exit_rfi if the signal was received while the process
* was running.
@@ -1979,7 +1979,7 @@ syscall_do_resched:
#else
nop
#endif
-ENDPROC(syscall_exit)
+ENDPROC_CFI(syscall_exit)
#ifdef CONFIG_FUNCTION_TRACER
@@ -2023,7 +2023,7 @@ ENDPROC(mcount)
.align 8
.globl return_to_handler
.type return_to_handler, @function
-ENTRY(return_to_handler)
+ENTRY_CFI(return_to_handler)
.proc
.callinfo caller,frame=FRAME_SIZE
.entry
@@ -2067,7 +2067,7 @@ parisc_return_to_handler:
LDREGM -FRAME_SIZE(%sp),%r3
.exit
.procend
-ENDPROC(return_to_handler)
+ENDPROC_CFI(return_to_handler)
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
@@ -2076,7 +2076,7 @@ ENDPROC(return_to_handler)
#ifdef CONFIG_IRQSTACKS
/* void call_on_stack(unsigned long param1, void *func,
unsigned long new_stack) */
-ENTRY(call_on_stack)
+ENTRY_CFI(call_on_stack)
copy %sp, %r1
/* Regarding the HPPA calling conventions for function pointers,
@@ -2112,10 +2112,10 @@ ENTRY(call_on_stack)
bv (%rp)
LDREG -68(%sp), %sp
# endif /* CONFIG_64BIT */
-ENDPROC(call_on_stack)
+ENDPROC_CFI(call_on_stack)
#endif /* CONFIG_IRQSTACKS */
-get_register:
+ENTRY_CFI(get_register)
/*
* get_register is used by the non access tlb miss handlers to
* copy the value of the general register specified in r8 into
@@ -2192,9 +2192,10 @@ get_register:
copy %r30,%r1
bv %r0(%r25) /* r31 */
copy %r31,%r1
+ENDPROC_CFI(get_register)
-set_register:
+ENTRY_CFI(set_register)
/*
* set_register is used by the non access tlb miss handlers to
* copy the value of r1 into the general register specified in
@@ -2266,4 +2267,5 @@ set_register:
copy %r1,%r30
bv %r0(%r25) /* r31 */
copy %r1,%r31
+ENDPROC_CFI(set_register)
diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S
index e158b6fbf1b4..0fbd0a0e1cda 100644
--- a/arch/parisc/kernel/hpmc.S
+++ b/arch/parisc/kernel/hpmc.S
@@ -41,12 +41,12 @@
*/
.level 1.1
- .data
#include <asm/assembly.h>
#include <asm/pdc.h>
#include <linux/linkage.h>
+#include <linux/init.h>
/*
* stack for os_hpmc, the HPMC handler.
@@ -55,22 +55,26 @@
* IODC requires 7K byte stack. That leaves 1K byte for os_hpmc.
*/
+ __PAGE_ALIGNED_BSS
.align 4096
hpmc_stack:
.block 16384
#define HPMC_IODC_BUF_SIZE 0x8000
+ __PAGE_ALIGNED_BSS
.align 4096
hpmc_iodc_buf:
.block HPMC_IODC_BUF_SIZE
+ .section .bss
.align 8
hpmc_raddr:
.block 128
#define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */
+ .section .bss
.align 8
ENTRY(hpmc_pim_data)
.block HPMC_PIM_DATA_SIZE
@@ -79,7 +83,7 @@ END(hpmc_pim_data)
.text
.import intr_save, code
-ENTRY(os_hpmc)
+ENTRY_CFI(os_hpmc)
.os_hpmc:
/*
@@ -295,11 +299,11 @@ os_hpmc_6:
b .
nop
-ENDPROC(os_hpmc)
+ENDPROC_CFI(os_hpmc)
.os_hpmc_end:
- nop
-.data
-.align 4
+
+
+ __INITRODATA
.export os_hpmc_size
os_hpmc_size:
.word .os_hpmc_end-.os_hpmc
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
index f0b6722fc706..545f9d2fe711 100644
--- a/arch/parisc/kernel/inventory.c
+++ b/arch/parisc/kernel/inventory.c
@@ -506,7 +506,7 @@ add_system_map_addresses(struct parisc_device *dev, int num_addrs,
long status;
struct pdc_system_map_addr_info addr_result;
- dev->addr = kmalloc(num_addrs * sizeof(unsigned long), GFP_KERNEL);
+ dev->addr = kmalloc_array(num_addrs, sizeof(*dev->addr), GFP_KERNEL);
if(!dev->addr) {
printk(KERN_ERR "%s %s(): memory allocation failure\n",
__FILE__, __func__);
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index b743a80eaba0..985e06da37f5 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -41,7 +41,7 @@
.text
.align 128
-ENTRY(flush_tlb_all_local)
+ENTRY_CFI(flush_tlb_all_local)
.proc
.callinfo NO_CALLS
.entry
@@ -190,11 +190,11 @@ fdtdone:
.exit
.procend
-ENDPROC(flush_tlb_all_local)
+ENDPROC_CFI(flush_tlb_all_local)
.import cache_info,data
-ENTRY(flush_instruction_cache_local)
+ENTRY_CFI(flush_instruction_cache_local)
.proc
.callinfo NO_CALLS
.entry
@@ -257,11 +257,11 @@ fisync:
.exit
.procend
-ENDPROC(flush_instruction_cache_local)
+ENDPROC_CFI(flush_instruction_cache_local)
.import cache_info, data
-ENTRY(flush_data_cache_local)
+ENTRY_CFI(flush_data_cache_local)
.proc
.callinfo NO_CALLS
.entry
@@ -325,7 +325,7 @@ fdsync:
.exit
.procend
-ENDPROC(flush_data_cache_local)
+ENDPROC_CFI(flush_data_cache_local)
.align 16
@@ -356,7 +356,7 @@ ENDPROC(flush_data_cache_local)
/* Clear page using kernel mapping. */
-ENTRY(clear_page_asm)
+ENTRY_CFI(clear_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -422,11 +422,11 @@ ENTRY(clear_page_asm)
.exit
.procend
-ENDPROC(clear_page_asm)
+ENDPROC_CFI(clear_page_asm)
/* Copy page using kernel mapping. */
-ENTRY(copy_page_asm)
+ENTRY_CFI(copy_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -540,7 +540,7 @@ ENTRY(copy_page_asm)
.exit
.procend
-ENDPROC(copy_page_asm)
+ENDPROC_CFI(copy_page_asm)
/*
* NOTE: Code in clear_user_page has a hard coded dependency on the
@@ -573,11 +573,17 @@ ENDPROC(copy_page_asm)
.endm
/*
- * We can't do this since copy_user_page is used to bring in
- * file data that might have instructions. Since the data would
- * then need to be flushed out so the i-fetch can see it, it
- * makes more sense to just copy through the kernel translation
- * and flush it.
+ * copy_user_page_asm() performs a page copy using mappings
+ * equivalent to the user page mappings. It can be used to
+ * implement copy_user_page() but unfortunately both the `from'
+ * and `to' pages need to be flushed through mappings equivalent
+ * to the user mappings after the copy because the kernel accesses
+ * the `from' page through the kmap kernel mapping and the `to'
+ * page needs to be flushed since code can be copied. As a
+ * result, this implementation is less efficient than the simpler
+ * copy using the kernel mapping. It only needs the `from' page
+ * to flushed via the user mapping. The kunmap routines handle
+ * the flushes needed for the kernel mapping.
*
* I'm still keeping this around because it may be possible to
* use it if more information is passed into copy_user_page().
@@ -586,7 +592,7 @@ ENDPROC(copy_page_asm)
*
*/
-ENTRY(copy_user_page_asm)
+ENTRY_CFI(copy_user_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -742,9 +748,9 @@ ENTRY(copy_user_page_asm)
.exit
.procend
-ENDPROC(copy_user_page_asm)
+ENDPROC_CFI(copy_user_page_asm)
-ENTRY(clear_user_page_asm)
+ENTRY_CFI(clear_user_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -828,9 +834,9 @@ ENTRY(clear_user_page_asm)
.exit
.procend
-ENDPROC(clear_user_page_asm)
+ENDPROC_CFI(clear_user_page_asm)
-ENTRY(flush_dcache_page_asm)
+ENTRY_CFI(flush_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -904,9 +910,9 @@ ENTRY(flush_dcache_page_asm)
.exit
.procend
-ENDPROC(flush_dcache_page_asm)
+ENDPROC_CFI(flush_dcache_page_asm)
-ENTRY(flush_icache_page_asm)
+ENTRY_CFI(flush_icache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -982,9 +988,9 @@ ENTRY(flush_icache_page_asm)
.exit
.procend
-ENDPROC(flush_icache_page_asm)
+ENDPROC_CFI(flush_icache_page_asm)
-ENTRY(flush_kernel_dcache_page_asm)
+ENTRY_CFI(flush_kernel_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1025,9 +1031,9 @@ ENTRY(flush_kernel_dcache_page_asm)
.exit
.procend
-ENDPROC(flush_kernel_dcache_page_asm)
+ENDPROC_CFI(flush_kernel_dcache_page_asm)
-ENTRY(purge_kernel_dcache_page_asm)
+ENTRY_CFI(purge_kernel_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1067,9 +1073,9 @@ ENTRY(purge_kernel_dcache_page_asm)
.exit
.procend
-ENDPROC(purge_kernel_dcache_page_asm)
+ENDPROC_CFI(purge_kernel_dcache_page_asm)
-ENTRY(flush_user_dcache_range_asm)
+ENTRY_CFI(flush_user_dcache_range_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1088,9 +1094,9 @@ ENTRY(flush_user_dcache_range_asm)
.exit
.procend
-ENDPROC(flush_user_dcache_range_asm)
+ENDPROC_CFI(flush_user_dcache_range_asm)
-ENTRY(flush_kernel_dcache_range_asm)
+ENTRY_CFI(flush_kernel_dcache_range_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1110,9 +1116,9 @@ ENTRY(flush_kernel_dcache_range_asm)
.exit
.procend
-ENDPROC(flush_kernel_dcache_range_asm)
+ENDPROC_CFI(flush_kernel_dcache_range_asm)
-ENTRY(flush_user_icache_range_asm)
+ENTRY_CFI(flush_user_icache_range_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1131,9 +1137,9 @@ ENTRY(flush_user_icache_range_asm)
.exit
.procend
-ENDPROC(flush_user_icache_range_asm)
+ENDPROC_CFI(flush_user_icache_range_asm)
-ENTRY(flush_kernel_icache_page)
+ENTRY_CFI(flush_kernel_icache_page)
.proc
.callinfo NO_CALLS
.entry
@@ -1174,9 +1180,9 @@ ENTRY(flush_kernel_icache_page)
.exit
.procend
-ENDPROC(flush_kernel_icache_page)
+ENDPROC_CFI(flush_kernel_icache_page)
-ENTRY(flush_kernel_icache_range_asm)
+ENTRY_CFI(flush_kernel_icache_range_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1194,13 +1200,13 @@ ENTRY(flush_kernel_icache_range_asm)
nop
.exit
.procend
-ENDPROC(flush_kernel_icache_range_asm)
+ENDPROC_CFI(flush_kernel_icache_range_asm)
/* align should cover use of rfi in disable_sr_hashing_asm and
* srdis_done.
*/
.align 256
-ENTRY(disable_sr_hashing_asm)
+ENTRY_CFI(disable_sr_hashing_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -1289,6 +1295,6 @@ srdis_done:
.exit
.procend
-ENDPROC(disable_sr_hashing_asm)
+ENDPROC_CFI(disable_sr_hashing_asm)
.end
diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S
index 5f3d3a1f9037..1db58e546230 100644
--- a/arch/parisc/kernel/real2.S
+++ b/arch/parisc/kernel/real2.S
@@ -61,7 +61,7 @@ save_cr_end:
* iodc_fn is the IODC function to call
*/
-ENTRY(real32_call_asm)
+ENTRY_CFI(real32_call_asm)
STREG %rp, -RP_OFFSET(%sp) /* save RP */
#ifdef CONFIG_64BIT
callee_save
@@ -119,14 +119,14 @@ ric_ret:
LDREG -RP_OFFSET(%sp), %rp /* restore RP */
bv 0(%rp)
nop
-ENDPROC(real32_call_asm)
+ENDPROC_CFI(real32_call_asm)
# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where)
# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r
.text
-save_control_regs:
+ENTRY_CFI(save_control_regs)
load32 PA(save_cr_space), %r28
PUSH_CR(%cr24, %r28)
PUSH_CR(%cr25, %r28)
@@ -139,8 +139,9 @@ save_control_regs:
PUSH_CR(%cr15, %r28)
bv 0(%r2)
nop
+ENDPROC_CFI(save_control_regs)
-restore_control_regs:
+ENTRY_CFI(restore_control_regs)
load32 PA(save_cr_end), %r26
POP_CR(%cr15, %r26)
POP_CR(%cr31, %r26)
@@ -153,13 +154,14 @@ restore_control_regs:
POP_CR(%cr24, %r26)
bv 0(%r2)
nop
+ENDPROC_CFI(restore_control_regs)
/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for
* more general-purpose use by the several places which need RFIs
*/
.text
.align 128
-rfi_virt2real:
+ENTRY_CFI(rfi_virt2real)
/* switch to real mode... */
rsm PSW_SM_I,%r0
load32 PA(rfi_v2r_1), %r1
@@ -191,10 +193,11 @@ rfi_v2r_1:
tophys_r1 %r2
bv 0(%r2)
nop
+ENDPROC_CFI(rfi_virt2real)
.text
.align 128
-rfi_real2virt:
+ENTRY_CFI(rfi_real2virt)
rsm PSW_SM_I,%r0
load32 (rfi_r2v_1), %r1
nop
@@ -225,6 +228,7 @@ rfi_r2v_1:
tovirt_r1 %r2
bv 0(%r2)
nop
+ENDPROC_CFI(rfi_real2virt)
#ifdef CONFIG_64BIT
@@ -238,7 +242,7 @@ rfi_r2v_1:
* arg0p points to where saved arg values may be found
* iodc_fn is the IODC function to call
*/
-ENTRY(real64_call_asm)
+ENTRY_CFI(real64_call_asm)
std %rp, -0x10(%sp) /* save RP */
std %sp, -8(%arg0) /* save SP on real-mode stack */
copy %arg0, %sp /* adopt the real-mode SP */
@@ -284,7 +288,7 @@ r64_ret:
ldd -0x10(%sp), %rp /* restore RP */
bv 0(%rp)
nop
-ENDPROC(real64_call_asm)
+ENDPROC_CFI(real64_call_asm)
#endif
@@ -293,12 +297,12 @@ ENDPROC(real64_call_asm)
** GCC 3.3 and later has a new function in libgcc.a for
** comparing function pointers.
*/
-ENTRY(__canonicalize_funcptr_for_compare)
+ENTRY_CFI(__canonicalize_funcptr_for_compare)
#ifdef CONFIG_64BIT
bve (%r2)
#else
bv %r0(%r2)
#endif
copy %r26,%r28
-ENDPROC(__canonicalize_funcptr_for_compare)
+ENDPROC_CFI(__canonicalize_funcptr_for_compare)
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index f7ea626e29c9..81d6f6391944 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -38,6 +38,7 @@
#include <linux/export.h>
#include <asm/processor.h>
+#include <asm/sections.h>
#include <asm/pdc.h>
#include <asm/led.h>
#include <asm/machdep.h> /* for pa7300lc_init() proto */
@@ -140,6 +141,13 @@ void __init setup_arch(char **cmdline_p)
#endif
printk(KERN_CONT ".\n");
+ /*
+ * Check if initial kernel page mappings are sufficient.
+ * panic early if not, else we may access kernel functions
+ * and variables which can't be reached.
+ */
+ if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
+ panic("KERNEL_INITIAL_ORDER too small!");
pdc_console_init();
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index c2a9cc55a62f..75dab2871346 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -412,8 +412,8 @@ void smp_cpus_done(unsigned int cpu_max)
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
- if (cpu != 0 && cpu < parisc_max_cpus)
- smp_boot_one_cpu(cpu, tidle);
+ if (cpu != 0 && cpu < parisc_max_cpus && smp_boot_one_cpu(cpu, tidle))
+ return -ENOSYS;
return cpu_online(cpu) ? 0 : -ENOSYS;
}
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 4b0b963d52a7..9b63b876a13a 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -226,12 +226,6 @@ void __init start_cpu_itimer(void)
unsigned int cpu = smp_processor_id();
unsigned long next_tick = mfctl(16) + clocktick;
-#if defined(CONFIG_HAVE_UNSTABLE_SCHED_CLOCK) && defined(CONFIG_64BIT)
- /* With multiple 64bit CPUs online, the cr16's are not syncronized. */
- if (cpu != 0)
- clear_sched_clock_stable();
-#endif
-
mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */
per_cpu(cpu_data, cpu).it_value = next_tick;
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index f3ead0b6ce46..b37787dbe775 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -69,6 +69,7 @@ SECTIONS
.text ALIGN(PAGE_SIZE) : {
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
@@ -138,8 +139,6 @@ SECTIONS
/* BSS */
BSS_SECTION(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE)
- /* bootmap is allocated in setup_bootmem() directly behind bss. */
-
. = ALIGN(HUGEPAGE_SIZE);
_end = . ;
diff --git a/arch/parisc/lib/fixup.S b/arch/parisc/lib/fixup.S
index 1052b747e011..a5b72f22c7a6 100644
--- a/arch/parisc/lib/fixup.S
+++ b/arch/parisc/lib/fixup.S
@@ -65,34 +65,34 @@
.section .fixup, "ax"
/* get_user() fixups, store -EFAULT in r8, and 0 in r9 */
-ENTRY(fixup_get_user_skip_1)
+ENTRY_CFI(fixup_get_user_skip_1)
get_fault_ip %r1,%r8
ldo 4(%r1), %r1
ldi -EFAULT, %r8
bv %r0(%r1)
copy %r0, %r9
-ENDPROC(fixup_get_user_skip_1)
+ENDPROC_CFI(fixup_get_user_skip_1)
-ENTRY(fixup_get_user_skip_2)
+ENTRY_CFI(fixup_get_user_skip_2)
get_fault_ip %r1,%r8
ldo 8(%r1), %r1
ldi -EFAULT, %r8
bv %r0(%r1)
copy %r0, %r9
-ENDPROC(fixup_get_user_skip_2)
+ENDPROC_CFI(fixup_get_user_skip_2)
/* put_user() fixups, store -EFAULT in r8 */
-ENTRY(fixup_put_user_skip_1)
+ENTRY_CFI(fixup_put_user_skip_1)
get_fault_ip %r1,%r8
ldo 4(%r1), %r1
bv %r0(%r1)
ldi -EFAULT, %r8
-ENDPROC(fixup_put_user_skip_1)
+ENDPROC_CFI(fixup_put_user_skip_1)
-ENTRY(fixup_put_user_skip_2)
+ENTRY_CFI(fixup_put_user_skip_2)
get_fault_ip %r1,%r8
ldo 8(%r1), %r1
bv %r0(%r1)
ldi -EFAULT, %r8
-ENDPROC(fixup_put_user_skip_2)
+ENDPROC_CFI(fixup_put_user_skip_2)
diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S
index a512f07d4feb..56845de6b5df 100644
--- a/arch/parisc/lib/lusercopy.S
+++ b/arch/parisc/lib/lusercopy.S
@@ -67,7 +67,7 @@
* otherwise, returns number of bytes not transferred.
*/
-ENTRY(lclear_user)
+ENTRY_CFI(lclear_user)
.proc
.callinfo NO_CALLS
.entry
@@ -81,7 +81,7 @@ $lclu_done:
bv %r0(%r2)
copy %r25,%r28
.exit
-ENDPROC(lclear_user)
+ENDPROC_CFI(lclear_user)
.section .fixup,"ax"
2: fixup_branch $lclu_done
@@ -100,7 +100,7 @@ ENDPROC(lclear_user)
* else strlen + 1 (i.e. includes zero byte).
*/
-ENTRY(lstrnlen_user)
+ENTRY_CFI(lstrnlen_user)
.proc
.callinfo NO_CALLS
.entry
@@ -120,7 +120,7 @@ $lslen_done:
$lslen_nzero:
b $lslen_done
ldo 1(%r26),%r26 /* special case for N == 0 */
-ENDPROC(lstrnlen_user)
+ENDPROC_CFI(lstrnlen_user)
.section .fixup,"ax"
3: fixup_branch $lslen_done
diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
index b2b441b32341..f82ff10ed974 100644
--- a/arch/parisc/lib/memcpy.c
+++ b/arch/parisc/lib/memcpy.c
@@ -489,20 +489,23 @@ static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
}
#ifdef __KERNEL__
-unsigned long copy_to_user(void __user *dst, const void *src, unsigned long len)
+unsigned long __copy_to_user(void __user *dst, const void *src,
+ unsigned long len)
{
mtsp(get_kernel_space(), 1);
mtsp(get_user_space(), 2);
return pa_memcpy((void __force *)dst, src, len);
}
+EXPORT_SYMBOL(__copy_to_user);
-EXPORT_SYMBOL(__copy_from_user);
-unsigned long __copy_from_user(void *dst, const void __user *src, unsigned long len)
+unsigned long __copy_from_user(void *dst, const void __user *src,
+ unsigned long len)
{
mtsp(get_user_space(), 1);
mtsp(get_kernel_space(), 2);
return pa_memcpy(dst, (void __force *)src, len);
}
+EXPORT_SYMBOL(__copy_from_user);
unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned long len)
{
@@ -520,8 +523,6 @@ void * memcpy(void * dst,const void *src, size_t count)
return dst;
}
-EXPORT_SYMBOL(copy_to_user);
-EXPORT_SYMBOL(copy_from_user);
EXPORT_SYMBOL(copy_in_user);
EXPORT_SYMBOL(memcpy);
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index 163af2c31d76..47a6ca4c9e40 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -168,6 +168,43 @@ int fixup_exception(struct pt_regs *regs)
}
/*
+ * parisc hardware trap list
+ *
+ * Documented in section 3 "Addressing and Access Control" of the
+ * "PA-RISC 1.1 Architecture and Instruction Set Reference Manual"
+ * https://parisc.wiki.kernel.org/index.php/File:Pa11_acd.pdf
+ *
+ * For implementation see handle_interruption() in traps.c
+ */
+static const char * const trap_description[] = {
+ [1] "High-priority machine check (HPMC)",
+ [2] "Power failure interrupt",
+ [3] "Recovery counter trap",
+ [5] "Low-priority machine check",
+ [6] "Instruction TLB miss fault",
+ [7] "Instruction access rights / protection trap",
+ [8] "Illegal instruction trap",
+ [9] "Break instruction trap",
+ [10] "Privileged operation trap",
+ [11] "Privileged register trap",
+ [12] "Overflow trap",
+ [13] "Conditional trap",
+ [14] "FP Assist Exception trap",
+ [15] "Data TLB miss fault",
+ [16] "Non-access ITLB miss fault",
+ [17] "Non-access DTLB miss fault",
+ [18] "Data memory protection/unaligned access trap",
+ [19] "Data memory break trap",
+ [20] "TLB dirty bit trap",
+ [21] "Page reference trap",
+ [22] "Assist emulation trap",
+ [25] "Taken branch trap",
+ [26] "Data memory access rights trap",
+ [27] "Data memory protection ID trap",
+ [28] "Unaligned data reference trap",
+};
+
+/*
* Print out info about fatal segfaults, if the show_unhandled_signals
* sysctl is set:
*/
@@ -176,6 +213,8 @@ show_signal_msg(struct pt_regs *regs, unsigned long code,
unsigned long address, struct task_struct *tsk,
struct vm_area_struct *vma)
{
+ const char *trap_name = NULL;
+
if (!unhandled_signal(tsk, SIGSEGV))
return;
@@ -186,8 +225,15 @@ show_signal_msg(struct pt_regs *regs, unsigned long code,
pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx",
tsk->comm, code, address);
print_vma_addr(KERN_CONT " in ", regs->iaoq[0]);
+
+ if (code < ARRAY_SIZE(trap_description))
+ trap_name = trap_description[code];
+ pr_warn(KERN_CONT " trap #%lu: %s%c", code,
+ trap_name ? trap_name : "unknown",
+ vma ? ',':'\n');
+
if (vma)
- pr_warn(" vm_start = 0x%08lx, vm_end = 0x%08lx\n",
+ pr_warn(KERN_CONT " vm_start = 0x%08lx, vm_end = 0x%08lx\n",
vma->vm_start, vma->vm_end);
show_regs(regs);
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 6b3e7c6ee096..356f38473b5d 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -79,6 +80,34 @@ static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __read_mostly;
physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __read_mostly;
int npmem_ranges __read_mostly;
+/*
+ * get_memblock() allocates pages via memblock.
+ * We can't use memblock_find_in_range(0, KERNEL_INITIAL_SIZE) here since it
+ * doesn't allocate from bottom to top which is needed because we only created
+ * the initial mapping up to KERNEL_INITIAL_SIZE in the assembly bootup code.
+ */
+static void * __init get_memblock(unsigned long size)
+{
+ static phys_addr_t search_addr __initdata;
+ phys_addr_t phys;
+
+ if (!search_addr)
+ search_addr = PAGE_ALIGN(__pa((unsigned long) &_end));
+ search_addr = ALIGN(search_addr, size);
+ while (!memblock_is_region_memory(search_addr, size) ||
+ memblock_is_region_reserved(search_addr, size)) {
+ search_addr += size;
+ }
+ phys = search_addr;
+
+ if (phys)
+ memblock_reserve(phys, size);
+ else
+ panic("get_memblock() failed.\n");
+
+ return __va(phys);
+}
+
#ifdef CONFIG_64BIT
#define MAX_MEM (~0UL)
#else /* !CONFIG_64BIT */
@@ -118,11 +147,7 @@ static void __init mem_limit_func(void)
static void __init setup_bootmem(void)
{
- unsigned long bootmap_size;
unsigned long mem_max;
- unsigned long bootmap_pages;
- unsigned long bootmap_start_pfn;
- unsigned long bootmap_pfn;
#ifndef CONFIG_DISCONTIGMEM
physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1];
int npmem_holes;
@@ -178,33 +203,29 @@ static void __init setup_bootmem(void)
}
#endif
- if (npmem_ranges > 1) {
-
- /* Print the memory ranges */
+ /* Print the memory ranges */
+ pr_info("Memory Ranges:\n");
- printk(KERN_INFO "Memory Ranges:\n");
+ for (i = 0; i < npmem_ranges; i++) {
+ struct resource *res = &sysram_resources[i];
+ unsigned long start;
+ unsigned long size;
- for (i = 0; i < npmem_ranges; i++) {
- unsigned long start;
- unsigned long size;
+ size = (pmem_ranges[i].pages << PAGE_SHIFT);
+ start = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+ pr_info("%2d) Start 0x%016lx End 0x%016lx Size %6ld MB\n",
+ i, start, start + (size - 1), size >> 20);
- size = (pmem_ranges[i].pages << PAGE_SHIFT);
- start = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
- printk(KERN_INFO "%2d) Start 0x%016lx End 0x%016lx Size %6ld MB\n",
- i,start, start + (size - 1), size >> 20);
- }
- }
-
- sysram_resource_count = npmem_ranges;
- for (i = 0; i < sysram_resource_count; i++) {
- struct resource *res = &sysram_resources[i];
+ /* request memory resource */
res->name = "System RAM";
- res->start = pmem_ranges[i].start_pfn << PAGE_SHIFT;
- res->end = res->start + (pmem_ranges[i].pages << PAGE_SHIFT)-1;
+ res->start = start;
+ res->end = start + size - 1;
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
request_resource(&iomem_resource, res);
}
+ sysram_resource_count = npmem_ranges;
+
/*
* For 32 bit kernels we limit the amount of memory we can
* support, in order to preserve enough kernel address space
@@ -263,16 +284,9 @@ static void __init setup_bootmem(void)
}
#endif
- bootmap_pages = 0;
- for (i = 0; i < npmem_ranges; i++)
- bootmap_pages += bootmem_bootmap_pages(pmem_ranges[i].pages);
-
- bootmap_start_pfn = PAGE_ALIGN(__pa((unsigned long) &_end)) >> PAGE_SHIFT;
-
#ifdef CONFIG_DISCONTIGMEM
for (i = 0; i < MAX_PHYSMEM_RANGES; i++) {
memset(NODE_DATA(i), 0, sizeof(pg_data_t));
- NODE_DATA(i)->bdata = &bootmem_node_data[i];
}
memset(pfnnid_map, 0xff, sizeof(pfnnid_map));
@@ -284,28 +298,24 @@ static void __init setup_bootmem(void)
/*
* Initialize and free the full range of memory in each range.
- * Note that the only writing these routines do are to the bootmap,
- * and we've made sure to locate the bootmap properly so that they
- * won't be writing over anything important.
*/
- bootmap_pfn = bootmap_start_pfn;
max_pfn = 0;
for (i = 0; i < npmem_ranges; i++) {
unsigned long start_pfn;
unsigned long npages;
+ unsigned long start;
+ unsigned long size;
start_pfn = pmem_ranges[i].start_pfn;
npages = pmem_ranges[i].pages;
- bootmap_size = init_bootmem_node(NODE_DATA(i),
- bootmap_pfn,
- start_pfn,
- (start_pfn + npages) );
- free_bootmem_node(NODE_DATA(i),
- (start_pfn << PAGE_SHIFT),
- (npages << PAGE_SHIFT) );
- bootmap_pfn += (bootmap_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ start = start_pfn << PAGE_SHIFT;
+ size = npages << PAGE_SHIFT;
+
+ /* add system RAM memblock */
+ memblock_add(start, size);
+
if ((start_pfn + npages) > max_pfn)
max_pfn = start_pfn + npages;
}
@@ -317,32 +327,22 @@ static void __init setup_bootmem(void)
*/
max_low_pfn = max_pfn;
- /* bootmap sizing messed up? */
- BUG_ON((bootmap_pfn - bootmap_start_pfn) != bootmap_pages);
-
/* reserve PAGE0 pdc memory, kernel text/data/bss & bootmap */
#define PDC_CONSOLE_IO_IODC_SIZE 32768
- reserve_bootmem_node(NODE_DATA(0), 0UL,
- (unsigned long)(PAGE0->mem_free +
- PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT);
- reserve_bootmem_node(NODE_DATA(0), __pa(KERNEL_BINARY_TEXT_START),
- (unsigned long)(_end - KERNEL_BINARY_TEXT_START),
- BOOTMEM_DEFAULT);
- reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
- ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT),
- BOOTMEM_DEFAULT);
+ memblock_reserve(0UL, (unsigned long)(PAGE0->mem_free +
+ PDC_CONSOLE_IO_IODC_SIZE));
+ memblock_reserve(__pa(KERNEL_BINARY_TEXT_START),
+ (unsigned long)(_end - KERNEL_BINARY_TEXT_START));
#ifndef CONFIG_DISCONTIGMEM
/* reserve the holes */
for (i = 0; i < npmem_holes; i++) {
- reserve_bootmem_node(NODE_DATA(0),
- (pmem_holes[i].start_pfn << PAGE_SHIFT),
- (pmem_holes[i].pages << PAGE_SHIFT),
- BOOTMEM_DEFAULT);
+ memblock_reserve((pmem_holes[i].start_pfn << PAGE_SHIFT),
+ (pmem_holes[i].pages << PAGE_SHIFT));
}
#endif
@@ -360,8 +360,7 @@ static void __init setup_bootmem(void)
initrd_below_start_ok = 1;
printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
- reserve_bootmem_node(NODE_DATA(0), __pa(initrd_start),
- initrd_reserve, BOOTMEM_DEFAULT);
+ memblock_reserve(__pa(initrd_start), initrd_reserve);
}
}
#endif
@@ -439,7 +438,7 @@ static void __init map_pages(unsigned long start_vaddr,
*/
if (!pmd) {
- pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE << PMD_ORDER);
+ pmd = (pmd_t *) get_memblock(PAGE_SIZE << PMD_ORDER);
pmd = (pmd_t *) __pa(pmd);
}
@@ -458,8 +457,7 @@ static void __init map_pages(unsigned long start_vaddr,
pg_table = (pte_t *)pmd_address(*pmd);
if (!pg_table) {
- pg_table = (pte_t *)
- alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE);
+ pg_table = (pte_t *) get_memblock(PAGE_SIZE);
pg_table = (pte_t *) __pa(pg_table);
}
@@ -737,7 +735,7 @@ static void __init pagetable_init(void)
}
#endif
- empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
+ empty_zero_page = get_memblock(PAGE_SIZE);
}
static void __init gateway_init(void)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 927d2ab2ce08..65fba4c34cd7 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -12,11 +12,6 @@ config 64BIT
bool
default y if PPC64
-config WORD_SIZE
- int
- default 64 if PPC64
- default 32 if !PPC64
-
config ARCH_PHYS_ADDR_T_64BIT
def_bool PPC64 || PHYS_64BIT
@@ -101,7 +96,7 @@ config PPC
select VIRT_TO_BUS if !PPC64
select HAVE_IDE
select HAVE_IOREMAP_PROT
- select HAVE_EFFICIENT_UNALIGNED_ACCESS if !CPU_LITTLE_ENDIAN
+ select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU)
select HAVE_KPROBES
select HAVE_ARCH_KGDB
select HAVE_KRETPROBES
@@ -113,7 +108,6 @@ config PPC
select HAVE_DEBUG_KMEMLEAK
select ARCH_HAS_SG_CHAIN
select GENERIC_ATOMIC64 if PPC32
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
@@ -167,6 +161,7 @@ config PPC
select GENERIC_CPU_AUTOPROBE
select HAVE_VIRT_CPU_ACCOUNTING
select HAVE_ARCH_HARDENED_USERCOPY
+ select HAVE_KERNEL_GZIP
config GENERIC_CSUM
def_bool CPU_LITTLE_ENDIAN
@@ -637,7 +632,7 @@ config FORCE_MAX_ZONEORDER
int "Maximum zone order"
range 8 9 if PPC64 && PPC_64K_PAGES
default "9" if PPC64 && PPC_64K_PAGES
- range 9 13 if PPC64 && !PPC_64K_PAGES
+ range 13 13 if PPC64 && !PPC_64K_PAGES
default "13" if PPC64 && !PPC_64K_PAGES
range 9 64 if PPC32 && PPC_16K_PAGES
default "9" if PPC32 && PPC_16K_PAGES
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 1934707bf321..50d020ac0f48 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -43,31 +43,24 @@ NM := $(NM) --synthetic
endif
endif
-ifeq ($(CONFIG_PPC64),y)
-ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-OLDARCH := ppc64le
-else
-OLDARCH := ppc64
-endif
-else
-ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-OLDARCH := ppcle
-else
-OLDARCH := ppc
-endif
-endif
+# BITS is used as extension for files which are available in a 32 bit
+# and a 64 bit version to simplify shared Makefiles.
+# e.g.: obj-y += foo_$(BITS).o
+export BITS
-# It seems there are times we use this Makefile without
-# including the config file, but this replicates the old behaviour
-ifeq ($(CONFIG_WORD_SIZE),)
-CONFIG_WORD_SIZE := 32
+ifdef CONFIG_PPC64
+ BITS := 64
+else
+ BITS := 32
endif
-UTS_MACHINE := $(OLDARCH)
+machine-y = ppc
+machine-$(CONFIG_PPC64) += 64
+machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le
+UTS_MACHINE := $(subst $(space),,$(machine-y))
ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
override LD += -EL
-override CROSS32AS += -mlittle-endian
LDEMULATION := lppc
GNUTARGET := powerpcle
MULTIPLEWORD := -mno-multiple
@@ -89,10 +82,10 @@ aflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mbig-endian)
aflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mlittle-endian
ifeq ($(HAS_BIARCH),y)
-override AS += -a$(CONFIG_WORD_SIZE)
-override LD += -m elf$(CONFIG_WORD_SIZE)$(LDEMULATION)
-override CC += -m$(CONFIG_WORD_SIZE)
-override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-$(GNUTARGET) $(AR)
+override AS += -a$(BITS)
+override LD += -m elf$(BITS)$(LDEMULATION)
+override CC += -m$(BITS)
+override AR := GNUTARGET=elf$(BITS)-$(GNUTARGET) $(AR)
endif
LDFLAGS_vmlinux-y := -Bstatic
@@ -179,7 +172,7 @@ KBUILD_CFLAGS += $(call cc-option,-msoft-float)
KBUILD_CFLAGS += -pipe -Iarch/$(ARCH) $(CFLAGS-y)
CPP = $(CC) -E $(KBUILD_CFLAGS)
-CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
+CHECKFLAGS += -m$(BITS) -D__powerpc__ -D__powerpc$(BITS)__
ifdef CONFIG_CPU_BIG_ENDIAN
CHECKFLAGS += -D__BIG_ENDIAN__
else
@@ -234,7 +227,7 @@ KBUILD_CFLAGS += $(cpu-as-y)
KBUILD_AFLAGS += $(aflags-y)
KBUILD_CFLAGS += $(cflags-y)
-head-y := arch/powerpc/kernel/head_$(CONFIG_WORD_SIZE).o
+head-y := arch/powerpc/kernel/head_$(BITS).o
head-$(CONFIG_8xx) := arch/powerpc/kernel/head_8xx.o
head-$(CONFIG_40x) := arch/powerpc/kernel/head_40x.o
head-$(CONFIG_44x) := arch/powerpc/kernel/head_44x.o
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 1a2a6e8dc40d..eae2dc8bc218 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -19,10 +19,15 @@
all: $(obj)/zImage
+compress-$(CONFIG_KERNEL_GZIP) := CONFIG_KERNEL_GZIP
+compress-$(CONFIG_KERNEL_XZ) := CONFIG_KERNEL_XZ
+
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)
+ -isystem $(shell $(CROSS32CC) -print-file-name=include) \
+ -D$(compress-y)
+
ifdef CONFIG_PPC64_BOOT_WRAPPER
BOOTCFLAGS += -m64
endif
@@ -59,13 +64,30 @@ $(obj)/treeboot-currituck.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-akebono.o: BOOTCFLAGS += -mcpu=405
$(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405
+# The pre-boot decompressors pull in a lot of kernel headers and other source
+# files. This creates a bit of a dependency headache since we need to copy
+# these files into the build dir, fix up any includes and ensure that dependent
+# files are copied in the right order.
+
+# these need to be seperate variables because they are copied out of different
+# directories in the kernel tree. Sure you COULd merge them, but it's a
+# cure-is-worse-than-disease situation.
+zlib-decomp-$(CONFIG_KERNEL_GZIP) := decompress_inflate.c
+zlib-$(CONFIG_KERNEL_GZIP) := inffast.c inflate.c inftrees.c
+zlibheader-$(CONFIG_KERNEL_GZIP) := inffast.h inffixed.h inflate.h inftrees.h infutil.h
+zliblinuxheader-$(CONFIG_KERNEL_GZIP) := zlib.h zconf.h zutil.h
-zlib := inffast.c inflate.c inftrees.c
-zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
-zliblinuxheader := zlib.h zconf.h zutil.h
+$(addprefix $(obj)/, decompress.o): \
+ $(addprefix $(obj)/,$(zlib-decomp-y))
-$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o): \
- $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
+$(addprefix $(obj)/, $(zlib-decomp-y)): \
+ $(addprefix $(obj)/,$(zliblinuxheader-y)) \
+ $(addprefix $(obj)/,$(zlibheader-y)) \
+ $(addprefix $(obj)/,$(zlib-y))
+
+$(addprefix $(obj)/,$(zlib-y)): \
+ $(addprefix $(obj)/,$(zliblinuxheader-y)) \
+ $(addprefix $(obj)/,$(zlibheader-y))
libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
libfdtheader := fdt.h libfdt.h libfdt_internal.h
@@ -73,10 +95,10 @@ libfdtheader := fdt.h libfdt.h libfdt_internal.h
$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \
$(addprefix $(obj)/,$(libfdtheader))
-src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
+src-wlib-y := string.S crt0.S crtsavres.S stdio.c decompress.c main.c \
$(libfdt) libfdt-wrapper.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
- gunzip_util.c elf_util.c $(zlib) devtree.c stdlib.c \
+ elf_util.c $(zlib-y) devtree.c stdlib.c \
oflib.c ofconsole.c cuboot.c mpsc.c cpm-serial.c \
uartlite.c mpc52xx-psc.c opal.c opal-calls.S
src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c
@@ -125,23 +147,20 @@ obj-wlib := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-wlib))))
obj-plat := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-plat))))
obj-plat: $(libfdt)
-quiet_cmd_copy_zlib = COPY $@
- cmd_copy_zlib = sed "s@__used@@;s@<linux/\([^>]*\).*@\"\1\"@" $< > $@
+quiet_cmd_copy_kern_src = COPY $@
+ cmd_copy_kern_src = sed -f $(srctree)/arch/powerpc/boot/fixup-headers.sed $< > $@
-quiet_cmd_copy_zlibheader = COPY $@
- cmd_copy_zlibheader = sed "s@<linux/\([^>]*\).*@\"\1\"@" $< > $@
-# stddef.h for NULL
-quiet_cmd_copy_zliblinuxheader = COPY $@
- cmd_copy_zliblinuxheader = sed "s@<linux/string.h>@\"string.h\"@;s@<linux/kernel.h>@<stddef.h>@;s@<linux/\([^>]*\).*@\"\1\"@" $< > $@
+$(addprefix $(obj)/,$(zlib-y)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+ $(call cmd,copy_kern_src)
-$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
- $(call cmd,copy_zlib)
+$(addprefix $(obj)/,$(zlibheader-y)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+ $(call cmd,copy_kern_src)
-$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
- $(call cmd,copy_zlibheader)
+$(addprefix $(obj)/,$(zliblinuxheader-y)): $(obj)/%: $(srctree)/include/linux/%
+ $(call cmd,copy_kern_src)
-$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
- $(call cmd,copy_zliblinuxheader)
+$(addprefix $(obj)/,$(zlib-decomp-y)): $(obj)/%: $(srctree)/lib/%
+ $(call cmd,copy_kern_src)
quiet_cmd_copy_libfdt = COPY $@
cmd_copy_libfdt = cp $< $@
@@ -150,17 +169,17 @@ $(addprefix $(obj)/,$(libfdt) $(libfdtheader)): $(obj)/%: $(srctree)/scripts/dtc
$(call cmd,copy_libfdt)
$(obj)/empty.c:
- @touch $@
+ $(Q)touch $@
$(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 $< $@
+ $(Q)cp $< $@
-clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
- $(libfdt) $(libfdtheader) \
+clean-files := $(zlib-) $(zlibheader-) $(zliblinuxheader-) \
+ $(zlib-decomp-) $(libfdt) $(libfdtheader) \
empty.c zImage.coff.lds zImage.ps3.lds zImage.lds
quiet_cmd_bootcc = BOOTCC $@
@@ -207,10 +226,14 @@ CROSSWRAP := -C "$(CROSS_COMPILE)"
endif
endif
+compressor-$(CONFIG_KERNEL_GZIP) := gz
+compressor-$(CONFIG_KERNEL_XZ) := xz
+
# args (to if_changed): 1 = (this rule), 2 = platform, 3 = dts 4=dtb 5=initrd
quiet_cmd_wrap = WRAP $@
- cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
- $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux
+ cmd_wrap =$(CONFIG_SHELL) $(wrapper) -Z $(compressor-y) -c -o $@ -p $2 \
+ $(CROSSWRAP) $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) \
+ vmlinux
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
image-$(CONFIG_PPC_POWERNV) += zImage.pseries
@@ -391,9 +414,9 @@ image-y := vmlinux.strip
endif
$(obj)/zImage: $(addprefix $(obj)/, $(image-y))
- @rm -f $@; ln $< $@
+ $(Q)rm -f $@; ln $< $@
$(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y))
- @rm -f $@; ln $< $@
+ $(Q)rm -f $@; ln $< $@
# Only install the vmlinux
install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
@@ -410,8 +433,9 @@ clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \
zImage.maple simpleImage.* otheros.bld *.dtb
# clean up files cached by wrapper
-clean-kernel := vmlinux.strip vmlinux.bin
-clean-kernel += $(addsuffix .gz,$(clean-kernel))
+clean-kernel-base := vmlinux.strip vmlinux.bin
+clean-kernel := $(addsuffix .gz,$(clean-kernel-base))
+clean-kernel += $(addsuffix .xz,$(clean-kernel-base))
# If not absolute clean-files are relative to $(obj).
clean-files += $(addprefix $(objtree)/, $(clean-kernel))
diff --git a/arch/powerpc/boot/cuboot-c2k.c b/arch/powerpc/boot/cuboot-c2k.c
index e43594950ba3..9309c51f1d65 100644
--- a/arch/powerpc/boot/cuboot-c2k.c
+++ b/arch/powerpc/boot/cuboot-c2k.c
@@ -18,7 +18,6 @@
#include "io.h"
#include "ops.h"
#include "elf.h"
-#include "gunzip_util.h"
#include "mv64x60.h"
#include "cuboot.h"
#include "ppcboot.h"
diff --git a/arch/powerpc/boot/decompress.c b/arch/powerpc/boot/decompress.c
new file mode 100644
index 000000000000..3aff4423ad01
--- /dev/null
+++ b/arch/powerpc/boot/decompress.c
@@ -0,0 +1,148 @@
+/*
+ * Wrapper around the kernel's pre-boot decompression library.
+ *
+ * Copyright (C) IBM Corporation 2016.
+ *
+ * This program is free software; 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 "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "reg.h"
+#include "types.h"
+
+/*
+ * The decompressor_*.c files play #ifdef games so they can be used in both
+ * pre-boot and regular kernel code. We need these definitions to make the
+ * includes work.
+ */
+
+#define STATIC static
+#define INIT
+#define __always_inline inline
+
+/*
+ * The build process will copy the required zlib source files and headers
+ * out of lib/ and "fix" the includes so they do not pull in other kernel
+ * headers.
+ */
+
+#ifdef CONFIG_KERNEL_GZIP
+# include "decompress_inflate.c"
+#endif
+
+#ifdef CONFIG_KERNEL_XZ
+# include "xz_config.h"
+# include "../../../lib/decompress_unxz.c"
+#endif
+
+/* globals for tracking the state of the decompression */
+static unsigned long decompressed_bytes;
+static unsigned long limit;
+static unsigned long skip;
+static char *output_buffer;
+
+/*
+ * flush() is called by __decompress() when the decompressor's scratch buffer is
+ * full.
+ */
+static long flush(void *v, unsigned long buffer_size)
+{
+ unsigned long end = decompressed_bytes + buffer_size;
+ unsigned long size = buffer_size;
+ unsigned long offset = 0;
+ char *in = v;
+ char *out;
+
+ /*
+ * if we hit our decompression limit, we need to fake an error to abort
+ * the in-progress decompression.
+ */
+ if (decompressed_bytes >= limit)
+ return -1;
+
+ /* skip this entire block */
+ if (end <= skip) {
+ decompressed_bytes += buffer_size;
+ return buffer_size;
+ }
+
+ /* skip some data at the start, but keep the rest of the block */
+ if (decompressed_bytes < skip && end > skip) {
+ offset = skip - decompressed_bytes;
+
+ in += offset;
+ size -= offset;
+ decompressed_bytes += offset;
+ }
+
+ out = &output_buffer[decompressed_bytes - skip];
+ size = min(decompressed_bytes + size, limit) - decompressed_bytes;
+
+ memcpy(out, in, size);
+ decompressed_bytes += size;
+
+ return buffer_size;
+}
+
+static void print_err(char *s)
+{
+ /* suppress the "error" when we terminate the decompressor */
+ if (decompressed_bytes >= limit)
+ return;
+
+ printf("Decompression error: '%s'\n\r", s);
+}
+
+/**
+ * partial_decompress - decompresses part or all of a compressed buffer
+ * @inbuf: input buffer
+ * @input_size: length of the input buffer
+ * @outbuf: input buffer
+ * @output_size: length of the input buffer
+ * @skip number of output bytes to ignore
+ *
+ * This function takes compressed data from inbuf, decompresses and write it to
+ * outbuf. Once output_size bytes are written to the output buffer, or the
+ * stream is exhausted the function will return the number of bytes that were
+ * decompressed. Otherwise it will return whatever error code the decompressor
+ * reported (NB: This is specific to each decompressor type).
+ *
+ * The skip functionality is mainly there so the program and discover
+ * the size of the compressed image so that it can ask firmware (if present)
+ * for an appropriately sized buffer.
+ */
+long partial_decompress(void *inbuf, unsigned long input_size,
+ void *outbuf, unsigned long output_size, unsigned long _skip)
+{
+ int ret;
+
+ /*
+ * The skipped bytes needs to be included in the size of data we want
+ * to decompress.
+ */
+ output_size += _skip;
+
+ decompressed_bytes = 0;
+ output_buffer = outbuf;
+ limit = output_size;
+ skip = _skip;
+
+ ret = __decompress(inbuf, input_size, NULL, flush, outbuf,
+ output_size, NULL, print_err);
+
+ /*
+ * If decompression was aborted due to an actual error rather than
+ * a fake error that we used to abort, then we should report it.
+ */
+ if (decompressed_bytes < limit)
+ return ret;
+
+ return decompressed_bytes - skip;
+}
diff --git a/arch/powerpc/boot/fixup-headers.sed b/arch/powerpc/boot/fixup-headers.sed
new file mode 100644
index 000000000000..96362428eb37
--- /dev/null
+++ b/arch/powerpc/boot/fixup-headers.sed
@@ -0,0 +1,12 @@
+# Copyright 2016 IBM 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 or later as
+# published by the Free Software Foundation.
+
+s@#include <linux/decompress/mm\.h>@@;
+s@\"zlib_inflate/\([^\"]*\).*@"\1"@;
+s@<linux/kernel.h>@<stddef.h>@;
+
+s@__used@@;
+s@<linux/\([^>]*\).*@"\1"@;
diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c
deleted file mode 100644
index 9dc52501de83..000000000000
--- a/arch/powerpc/boot/gunzip_util.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2007 David Gibson, IBM Corporation.
- * Based on earlier work, Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; 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 <stddef.h>
-#include "string.h"
-#include "stdio.h"
-#include "ops.h"
-#include "gunzip_util.h"
-
-#define HEAD_CRC 2
-#define EXTRA_FIELD 4
-#define ORIG_NAME 8
-#define COMMENT 0x10
-#define RESERVED 0xe0
-
-/**
- * gunzip_start - prepare to decompress gzip data
- * @state: decompressor state structure to be initialized
- * @src: buffer containing gzip compressed or uncompressed data
- * @srclen: size in bytes of the buffer at src
- *
- * If the buffer at @src contains a gzip header, this function
- * initializes zlib to decompress the data, storing the decompression
- * state in @state. The other functions in this file can then be used
- * to decompress data from the gzipped stream.
- *
- * If the buffer at @src does not contain a gzip header, it is assumed
- * to contain uncompressed data. The buffer information is recorded
- * in @state and the other functions in this file will simply copy
- * data from the uncompressed data stream at @src.
- *
- * Any errors, such as bad compressed data, cause an error to be
- * printed an the platform's exit() function to be called.
- */
-void gunzip_start(struct gunzip_state *state, void *src, int srclen)
-{
- char *hdr = src;
- int hdrlen = 0;
-
- memset(state, 0, sizeof(*state));
-
- /* Check for gzip magic number */
- if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
- /* gzip data, initialize zlib parameters */
- int r, flags;
-
- state->s.workspace = state->scratch;
- if (zlib_inflate_workspacesize() > sizeof(state->scratch))
- fatal("insufficient scratch space for gunzip\n\r");
-
- /* skip header */
- hdrlen = 10;
- flags = hdr[3];
- if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0)
- fatal("bad gzipped data\n\r");
- if ((flags & EXTRA_FIELD) != 0)
- hdrlen = 12 + hdr[10] + (hdr[11] << 8);
- if ((flags & ORIG_NAME) != 0)
- while (hdr[hdrlen++] != 0)
- ;
- if ((flags & COMMENT) != 0)
- while (hdr[hdrlen++] != 0)
- ;
- if ((flags & HEAD_CRC) != 0)
- hdrlen += 2;
- if (hdrlen >= srclen)
- fatal("gunzip_start: ran out of data in header\n\r");
-
- r = zlib_inflateInit2(&state->s, -MAX_WBITS);
- if (r != Z_OK)
- fatal("inflateInit2 returned %d\n\r", r);
- }
-
- state->s.total_in = hdrlen;
- state->s.next_in = src + hdrlen;
- state->s.avail_in = srclen - hdrlen;
-}
-
-/**
- * gunzip_partial - extract bytes from a gzip data stream
- * @state: gzip state structure previously initialized by gunzip_start()
- * @dst: buffer to store extracted data
- * @dstlen: maximum number of bytes to extract
- *
- * This function extracts at most @dstlen bytes from the data stream
- * previously associated with @state by gunzip_start(), decompressing
- * if necessary. Exactly @dstlen bytes are extracted unless the data
- * stream doesn't contain enough bytes, in which case the entire
- * remainder of the stream is decompressed.
- *
- * Returns the actual number of bytes extracted. If any errors occur,
- * such as a corrupted compressed stream, an error is printed an the
- * platform's exit() function is called.
- */
-int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
-{
- int len;
-
- if (state->s.workspace) {
- /* gunzipping */
- int r;
-
- state->s.next_out = dst;
- state->s.avail_out = dstlen;
- r = zlib_inflate(&state->s, Z_FULL_FLUSH);
- if (r != Z_OK && r != Z_STREAM_END)
- fatal("inflate returned %d msg: %s\n\r", r, state->s.msg);
- len = state->s.next_out - (Byte *)dst;
- } else {
- /* uncompressed image */
- len = min(state->s.avail_in, (uLong)dstlen);
- memcpy(dst, state->s.next_in, len);
- state->s.next_in += len;
- state->s.avail_in -= len;
- }
- return len;
-}
-
-/**
- * gunzip_exactly - extract a fixed number of bytes from a gzip data stream
- * @state: gzip state structure previously initialized by gunzip_start()
- * @dst: buffer to store extracted data
- * @dstlen: number of bytes to extract
- *
- * This function extracts exactly @dstlen bytes from the data stream
- * previously associated with @state by gunzip_start(), decompressing
- * if necessary.
- *
- * If there are less @dstlen bytes available in the data stream, or if
- * any other errors occur, such as a corrupted compressed stream, an
- * error is printed an the platform's exit() function is called.
- */
-void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
-{
- int len;
-
- len = gunzip_partial(state, dst, dstlen);
- if (len < dstlen)
- fatal("\n\rgunzip_exactly: ran out of data!"
- " Wanted %d, got %d.\n\r", dstlen, len);
-}
-
-/**
- * gunzip_discard - discard bytes from a gzip data stream
- * @state: gzip state structure previously initialized by gunzip_start()
- * @len: number of bytes to discard
- *
- * This function extracts, then discards exactly @len bytes from the
- * data stream previously associated with @state by gunzip_start().
- * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
- * calls will extract the data following the discarded bytes in the
- * data stream.
- *
- * If there are less @len bytes available in the data stream, or if
- * any other errors occur, such as a corrupted compressed stream, an
- * error is printed an the platform's exit() function is called.
- */
-void gunzip_discard(struct gunzip_state *state, int len)
-{
- static char discard_buf[128];
-
- while (len > sizeof(discard_buf)) {
- gunzip_exactly(state, discard_buf, sizeof(discard_buf));
- len -= sizeof(discard_buf);
- }
-
- if (len > 0)
- gunzip_exactly(state, discard_buf, len);
-}
-
-/**
- * gunzip_finish - extract all remaining bytes from a gzip data stream
- * @state: gzip state structure previously initialized by gunzip_start()
- * @dst: buffer to store extracted data
- * @dstlen: maximum number of bytes to extract
- *
- * This function extracts all remaining data, or at most @dstlen
- * bytes, from the stream previously associated with @state by
- * gunzip_start(). zlib is then shut down, so it is an error to use
- * any of the functions in this file on @state until it is
- * re-initialized with another call to gunzip_start().
- *
- * If any errors occur, such as a corrupted compressed stream, an
- * error is printed an the platform's exit() function is called.
- */
-int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
-{
- int len;
-
- len = gunzip_partial(state, dst, dstlen);
-
- if (state->s.workspace) {
- zlib_inflateEnd(&state->s);
- }
-
- return len;
-}
diff --git a/arch/powerpc/boot/gunzip_util.h b/arch/powerpc/boot/gunzip_util.h
deleted file mode 100644
index b3dfa6e87b3a..000000000000
--- a/arch/powerpc/boot/gunzip_util.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Decompression convenience functions
- *
- * Copyright 2007 David Gibson, 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.
- */
-#ifndef _PPC_BOOT_GUNZIP_UTIL_H_
-#define _PPC_BOOT_GUNZIP_UTIL_H_
-
-#include "zlib.h"
-
-/*
- * These functions are designed to make life easy for decompressing
- * kernel images, initrd images or any other gzip compressed image,
- * particularly if its useful to decompress part of the image (e.g. to
- * examine headers) before decompressing the remainder.
- *
- * To use:
- * - declare a gunzip_state structure
- * - use gunzip_start() to initialize the state, associating it
- * with a stream of compressed data
- * - use gunzip_partial(), gunzip_exactly() and gunzip_discard()
- * in any combination to extract pieces of data from the stream
- * - Finally use gunzip_finish() to extract the tail of the
- * compressed stream and wind up zlib
- */
-
-/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
-#define GUNZIP_SCRATCH_SIZE 46912
-
-struct gunzip_state {
- z_stream s;
- char scratch[46912];
-};
-
-void gunzip_start(struct gunzip_state *state, void *src, int srclen);
-int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen);
-void gunzip_exactly(struct gunzip_state *state, void *dst, int len);
-void gunzip_discard(struct gunzip_state *state, int len);
-int gunzip_finish(struct gunzip_state *state, void *dst, int len);
-
-#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index d80161b633f4..f7a184b6c35b 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -15,11 +15,8 @@
#include "string.h"
#include "stdio.h"
#include "ops.h"
-#include "gunzip_util.h"
#include "reg.h"
-static struct gunzip_state gzstate;
-
struct addr_range {
void *addr;
unsigned long size;
@@ -30,15 +27,14 @@ struct addr_range {
static struct addr_range prep_kernel(void)
{
char elfheader[256];
- void *vmlinuz_addr = _vmlinux_start;
+ unsigned char *vmlinuz_addr = (unsigned char *)_vmlinux_start;
unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
void *addr = 0;
struct elf_info ei;
- int len;
+ long len;
- /* gunzip the ELF header of the kernel */
- gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
- gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+ partial_decompress(vmlinuz_addr, vmlinuz_size,
+ elfheader, sizeof(elfheader), 0);
if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
@@ -51,7 +47,7 @@ static struct addr_range prep_kernel(void)
* the kernel bss must be claimed (it will be zero'd by the
* kernel itself)
*/
- printf("Allocating 0x%lx bytes for kernel ...\n\r", ei.memsize);
+ printf("Allocating 0x%lx bytes for kernel...\n\r", ei.memsize);
if (platform_ops.vmlinux_alloc) {
addr = platform_ops.vmlinux_alloc(ei.memsize);
@@ -71,16 +67,21 @@ static struct addr_range prep_kernel(void)
"device tree\n\r");
}
- /* Finally, gunzip the kernel */
- printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr,
+ /* Finally, decompress the kernel */
+ printf("Decompressing (0x%p <- 0x%p:0x%p)...\n\r", addr,
vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
- /* discard up to the actual load data */
- gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
- len = gunzip_finish(&gzstate, addr, ei.loadsize);
+
+ len = partial_decompress(vmlinuz_addr, vmlinuz_size,
+ addr, ei.loadsize, ei.elfoffset);
+
+ if (len < 0)
+ fatal("Decompression failed with error code %ld\n\r", len);
+
if (len != ei.loadsize)
- fatal("ran out of data! only got 0x%x of 0x%lx bytes.\n\r",
- len, ei.loadsize);
- printf("done 0x%x bytes\n\r", len);
+ fatal("Decompression error: got 0x%lx bytes, expected 0x%lx.\n\r",
+ len, ei.loadsize);
+
+ printf("Done! Decompressed 0x%lx bytes\n\r", len);
flush_cache(addr, ei.loadsize);
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index e19b64ef977a..309d1b127e96 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -260,4 +260,7 @@ int __ilog2_u32(u32 n)
return 31 - bit;
}
+long partial_decompress(void *inbuf, unsigned long input_size, void *outbuf,
+ unsigned long output_size, unsigned long skip);
+
#endif /* _PPC_BOOT_OPS_H_ */
diff --git a/arch/powerpc/boot/stdbool.h b/arch/powerpc/boot/stdbool.h
new file mode 100644
index 000000000000..f818efb08891
--- /dev/null
+++ b/arch/powerpc/boot/stdbool.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) IBM Corporation 2016.
+ *
+ * This program is free software; 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 file is only necessary because some of the pre-boot decompressors
+ * expect stdbool.h to be available.
+ *
+ */
+
+#include "types.h"
diff --git a/arch/powerpc/boot/stdint.h b/arch/powerpc/boot/stdint.h
new file mode 100644
index 000000000000..c1c853be7490
--- /dev/null
+++ b/arch/powerpc/boot/stdint.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) IBM Corporation 2016.
+ *
+ * This program is free software; 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 file is only necessary because some of the pre-boot decompressors
+ * expect stdint.h to be available.
+ */
+
+#include "types.h"
diff --git a/arch/powerpc/boot/types.h b/arch/powerpc/boot/types.h
index 85565a89bcc2..af6b66b842c4 100644
--- a/arch/powerpc/boot/types.h
+++ b/arch/powerpc/boot/types.h
@@ -1,6 +1,8 @@
#ifndef _TYPES_H_
#define _TYPES_H_
+#include <stdbool.h>
+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
typedef unsigned char u8;
@@ -34,4 +36,16 @@ typedef s64 int64_t;
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
+#define min_t(type, a, b) min(((type) a), ((type) b))
+#define max_t(type, a, b) max(((type) a), ((type) b))
+
+typedef int bool;
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
#endif /* _TYPES_H_ */
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 6681ec3625c9..404b3aabdb4d 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -20,6 +20,8 @@
# -D dir specify directory containing data files used by script
# (default ./arch/powerpc/boot)
# -W dir specify working directory for temporary files (default .)
+# -z use gzip (legacy)
+# -Z zsuffix compression to use (gz, xz or none)
# Stop execution if any command fails
set -e
@@ -38,7 +40,7 @@ dtb=
dts=
cacheit=
binary=
-gzip=.gz
+compression=.gz
pie=
format=
@@ -59,7 +61,8 @@ tmpdir=.
usage() {
echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2
echo ' [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2
- echo ' [-D datadir] [-W workingdir] [--no-gzip] [vmlinux]' >&2
+ echo ' [-D datadir] [-W workingdir] [-Z (gz|xz|none)]' >&2
+ echo ' [--no-compression] [vmlinux]' >&2
exit 1
}
@@ -126,8 +129,24 @@ while [ "$#" -gt 0 ]; do
[ "$#" -gt 0 ] || usage
tmpdir="$1"
;;
+ -z)
+ compression=.gz
+ ;;
+ -Z)
+ shift
+ [ "$#" -gt 0 ] || usage
+ [ "$1" != "gz" -o "$1" != "xz" -o "$1" != "none" ] || usage
+
+ compression=".$1"
+
+ if [ $compression = ".none" ]; then
+ compression=
+ fi
+ ;;
--no-gzip)
- gzip=
+ # a "feature" of the the wrapper script is that it can be used outside
+ # the kernel tree. So keeping this around for backwards compatibility.
+ compression=
;;
-?)
usage
@@ -140,6 +159,7 @@ while [ "$#" -gt 0 ]; do
shift
done
+
if [ -n "$dts" ]; then
if [ ! -r "$dts" -a -r "$object/dts/$dts" ]; then
dts="$object/dts/$dts"
@@ -212,7 +232,7 @@ miboot|uboot*)
;;
cuboot*)
binary=y
- gzip=
+ compression=
case "$platform" in
*-mpc866ads|*-mpc885ads|*-adder875*|*-ep88xc)
platformo=$object/cuboot-8xx.o
@@ -243,7 +263,7 @@ cuboot*)
ps3)
platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
lds=$object/zImage.ps3.lds
- gzip=
+ compression=
ext=bin
objflags="-O binary --set-section-flags=.bss=contents,alloc,load,data"
ksection=.kernel:vmlinux.bin
@@ -310,27 +330,37 @@ mvme7100)
esac
vmz="$tmpdir/`basename \"$kernel\"`.$ext"
-if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then
- ${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
- strip_size=$(stat -c %s $vmz.$$)
+# Calculate the vmlinux.strip size
+${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
+strip_size=$(stat -c %s $vmz.$$)
- if [ -n "$gzip" ]; then
+if [ -z "$cacheit" -o ! -f "$vmz$compression" -o "$vmz$compression" -ot "$kernel" ]; then
+ # recompress the image if we need to
+ case $compression in
+ .xz)
+ xz --check=crc32 -f -6 "$vmz.$$"
+ ;;
+ .gz)
gzip -n -f -9 "$vmz.$$"
- fi
+ ;;
+ *)
+ # drop the compression suffix so the stripped vmlinux is used
+ compression=
+ ;;
+ esac
if [ -n "$cacheit" ]; then
- mv -f "$vmz.$$$gzip" "$vmz$gzip"
+ mv -f "$vmz.$$$compression" "$vmz$compression"
else
vmz="$vmz.$$"
fi
else
- # Calculate the vmlinux.strip size
- ${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
- strip_size=$(stat -c %s $vmz.$$)
rm -f $vmz.$$
fi
+vmz="$vmz$compression"
+
if [ "$make_space" = "y" ]; then
# Round the size to next higher MB limit
round_size=$(((strip_size + 0xfffff) & 0xfff00000))
@@ -346,8 +376,6 @@ if [ "$make_space" = "y" ]; then
fi
fi
-vmz="$vmz$gzip"
-
# Extract kernel version information, some platforms want to include
# it in the image header
version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
@@ -417,6 +445,7 @@ if [ "$platform" != "miboot" ]; then
if [ -n "$link_address" ] ; then
text_start="-Ttext $link_address"
fi
+#link everything
${CROSS}ld -m $format -T $lds $text_start $pie -o "$ofile" \
$platformo $tmp $object/wrapper.a
rm $tmp
diff --git a/arch/powerpc/boot/xz_config.h b/arch/powerpc/boot/xz_config.h
new file mode 100644
index 000000000000..5c6afdbca642
--- /dev/null
+++ b/arch/powerpc/boot/xz_config.h
@@ -0,0 +1,39 @@
+#ifndef __XZ_CONFIG_H__
+#define __XZ_CONFIG_H__
+
+/*
+ * most of this is copied from lib/xz/xz_private.h, we can't use their defines
+ * since the boot wrapper is not built in the same environment as the rest of
+ * the kernel.
+ */
+
+#include "types.h"
+#include "swab.h"
+
+static inline uint32_t swab32p(void *p)
+{
+ uint32_t *q = p;
+
+ return swab32(*q);
+}
+
+#ifdef __LITTLE_ENDIAN__
+#define get_le32(p) (*((uint32_t *) (p)))
+#else
+#define get_le32(p) swab32p(p)
+#endif
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#define memzero(buf, size) memset(buf, 0, size)
+
+/* prevent the inclusion of the xz-preboot MM headers */
+#define DECOMPR_MM_H
+#define memmove memmove
+#define XZ_EXTERN static
+
+/* xz.h needs to be included directly since we need enum xz_mode */
+#include "../../../include/linux/xz.h"
+
+#undef XZ_EXTERN
+
+#endif
diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig
index dce352e9153b..d98b6eb3254f 100644
--- a/arch/powerpc/configs/powernv_defconfig
+++ b/arch/powerpc/configs/powernv_defconfig
@@ -15,6 +15,8 @@ CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=13
CONFIG_NUMA_BALANCING=y
CONFIG_CGROUPS=y
CONFIG_MEMCG=y
@@ -95,7 +97,7 @@ CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_AMD74XX=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
@@ -107,7 +109,7 @@ CONFIG_SCSI_CXGB4_ISCSI=m
CONFIG_SCSI_BNX2_ISCSI=m
CONFIG_BE2ISCSI=m
CONFIG_SCSI_MPT2SAS=m
-CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_2=m
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_IPR=y
CONFIG_SCSI_QLA_FC=m
@@ -149,10 +151,10 @@ CONFIG_TUN=m
CONFIG_VETH=m
CONFIG_VIRTIO_NET=m
CONFIG_VHOST_NET=m
-CONFIG_VORTEX=y
+CONFIG_VORTEX=m
CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_PCNET32=y
+CONFIG_PCNET32=m
CONFIG_TIGON3=y
CONFIG_BNX2X=m
CONFIG_CHELSIO_T1=m
@@ -163,6 +165,7 @@ CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_IXGB=m
CONFIG_IXGBE=m
+CONFIG_I40E=m
CONFIG_MLX4_EN=m
CONFIG_MYRI10GE=m
CONFIG_QLGE=m
@@ -238,7 +241,7 @@ CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-CONFIG_REISERFS_FS=y
+CONFIG_REISERFS_FS=m
CONFIG_REISERFS_FS_XATTR=y
CONFIG_REISERFS_FS_POSIX_ACL=y
CONFIG_REISERFS_FS_SECURITY=y
@@ -253,10 +256,10 @@ CONFIG_NILFS2_FS=m
CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=m
CONFIG_OVERLAY_FS=m
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
@@ -310,6 +313,8 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_DEV_NX=y
+CONFIG_CRYPTO_DEV_VMX=y
+CONFIG_CRYPTO_DEV_VMX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=m
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 0a8d250cb97e..58a98d40086f 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -10,6 +10,8 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=13
CONFIG_CGROUPS=y
CONFIG_CPUSETS=y
CONFIG_BLK_DEV_INITRD=y
@@ -90,7 +92,7 @@ CONFIG_BLK_DEV_AMD74XX=y
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
@@ -103,7 +105,7 @@ CONFIG_BE2ISCSI=m
CONFIG_SCSI_MPT2SAS=m
CONFIG_SCSI_IBMVSCSI=y
CONFIG_SCSI_IBMVFC=m
-CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_2=m
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_IPR=y
CONFIG_SCSI_QLA_FC=m
@@ -149,10 +151,10 @@ CONFIG_NETCONSOLE=y
CONFIG_TUN=m
CONFIG_VIRTIO_NET=m
CONFIG_VHOST_NET=m
-CONFIG_VORTEX=y
+CONFIG_VORTEX=m
CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_PCNET32=y
+CONFIG_PCNET32=m
CONFIG_TIGON3=y
CONFIG_BNX2X=m
CONFIG_CHELSIO_T1=m
@@ -165,6 +167,7 @@ CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_IXGB=m
CONFIG_IXGBE=m
+CONFIG_I40E=m
CONFIG_MLX4_EN=m
CONFIG_MYRI10GE=m
CONFIG_PASEMI_MAC=y
@@ -269,7 +272,7 @@ CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-CONFIG_REISERFS_FS=y
+CONFIG_REISERFS_FS=m
CONFIG_REISERFS_FS_XATTR=y
CONFIG_REISERFS_FS_POSIX_ACL=y
CONFIG_REISERFS_FS_SECURITY=y
@@ -284,10 +287,10 @@ CONFIG_NILFS2_FS=m
CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=m
CONFIG_OVERLAY_FS=m
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
@@ -347,6 +350,8 @@ CONFIG_CRYPTO_LZO=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_DEV_NX=y
CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
+CONFIG_CRYPTO_DEV_VMX=y
+CONFIG_CRYPTO_DEV_VMX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=m
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 654aeffc57ef..8a3bc016b732 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -15,6 +15,8 @@ CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=13
CONFIG_NUMA_BALANCING=y
CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
CONFIG_CGROUPS=y
@@ -95,7 +97,7 @@ CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_AMD74XX=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_ST=m
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
@@ -108,7 +110,7 @@ CONFIG_BE2ISCSI=m
CONFIG_SCSI_MPT2SAS=m
CONFIG_SCSI_IBMVSCSI=y
CONFIG_SCSI_IBMVFC=m
-CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_2=m
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_IPR=y
CONFIG_SCSI_QLA_FC=m
@@ -150,10 +152,10 @@ CONFIG_TUN=m
CONFIG_VETH=m
CONFIG_VIRTIO_NET=m
CONFIG_VHOST_NET=m
-CONFIG_VORTEX=y
+CONFIG_VORTEX=m
CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_PCNET32=y
+CONFIG_PCNET32=m
CONFIG_TIGON3=y
CONFIG_BNX2X=m
CONFIG_CHELSIO_T1=m
@@ -166,6 +168,7 @@ CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_IXGB=m
CONFIG_IXGBE=m
+CONFIG_I40E=m
CONFIG_MLX4_EN=m
CONFIG_MYRI10GE=m
CONFIG_QLGE=m
@@ -241,7 +244,7 @@ CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-CONFIG_REISERFS_FS=y
+CONFIG_REISERFS_FS=m
CONFIG_REISERFS_FS_XATTR=y
CONFIG_REISERFS_FS_POSIX_ACL=y
CONFIG_REISERFS_FS_SECURITY=y
@@ -256,10 +259,10 @@ CONFIG_NILFS2_FS=m
CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=m
CONFIG_OVERLAY_FS=m
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
@@ -314,6 +317,8 @@ CONFIG_CRYPTO_LZO=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_DEV_NX=y
CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
+CONFIG_CRYPTO_DEV_VMX=y
+CONFIG_CRYPTO_DEV_VMX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=m
diff --git a/arch/powerpc/crypto/sha1-powerpc-asm.S b/arch/powerpc/crypto/sha1-powerpc-asm.S
index 125e16520061..82ddc9bdfeb1 100644
--- a/arch/powerpc/crypto/sha1-powerpc-asm.S
+++ b/arch/powerpc/crypto/sha1-powerpc-asm.S
@@ -7,6 +7,15 @@
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
+#ifdef __BIG_ENDIAN__
+#define LWZ(rt, d, ra) \
+ lwz rt,d(ra)
+#else
+#define LWZ(rt, d, ra) \
+ li rt,d; \
+ lwbrx rt,rt,ra
+#endif
+
/*
* We roll the registers for T, A, B, C, D, E around on each
* iteration; T on iteration t is A on iteration t+1, and so on.
@@ -23,7 +32,7 @@
#define W(t) (((t)%16)+16)
#define LOADW(t) \
- lwz W(t),(t)*4(r4)
+ LWZ(W(t),(t)*4,r4)
#define STEPD0_LOAD(t) \
andc r0,RD(t),RB(t); \
@@ -33,7 +42,7 @@
add r0,RE(t),r15; \
add RT(t),RT(t),r6; \
add r14,r0,W(t); \
- lwz W((t)+4),((t)+4)*4(r4); \
+ LWZ(W((t)+4),((t)+4)*4,r4); \
rotlwi RB(t),RB(t),30; \
add RT(t),RT(t),r14
diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h
index e71b9097594c..d1492736d852 100644
--- a/arch/powerpc/include/asm/asm-prototypes.h
+++ b/arch/powerpc/include/asm/asm-prototypes.h
@@ -15,6 +15,8 @@
#include <linux/threads.h>
#include <linux/kprobes.h>
+#include <uapi/asm/ucontext.h>
+
/* SMP */
extern struct thread_info *current_set[NR_CPUS];
extern struct thread_info *secondary_ti;
@@ -52,8 +54,8 @@ void SMIException(struct pt_regs *regs);
void handle_hmi_exception(struct pt_regs *regs);
void instruction_breakpoint_exception(struct pt_regs *regs);
void RunModeException(struct pt_regs *regs);
-void __kprobes single_step_exception(struct pt_regs *regs);
-void __kprobes program_check_exception(struct pt_regs *regs);
+void single_step_exception(struct pt_regs *regs);
+void program_check_exception(struct pt_regs *regs);
void alignment_exception(struct pt_regs *regs);
void StackOverflow(struct pt_regs *regs);
void nonrecoverable_exception(struct pt_regs *regs);
@@ -70,6 +72,41 @@ void unrecoverable_exception(struct pt_regs *regs);
void kernel_bad_stack(struct pt_regs *regs);
void system_reset_exception(struct pt_regs *regs);
void machine_check_exception(struct pt_regs *regs);
-void __kprobes emulation_assist_interrupt(struct pt_regs *regs);
+void emulation_assist_interrupt(struct pt_regs *regs);
+
+/* signals, syscalls and interrupts */
+#ifdef CONFIG_PPC64
+int sys_swapcontext(struct ucontext __user *old_ctx,
+ struct ucontext __user *new_ctx,
+ long ctx_size, long r6, long r7, long r8, struct pt_regs *regs);
+#else
+long sys_swapcontext(struct ucontext __user *old_ctx,
+ struct ucontext __user *new_ctx,
+ int ctx_size, int r6, int r7, int r8, struct pt_regs *regs);
+#endif
+long sys_switch_endian(void);
+notrace unsigned int __check_irq_replay(void);
+void notrace restore_interrupts(void);
+
+/* ptrace */
+long do_syscall_trace_enter(struct pt_regs *regs);
+void do_syscall_trace_leave(struct pt_regs *regs);
+
+/* process */
+void restore_math(struct pt_regs *regs);
+void restore_tm_state(struct pt_regs *regs);
+
+/* prom_init (OpenFirmware) */
+unsigned long __init prom_init(unsigned long r3, unsigned long r4,
+ unsigned long pp,
+ unsigned long r6, unsigned long r7,
+ unsigned long kbase);
+
+/* setup */
+void __init early_setup(unsigned long dt_ptr);
+void early_setup_secondary(void);
+
+/* time */
+void accumulate_stolen_time(void);
#endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index f08d567e0ca4..2b90335194a7 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -233,7 +233,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
PPC_ATOMIC_ENTRY_BARRIER
"1: lwarx %0,0,%1 # __atomic_add_unless\n\
cmpw 0,%0,%3 \n\
- beq- 2f \n\
+ beq 2f \n\
add %0,%2,%0 \n"
PPC405_ERR77(0,%2)
" stwcx. %0,0,%1 \n\
@@ -539,7 +539,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
PPC_ATOMIC_ENTRY_BARRIER
"1: ldarx %0,0,%1 # __atomic_add_unless\n\
cmpd 0,%0,%3 \n\
- beq- 2f \n\
+ beq 2f \n\
add %0,%2,%0 \n"
" stdcx. %0,0,%1 \n\
bne- 1b \n"
diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 38b33dcfcc9d..6b8b2d57fdc8 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -223,7 +223,8 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
}
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
+static inline void __ptep_set_access_flags(struct mm_struct *mm,
+ pte_t *ptep, pte_t entry)
{
unsigned long set = pte_val(entry) &
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 263bf39ced40..9fd77f8794a0 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -6,6 +6,8 @@
*/
#define _PAGE_BIT_SWAP_TYPE 0
+#define _PAGE_RO 0
+
#define _PAGE_EXEC 0x00001 /* execute permission */
#define _PAGE_WRITE 0x00002 /* write access allowed */
#define _PAGE_READ 0x00004 /* read access allowed */
@@ -565,10 +567,11 @@ static inline bool check_pte_access(unsigned long access, unsigned long ptev)
* Generic functions with hash/radix callbacks
*/
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
+static inline void __ptep_set_access_flags(struct mm_struct *mm,
+ pte_t *ptep, pte_t entry)
{
if (radix_enabled())
- return radix__ptep_set_access_flags(ptep, entry);
+ return radix__ptep_set_access_flags(mm, ptep, entry);
return hash__ptep_set_access_flags(ptep, entry);
}
diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h
index df294224e280..2a46dea8e1b1 100644
--- a/arch/powerpc/include/asm/book3s/64/radix.h
+++ b/arch/powerpc/include/asm/book3s/64/radix.h
@@ -11,6 +11,11 @@
#include <asm/book3s/64/radix-4k.h>
#endif
+#ifndef __ASSEMBLY__
+#include <asm/book3s/64/tlbflush-radix.h>
+#include <asm/cpu_has_feature.h>
+#endif
+
/* An empty PTE can still have a R or C writeback */
#define RADIX_PTE_NONE_MASK (_PAGE_DIRTY | _PAGE_ACCESSED)
@@ -105,11 +110,8 @@
#define RADIX_PUD_TABLE_SIZE (sizeof(pud_t) << RADIX_PUD_INDEX_SIZE)
#define RADIX_PGD_TABLE_SIZE (sizeof(pgd_t) << RADIX_PGD_INDEX_SIZE)
-static inline unsigned long radix__pte_update(struct mm_struct *mm,
- unsigned long addr,
- pte_t *ptep, unsigned long clr,
- unsigned long set,
- int huge)
+static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr,
+ unsigned long set)
{
pte_t pte;
unsigned long old_pte, new_pte;
@@ -121,9 +123,39 @@ static inline unsigned long radix__pte_update(struct mm_struct *mm,
} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
- /* We already do a sync in cmpxchg, is ptesync needed ?*/
+ return old_pte;
+}
+
+
+static inline unsigned long radix__pte_update(struct mm_struct *mm,
+ unsigned long addr,
+ pte_t *ptep, unsigned long clr,
+ unsigned long set,
+ int huge)
+{
+ unsigned long old_pte;
+
+ if (cpu_has_feature(CPU_FTR_POWER9_DD1)) {
+
+ unsigned long new_pte;
+
+ old_pte = __radix_pte_update(ptep, ~0, 0);
+ asm volatile("ptesync" : : : "memory");
+ /*
+ * new value of pte
+ */
+ new_pte = (old_pte | set) & ~clr;
+
+ /*
+ * For now let's do heavy pid flush
+ * radix__flush_tlb_page_psize(mm, addr, mmu_virtual_psize);
+ */
+ radix__flush_tlb_mm(mm);
+
+ __radix_pte_update(ptep, 0, new_pte);
+ } else
+ old_pte = __radix_pte_update(ptep, clr, set);
asm volatile("ptesync" : : : "memory");
- /* huge pages use the old page table lock */
if (!huge)
assert_pte_locked(mm, addr);
@@ -134,20 +166,33 @@ static inline unsigned long radix__pte_update(struct mm_struct *mm,
* Set the dirty and/or accessed bits atomically in a linux PTE, this
* function doesn't need to invalidate tlb.
*/
-static inline void radix__ptep_set_access_flags(pte_t *ptep, pte_t entry)
+static inline void radix__ptep_set_access_flags(struct mm_struct *mm,
+ pte_t *ptep, pte_t entry)
{
- pte_t pte;
- unsigned long old_pte, new_pte;
+
unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED |
_PAGE_RW | _PAGE_EXEC);
- do {
- pte = READ_ONCE(*ptep);
- old_pte = pte_val(pte);
+
+ if (cpu_has_feature(CPU_FTR_POWER9_DD1)) {
+
+ unsigned long old_pte, new_pte;
+
+ old_pte = __radix_pte_update(ptep, ~0, 0);
+ asm volatile("ptesync" : : : "memory");
+ /*
+ * new value of pte
+ */
new_pte = old_pte | set;
- } while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
+ /*
+ * For now let's do heavy pid flush
+ * radix__flush_tlb_page_psize(mm, addr, mmu_virtual_psize);
+ */
+ radix__flush_tlb_mm(mm);
- /* We already do a sync in cmpxchg, is ptesync needed ?*/
+ __radix_pte_update(ptep, 0, new_pte);
+ } else
+ __radix_pte_update(ptep, 0, set);
asm volatile("ptesync" : : : "memory");
}
@@ -233,14 +278,19 @@ static inline unsigned long radix__get_tree_size(void)
{
unsigned long rts_field;
/*
- * we support 52 bits, hence 52-31 = 21, 0b10101
+ * We support 52 bits, hence:
+ * DD1 52-28 = 24, 0b11000
+ * Others 52-31 = 21, 0b10101
* RTS encoding details
* bits 0 - 3 of rts -> bits 6 - 8 unsigned long
* bits 4 - 5 of rts -> bits 62 - 63 of unsigned long
*/
- rts_field = (0x5UL << 5); /* 6 - 8 bits */
- rts_field |= (0x2UL << 61);
-
+ if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+ rts_field = (0x3UL << 61);
+ else {
+ rts_field = (0x5UL << 5); /* 6 - 8 bits */
+ rts_field |= (0x2UL << 61);
+ }
return rts_field;
}
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
index 65037762b120..a9e19cb2f7c5 100644
--- a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
+++ b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
@@ -41,4 +41,5 @@ extern void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmad
extern void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
unsigned long page_size);
extern void radix__flush_tlb_lpid(unsigned long lpid);
+extern void radix__flush_tlb_all(void);
#endif
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 82026b419341..f752e6f7cfbe 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -212,6 +212,7 @@ enum {
#define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000)
#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000)
#define CPU_FTR_SUBCORE LONG_ASM_CONST(0x2000000000000000)
+#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x4000000000000000)
#ifndef __ASSEMBLY__
@@ -472,6 +473,7 @@ enum {
CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300)
+#define CPU_FTRS_POWER9_DD1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1)
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -490,7 +492,7 @@ enum {
(CPU_FTRS_POWER4 | CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | \
CPU_FTRS_POWER6 | CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | \
CPU_FTRS_POWER8 | CPU_FTRS_POWER8_DD1 | CPU_FTRS_CELL | \
- CPU_FTRS_PA6T | CPU_FTR_VSX | CPU_FTRS_POWER9)
+ CPU_FTRS_PA6T | CPU_FTR_VSX | CPU_FTRS_POWER9 | CPU_FTRS_POWER9_DD1)
#endif
#else
enum {
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index bed66e5743b3..2e4e7d878c8e 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -34,6 +34,7 @@
* exception handlers (including pSeries LPAR) and iSeries LPAR
* implementations as possible.
*/
+#include <asm/head-64.h>
#define EX_R9 0
#define EX_R10 8
@@ -52,7 +53,6 @@
#ifdef CONFIG_RELOCATABLE
#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
- ld r12,PACAKBASE(r13); /* get high part of &label */ \
mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label); \
mtctr r12; \
@@ -84,13 +84,14 @@
/*
* We're short on space and time in the exception prolog, so we can't
- * use the normal SET_REG_IMMEDIATE macro. Normally we just need the
- * low halfword of the address, but for Kdump we need the whole low
- * word.
+ * use the normal LOAD_REG_IMMEDIATE macro to load the address of label.
+ * Instead we get the base of the kernel from paca->kernelbase and or in the low
+ * part of label. This requires that the label be within 64KB of kernelbase, and
+ * that kernelbase be 64K aligned.
*/
#define LOAD_HANDLER(reg, label) \
- /* Handlers must be within 64K of kbase, which must be 64k aligned */ \
- ori reg,reg,(label)-_stext; /* virt addr of handler ... */
+ ld reg,PACAKBASE(r13); /* get high part of &label */ \
+ ori reg,reg,(FIXED_SYMBOL_ABS_ADDR(label))@l;
/* Exception register prefixes */
#define EXC_HV H
@@ -175,7 +176,6 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
__EXCEPTION_PROLOG_1(area, extra, vec)
#define __EXCEPTION_PROLOG_PSERIES_1(label, h) \
- ld r12,PACAKBASE(r13); /* get high part of &label */ \
ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \
mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label) \
@@ -192,10 +192,10 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
EXCEPTION_PROLOG_1(area, extra, vec); \
EXCEPTION_PROLOG_PSERIES_1(label, h);
-#define __KVMTEST(n) \
- lbz r10,HSTATE_IN_GUEST(r13); \
+#define __KVMTEST(h, n) \
+ lbz r10,HSTATE_IN_GUEST(r13); \
cmpwi r10,0; \
- bne do_kvm_##n
+ bne do_kvm_##h##n
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
/*
@@ -208,8 +208,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
#define kvmppc_interrupt kvmppc_interrupt_pr
#endif
-#define __KVM_HANDLER(area, h, n) \
-do_kvm_##n: \
+#define __KVM_HANDLER_PROLOG(area, n) \
BEGIN_FTR_SECTION_NESTED(947) \
ld r10,area+EX_CFAR(r13); \
std r10,HSTATE_CFAR(r13); \
@@ -222,21 +221,23 @@ do_kvm_##n: \
stw r9,HSTATE_SCRATCH1(r13); \
ld r9,area+EX_R9(r13); \
std r12,HSTATE_SCRATCH0(r13); \
+
+#define __KVM_HANDLER(area, h, n) \
+ __KVM_HANDLER_PROLOG(area, n) \
li r12,n; \
b kvmppc_interrupt
#define __KVM_HANDLER_SKIP(area, h, n) \
-do_kvm_##n: \
cmpwi r10,KVM_GUEST_MODE_SKIP; \
ld r10,area+EX_R10(r13); \
beq 89f; \
- stw r9,HSTATE_SCRATCH1(r13); \
+ stw r9,HSTATE_SCRATCH1(r13); \
BEGIN_FTR_SECTION_NESTED(948) \
ld r9,area+EX_PPR(r13); \
std r9,HSTATE_PPR(r13); \
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \
ld r9,area+EX_R9(r13); \
- std r12,HSTATE_SCRATCH0(r13); \
+ std r12,HSTATE_SCRATCH0(r13); \
li r12,n; \
b kvmppc_interrupt; \
89: mtocrf 0x80,r9; \
@@ -244,12 +245,12 @@ do_kvm_##n: \
b kvmppc_skip_##h##interrupt
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#define KVMTEST(n) __KVMTEST(n)
+#define KVMTEST(h, n) __KVMTEST(h, n)
#define KVM_HANDLER(area, h, n) __KVM_HANDLER(area, h, n)
#define KVM_HANDLER_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n)
#else
-#define KVMTEST(n)
+#define KVMTEST(h, n)
#define KVM_HANDLER(area, h, n)
#define KVM_HANDLER_SKIP(area, h, n)
#endif
@@ -333,94 +334,79 @@ do_kvm_##n: \
/*
* Exception vectors.
*/
-#define STD_EXCEPTION_PSERIES(vec, label) \
- . = vec; \
- .globl label##_pSeries; \
-label##_pSeries: \
+#define STD_EXCEPTION_PSERIES(vec, label) \
SET_SCRATCH0(r13); /* save r13 */ \
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_STD, KVMTEST, vec)
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label, \
+ EXC_STD, KVMTEST_PR, vec); \
/* Version of above for when we have to branch out-of-line */
+#define __OOL_EXCEPTION(vec, label, hdlr) \
+ SET_SCRATCH0(r13) \
+ EXCEPTION_PROLOG_0(PACA_EXGEN) \
+ b hdlr;
+
#define STD_EXCEPTION_PSERIES_OOL(vec, label) \
- .globl label##_pSeries; \
-label##_pSeries: \
- EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
- EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD)
-
-#define STD_EXCEPTION_HV(loc, vec, label) \
- . = loc; \
- .globl label##_hv; \
-label##_hv: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label, EXC_STD)
+
+#define STD_EXCEPTION_HV(loc, vec, label) \
SET_SCRATCH0(r13); /* save r13 */ \
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_HV, KVMTEST, vec)
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label, \
+ EXC_HV, KVMTEST_HV, vec);
-/* Version of above for when we have to branch out-of-line */
-#define STD_EXCEPTION_HV_OOL(vec, label) \
- .globl label##_hv; \
-label##_hv: \
- EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
- EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV)
+#define STD_EXCEPTION_HV_OOL(vec, label) \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV)
#define STD_RELON_EXCEPTION_PSERIES(loc, vec, label) \
- . = loc; \
- .globl label##_relon_pSeries; \
-label##_relon_pSeries: \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
- EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_STD, NOTEST, vec)
+ EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label, EXC_STD, NOTEST, vec);
#define STD_RELON_EXCEPTION_PSERIES_OOL(vec, label) \
- .globl label##_relon_pSeries; \
-label##_relon_pSeries: \
EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \
- EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_STD)
+ EXCEPTION_RELON_PROLOG_PSERIES_1(label, EXC_STD)
#define STD_RELON_EXCEPTION_HV(loc, vec, label) \
- . = loc; \
- .globl label##_relon_hv; \
-label##_relon_hv: \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
- EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_HV, NOTEST, vec)
+ EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label, EXC_HV, NOTEST, vec);
#define STD_RELON_EXCEPTION_HV_OOL(vec, label) \
- .globl label##_relon_hv; \
-label##_relon_hv: \
EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \
- EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_HV)
+ EXCEPTION_RELON_PROLOG_PSERIES_1(label, EXC_HV)
/* This associate vector numbers with bits in paca->irq_happened */
#define SOFTEN_VALUE_0x500 PACA_IRQ_EE
-#define SOFTEN_VALUE_0x502 PACA_IRQ_EE
#define SOFTEN_VALUE_0x900 PACA_IRQ_DEC
-#define SOFTEN_VALUE_0x982 PACA_IRQ_DEC
+#define SOFTEN_VALUE_0x980 PACA_IRQ_DEC
#define SOFTEN_VALUE_0xa00 PACA_IRQ_DBELL
#define SOFTEN_VALUE_0xe80 PACA_IRQ_DBELL
-#define SOFTEN_VALUE_0xe82 PACA_IRQ_DBELL
#define SOFTEN_VALUE_0xe60 PACA_IRQ_HMI
-#define SOFTEN_VALUE_0xe62 PACA_IRQ_HMI
#define SOFTEN_VALUE_0xea0 PACA_IRQ_EE
-#define SOFTEN_VALUE_0xea2 PACA_IRQ_EE
#define __SOFTEN_TEST(h, vec) \
lbz r10,PACASOFTIRQEN(r13); \
cmpwi r10,0; \
li r10,SOFTEN_VALUE_##vec; \
beq masked_##h##interrupt
+
#define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec)
#define SOFTEN_TEST_PR(vec) \
- KVMTEST(vec); \
+ KVMTEST(EXC_STD, vec); \
_SOFTEN_TEST(EXC_STD, vec)
#define SOFTEN_TEST_HV(vec) \
- KVMTEST(vec); \
+ KVMTEST(EXC_HV, vec); \
_SOFTEN_TEST(EXC_HV, vec)
+#define KVMTEST_PR(vec) \
+ KVMTEST(EXC_STD, vec)
+
+#define KVMTEST_HV(vec) \
+ KVMTEST(EXC_HV, vec)
+
#define SOFTEN_NOTEST_PR(vec) _SOFTEN_TEST(EXC_STD, vec)
#define SOFTEN_NOTEST_HV(vec) _SOFTEN_TEST(EXC_HV, vec)
@@ -428,58 +414,47 @@ label##_relon_hv: \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_0(PACA_EXGEN); \
__EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
- EXCEPTION_PROLOG_PSERIES_1(label##_common, h);
+ EXCEPTION_PROLOG_PSERIES_1(label, h);
#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \
__MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)
#define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \
- . = loc; \
- .globl label##_pSeries; \
-label##_pSeries: \
_MASKABLE_EXCEPTION_PSERIES(vec, label, \
EXC_STD, SOFTEN_TEST_PR)
+#define MASKABLE_EXCEPTION_PSERIES_OOL(vec, label) \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_PR, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label, EXC_STD)
+
#define MASKABLE_EXCEPTION_HV(loc, vec, label) \
- . = loc; \
- .globl label##_hv; \
-label##_hv: \
_MASKABLE_EXCEPTION_PSERIES(vec, label, \
EXC_HV, SOFTEN_TEST_HV)
#define MASKABLE_EXCEPTION_HV_OOL(vec, label) \
- .globl label##_hv; \
-label##_hv: \
EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_HV, vec); \
- EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
+ EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV)
#define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_0(PACA_EXGEN); \
- __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
- EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, h);
-#define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \
+ __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
+ EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)
+
+#define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \
__MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)
#define MASKABLE_RELON_EXCEPTION_PSERIES(loc, vec, label) \
- . = loc; \
- .globl label##_relon_pSeries; \
-label##_relon_pSeries: \
_MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \
EXC_STD, SOFTEN_NOTEST_PR)
#define MASKABLE_RELON_EXCEPTION_HV(loc, vec, label) \
- . = loc; \
- .globl label##_relon_hv; \
-label##_relon_hv: \
_MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \
EXC_HV, SOFTEN_NOTEST_HV)
#define MASKABLE_RELON_EXCEPTION_HV_OOL(vec, label) \
- .globl label##_relon_hv; \
-label##_relon_hv: \
EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_HV, vec); \
- EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
+ EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV)
/*
* Our exception common code can be passed various "additions"
@@ -505,9 +480,6 @@ BEGIN_FTR_SECTION \
END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
#define EXCEPTION_COMMON(trap, label, hdlr, ret, additions) \
- .align 7; \
- .globl label##_common; \
-label##_common: \
EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \
/* Volatile regs are potentially clobbered here */ \
additions; \
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
index b4407d0add27..0031806475f0 100644
--- a/arch/powerpc/include/asm/fadump.h
+++ b/arch/powerpc/include/asm/fadump.h
@@ -45,10 +45,6 @@
#define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt)
-#ifndef ELF_CORE_EFLAGS
-#define ELF_CORE_EFLAGS 0
-#endif
-
/* Firmware provided dump sections */
#define FADUMP_CPU_STATE_DATA 0x0001
#define FADUMP_HPTE_REGION 0x0002
diff --git a/arch/powerpc/include/asm/head-64.h b/arch/powerpc/include/asm/head-64.h
new file mode 100644
index 000000000000..ab90c2fa1ea6
--- /dev/null
+++ b/arch/powerpc/include/asm/head-64.h
@@ -0,0 +1,393 @@
+#ifndef _ASM_POWERPC_HEAD_64_H
+#define _ASM_POWERPC_HEAD_64_H
+
+#include <asm/cache.h>
+
+/*
+ * We can't do CPP stringification and concatination directly into the section
+ * name for some reason, so these macros can do it for us.
+ */
+.macro define_ftsec name
+ .section ".head.text.\name\()","ax",@progbits
+.endm
+.macro define_data_ftsec name
+ .section ".head.data.\name\()","a",@progbits
+.endm
+.macro use_ftsec name
+ .section ".head.text.\name\()"
+.endm
+
+/*
+ * Fixed (location) sections are used by opening fixed sections and emitting
+ * fixed section entries into them before closing them. Multiple fixed sections
+ * can be open at any time.
+ *
+ * Each fixed section created in a .S file must have corresponding linkage
+ * directives including location, added to arch/powerpc/kernel/vmlinux.lds.S
+ *
+ * For each fixed section, code is generated into it in the order which it
+ * appears in the source. Fixed section entries can be placed at a fixed
+ * location within the section using _LOCATION postifx variants. These must
+ * be ordered according to their relative placements within the section.
+ *
+ * OPEN_FIXED_SECTION(section_name, start_address, end_address)
+ * FIXED_SECTION_ENTRY_BEGIN(section_name, label1)
+ *
+ * USE_FIXED_SECTION(section_name)
+ * label3:
+ * li r10,128
+ * mv r11,r10
+
+ * FIXED_SECTION_ENTRY_BEGIN_LOCATION(section_name, label2, start_address)
+ * FIXED_SECTION_ENTRY_END_LOCATION(section_name, label2, end_address)
+ * CLOSE_FIXED_SECTION(section_name)
+ *
+ * ZERO_FIXED_SECTION can be used to emit zeroed data.
+ *
+ * Troubleshooting:
+ * - If the build dies with "Error: attempt to move .org backwards" at
+ * CLOSE_FIXED_SECTION() or elsewhere, there may be something
+ * unexpected being added there. Remove the '. = x_len' line, rebuild, and
+ * check what is pushing the section down.
+ * - If the build dies in linking, check arch/powerpc/kernel/vmlinux.lds.S
+ * for instructions.
+ * - If the kernel crashes or hangs in very early boot, it could be linker
+ * stubs at the start of the main text.
+ */
+
+#define OPEN_FIXED_SECTION(sname, start, end) \
+ sname##_start = (start); \
+ sname##_end = (end); \
+ sname##_len = (end) - (start); \
+ define_ftsec sname; \
+ . = 0x0; \
+start_##sname:
+
+#define OPEN_TEXT_SECTION(start) \
+ text_start = (start); \
+ .section ".text","ax",@progbits; \
+ . = 0x0; \
+start_text:
+
+#define ZERO_FIXED_SECTION(sname, start, end) \
+ sname##_start = (start); \
+ sname##_end = (end); \
+ sname##_len = (end) - (start); \
+ define_data_ftsec sname; \
+ . = 0x0; \
+ . = sname##_len;
+
+#define USE_FIXED_SECTION(sname) \
+ fs_label = start_##sname; \
+ fs_start = sname##_start; \
+ use_ftsec sname;
+
+#define USE_TEXT_SECTION() \
+ fs_label = start_text; \
+ fs_start = text_start; \
+ .text
+
+#define CLOSE_FIXED_SECTION(sname) \
+ USE_FIXED_SECTION(sname); \
+ . = sname##_len; \
+end_##sname:
+
+
+#define __FIXED_SECTION_ENTRY_BEGIN(sname, name, __align) \
+ USE_FIXED_SECTION(sname); \
+ .align __align; \
+ .global name; \
+name:
+
+#define FIXED_SECTION_ENTRY_BEGIN(sname, name) \
+ __FIXED_SECTION_ENTRY_BEGIN(sname, name, 0)
+
+#define FIXED_SECTION_ENTRY_BEGIN_LOCATION(sname, name, start) \
+ USE_FIXED_SECTION(sname); \
+ name##_start = (start); \
+ .if (start) < sname##_start; \
+ .error "Fixed section underflow"; \
+ .abort; \
+ .endif; \
+ . = (start) - sname##_start; \
+ .global name; \
+name:
+
+#define FIXED_SECTION_ENTRY_END_LOCATION(sname, name, end) \
+ .if (end) > sname##_end; \
+ .error "Fixed section overflow"; \
+ .abort; \
+ .endif; \
+ .if (. - name > end - name##_start); \
+ .error "Fixed entry overflow"; \
+ .abort; \
+ .endif; \
+ . = ((end) - sname##_start); \
+
+
+/*
+ * These macros are used to change symbols in other fixed sections to be
+ * absolute or related to our current fixed section.
+ *
+ * - DEFINE_FIXED_SYMBOL / FIXED_SYMBOL_ABS_ADDR is used to find the
+ * absolute address of a symbol within a fixed section, from any section.
+ *
+ * - ABS_ADDR is used to find the absolute address of any symbol, from within
+ * a fixed section.
+ */
+#define DEFINE_FIXED_SYMBOL(label) \
+ label##_absolute = (label - fs_label + fs_start)
+
+#define FIXED_SYMBOL_ABS_ADDR(label) \
+ (label##_absolute)
+
+#define ABS_ADDR(label) (label - fs_label + fs_start)
+
+/*
+ * Following are the BOOK3S exception handler helper macros.
+ * Handlers come in a number of types, and each type has a number of varieties.
+ *
+ * EXC_REAL_* - real, unrelocated exception vectors
+ * EXC_VIRT_* - virt (AIL), unrelocated exception vectors
+ * TRAMP_REAL_* - real, unrelocated helpers (virt can call these)
+ * TRAMP_VIRT_* - virt, unreloc helpers (in practice, real can use)
+ * TRAMP_KVM - KVM handlers that get put into real, unrelocated
+ * EXC_COMMON_* - virt, relocated common handlers
+ *
+ * The EXC handlers are given a name, and branch to name_common, or the
+ * appropriate KVM or masking function. Vector handler verieties are as
+ * follows:
+ *
+ * EXC_{REAL|VIRT}_BEGIN/END - used to open-code the exception
+ *
+ * EXC_{REAL|VIRT} - standard exception
+ *
+ * EXC_{REAL|VIRT}_suffix
+ * where _suffix is:
+ * - _MASKABLE - maskable exception
+ * - _OOL - out of line with trampoline to common handler
+ * - _HV - HV exception
+ *
+ * There can be combinations, e.g., EXC_VIRT_OOL_MASKABLE_HV
+ *
+ * The one unusual case is __EXC_REAL_OOL_HV_DIRECT, which is
+ * an OOL vector that branches to a specified handler rather than the usual
+ * trampoline that goes to common. It, and other underscore macros, should
+ * be used with care.
+ *
+ * KVM handlers come in the following verieties:
+ * TRAMP_KVM
+ * TRAMP_KVM_SKIP
+ * TRAMP_KVM_HV
+ * TRAMP_KVM_HV_SKIP
+ *
+ * COMMON handlers come in the following verieties:
+ * EXC_COMMON_BEGIN/END - used to open-code the handler
+ * EXC_COMMON
+ * EXC_COMMON_ASYNC
+ * EXC_COMMON_HV
+ *
+ * TRAMP_REAL and TRAMP_VIRT can be used with BEGIN/END. KVM
+ * and OOL handlers are implemented as types of TRAMP and TRAMP_VIRT handlers.
+ */
+
+#define EXC_REAL_BEGIN(name, start, end) \
+ FIXED_SECTION_ENTRY_BEGIN_LOCATION(real_vectors, exc_real_##start##_##name, start)
+
+#define EXC_REAL_END(name, start, end) \
+ FIXED_SECTION_ENTRY_END_LOCATION(real_vectors, exc_real_##start##_##name, end)
+
+#define EXC_VIRT_BEGIN(name, start, end) \
+ FIXED_SECTION_ENTRY_BEGIN_LOCATION(virt_vectors, exc_virt_##start##_##name, start)
+
+#define EXC_VIRT_END(name, start, end) \
+ FIXED_SECTION_ENTRY_END_LOCATION(virt_vectors, exc_virt_##start##_##name, end)
+
+#define EXC_COMMON_BEGIN(name) \
+ USE_TEXT_SECTION(); \
+ .align 7; \
+ .global name; \
+ DEFINE_FIXED_SYMBOL(name); \
+name:
+
+#define TRAMP_REAL_BEGIN(name) \
+ FIXED_SECTION_ENTRY_BEGIN(real_trampolines, name)
+
+#define TRAMP_VIRT_BEGIN(name) \
+ FIXED_SECTION_ENTRY_BEGIN(virt_trampolines, name)
+
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+#define TRAMP_KVM_BEGIN(name) \
+ TRAMP_REAL_BEGIN(name)
+#else
+#define TRAMP_KVM_BEGIN(name)
+#endif
+
+#define EXC_REAL_NONE(start, end) \
+ FIXED_SECTION_ENTRY_BEGIN_LOCATION(real_vectors, exc_real_##start##_##unused, start); \
+ FIXED_SECTION_ENTRY_END_LOCATION(real_vectors, exc_real_##start##_##unused, end)
+
+#define EXC_VIRT_NONE(start, end) \
+ FIXED_SECTION_ENTRY_BEGIN_LOCATION(virt_vectors, exc_virt_##start##_##unused, start); \
+ FIXED_SECTION_ENTRY_END_LOCATION(virt_vectors, exc_virt_##start##_##unused, end);
+
+
+#define EXC_REAL(name, start, end) \
+ EXC_REAL_BEGIN(name, start, end); \
+ STD_EXCEPTION_PSERIES(start, name##_common); \
+ EXC_REAL_END(name, start, end);
+
+#define EXC_VIRT(name, start, end, realvec) \
+ EXC_VIRT_BEGIN(name, start, end); \
+ STD_RELON_EXCEPTION_PSERIES(start, realvec, name##_common); \
+ EXC_VIRT_END(name, start, end);
+
+#define EXC_REAL_MASKABLE(name, start, end) \
+ EXC_REAL_BEGIN(name, start, end); \
+ MASKABLE_EXCEPTION_PSERIES(start, start, name##_common); \
+ EXC_REAL_END(name, start, end);
+
+#define EXC_VIRT_MASKABLE(name, start, end, realvec) \
+ EXC_VIRT_BEGIN(name, start, end); \
+ MASKABLE_RELON_EXCEPTION_PSERIES(start, realvec, name##_common); \
+ EXC_VIRT_END(name, start, end);
+
+#define EXC_REAL_HV(name, start, end) \
+ EXC_REAL_BEGIN(name, start, end); \
+ STD_EXCEPTION_HV(start, start, name##_common); \
+ EXC_REAL_END(name, start, end);
+
+#define EXC_VIRT_HV(name, start, end, realvec) \
+ EXC_VIRT_BEGIN(name, start, end); \
+ STD_RELON_EXCEPTION_HV(start, realvec, name##_common); \
+ EXC_VIRT_END(name, start, end);
+
+#define __EXC_REAL_OOL(name, start, end) \
+ EXC_REAL_BEGIN(name, start, end); \
+ __OOL_EXCEPTION(start, label, tramp_real_##name); \
+ EXC_REAL_END(name, start, end);
+
+#define __TRAMP_REAL_REAL_OOL(name, vec) \
+ TRAMP_REAL_BEGIN(tramp_real_##name); \
+ STD_EXCEPTION_PSERIES_OOL(vec, name##_common); \
+
+#define EXC_REAL_OOL(name, start, end) \
+ __EXC_REAL_OOL(name, start, end); \
+ __TRAMP_REAL_REAL_OOL(name, start);
+
+#define __EXC_REAL_OOL_MASKABLE(name, start, end) \
+ __EXC_REAL_OOL(name, start, end);
+
+#define __TRAMP_REAL_REAL_OOL_MASKABLE(name, vec) \
+ TRAMP_REAL_BEGIN(tramp_real_##name); \
+ MASKABLE_EXCEPTION_PSERIES_OOL(vec, name##_common); \
+
+#define EXC_REAL_OOL_MASKABLE(name, start, end) \
+ __EXC_REAL_OOL_MASKABLE(name, start, end); \
+ __TRAMP_REAL_REAL_OOL_MASKABLE(name, start);
+
+#define __EXC_REAL_OOL_HV_DIRECT(name, start, end, handler) \
+ EXC_REAL_BEGIN(name, start, end); \
+ __OOL_EXCEPTION(start, label, handler); \
+ EXC_REAL_END(name, start, end);
+
+#define __EXC_REAL_OOL_HV(name, start, end) \
+ __EXC_REAL_OOL(name, start, end);
+
+#define __TRAMP_REAL_REAL_OOL_HV(name, vec) \
+ TRAMP_REAL_BEGIN(tramp_real_##name); \
+ STD_EXCEPTION_HV_OOL(vec, name##_common); \
+
+#define EXC_REAL_OOL_HV(name, start, end) \
+ __EXC_REAL_OOL_HV(name, start, end); \
+ __TRAMP_REAL_REAL_OOL_HV(name, start);
+
+#define __EXC_REAL_OOL_MASKABLE_HV(name, start, end) \
+ __EXC_REAL_OOL(name, start, end);
+
+#define __TRAMP_REAL_REAL_OOL_MASKABLE_HV(name, vec) \
+ TRAMP_REAL_BEGIN(tramp_real_##name); \
+ MASKABLE_EXCEPTION_HV_OOL(vec, name##_common); \
+
+#define EXC_REAL_OOL_MASKABLE_HV(name, start, end) \
+ __EXC_REAL_OOL_MASKABLE_HV(name, start, end); \
+ __TRAMP_REAL_REAL_OOL_MASKABLE_HV(name, start);
+
+#define __EXC_VIRT_OOL(name, start, end) \
+ EXC_VIRT_BEGIN(name, start, end); \
+ __OOL_EXCEPTION(start, label, tramp_virt_##name); \
+ EXC_VIRT_END(name, start, end);
+
+#define __TRAMP_REAL_VIRT_OOL(name, realvec) \
+ TRAMP_VIRT_BEGIN(tramp_virt_##name); \
+ STD_RELON_EXCEPTION_PSERIES_OOL(realvec, name##_common); \
+
+#define EXC_VIRT_OOL(name, start, end, realvec) \
+ __EXC_VIRT_OOL(name, start, end); \
+ __TRAMP_REAL_VIRT_OOL(name, realvec);
+
+#define __EXC_VIRT_OOL_MASKABLE(name, start, end) \
+ __EXC_VIRT_OOL(name, start, end);
+
+#define __TRAMP_REAL_VIRT_OOL_MASKABLE(name, realvec) \
+ TRAMP_VIRT_BEGIN(tramp_virt_##name); \
+ MASKABLE_RELON_EXCEPTION_PSERIES_OOL(realvec, name##_common); \
+
+#define EXC_VIRT_OOL_MASKABLE(name, start, end, realvec) \
+ __EXC_VIRT_OOL_MASKABLE(name, start, end); \
+ __TRAMP_REAL_VIRT_OOL_MASKABLE(name, realvec);
+
+#define __EXC_VIRT_OOL_HV(name, start, end) \
+ __EXC_VIRT_OOL(name, start, end);
+
+#define __TRAMP_REAL_VIRT_OOL_HV(name, realvec) \
+ TRAMP_VIRT_BEGIN(tramp_virt_##name); \
+ STD_RELON_EXCEPTION_HV_OOL(realvec, name##_common); \
+
+#define EXC_VIRT_OOL_HV(name, start, end, realvec) \
+ __EXC_VIRT_OOL_HV(name, start, end); \
+ __TRAMP_REAL_VIRT_OOL_HV(name, realvec);
+
+#define __EXC_VIRT_OOL_MASKABLE_HV(name, start, end) \
+ __EXC_VIRT_OOL(name, start, end);
+
+#define __TRAMP_REAL_VIRT_OOL_MASKABLE_HV(name, realvec) \
+ TRAMP_VIRT_BEGIN(tramp_virt_##name); \
+ MASKABLE_RELON_EXCEPTION_HV_OOL(realvec, name##_common); \
+
+#define EXC_VIRT_OOL_MASKABLE_HV(name, start, end, realvec) \
+ __EXC_VIRT_OOL_MASKABLE_HV(name, start, end); \
+ __TRAMP_REAL_VIRT_OOL_MASKABLE_HV(name, realvec);
+
+#define TRAMP_KVM(area, n) \
+ TRAMP_KVM_BEGIN(do_kvm_##n); \
+ KVM_HANDLER(area, EXC_STD, n); \
+
+#define TRAMP_KVM_SKIP(area, n) \
+ TRAMP_KVM_BEGIN(do_kvm_##n); \
+ KVM_HANDLER_SKIP(area, EXC_STD, n); \
+
+/*
+ * HV variant exceptions get the 0x2 bit added to their trap number.
+ */
+#define TRAMP_KVM_HV(area, n) \
+ TRAMP_KVM_BEGIN(do_kvm_H##n); \
+ KVM_HANDLER(area, EXC_HV, n + 0x2); \
+
+#define TRAMP_KVM_HV_SKIP(area, n) \
+ TRAMP_KVM_BEGIN(do_kvm_H##n); \
+ KVM_HANDLER_SKIP(area, EXC_HV, n + 0x2); \
+
+#define EXC_COMMON(name, realvec, hdlr) \
+ EXC_COMMON_BEGIN(name); \
+ STD_EXCEPTION_COMMON(realvec, name, hdlr); \
+
+#define EXC_COMMON_ASYNC(name, realvec, hdlr) \
+ EXC_COMMON_BEGIN(name); \
+ STD_EXCEPTION_COMMON_ASYNC(realvec, name, hdlr); \
+
+#define EXC_COMMON_HV(name, realvec, hdlr) \
+ EXC_COMMON_BEGIN(name); \
+ STD_EXCEPTION_COMMON(realvec + 0x2, name, hdlr); \
+
+#endif /* _ASM_POWERPC_HEAD_64_H */
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 0420b388dd83..e02cbc6a6c70 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -61,7 +61,7 @@ struct machdep_calls {
void (*init_IRQ)(void);
- /* Return an irq, or NO_IRQ to indicate there are none pending. */
+ /* Return an irq, or 0 to indicate there are none pending. */
unsigned int (*get_irq)(void);
/* PCI stuff */
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index cd4f04a74802..b62a8d43a06c 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -313,6 +313,9 @@ extern int book3e_htw_mode;
* return 1, indicating that the tlb requires preloading.
*/
#define HUGETLB_NEED_PRELOAD
+
+#define mmu_cleanup_all NULL
+
#endif
#endif /* !__ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index b78e8d3377f6..e88368354e49 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -204,6 +204,10 @@ extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
* make it match the size our of bolted TLB area
*/
extern u64 ppc64_rma_size;
+
+/* Cleanup function used by kexec */
+extern void mmu_cleanup_all(void);
+extern void radix__mmu_cleanup_all(void);
#endif /* CONFIG_PPC64 */
struct mm_struct;
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 9d2cd0c36ec2..5c451140660a 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -18,6 +18,7 @@ extern void destroy_context(struct mm_struct *mm);
#ifdef CONFIG_SPAPR_TCE_IOMMU
struct mm_iommu_table_group_mem_t;
+extern int isolate_lru_page(struct page *page); /* from internal.h */
extern bool mm_iommu_preregistered(void);
extern long mm_iommu_get(unsigned long ua, unsigned long entries,
struct mm_iommu_table_group_mem_t **pmem);
@@ -71,7 +72,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
/* Mark this context has been used on the new CPU */
- cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
+ if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next)))
+ cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
/* 32-bit keeps track of the current PGDIR in the thread struct */
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h
index 7b589178be46..4d52ccfc2366 100644
--- a/arch/powerpc/include/asm/mmzone.h
+++ b/arch/powerpc/include/asm/mmzone.h
@@ -41,6 +41,9 @@ u64 memory_hotplug_max(void);
#else
#define memory_hotplug_max() memblock_end_of_DRAM()
#endif /* CONFIG_NEED_MULTIPLE_NODES */
+#ifdef CONFIG_FA_DUMP
+#define __HAVE_ARCH_RESERVED_KERNEL_PAGES
+#endif
#endif /* __KERNEL__ */
#endif /* _ASM_MMZONE_H_ */
diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h
index d4f471fb1031..088420d8aa59 100644
--- a/arch/powerpc/include/asm/mpic_msgr.h
+++ b/arch/powerpc/include/asm/mpic_msgr.h
@@ -122,9 +122,9 @@ static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr,
* @msgr: the message register whose IRQ is to be returned
*
* Returns the IRQ number associated with the given message register.
- * NO_IRQ is returned if this message register is not capable of
- * receiving interrupts. What message register can and cannot receive
- * interrupts is specified in the device tree for the system.
+ * 0 is returned if this message register is not capable of receiving
+ * interrupts. What message register can and cannot receive interrupts is
+ * specified in the device tree for the system.
*/
static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr)
{
diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 780847597514..c219ef7be53b 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -267,7 +267,8 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
}
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
+static inline void __ptep_set_access_flags(struct mm_struct *mm,
+ pte_t *ptep, pte_t entry)
{
unsigned long set = pte_val(entry) &
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h
index d4d808cf905e..653a1838469d 100644
--- a/arch/powerpc/include/asm/nohash/64/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/64/pgtable.h
@@ -300,7 +300,8 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
/* Set the dirty and/or accessed bits atomically in a linux PTE, this
* function doesn't need to flush the hash entry
*/
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
+static inline void __ptep_set_access_flags(struct mm_struct *mm,
+ pte_t *ptep, pte_t entry)
{
unsigned long bits = pte_val(entry) &
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
diff --git a/arch/powerpc/include/asm/parport.h b/arch/powerpc/include/asm/parport.h
index a452968b29ea..6595ad1d18cc 100644
--- a/arch/powerpc/include/asm/parport.h
+++ b/arch/powerpc/include/asm/parport.h
@@ -28,7 +28,7 @@ static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
io1 = prop[1]; io2 = prop[2];
virq = irq_of_parse_and_map(np, 0);
- if (virq == NO_IRQ)
+ if (!virq)
continue;
if (parport_pc_probe_port(io1, io2, virq, autodma, NULL, 0)
diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h
index 1b46b52d3212..696438f09aea 100644
--- a/arch/powerpc/include/asm/pnv-pci.h
+++ b/arch/powerpc/include/asm/pnv-pci.h
@@ -16,7 +16,7 @@
#include <misc/cxl-base.h>
#include <asm/opal-api.h>
-#define PCI_SLOT_ID_PREFIX 0x8000000000000000
+#define PCI_SLOT_ID_PREFIX (1UL << 63)
#define PCI_SLOT_ID(phb_id, bdfn) \
(PCI_SLOT_ID_PREFIX | ((uint64_t)(bdfn) << 16) | (phb_id))
@@ -63,6 +63,8 @@ struct pnv_php_slot {
#define PNV_PHP_STATE_POPULATED 2
#define PNV_PHP_STATE_OFFLINE 3
int state;
+ int irq;
+ struct workqueue_struct *wq;
struct device_node *dn;
struct pci_dev *pdev;
struct pci_bus *bus;
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 127ebf5862b4..54ff8ce7fa96 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -236,6 +236,7 @@
#define PPC_INST_STWU 0x94000000
#define PPC_INST_MFLR 0x7c0802a6
#define PPC_INST_MTLR 0x7c0803a6
+#define PPC_INST_MTCTR 0x7c0903a6
#define PPC_INST_CMPWI 0x2c000000
#define PPC_INST_CMPDI 0x2c200000
#define PPC_INST_CMPW 0x7c000000
@@ -250,6 +251,7 @@
#define PPC_INST_SUB 0x7c000050
#define PPC_INST_BLR 0x4e800020
#define PPC_INST_BLRL 0x4e800021
+#define PPC_INST_BCTR 0x4e800420
#define PPC_INST_MULLD 0x7c0001d2
#define PPC_INST_MULLW 0x7c0001d6
#define PPC_INST_MULHWU 0x7c000016
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index d5d5b5e348f2..c73750b0d9fa 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -201,14 +201,12 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
#ifdef PPC64_ELF_ABI_v2
#define _GLOBAL(name) \
- .section ".text"; \
.align 2 ; \
.type name,@function; \
.globl name; \
name:
#define _GLOBAL_TOC(name) \
- .section ".text"; \
.align 2 ; \
.type name,@function; \
.globl name; \
@@ -217,13 +215,6 @@ name: \
addi r2,r2,(.TOC.-0b)@l; \
.localentry name,.-name
-#define _KPROBE(name) \
- .section ".kprobes.text","a"; \
- .align 2 ; \
- .type name,@function; \
- .globl name; \
-name:
-
#define DOTSYM(a) a
#else
@@ -232,35 +223,20 @@ name:
#define GLUE(a,b) XGLUE(a,b)
#define _GLOBAL(name) \
- .section ".text"; \
.align 2 ; \
.globl name; \
.globl GLUE(.,name); \
- .section ".opd","aw"; \
+ .pushsection ".opd","aw"; \
name: \
.quad GLUE(.,name); \
.quad .TOC.@tocbase; \
.quad 0; \
- .previous; \
+ .popsection; \
.type GLUE(.,name),@function; \
GLUE(.,name):
#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); \
- .quad .TOC.@tocbase; \
- .quad 0; \
- .previous; \
- .type GLUE(.,name),@function; \
-GLUE(.,name):
-
#define DOTSYM(a) GLUE(.,a)
#endif
@@ -272,20 +248,28 @@ GLUE(.,name):
n:
#define _GLOBAL(n) \
- .text; \
.stabs __stringify(n:F-1),N_FUN,0,0,n;\
.globl n; \
n:
#define _GLOBAL_TOC(name) _GLOBAL(name)
-#define _KPROBE(n) \
- .section ".kprobes.text","a"; \
- .globl n; \
-n:
-
#endif
+/*
+ * __kprobes (the C annotation) puts the symbol into the .kprobes.text
+ * section, which gets emitted at the end of regular text.
+ *
+ * _ASM_NOKPROBE_SYMBOL and NOKPROBE_SYMBOL just adds the symbol to
+ * a blacklist. The former is for core kprobe functions/data, the
+ * latter is for those that incdentially must be excluded from probing
+ * and allows them to be linked at more optimal location within text.
+ */
+#define _ASM_NOKPROBE_SYMBOL(entry) \
+ .pushsection "_kprobe_blacklist","aw"; \
+ PPC_LONG (entry) ; \
+ .popsection
+
#define FUNC_START(name) _GLOBAL(name)
#define FUNC_END(name)
@@ -527,7 +511,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
#endif
#define MTMSRD(r) mtmsr r
#define MTMSR_EERI(reg) mtmsr reg
-#define CLR_TOP32(r)
#endif
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 68e3bf57b027..c07c31b0e89e 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -147,7 +147,7 @@ typedef struct {
} mm_segment_t;
#define TS_FPR(i) fp_state.fpr[i][TS_FPROFFSET]
-#define TS_TRANS_FPR(i) transact_fp.fpr[i][TS_FPROFFSET]
+#define TS_CKFPR(i) ckfp_state.fpr[i][TS_FPROFFSET]
/* FP and VSX 0-31 register set */
struct thread_fp_state {
@@ -257,6 +257,7 @@ struct thread_struct {
int used_spe; /* set if process has used spe */
#endif /* CONFIG_SPE */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ u8 load_tm;
u64 tm_tfhar; /* Transaction fail handler addr */
u64 tm_texasr; /* Transaction exception & summary */
u64 tm_tfiar; /* Transaction fail instr address reg */
@@ -267,20 +268,17 @@ struct thread_struct {
unsigned long tm_dscr;
/*
- * Transactional FP and VSX 0-31 register set.
- * NOTE: the sense of these is the opposite of the integer ckpt_regs!
+ * Checkpointed FP and VSX 0-31 register set.
*
* When a transaction is active/signalled/scheduled etc., *regs is the
* most recent set of/speculated GPRs with ckpt_regs being the older
* checkpointed regs to which we roll back if transaction aborts.
*
- * However, fpr[] is the checkpointed 'base state' of FP regs, and
- * transact_fpr[] is the new set of transactional values.
- * VRs work the same way.
+ * These are analogous to how ckpt_regs and pt_regs work
*/
- struct thread_fp_state transact_fp;
- struct thread_vr_state transact_vr;
- unsigned long transact_vrsave;
+ struct thread_fp_state ckfp_state; /* Checkpointed FP state */
+ struct thread_vr_state ckvr_state; /* Checkpointed VR state */
+ unsigned long ckvrsave; /* Checkpointed VRSAVE */
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
void* kvm_shadow_vcpu; /* KVM internal data */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 978dada662ae..2a620789954b 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -475,6 +475,9 @@
#define HID0_POWER8_1TO4LPAR __MASK(51)
#define HID0_POWER8_DYNLPARDIS __MASK(48)
+/* POWER9 HID0 bits */
+#define HID0_POWER9_RADIX __MASK(63 - 8)
+
#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */
#ifdef CONFIG_6xx
#define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */
@@ -1248,7 +1251,7 @@ static inline void mtmsr_isync(unsigned long val)
: "memory")
#endif
-extern void msr_check_and_set(unsigned long bits);
+extern unsigned long msr_check_and_set(unsigned long bits);
extern bool strict_msr_control;
extern void __msr_check_and_clear(unsigned long bits);
static inline void msr_check_and_clear(unsigned long bits)
diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h
index 9322c28aebd2..5ff77722a52d 100644
--- a/arch/powerpc/include/asm/signal.h
+++ b/arch/powerpc/include/asm/signal.h
@@ -5,6 +5,4 @@
#include <uapi/asm/signal.h>
#include <uapi/asm/ptrace.h>
-extern unsigned long get_tm_stackpointer(struct pt_regs *regs);
-
#endif /* _ASM_POWERPC_SIGNAL_H */
diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h
index c22d704b6d41..82e06ca3a49b 100644
--- a/arch/powerpc/include/asm/tm.h
+++ b/arch/powerpc/include/asm/tm.h
@@ -9,11 +9,6 @@
#ifndef __ASSEMBLY__
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-extern void do_load_up_transact_fpu(struct thread_struct *thread);
-extern void do_load_up_transact_altivec(struct thread_struct *thread);
-#endif
-
extern void tm_enable(void);
extern void tm_reclaim(struct thread_struct *thread,
unsigned long orig_msr, uint8_t cause);
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index fe4c075bcf50..aded29ad2e8f 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -31,8 +31,7 @@ obj-y := cputable.o ptrace.o syscalls.o \
process.o systbl.o idle.o \
signal.o sysfs.o cacheinfo.o time.o \
prom.o traps.o setup-common.o \
- udbg.o misc.o io.o dma.o \
- misc_$(CONFIG_WORD_SIZE).o \
+ udbg.o misc.o io.o dma.o misc_$(BITS).o \
of_platform.o prom_parse.o
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
signal_64.o ptrace32.o \
@@ -70,23 +69,23 @@ obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o
ifeq ($(CONFIG_FSL_BOOKE),y)
obj-$(CONFIG_HIBERNATION) += swsusp_booke.o
else
-obj-$(CONFIG_HIBERNATION) += swsusp_$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_HIBERNATION) += swsusp_$(BITS).o
endif
obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o
-obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_MODULES) += module.o module_$(BITS).o
obj-$(CONFIG_44x) += cpu_setup_44x.o
obj-$(CONFIG_PPC_FSL_BOOK3E) += cpu_setup_fsl_booke.o
obj-$(CONFIG_PPC_DOORBELL) += dbell.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
-extra-y := head_$(CONFIG_WORD_SIZE).o
+extra-y := head_$(BITS).o
extra-$(CONFIG_40x) := head_40x.o
extra-$(CONFIG_44x) := head_44x.o
extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o
extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds
-obj-$(CONFIG_RELOCATABLE) += reloc_$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_RELOCATABLE) += reloc_$(BITS).o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o
@@ -104,11 +103,11 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
pci64-$(CONFIG_PPC64) += pci_dn.o pci-hotplug.o isa-bridge.o
-obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
+obj-$(CONFIG_PCI) += pci_$(BITS).o $(pci64-y) \
pci-common.o pci_of_scan.o
obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \
- machine_kexec_$(CONFIG_WORD_SIZE).o
+ machine_kexec_$(BITS).o
obj-$(CONFIG_AUDIT) += audit.o
obj64-$(CONFIG_AUDIT) += compat_audit.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index a51ae9b165e0..caec7bf3b99a 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -142,12 +142,12 @@ int main(void)
DEFINE(THREAD_TM_PPR, offsetof(struct thread_struct, tm_ppr));
DEFINE(THREAD_TM_DSCR, offsetof(struct thread_struct, tm_dscr));
DEFINE(PT_CKPT_REGS, offsetof(struct thread_struct, ckpt_regs));
- DEFINE(THREAD_TRANSACT_VRSTATE, offsetof(struct thread_struct,
- transact_vr));
- DEFINE(THREAD_TRANSACT_VRSAVE, offsetof(struct thread_struct,
- transact_vrsave));
- DEFINE(THREAD_TRANSACT_FPSTATE, offsetof(struct thread_struct,
- transact_fp));
+ DEFINE(THREAD_CKVRSTATE, offsetof(struct thread_struct,
+ ckvr_state));
+ DEFINE(THREAD_CKVRSAVE, offsetof(struct thread_struct,
+ ckvrsave));
+ DEFINE(THREAD_CKFPSTATE, offsetof(struct thread_struct,
+ ckfp_state));
/* Local pt_regs on stack for Transactional Memory funcs. */
DEFINE(TM_FRAME_SIZE, STACK_FRAME_OVERHEAD +
sizeof(struct pt_regs) + 16);
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 74248ab18e98..6c4646ac9234 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -506,6 +506,25 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check_early = __machine_check_early_realmode_p8,
.platform = "power8",
},
+ { /* Power9 DD1*/
+ .pvr_mask = 0xffffff00,
+ .pvr_value = 0x004e0100,
+ .cpu_name = "POWER9 (raw)",
+ .cpu_features = CPU_FTRS_POWER9_DD1,
+ .cpu_user_features = COMMON_USER_POWER9,
+ .cpu_user_features2 = COMMON_USER2_POWER9,
+ .mmu_features = MMU_FTRS_POWER9,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .num_pmcs = 6,
+ .pmc_type = PPC_PMC_IBM,
+ .oprofile_cpu_type = "ppc64/power9",
+ .oprofile_type = PPC_OPROFILE_INVALID,
+ .cpu_setup = __setup_cpu_power9,
+ .cpu_restore = __restore_cpu_power9,
+ .flush_tlb = __flush_tlb_power9,
+ .platform = "power9",
+ },
{ /* Power9 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x004e0000,
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 7429556eb8df..f25731627d7f 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -116,6 +116,7 @@ struct eeh_ops *eeh_ops = NULL;
/* Lock to avoid races due to multiple reports of an error */
DEFINE_RAW_SPINLOCK(confirm_error_lock);
+EXPORT_SYMBOL_GPL(confirm_error_lock);
/* Lock to protect passed flags */
static DEFINE_MUTEX(eeh_dev_mutex);
@@ -1044,7 +1045,7 @@ int eeh_init(void)
if (eeh_enabled())
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
else
- pr_warn("EEH: No capable adapters found\n");
+ pr_info("EEH: No capable adapters found\n");
return ret;
}
@@ -1502,6 +1503,7 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)
break;
case EEH_OPT_THAW_MMIO:
case EEH_OPT_THAW_DMA:
+ case EEH_OPT_FREEZE_PE:
if (!eeh_ops || !eeh_ops->set_option) {
ret = -ENOENT;
break;
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 5f36e8a70daa..a62be72da274 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -993,9 +993,17 @@ static void eeh_handle_special_event(void)
/* Notify all devices to be down */
eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
- bus = eeh_pe_bus_get(phb_pe);
eeh_pe_dev_traverse(pe,
eeh_report_failure, NULL);
+ bus = eeh_pe_bus_get(phb_pe);
+ if (!bus) {
+ pr_err("%s: Cannot find PCI bus for "
+ "PHB#%d-PE#%x\n",
+ __func__,
+ pe->phb->global_number,
+ pe->addr);
+ break;
+ }
pci_hp_remove_devices(bus);
}
pci_unlock_rescan_remove();
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index f0520da85759..de7d091c4c31 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -581,6 +581,7 @@ void eeh_pe_state_mark(struct eeh_pe *pe, int state)
{
eeh_pe_traverse(pe, __eeh_pe_state_mark, &state);
}
+EXPORT_SYMBOL_GPL(eeh_pe_state_mark);
static void *__eeh_pe_dev_mode_mark(void *data, void *flag)
{
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 9899032230b4..83428a283fa0 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -654,7 +654,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPE)
#endif /* CONFIG_SMP */
tophys(r0,r4)
- CLR_TOP32(r0)
mtspr SPRN_SPRG_THREAD,r0 /* Update current THREAD phys addr */
lwz r1,KSP(r4) /* Load new stack pointer */
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 5afd03e5e8b8..51df82b61084 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -139,7 +139,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
#ifdef CONFIG_PPC_BOOK3E
wrteei 1
#else
- ld r11,PACAKMSR(r13)
+ li r11,MSR_RI
ori r11,r11,MSR_EE
mtmsrd r11,1
#endif /* CONFIG_PPC_BOOK3E */
@@ -195,7 +195,6 @@ system_call: /* label this so stack traces look sane */
#ifdef CONFIG_PPC_BOOK3E
wrteei 0
#else
- ld r10,PACAKMSR(r13)
/*
* For performance reasons we clear RI the same time that we
* clear EE. We only need to clear RI just before we restore r13
@@ -203,8 +202,7 @@ system_call: /* label this so stack traces look sane */
* We have to be careful to restore RI if we branch anywhere from
* here (eg syscall_exit_work).
*/
- li r9,MSR_RI
- andc r11,r10,r9
+ li r11,0
mtmsrd r11,1
#endif /* CONFIG_PPC_BOOK3E */
@@ -221,13 +219,12 @@ system_call: /* label this so stack traces look sane */
#endif
2: addi r3,r1,STACK_FRAME_OVERHEAD
#ifdef CONFIG_PPC_BOOK3S
+ li r10,MSR_RI
mtmsrd r10,1 /* Restore RI */
#endif
bl restore_math
#ifdef CONFIG_PPC_BOOK3S
- ld r10,PACAKMSR(r13)
- li r9,MSR_RI
- andc r11,r10,r9 /* Re-clear RI */
+ li r11,0
mtmsrd r11,1
#endif
ld r8,_MSR(r1)
@@ -308,6 +305,7 @@ syscall_enosys:
syscall_exit_work:
#ifdef CONFIG_PPC_BOOK3S
+ li r10,MSR_RI
mtmsrd r10,1 /* Restore RI */
#endif
/* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr.
@@ -354,7 +352,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
#ifdef CONFIG_PPC_BOOK3E
wrteei 1
#else
- ld r10,PACAKMSR(r13)
+ li r10,MSR_RI
ori r10,r10,MSR_EE
mtmsrd r10,1
#endif /* CONFIG_PPC_BOOK3E */
@@ -619,7 +617,7 @@ _GLOBAL(ret_from_except_lite)
#ifdef CONFIG_PPC_BOOK3E
wrteei 0
#else
- ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */
+ li r10,MSR_RI
mtmsrd r10,1 /* Update machine state */
#endif /* CONFIG_PPC_BOOK3E */
@@ -751,7 +749,7 @@ resume_kernel:
#ifdef CONFIG_PPC_BOOK3E
wrteei 0
#else
- ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */
+ li r10,MSR_RI
mtmsrd r10,1 /* Update machine state */
#endif /* CONFIG_PPC_BOOK3E */
#endif /* CONFIG_PREEMPT */
@@ -841,8 +839,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
* userspace and we take an exception after restoring r13,
* we end up corrupting the userspace r13 value.
*/
- ld r4,PACAKMSR(r13) /* Get kernel MSR without EE */
- andc r4,r4,r0 /* r0 contains MSR_RI here */
+ li r4,0
mtmsrd r4,1
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index bffec73dbffc..08992f8f5036 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -16,72 +16,71 @@
#include <asm/exception-64s.h>
#include <asm/ptrace.h>
#include <asm/cpuidle.h>
+#include <asm/head-64.h>
/*
+ * There are a few constraints to be concerned with.
+ * - Real mode exceptions code/data must be located at their physical location.
+ * - Virtual mode exceptions must be mapped at their 0xc000... location.
+ * - Fixed location code must not call directly beyond the __end_interrupts
+ * area when built with CONFIG_RELOCATABLE. LOAD_HANDLER / bctr sequence
+ * must be used.
+ * - LOAD_HANDLER targets must be within first 64K of physical 0 /
+ * virtual 0xc00...
+ * - Conditional branch targets must be within +/-32K of caller.
+ *
+ * "Virtual exceptions" run with relocation on (MSR_IR=1, MSR_DR=1), and
+ * therefore don't have to run in physically located code or rfid to
+ * virtual mode kernel code. However on relocatable kernels they do have
+ * to branch to KERNELBASE offset because the rest of the kernel (outside
+ * the exception vectors) may be located elsewhere.
+ *
+ * Virtual exceptions correspond with physical, except their entry points
+ * are offset by 0xc000000000000000 and also tend to get an added 0x4000
+ * offset applied. Virtual exceptions are enabled with the Alternate
+ * Interrupt Location (AIL) bit set in the LPCR. However this does not
+ * guarantee they will be delivered virtually. Some conditions (see the ISA)
+ * cause exceptions to be delivered in real mode.
+ *
+ * It's impossible to receive interrupts below 0x300 via AIL.
+ *
+ * KVM: None of the virtual exceptions are from the guest. Anything that
+ * escalated to HV=1 from HV=0 is delivered via real mode handlers.
+ *
+ *
* We layout physical memory as follows:
* 0x0000 - 0x00ff : Secondary processor spin code
- * 0x0100 - 0x17ff : pSeries Interrupt prologs
- * 0x1800 - 0x4000 : interrupt support common interrupt prologs
- * 0x4000 - 0x5fff : pSeries interrupts with IR=1,DR=1
- * 0x6000 - 0x6fff : more interrupt support including for IR=1,DR=1
+ * 0x0100 - 0x18ff : Real mode pSeries interrupt vectors
+ * 0x1900 - 0x3fff : Real mode trampolines
+ * 0x4000 - 0x58ff : Relon (IR=1,DR=1) mode pSeries interrupt vectors
+ * 0x5900 - 0x6fff : Relon mode trampolines
* 0x7000 - 0x7fff : FWNMI data area
- * 0x8000 - 0x8fff : Initial (CPU0) segment table
- * 0x9000 - : Early init and support code
+ * 0x8000 - .... : Common interrupt handlers, remaining early
+ * setup code, rest of kernel.
+ *
+ * We could reclaim 0x4000-0x42ff for real mode trampolines if the space
+ * is necessary. Until then it's more consistent to explicitly put VIRT_NONE
+ * vectors there.
*/
- /* Syscall routine is used twice, in reloc-off and reloc-on paths */
-#define SYSCALL_PSERIES_1 \
-BEGIN_FTR_SECTION \
- cmpdi r0,0x1ebe ; \
- beq- 1f ; \
-END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
- mr r9,r13 ; \
- GET_PACA(r13) ; \
- mfspr r11,SPRN_SRR0 ; \
-0:
-
-#define SYSCALL_PSERIES_2_RFID \
- mfspr r12,SPRN_SRR1 ; \
- ld r10,PACAKBASE(r13) ; \
- LOAD_HANDLER(r10, system_call_entry) ; \
- mtspr SPRN_SRR0,r10 ; \
- ld r10,PACAKMSR(r13) ; \
- mtspr SPRN_SRR1,r10 ; \
- rfid ; \
- b . ; /* prevent speculative execution */
-
-#define SYSCALL_PSERIES_3 \
- /* Fast LE/BE switch system call */ \
-1: mfspr r12,SPRN_SRR1 ; \
- xori r12,r12,MSR_LE ; \
- mtspr SPRN_SRR1,r12 ; \
- rfid ; /* return to userspace */ \
- b . ; /* prevent speculative execution */
-
-#if defined(CONFIG_RELOCATABLE)
- /*
- * We can't branch directly so we do it via the CTR which
- * is volatile across system calls.
- */
-#define SYSCALL_PSERIES_2_DIRECT \
- mflr r10 ; \
- ld r12,PACAKBASE(r13) ; \
- LOAD_HANDLER(r12, system_call_entry) ; \
- mtctr r12 ; \
- mfspr r12,SPRN_SRR1 ; \
- /* Re-use of r13... No spare regs to do this */ \
- li r13,MSR_RI ; \
- mtmsrd r13,1 ; \
- GET_PACA(r13) ; /* get r13 back */ \
- bctr ;
+OPEN_FIXED_SECTION(real_vectors, 0x0100, 0x1900)
+OPEN_FIXED_SECTION(real_trampolines, 0x1900, 0x4000)
+OPEN_FIXED_SECTION(virt_vectors, 0x4000, 0x5900)
+OPEN_FIXED_SECTION(virt_trampolines, 0x5900, 0x7000)
+#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
+/*
+ * Data area reserved for FWNMI option.
+ * This address (0x7000) is fixed by the RPA.
+ * pseries and powernv need to keep the whole page from
+ * 0x7000 to 0x8000 free for use by the firmware
+ */
+ZERO_FIXED_SECTION(fwnmi_page, 0x7000, 0x8000)
+OPEN_TEXT_SECTION(0x8000)
#else
- /* We can branch directly */
-#define SYSCALL_PSERIES_2_DIRECT \
- mfspr r12,SPRN_SRR1 ; \
- li r10,MSR_RI ; \
- mtmsrd r10,1 ; /* Set RI (EE=0) */ \
- b system_call_common ;
+OPEN_TEXT_SECTION(0x7000)
#endif
+USE_FIXED_SECTION(real_vectors)
+
/*
* This is the start of the interrupt handlers for pSeries
* This code runs with relocation off.
@@ -90,12 +89,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
* Therefore any relative branches in this section must only
* branch to labels in this section.
*/
- . = 0x100
.globl __start_interrupts
__start_interrupts:
- .globl system_reset_pSeries;
-system_reset_pSeries:
+/* No virt vectors corresponding with 0x0..0x100 */
+EXC_VIRT_NONE(0x4000, 0x4100)
+
+EXC_REAL_BEGIN(system_reset, 0x100, 0x200)
SET_SCRATCH0(r13)
#ifdef CONFIG_PPC_P7_NAP
BEGIN_FTR_SECTION
@@ -136,9 +136,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
#endif /* CONFIG_PPC_P7_NAP */
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
NOTEST, 0x100)
+EXC_REAL_END(system_reset, 0x100, 0x200)
+EXC_VIRT_NONE(0x4100, 0x4200)
+EXC_COMMON(system_reset_common, 0x100, system_reset_exception)
+
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Vectors for the FWNMI option. Share common code.
+ */
+TRAMP_REAL_BEGIN(system_reset_fwnmi)
+ SET_SCRATCH0(r13) /* save r13 */
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
+ NOTEST, 0x100)
+#endif /* CONFIG_PPC_PSERIES */
+
- . = 0x200
-machine_check_pSeries_1:
+EXC_REAL_BEGIN(machine_check, 0x200, 0x300)
/* This is moved out of line as it can be patched by FW, but
* some code path might still want to branch into the original
* vector
@@ -158,253 +171,9 @@ BEGIN_FTR_SECTION
FTR_SECTION_ELSE
b machine_check_pSeries_0
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
-
- . = 0x300
- .globl data_access_pSeries
-data_access_pSeries:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
- KVMTEST, 0x300)
-
- . = 0x380
- .globl data_access_slb_pSeries
-data_access_slb_pSeries:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXSLB)
- EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_DAR
- mfspr r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
- b slb_miss_realmode
-#else
- /*
- * 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)
- mtctr r10
- bctr
-#endif
-
- STD_EXCEPTION_PSERIES(0x400, instruction_access)
-
- . = 0x480
- .globl instruction_access_slb_pSeries
-instruction_access_slb_pSeries:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXSLB)
- EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x480)
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
- mfspr r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
- b slb_miss_realmode
-#else
- mfctr r11
- ld r10,PACAKBASE(r13)
- LOAD_HANDLER(r10, slb_miss_realmode)
- mtctr r10
- bctr
-#endif
-
- /* We open code these as we can't have a ". = x" (even with
- * x = "." within a feature section
- */
- . = 0x500;
- .globl hardware_interrupt_pSeries;
- .globl hardware_interrupt_hv;
-hardware_interrupt_pSeries:
-hardware_interrupt_hv:
- BEGIN_FTR_SECTION
- _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt,
- EXC_HV, SOFTEN_TEST_HV)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502)
- FTR_SECTION_ELSE
- _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt,
- EXC_STD, SOFTEN_TEST_PR)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500)
- ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
-
- STD_EXCEPTION_PSERIES(0x600, alignment)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x600)
-
- STD_EXCEPTION_PSERIES(0x700, program_check)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x700)
-
- STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x800)
-
- . = 0x900
- .globl decrementer_pSeries
-decrementer_pSeries:
- _MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD, SOFTEN_TEST_PR)
-
- STD_EXCEPTION_HV(0x980, 0x982, hdecrementer)
-
- MASKABLE_EXCEPTION_PSERIES(0xa00, 0xa00, doorbell_super)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xa00)
-
- STD_EXCEPTION_PSERIES(0xb00, trap_0b)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xb00)
-
- . = 0xc00
- .globl system_call_pSeries
-system_call_pSeries:
- /*
- * If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems
- * that support it) before changing to HMT_MEDIUM. That allows the KVM
- * code to save that value into the guest state (it is the guest's PPR
- * value). Otherwise just change to HMT_MEDIUM as userspace has
- * already saved the PPR.
- */
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
- SET_SCRATCH0(r13)
- GET_PACA(r13)
- std r9,PACA_EXGEN+EX_R9(r13)
- OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);
- HMT_MEDIUM;
- std r10,PACA_EXGEN+EX_R10(r13)
- OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR);
- mfcr r9
- KVMTEST(0xc00)
- GET_SCRATCH0(r13)
-#else
- HMT_MEDIUM;
-#endif
- SYSCALL_PSERIES_1
- SYSCALL_PSERIES_2_RFID
- SYSCALL_PSERIES_3
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00)
-
- STD_EXCEPTION_PSERIES(0xd00, single_step)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xd00)
-
- /* At 0xe??? we have a bunch of hypervisor exceptions, we branch
- * out of line to handle them
- */
- . = 0xe00
-hv_data_storage_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_data_storage_hv
-
- . = 0xe20
-hv_instr_storage_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_instr_storage_hv
-
- . = 0xe40
-emulation_assist_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b emulation_assist_hv
-
- . = 0xe60
-hv_exception_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b hmi_exception_early
-
- . = 0xe80
-hv_doorbell_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_doorbell_hv
-
- . = 0xea0
-hv_virt_irq_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_virt_irq_hv
-
- /* We need to deal with the Altivec unavailable exception
- * here which is at 0xf20, thus in the middle of the
- * prolog code of the PerformanceMonitor one. A little
- * trickery is thus necessary
- */
- . = 0xf00
-performance_monitor_pseries_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b performance_monitor_pSeries
-
- . = 0xf20
-altivec_unavailable_pseries_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b altivec_unavailable_pSeries
-
- . = 0xf40
-vsx_unavailable_pseries_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b vsx_unavailable_pSeries
-
- . = 0xf60
-facility_unavailable_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b facility_unavailable_pSeries
-
- . = 0xf80
-hv_facility_unavailable_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b facility_unavailable_hv
-
-#ifdef CONFIG_CBE_RAS
- STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
-#endif /* CONFIG_CBE_RAS */
-
- STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1300)
-
- . = 0x1500
- .global denorm_exception_hv
-denorm_exception_hv:
- mtspr SPRN_SPRG_HSCRATCH0,r13
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0x1500)
-
-#ifdef CONFIG_PPC_DENORMALISATION
- mfspr r10,SPRN_HSRR1
- mfspr r11,SPRN_HSRR0 /* save HSRR0 */
- andis. r10,r10,(HSRR1_DENORM)@h /* denorm? */
- addi r11,r11,-4 /* HSRR0 is next instruction */
- bne+ denorm_assist
-#endif
-
- KVMTEST(0x1500)
- EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1500)
-
-#ifdef CONFIG_CBE_RAS
- STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602)
-#endif /* CONFIG_CBE_RAS */
-
- STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x1700)
-
-#ifdef CONFIG_CBE_RAS
- STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1802)
-#else
- . = 0x1800
-#endif /* CONFIG_CBE_RAS */
-
-
-/*** Out of line interrupts support ***/
-
- .align 7
- /* moved from 0x200 */
-machine_check_powernv_early:
+EXC_REAL_END(machine_check, 0x200, 0x300)
+EXC_VIRT_NONE(0x4200, 0x4300)
+TRAMP_REAL_BEGIN(machine_check_powernv_early)
BEGIN_FTR_SECTION
EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
/*
@@ -457,7 +226,6 @@ BEGIN_FTR_SECTION
mfmsr r11 /* get MSR value */
ori r11,r11,MSR_ME /* turn on ME bit */
ori r11,r11,MSR_RI /* turn on RI bit */
- ld r12,PACAKBASE(r13) /* get high part of &label */
LOAD_HANDLER(r12, machine_check_handle_early)
1: mtspr SPRN_SRR0,r12
mtspr SPRN_SRR1,r11
@@ -470,7 +238,6 @@ BEGIN_FTR_SECTION
*/
addi r1,r1,INT_FRAME_SIZE /* go back to previous stack frame */
ld r11,PACAKMSR(r13)
- ld r12,PACAKBASE(r13)
LOAD_HANDLER(r12, unrecover_mce)
li r10,MSR_ME
andc r11,r11,r10 /* Turn off MSR_ME */
@@ -478,20 +245,19 @@ BEGIN_FTR_SECTION
b . /* prevent speculative execution */
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
-machine_check_pSeries:
+TRAMP_REAL_BEGIN(machine_check_pSeries)
.globl machine_check_fwnmi
machine_check_fwnmi:
SET_SCRATCH0(r13) /* save r13 */
EXCEPTION_PROLOG_0(PACA_EXMC)
machine_check_pSeries_0:
- EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST, 0x200)
+ EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200)
/*
* The following is essentially EXCEPTION_PROLOG_PSERIES_1 with the
* difference that MSR_RI is not enabled, because PACA_EXMC is being
* used, so nested machine check corrupts it. machine_check_common
* enables MSR_RI.
*/
- ld r12,PACAKBASE(r13)
ld r10,PACAKMSR(r13)
xori r10,r10,MSR_RI
mfspr r11,SPRN_SRR0
@@ -502,488 +268,13 @@ machine_check_pSeries_0:
rfid
b . /* prevent speculative execution */
- KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
- KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x400)
- KVM_HANDLER(PACA_EXSLB, EXC_STD, 0x480)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x900)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982)
-
-#ifdef CONFIG_PPC_DENORMALISATION
-denorm_assist:
-BEGIN_FTR_SECTION
-/*
- * To denormalise we need to move a copy of the register to itself.
- * For POWER6 do that here for all FP regs.
- */
- mfmsr r10
- ori r10,r10,(MSR_FP|MSR_FE0|MSR_FE1)
- xori r10,r10,(MSR_FE0|MSR_FE1)
- mtmsrd r10
- sync
-
-#define FMR2(n) fmr (n), (n) ; fmr n+1, n+1
-#define FMR4(n) FMR2(n) ; FMR2(n+2)
-#define FMR8(n) FMR4(n) ; FMR4(n+4)
-#define FMR16(n) FMR8(n) ; FMR8(n+8)
-#define FMR32(n) FMR16(n) ; FMR16(n+16)
- FMR32(0)
-
-FTR_SECTION_ELSE
-/*
- * To denormalise we need to move a copy of the register to itself.
- * For POWER7 do that here for the first 32 VSX registers only.
- */
- mfmsr r10
- oris r10,r10,MSR_VSX@h
- mtmsrd r10
- sync
-
-#define XVCPSGNDP2(n) XVCPSGNDP(n,n,n) ; XVCPSGNDP(n+1,n+1,n+1)
-#define XVCPSGNDP4(n) XVCPSGNDP2(n) ; XVCPSGNDP2(n+2)
-#define XVCPSGNDP8(n) XVCPSGNDP4(n) ; XVCPSGNDP4(n+4)
-#define XVCPSGNDP16(n) XVCPSGNDP8(n) ; XVCPSGNDP8(n+8)
-#define XVCPSGNDP32(n) XVCPSGNDP16(n) ; XVCPSGNDP16(n+16)
- XVCPSGNDP32(0)
-
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
-
-BEGIN_FTR_SECTION
- b denorm_done
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-/*
- * To denormalise we need to move a copy of the register to itself.
- * For POWER8 we need to do that for all 64 VSX registers
- */
- XVCPSGNDP32(32)
-denorm_done:
- mtspr SPRN_HSRR0,r11
- mtcrf 0x80,r9
- ld r9,PACA_EXGEN+EX_R9(r13)
- RESTORE_PPR_PACA(PACA_EXGEN, r10)
-BEGIN_FTR_SECTION
- ld r10,PACA_EXGEN+EX_CFAR(r13)
- mtspr SPRN_CFAR,r10
-END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
- ld r10,PACA_EXGEN+EX_R10(r13)
- ld r11,PACA_EXGEN+EX_R11(r13)
- ld r12,PACA_EXGEN+EX_R12(r13)
- ld r13,PACA_EXGEN+EX_R13(r13)
- HRFID
- b .
-#endif
-
- .align 7
- /* moved from 0xe00 */
- STD_EXCEPTION_HV_OOL(0xe02, h_data_storage)
- KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02)
- STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22)
- STD_EXCEPTION_HV_OOL(0xe42, emulation_assist)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42)
- MASKABLE_EXCEPTION_HV_OOL(0xe62, hmi_exception)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62)
-
- MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82)
-
- MASKABLE_EXCEPTION_HV_OOL(0xea2, h_virt_irq)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xea2)
-
- /* moved from 0xf00 */
- STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf00)
- STD_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf20)
- STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf40)
- STD_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
- KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf60)
- STD_EXCEPTION_HV_OOL(0xf82, facility_unavailable)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xf82)
-
-/*
- * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
- * - If it was a decrementer interrupt, we bump the dec to max and and return.
- * - If it was a doorbell we return immediately since doorbells are edge
- * triggered and won't automatically refire.
- * - If it was a HMI we return immediately since we handled it in realmode
- * and it won't refire.
- * - else we hard disable and return.
- * This is called with r10 containing the value to OR to the paca field.
- */
-#define MASKED_INTERRUPT(_H) \
-masked_##_H##interrupt: \
- std r11,PACA_EXGEN+EX_R11(r13); \
- lbz r11,PACAIRQHAPPENED(r13); \
- or r11,r11,r10; \
- stb r11,PACAIRQHAPPENED(r13); \
- cmpwi r10,PACA_IRQ_DEC; \
- bne 1f; \
- lis r10,0x7fff; \
- ori r10,r10,0xffff; \
- mtspr SPRN_DEC,r10; \
- b 2f; \
-1: cmpwi r10,PACA_IRQ_DBELL; \
- beq 2f; \
- cmpwi r10,PACA_IRQ_HMI; \
- beq 2f; \
- mfspr r10,SPRN_##_H##SRR1; \
- rldicl r10,r10,48,1; /* clear MSR_EE */ \
- rotldi r10,r10,16; \
- mtspr SPRN_##_H##SRR1,r10; \
-2: mtcrf 0x80,r9; \
- ld r9,PACA_EXGEN+EX_R9(r13); \
- ld r10,PACA_EXGEN+EX_R10(r13); \
- ld r11,PACA_EXGEN+EX_R11(r13); \
- GET_SCRATCH0(r13); \
- ##_H##rfid; \
- b .
-
- MASKED_INTERRUPT()
- MASKED_INTERRUPT(H)
-
-/*
- * Called from arch_local_irq_enable when an interrupt needs
- * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
- * which kind of interrupt. MSR:EE is already off. We generate a
- * stackframe like if a real interrupt had happened.
- *
- * Note: While MSR:EE is off, we need to make sure that _MSR
- * in the generated frame has EE set to 1 or the exception
- * handler will not properly re-enable them.
- */
-_GLOBAL(__replay_interrupt)
- /* We are going to jump to the exception common code which
- * will retrieve various register values from the PACA which
- * we don't give a damn about, so we don't bother storing them.
- */
- mfmsr r12
- mflr r11
- mfcr r9
- ori r12,r12,MSR_EE
- cmpwi r3,0x900
- beq decrementer_common
- cmpwi r3,0x500
- beq hardware_interrupt_common
-BEGIN_FTR_SECTION
- cmpwi r3,0xe80
- beq h_doorbell_common
- cmpwi r3,0xea0
- beq h_virt_irq_common
- cmpwi r3,0xe60
- beq hmi_exception_common
-FTR_SECTION_ELSE
- cmpwi r3,0xa00
- beq doorbell_super_common
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
- blr
-
-#ifdef CONFIG_PPC_PSERIES
-/*
- * Vectors for the FWNMI option. Share common code.
- */
- .globl system_reset_fwnmi
- .align 7
-system_reset_fwnmi:
- SET_SCRATCH0(r13) /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
- NOTEST, 0x100)
-
-#endif /* CONFIG_PPC_PSERIES */
-
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-kvmppc_skip_interrupt:
- /*
- * Here all GPRs are unchanged from when the interrupt happened
- * except for r13, which is saved in SPRG_SCRATCH0.
- */
- mfspr r13, SPRN_SRR0
- addi r13, r13, 4
- mtspr SPRN_SRR0, r13
- GET_SCRATCH0(r13)
- rfid
- b .
-
-kvmppc_skip_Hinterrupt:
- /*
- * Here all GPRs are unchanged from when the interrupt happened
- * except for r13, which is saved in SPRG_SCRATCH0.
- */
- mfspr r13, SPRN_HSRR0
- addi r13, r13, 4
- mtspr SPRN_HSRR0, r13
- GET_SCRATCH0(r13)
- hrfid
- b .
-#endif
-
-/*
- * Ensure that any handlers that get invoked from the exception prologs
- * above are below the first 64KB (0x10000) of the kernel image because
- * the prologs assemble the addresses of these handlers using the
- * LOAD_HANDLER macro, which uses an ori instruction.
- */
-
-/*** Common interrupt handlers ***/
-
- 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)
-#ifdef CONFIG_PPC_DOORBELL
- STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, doorbell_exception)
-#else
- 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_ASYNC(0xe60, hmi_exception, handle_hmi_exception)
-#ifdef CONFIG_PPC_DOORBELL
- STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception)
-#else
- STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, unknown_exception)
-#endif
- STD_EXCEPTION_COMMON_ASYNC(0xea0, h_virt_irq, do_IRQ)
- 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)
-#else
- STD_EXCEPTION_COMMON(0x1700, altivec_assist, unknown_exception)
-#endif
-
- /*
- * Relocation-on interrupts: A subset of the interrupts can be delivered
- * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering
- * it. Addresses are the same as the original interrupt addresses, but
- * offset by 0xc000000000004000.
- * It's impossible to receive interrupts below 0x300 via this mechanism.
- * KVM: None of these traps are from the guest ; anything that escalated
- * to HV=1 from HV=0 is delivered via real mode handlers.
- */
-
- /*
- * This uses the standard macro, since the original 0x300 vector
- * only has extra guff for STAB-based processors -- which never
- * come here.
- */
- STD_RELON_EXCEPTION_PSERIES(0x4300, 0x300, data_access)
- . = 0x4380
- .globl data_access_slb_relon_pSeries
-data_access_slb_relon_pSeries:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXSLB)
- EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_DAR
- mfspr r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
- b slb_miss_realmode
-#else
- /*
- * 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)
- mtctr r10
- bctr
-#endif
-
- STD_RELON_EXCEPTION_PSERIES(0x4400, 0x400, instruction_access)
- . = 0x4480
- .globl instruction_access_slb_relon_pSeries
-instruction_access_slb_relon_pSeries:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXSLB)
- EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
- mfspr r12,SPRN_SRR1
-#ifndef CONFIG_RELOCATABLE
- b slb_miss_realmode
-#else
- mfctr r11
- ld r10,PACAKBASE(r13)
- LOAD_HANDLER(r10, slb_miss_realmode)
- mtctr r10
- bctr
-#endif
-
- . = 0x4500
- .globl hardware_interrupt_relon_pSeries;
- .globl hardware_interrupt_relon_hv;
-hardware_interrupt_relon_pSeries:
-hardware_interrupt_relon_hv:
- BEGIN_FTR_SECTION
- _MASKABLE_RELON_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV, SOFTEN_TEST_HV)
- FTR_SECTION_ELSE
- _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD, SOFTEN_TEST_PR)
- ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
- STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment)
- STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check)
- STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable)
- MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer)
- STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer)
- MASKABLE_RELON_EXCEPTION_PSERIES(0x4a00, 0xa00, doorbell_super)
- STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b)
-
- . = 0x4c00
- .globl system_call_relon_pSeries
-system_call_relon_pSeries:
- HMT_MEDIUM
- SYSCALL_PSERIES_1
- SYSCALL_PSERIES_2_DIRECT
- SYSCALL_PSERIES_3
-
- STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step)
-
- . = 0x4e00
- b . /* Can't happen, see v2.07 Book III-S section 6.5 */
-
- . = 0x4e20
- b . /* Can't happen, see v2.07 Book III-S section 6.5 */
-
- . = 0x4e40
-emulation_assist_relon_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b emulation_assist_relon_hv
-
- . = 0x4e60
- b . /* Can't happen, see v2.07 Book III-S section 6.5 */
-
- . = 0x4e80
-h_doorbell_relon_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_doorbell_relon_hv
-
- . = 0x4ea0
-h_virt_irq_relon_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_virt_irq_relon_hv
-
- . = 0x4f00
-performance_monitor_relon_pseries_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b performance_monitor_relon_pSeries
-
- . = 0x4f20
-altivec_unavailable_relon_pseries_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b altivec_unavailable_relon_pSeries
-
- . = 0x4f40
-vsx_unavailable_relon_pseries_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b vsx_unavailable_relon_pSeries
-
- . = 0x4f60
-facility_unavailable_relon_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b facility_unavailable_relon_pSeries
-
- . = 0x4f80
-hv_facility_unavailable_relon_trampoline:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b hv_facility_unavailable_relon_hv
-
- STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
-#ifdef CONFIG_PPC_DENORMALISATION
- . = 0x5500
- b denorm_exception_hv
-#endif
- STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist)
-
- .align 7
-system_call_entry:
- b system_call_common
-
-ppc64_runlatch_on_trampoline:
- b __ppc64_runlatch_on
-
-/*
- * Here r13 points to the paca, r9 contains the saved CR,
- * SRR0 and SRR1 are saved in r11 and r12,
- * r9 - r13 are saved in paca->exgen.
- */
- .align 7
- .globl data_access_common
-data_access_common:
- mfspr r10,SPRN_DAR
- std r10,PACA_EXGEN+EX_DAR(r13)
- mfspr r10,SPRN_DSISR
- stw r10,PACA_EXGEN+EX_DSISR(r13)
- EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
- RECONCILE_IRQ_STATE(r10, r11)
- ld r12,_MSR(r1)
- ld r3,PACA_EXGEN+EX_DAR(r13)
- lwz r4,PACA_EXGEN+EX_DSISR(r13)
- li r5,0x300
- std r3,_DAR(r1)
- std r4,_DSISR(r1)
-BEGIN_MMU_FTR_SECTION
- b do_hash_page /* Try to handle as hpte fault */
-MMU_FTR_SECTION_ELSE
- b handle_page_fault
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
-
- .align 7
- .globl h_data_storage_common
-h_data_storage_common:
- mfspr r10,SPRN_HDAR
- std r10,PACA_EXGEN+EX_DAR(r13)
- mfspr r10,SPRN_HDSISR
- stw r10,PACA_EXGEN+EX_DSISR(r13)
- EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl unknown_exception
- b ret_from_except
-
- .align 7
- .globl instruction_access_common
-instruction_access_common:
- EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
- RECONCILE_IRQ_STATE(r10, r11)
- ld r12,_MSR(r1)
- ld r3,_NIP(r1)
- andis. r4,r12,0x5820
- li r5,0x400
- std r3,_DAR(r1)
- std r4,_DSISR(r1)
-BEGIN_MMU_FTR_SECTION
- b do_hash_page /* Try to handle as hpte fault */
-MMU_FTR_SECTION_ELSE
- b handle_page_fault
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
-
- STD_EXCEPTION_COMMON(0xe20, h_instr_storage, unknown_exception)
+TRAMP_KVM_SKIP(PACA_EXMC, 0x200)
+EXC_COMMON_BEGIN(machine_check_common)
/*
* Machine check is different because we use a different
* save area: PACA_EXMC instead of PACA_EXGEN.
*/
- .align 7
- .globl machine_check_common
-machine_check_common:
-
mfspr r10,SPRN_DAR
std r10,PACA_EXMC+EX_DAR(r13)
mfspr r10,SPRN_DSISR
@@ -1003,230 +294,6 @@ machine_check_common:
bl machine_check_exception
b ret_from_except
- .align 7
- .globl alignment_common
-alignment_common:
- mfspr r10,SPRN_DAR
- std r10,PACA_EXGEN+EX_DAR(r13)
- mfspr r10,SPRN_DSISR
- stw r10,PACA_EXGEN+EX_DSISR(r13)
- EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN)
- ld r3,PACA_EXGEN+EX_DAR(r13)
- lwz r4,PACA_EXGEN+EX_DSISR(r13)
- std r3,_DAR(r1)
- std r4,_DSISR(r1)
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- 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
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- 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
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl kernel_fp_unavailable_exception
- BUG_OPCODE
-1:
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-BEGIN_FTR_SECTION
- /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
- * transaction), go do TM stuff
- */
- rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
- bne- 2f
-END_FTR_SECTION_IFSET(CPU_FTR_TM)
-#endif
- bl load_up_fpu
- b fast_exception_return
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-2: /* User process was in a transaction */
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl fp_unavailable_tm
- b ret_from_except
-#endif
- .align 7
- .globl altivec_unavailable_common
-altivec_unavailable_common:
- EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
-#ifdef CONFIG_ALTIVEC
-BEGIN_FTR_SECTION
- beq 1f
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- BEGIN_FTR_SECTION_NESTED(69)
- /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
- * transaction), go do TM stuff
- */
- rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
- bne- 2f
- END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
-#endif
- bl load_up_altivec
- b fast_exception_return
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-2: /* User process was in a transaction */
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl altivec_unavailable_tm
- b ret_from_except
-#endif
-1:
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-#endif
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl altivec_unavailable_exception
- b ret_from_except
-
- .align 7
- .globl vsx_unavailable_common
-vsx_unavailable_common:
- EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
- beq 1f
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- BEGIN_FTR_SECTION_NESTED(69)
- /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
- * transaction), go do TM stuff
- */
- rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
- bne- 2f
- END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
-#endif
- b load_up_vsx
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-2: /* User process was in a transaction */
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl vsx_unavailable_tm
- b ret_from_except
-#endif
-1:
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
- bl save_nvgprs
- RECONCILE_IRQ_STATE(r10, r11)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl vsx_unavailable_exception
- b ret_from_except
-
- /* Equivalents to the above handlers for relocation-on interrupt vectors */
- STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist)
- MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell)
- MASKABLE_RELON_EXCEPTION_HV_OOL(0xea0, h_virt_irq)
-
- STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
- STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
- STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
- STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
- STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable)
-
- /*
- * The __end_interrupts marker must be past the out-of-line (OOL)
- * handlers, so that they are copied to real address 0x100 when running
- * a relocatable kernel. This ensures they can be reached from the short
- * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch
- * directly, without using LOAD_HANDLER().
- */
- .align 7
- .globl __end_interrupts
-__end_interrupts:
-
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
-/*
- * Data area reserved for FWNMI option.
- * This address (0x7000) is fixed by the RPA.
- */
- .= 0x7000
- .globl fwnmi_data_area
-fwnmi_data_area:
-
- /* pseries and powernv need to keep the whole page from
- * 0x7000 to 0x8000 free for use by the firmware
- */
- . = 0x8000
-#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
-
- STD_EXCEPTION_COMMON(0xf60, facility_unavailable, facility_unavailable_exception)
- STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, facility_unavailable_exception)
-
-#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)
-#endif /* CONFIG_CBE_RAS */
-
- .globl hmi_exception_early
-hmi_exception_early:
- EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, 0xe62)
- mr r10,r1 /* Save r1 */
- ld r1,PACAEMERGSP(r13) /* Use emergency stack */
- subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
- std r9,_CCR(r1) /* save CR in stackframe */
- mfspr r11,SPRN_HSRR0 /* Save HSRR0 */
- std r11,_NIP(r1) /* save HSRR0 in stackframe */
- mfspr r12,SPRN_HSRR1 /* Save SRR1 */
- std r12,_MSR(r1) /* save SRR1 in stackframe */
- std r10,0(r1) /* make stack chain pointer */
- std r0,GPR0(r1) /* save r0 in stackframe */
- std r10,GPR1(r1) /* save r1 in stackframe */
- EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
- EXCEPTION_PROLOG_COMMON_3(0xe60)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl hmi_exception_realmode
- /* Windup the stack. */
- /* Move original HSRR0 and HSRR1 into the respective regs */
- ld r9,_MSR(r1)
- mtspr SPRN_HSRR1,r9
- ld r3,_NIP(r1)
- mtspr SPRN_HSRR0,r3
- ld r9,_CTR(r1)
- mtctr r9
- ld r9,_XER(r1)
- mtxer r9
- ld r9,_LINK(r1)
- mtlr r9
- REST_GPR(0, r1)
- REST_8GPRS(2, r1)
- REST_GPR(10, r1)
- ld r11,_CCR(r1)
- mtcr r11
- REST_GPR(11, r1)
- REST_2GPRS(12, r1)
- /* restore original r1. */
- ld r1,GPR1(r1)
-
- /*
- * Go to virtual mode and pull the HMI event information from
- * firmware.
- */
- .globl hmi_exception_after_realmode
-hmi_exception_after_realmode:
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b hmi_exception_hv
-
-
#define MACHINE_CHECK_HANDLER_WINDUP \
/* Clear MSR_RI before setting SRR0 and SRR1. */\
li r0,MSR_RI; \
@@ -1262,9 +329,7 @@ hmi_exception_after_realmode:
* Handle machine check early in real mode. We come here with
* ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack.
*/
- .align 7
- .globl machine_check_handle_early
-machine_check_handle_early:
+EXC_COMMON_BEGIN(machine_check_handle_early)
std r0,GPR0(r1) /* Save r0 */
EXCEPTION_PROLOG_COMMON_3(0x200)
bl save_nvgprs
@@ -1353,7 +418,6 @@ machine_check_handle_early:
andi. r11,r12,MSR_RI
bne 2f
1: mfspr r11,SPRN_SRR0
- ld r10,PACAKBASE(r13)
LOAD_HANDLER(r10,unrecover_mce)
mtspr SPRN_SRR0,r10
ld r10,PACAKMSR(r13)
@@ -1391,7 +455,7 @@ machine_check_handle_early:
MACHINE_CHECK_HANDLER_WINDUP
b machine_check_pSeries
-unrecover_mce:
+EXC_COMMON_BEGIN(unrecover_mce)
/* Invoke machine_check_exception to print MCE event and panic. */
addi r3,r1,STACK_FRAME_OVERHEAD
bl machine_check_exception
@@ -1402,15 +466,155 @@ unrecover_mce:
1: addi r3,r1,STACK_FRAME_OVERHEAD
bl unrecoverable_exception
b 1b
-/*
- * r13 points to the PACA, r9 contains the saved CR,
- * r12 contain the saved SRR1, SRR0 is still ready for return
- * r3 has the faulting address
- * r9 - r13 are saved in paca->exslb.
- * r3 is saved in paca->slb_r3
- * We assume we aren't going to take any exceptions during this procedure.
- */
-slb_miss_realmode:
+
+
+EXC_REAL(data_access, 0x300, 0x380)
+EXC_VIRT(data_access, 0x4300, 0x4380, 0x300)
+TRAMP_KVM_SKIP(PACA_EXGEN, 0x300)
+
+EXC_COMMON_BEGIN(data_access_common)
+ /*
+ * Here r13 points to the paca, r9 contains the saved CR,
+ * SRR0 and SRR1 are saved in r11 and r12,
+ * r9 - r13 are saved in paca->exgen.
+ */
+ mfspr r10,SPRN_DAR
+ std r10,PACA_EXGEN+EX_DAR(r13)
+ mfspr r10,SPRN_DSISR
+ stw r10,PACA_EXGEN+EX_DSISR(r13)
+ EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
+ RECONCILE_IRQ_STATE(r10, r11)
+ ld r12,_MSR(r1)
+ ld r3,PACA_EXGEN+EX_DAR(r13)
+ lwz r4,PACA_EXGEN+EX_DSISR(r13)
+ li r5,0x300
+ std r3,_DAR(r1)
+ std r4,_DSISR(r1)
+BEGIN_MMU_FTR_SECTION
+ b do_hash_page /* Try to handle as hpte fault */
+MMU_FTR_SECTION_ELSE
+ b handle_page_fault
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
+
+
+EXC_REAL_BEGIN(data_access_slb, 0x380, 0x400)
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
+ EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380)
+ std r3,PACA_EXSLB+EX_R3(r13)
+ mfspr r3,SPRN_DAR
+ mfspr r12,SPRN_SRR1
+ crset 4*cr6+eq
+#ifndef CONFIG_RELOCATABLE
+ b slb_miss_realmode
+#else
+ /*
+ * 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
+ LOAD_HANDLER(r10, slb_miss_realmode)
+ mtctr r10
+ bctr
+#endif
+EXC_REAL_END(data_access_slb, 0x380, 0x400)
+
+EXC_VIRT_BEGIN(data_access_slb, 0x4380, 0x4400)
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
+ EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
+ std r3,PACA_EXSLB+EX_R3(r13)
+ mfspr r3,SPRN_DAR
+ mfspr r12,SPRN_SRR1
+ crset 4*cr6+eq
+#ifndef CONFIG_RELOCATABLE
+ b slb_miss_realmode
+#else
+ /*
+ * 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
+ LOAD_HANDLER(r10, slb_miss_realmode)
+ mtctr r10
+ bctr
+#endif
+EXC_VIRT_END(data_access_slb, 0x4380, 0x4400)
+TRAMP_KVM_SKIP(PACA_EXSLB, 0x380)
+
+
+EXC_REAL(instruction_access, 0x400, 0x480)
+EXC_VIRT(instruction_access, 0x4400, 0x4480, 0x400)
+TRAMP_KVM(PACA_EXGEN, 0x400)
+
+EXC_COMMON_BEGIN(instruction_access_common)
+ EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
+ RECONCILE_IRQ_STATE(r10, r11)
+ ld r12,_MSR(r1)
+ ld r3,_NIP(r1)
+ andis. r4,r12,0x5820
+ li r5,0x400
+ std r3,_DAR(r1)
+ std r4,_DSISR(r1)
+BEGIN_MMU_FTR_SECTION
+ b do_hash_page /* Try to handle as hpte fault */
+MMU_FTR_SECTION_ELSE
+ b handle_page_fault
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
+
+
+EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x500)
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
+ EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
+ std r3,PACA_EXSLB+EX_R3(r13)
+ mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
+ mfspr r12,SPRN_SRR1
+ crclr 4*cr6+eq
+#ifndef CONFIG_RELOCATABLE
+ b slb_miss_realmode
+#else
+ mfctr r11
+ LOAD_HANDLER(r10, slb_miss_realmode)
+ mtctr r10
+ bctr
+#endif
+EXC_REAL_END(instruction_access_slb, 0x480, 0x500)
+
+EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x4500)
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
+ EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
+ std r3,PACA_EXSLB+EX_R3(r13)
+ mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
+ mfspr r12,SPRN_SRR1
+ crclr 4*cr6+eq
+#ifndef CONFIG_RELOCATABLE
+ b slb_miss_realmode
+#else
+ mfctr r11
+ LOAD_HANDLER(r10, slb_miss_realmode)
+ mtctr r10
+ bctr
+#endif
+EXC_VIRT_END(instruction_access_slb, 0x4480, 0x4500)
+TRAMP_KVM(PACA_EXSLB, 0x480)
+
+
+/* This handler is used by both 0x380 and 0x480 slb miss interrupts */
+EXC_COMMON_BEGIN(slb_miss_realmode)
+ /*
+ * r13 points to the PACA, r9 contains the saved CR,
+ * r12 contain the saved SRR1, SRR0 is still ready for return
+ * r3 has the faulting address
+ * r9 - r13 are saved in paca->exslb.
+ * r3 is saved in paca->slb_r3
+ * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss
+ * We assume we aren't going to take any exceptions during this
+ * procedure.
+ */
mflr r10
#ifdef CONFIG_RELOCATABLE
mtctr r11
@@ -1418,29 +622,31 @@ slb_miss_realmode:
stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
std r10,PACA_EXSLB+EX_LR(r13) /* save LR */
+ std r3,PACA_EXSLB+EX_DAR(r13)
+ crset 4*cr0+eq
#ifdef CONFIG_PPC_STD_MMU_64
BEGIN_MMU_FTR_SECTION
bl slb_allocate_realmode
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
#endif
- /* All done -- return from exception. */
ld r10,PACA_EXSLB+EX_LR(r13)
ld r3,PACA_EXSLB+EX_R3(r13)
lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
-
mtlr r10
+
+ beq 8f /* if bad address, make full stack frame */
+
andi. r10,r12,MSR_RI /* check for unrecoverable exception */
-BEGIN_MMU_FTR_SECTION
beq- 2f
-FTR_SECTION_ELSE
- b 2f
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
+
+ /* All done -- return from exception. */
.machine push
.machine "power4"
mtcrf 0x80,r9
+ mtcrf 0x02,r9 /* I/D indication is in cr6 */
mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
.machine pop
@@ -1454,7 +660,6 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
b . /* prevent speculative execution */
2: mfspr r11,SPRN_SRR0
- ld r10,PACAKBASE(r13)
LOAD_HANDLER(r10,unrecov_slb)
mtspr SPRN_SRR0,r10
ld r10,PACAKMSR(r13)
@@ -1462,7 +667,15 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
rfid
b .
-unrecov_slb:
+8: mfspr r11,SPRN_SRR0
+ LOAD_HANDLER(r10,bad_addr_slb)
+ mtspr SPRN_SRR0,r10
+ ld r10,PACAKMSR(r13)
+ mtspr SPRN_SRR1,r10
+ rfid
+ b .
+
+EXC_COMMON_BEGIN(unrecov_slb)
EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
RECONCILE_IRQ_STATE(r10, r11)
bl save_nvgprs
@@ -1470,9 +683,701 @@ unrecov_slb:
bl unrecoverable_exception
b 1b
+EXC_COMMON_BEGIN(bad_addr_slb)
+ EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB)
+ RECONCILE_IRQ_STATE(r10, r11)
+ ld r3, PACA_EXSLB+EX_DAR(r13)
+ std r3, _DAR(r1)
+ beq cr6, 2f
+ li r10, 0x480 /* fix trap number for I-SLB miss */
+ std r10, _TRAP(r1)
+2: bl save_nvgprs
+ addi r3, r1, STACK_FRAME_OVERHEAD
+ bl slb_miss_bad_addr
+ b ret_from_except
+
+EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x600)
+ .globl hardware_interrupt_hv;
+hardware_interrupt_hv:
+ BEGIN_FTR_SECTION
+ _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common,
+ EXC_HV, SOFTEN_TEST_HV)
+do_kvm_H0x500:
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502)
+ FTR_SECTION_ELSE
+ _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common,
+ EXC_STD, SOFTEN_TEST_PR)
+do_kvm_0x500:
+ KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500)
+ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
+EXC_REAL_END(hardware_interrupt, 0x500, 0x600)
+
+EXC_VIRT_BEGIN(hardware_interrupt, 0x4500, 0x4600)
+ .globl hardware_interrupt_relon_hv;
+hardware_interrupt_relon_hv:
+ BEGIN_FTR_SECTION
+ _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_HV, SOFTEN_TEST_HV)
+ FTR_SECTION_ELSE
+ _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_STD, SOFTEN_TEST_PR)
+ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+EXC_VIRT_END(hardware_interrupt, 0x4500, 0x4600)
+
+EXC_COMMON_ASYNC(hardware_interrupt_common, 0x500, do_IRQ)
+
+
+EXC_REAL(alignment, 0x600, 0x700)
+EXC_VIRT(alignment, 0x4600, 0x4700, 0x600)
+TRAMP_KVM(PACA_EXGEN, 0x600)
+EXC_COMMON_BEGIN(alignment_common)
+ mfspr r10,SPRN_DAR
+ std r10,PACA_EXGEN+EX_DAR(r13)
+ mfspr r10,SPRN_DSISR
+ stw r10,PACA_EXGEN+EX_DSISR(r13)
+ EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN)
+ ld r3,PACA_EXGEN+EX_DAR(r13)
+ lwz r4,PACA_EXGEN+EX_DSISR(r13)
+ std r3,_DAR(r1)
+ std r4,_DSISR(r1)
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl alignment_exception
+ b ret_from_except
+
+
+EXC_REAL(program_check, 0x700, 0x800)
+EXC_VIRT(program_check, 0x4700, 0x4800, 0x700)
+TRAMP_KVM(PACA_EXGEN, 0x700)
+EXC_COMMON_BEGIN(program_check_common)
+ EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl program_check_exception
+ b ret_from_except
+
+
+EXC_REAL(fp_unavailable, 0x800, 0x900)
+EXC_VIRT(fp_unavailable, 0x4800, 0x4900, 0x800)
+TRAMP_KVM(PACA_EXGEN, 0x800)
+EXC_COMMON_BEGIN(fp_unavailable_common)
+ EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
+ bne 1f /* if from user, just load it up */
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl kernel_fp_unavailable_exception
+ BUG_OPCODE
+1:
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+ bl load_up_fpu
+ b fast_exception_return
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl fp_unavailable_tm
+ b ret_from_except
+#endif
+
+
+EXC_REAL_MASKABLE(decrementer, 0x900, 0x980)
+EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x4980, 0x900)
+TRAMP_KVM(PACA_EXGEN, 0x900)
+EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt)
+
+
+EXC_REAL_HV(hdecrementer, 0x980, 0xa00)
+EXC_VIRT_HV(hdecrementer, 0x4980, 0x4a00, 0x980)
+TRAMP_KVM_HV(PACA_EXGEN, 0x980)
+EXC_COMMON(hdecrementer_common, 0x980, hdec_interrupt)
+
+
+EXC_REAL_MASKABLE(doorbell_super, 0xa00, 0xb00)
+EXC_VIRT_MASKABLE(doorbell_super, 0x4a00, 0x4b00, 0xa00)
+TRAMP_KVM(PACA_EXGEN, 0xa00)
+#ifdef CONFIG_PPC_DOORBELL
+EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, doorbell_exception)
+#else
+EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, unknown_exception)
+#endif
+
+
+EXC_REAL(trap_0b, 0xb00, 0xc00)
+EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00)
+TRAMP_KVM(PACA_EXGEN, 0xb00)
+EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
+
+
+#define LOAD_SYSCALL_HANDLER(reg) \
+ ld reg,PACAKBASE(r13); \
+ ori reg,reg,(ABS_ADDR(system_call_common))@l;
+
+/* Syscall routine is used twice, in reloc-off and reloc-on paths */
+#define SYSCALL_PSERIES_1 \
+BEGIN_FTR_SECTION \
+ cmpdi r0,0x1ebe ; \
+ beq- 1f ; \
+END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
+ mr r9,r13 ; \
+ GET_PACA(r13) ; \
+ mfspr r11,SPRN_SRR0 ; \
+0:
+
+#define SYSCALL_PSERIES_2_RFID \
+ mfspr r12,SPRN_SRR1 ; \
+ LOAD_SYSCALL_HANDLER(r10) ; \
+ mtspr SPRN_SRR0,r10 ; \
+ ld r10,PACAKMSR(r13) ; \
+ mtspr SPRN_SRR1,r10 ; \
+ rfid ; \
+ b . ; /* prevent speculative execution */
+
+#define SYSCALL_PSERIES_3 \
+ /* Fast LE/BE switch system call */ \
+1: mfspr r12,SPRN_SRR1 ; \
+ xori r12,r12,MSR_LE ; \
+ mtspr SPRN_SRR1,r12 ; \
+ rfid ; /* return to userspace */ \
+ b . ; /* prevent speculative execution */
+
+#if defined(CONFIG_RELOCATABLE)
+ /*
+ * We can't branch directly so we do it via the CTR which
+ * is volatile across system calls.
+ */
+#define SYSCALL_PSERIES_2_DIRECT \
+ LOAD_SYSCALL_HANDLER(r12) ; \
+ mtctr r12 ; \
+ mfspr r12,SPRN_SRR1 ; \
+ li r10,MSR_RI ; \
+ mtmsrd r10,1 ; \
+ bctr ;
+#else
+ /* We can branch directly */
+#define SYSCALL_PSERIES_2_DIRECT \
+ mfspr r12,SPRN_SRR1 ; \
+ li r10,MSR_RI ; \
+ mtmsrd r10,1 ; /* Set RI (EE=0) */ \
+ b system_call_common ;
+#endif
+
+EXC_REAL_BEGIN(system_call, 0xc00, 0xd00)
+ /*
+ * If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems
+ * that support it) before changing to HMT_MEDIUM. That allows the KVM
+ * code to save that value into the guest state (it is the guest's PPR
+ * value). Otherwise just change to HMT_MEDIUM as userspace has
+ * already saved the PPR.
+ */
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+ SET_SCRATCH0(r13)
+ GET_PACA(r13)
+ std r9,PACA_EXGEN+EX_R9(r13)
+ OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);
+ HMT_MEDIUM;
+ std r10,PACA_EXGEN+EX_R10(r13)
+ OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR);
+ mfcr r9
+ KVMTEST_PR(0xc00)
+ GET_SCRATCH0(r13)
+#else
+ HMT_MEDIUM;
+#endif
+ SYSCALL_PSERIES_1
+ SYSCALL_PSERIES_2_RFID
+ SYSCALL_PSERIES_3
+EXC_REAL_END(system_call, 0xc00, 0xd00)
+
+EXC_VIRT_BEGIN(system_call, 0x4c00, 0x4d00)
+ HMT_MEDIUM
+ SYSCALL_PSERIES_1
+ SYSCALL_PSERIES_2_DIRECT
+ SYSCALL_PSERIES_3
+EXC_VIRT_END(system_call, 0x4c00, 0x4d00)
+
+TRAMP_KVM(PACA_EXGEN, 0xc00)
+
+
+EXC_REAL(single_step, 0xd00, 0xe00)
+EXC_VIRT(single_step, 0x4d00, 0x4e00, 0xd00)
+TRAMP_KVM(PACA_EXGEN, 0xd00)
+EXC_COMMON(single_step_common, 0xd00, single_step_exception)
+
+EXC_REAL_OOL_HV(h_data_storage, 0xe00, 0xe20)
+EXC_VIRT_NONE(0x4e00, 0x4e20)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0xe00)
+EXC_COMMON_BEGIN(h_data_storage_common)
+ mfspr r10,SPRN_HDAR
+ std r10,PACA_EXGEN+EX_DAR(r13)
+ mfspr r10,SPRN_HDSISR
+ stw r10,PACA_EXGEN+EX_DSISR(r13)
+ EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl unknown_exception
+ b ret_from_except
+
+
+EXC_REAL_OOL_HV(h_instr_storage, 0xe20, 0xe40)
+EXC_VIRT_NONE(0x4e20, 0x4e40)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe20)
+EXC_COMMON(h_instr_storage_common, 0xe20, unknown_exception)
+
+
+EXC_REAL_OOL_HV(emulation_assist, 0xe40, 0xe60)
+EXC_VIRT_OOL_HV(emulation_assist, 0x4e40, 0x4e60, 0xe40)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe40)
+EXC_COMMON(emulation_assist_common, 0xe40, emulation_assist_interrupt)
+
+
+/*
+ * hmi_exception trampoline is a special case. It jumps to hmi_exception_early
+ * first, and then eventaully from there to the trampoline to get into virtual
+ * mode.
+ */
+__EXC_REAL_OOL_HV_DIRECT(hmi_exception, 0xe60, 0xe80, hmi_exception_early)
+__TRAMP_REAL_REAL_OOL_MASKABLE_HV(hmi_exception, 0xe60)
+EXC_VIRT_NONE(0x4e60, 0x4e80)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe60)
+TRAMP_REAL_BEGIN(hmi_exception_early)
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, 0xe60)
+ mr r10,r1 /* Save r1 */
+ ld r1,PACAEMERGSP(r13) /* Use emergency stack */
+ subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
+ std r9,_CCR(r1) /* save CR in stackframe */
+ mfspr r11,SPRN_HSRR0 /* Save HSRR0 */
+ std r11,_NIP(r1) /* save HSRR0 in stackframe */
+ mfspr r12,SPRN_HSRR1 /* Save SRR1 */
+ std r12,_MSR(r1) /* save SRR1 in stackframe */
+ std r10,0(r1) /* make stack chain pointer */
+ std r0,GPR0(r1) /* save r0 in stackframe */
+ std r10,GPR1(r1) /* save r1 in stackframe */
+ EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
+ EXCEPTION_PROLOG_COMMON_3(0xe60)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl hmi_exception_realmode
+ /* Windup the stack. */
+ /* Move original HSRR0 and HSRR1 into the respective regs */
+ ld r9,_MSR(r1)
+ mtspr SPRN_HSRR1,r9
+ ld r3,_NIP(r1)
+ mtspr SPRN_HSRR0,r3
+ ld r9,_CTR(r1)
+ mtctr r9
+ ld r9,_XER(r1)
+ mtxer r9
+ ld r9,_LINK(r1)
+ mtlr r9
+ REST_GPR(0, r1)
+ REST_8GPRS(2, r1)
+ REST_GPR(10, r1)
+ ld r11,_CCR(r1)
+ mtcr r11
+ REST_GPR(11, r1)
+ REST_2GPRS(12, r1)
+ /* restore original r1. */
+ ld r1,GPR1(r1)
+
+ /*
+ * Go to virtual mode and pull the HMI event information from
+ * firmware.
+ */
+ .globl hmi_exception_after_realmode
+hmi_exception_after_realmode:
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b tramp_real_hmi_exception
+
+EXC_COMMON_ASYNC(hmi_exception_common, 0xe60, handle_hmi_exception)
+
+
+EXC_REAL_OOL_MASKABLE_HV(h_doorbell, 0xe80, 0xea0)
+EXC_VIRT_OOL_MASKABLE_HV(h_doorbell, 0x4e80, 0x4ea0, 0xe80)
+TRAMP_KVM_HV(PACA_EXGEN, 0xe80)
+#ifdef CONFIG_PPC_DOORBELL
+EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, doorbell_exception)
+#else
+EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, unknown_exception)
+#endif
+
+
+EXC_REAL_OOL_MASKABLE_HV(h_virt_irq, 0xea0, 0xec0)
+EXC_VIRT_OOL_MASKABLE_HV(h_virt_irq, 0x4ea0, 0x4ec0, 0xea0)
+TRAMP_KVM_HV(PACA_EXGEN, 0xea0)
+EXC_COMMON_ASYNC(h_virt_irq_common, 0xea0, do_IRQ)
+
+
+EXC_REAL_NONE(0xec0, 0xf00)
+EXC_VIRT_NONE(0x4ec0, 0x4f00)
+
+
+EXC_REAL_OOL(performance_monitor, 0xf00, 0xf20)
+EXC_VIRT_OOL(performance_monitor, 0x4f00, 0x4f20, 0xf00)
+TRAMP_KVM(PACA_EXGEN, 0xf00)
+EXC_COMMON_ASYNC(performance_monitor_common, 0xf00, performance_monitor_exception)
+
+
+EXC_REAL_OOL(altivec_unavailable, 0xf20, 0xf40)
+EXC_VIRT_OOL(altivec_unavailable, 0x4f20, 0x4f40, 0xf20)
+TRAMP_KVM(PACA_EXGEN, 0xf20)
+EXC_COMMON_BEGIN(altivec_unavailable_common)
+ EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
+#ifdef CONFIG_ALTIVEC
+BEGIN_FTR_SECTION
+ beq 1f
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
+ bl load_up_altivec
+ b fast_exception_return
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl altivec_unavailable_tm
+ b ret_from_except
+#endif
+1:
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+#endif
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl altivec_unavailable_exception
+ b ret_from_except
+
+
+EXC_REAL_OOL(vsx_unavailable, 0xf40, 0xf60)
+EXC_VIRT_OOL(vsx_unavailable, 0x4f40, 0x4f60, 0xf40)
+TRAMP_KVM(PACA_EXGEN, 0xf40)
+EXC_COMMON_BEGIN(vsx_unavailable_common)
+ EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+ beq 1f
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
+ b load_up_vsx
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl vsx_unavailable_tm
+ b ret_from_except
+#endif
+1:
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ bl save_nvgprs
+ RECONCILE_IRQ_STATE(r10, r11)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl vsx_unavailable_exception
+ b ret_from_except
+
+
+EXC_REAL_OOL(facility_unavailable, 0xf60, 0xf80)
+EXC_VIRT_OOL(facility_unavailable, 0x4f60, 0x4f80, 0xf60)
+TRAMP_KVM(PACA_EXGEN, 0xf60)
+EXC_COMMON(facility_unavailable_common, 0xf60, facility_unavailable_exception)
+
+
+EXC_REAL_OOL_HV(h_facility_unavailable, 0xf80, 0xfa0)
+EXC_VIRT_OOL_HV(h_facility_unavailable, 0x4f80, 0x4fa0, 0xf80)
+TRAMP_KVM_HV(PACA_EXGEN, 0xf80)
+EXC_COMMON(h_facility_unavailable_common, 0xf80, facility_unavailable_exception)
+
+
+EXC_REAL_NONE(0xfa0, 0x1200)
+EXC_VIRT_NONE(0x4fa0, 0x5200)
+
+#ifdef CONFIG_CBE_RAS
+EXC_REAL_HV(cbe_system_error, 0x1200, 0x1300)
+EXC_VIRT_NONE(0x5200, 0x5300)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1200)
+EXC_COMMON(cbe_system_error_common, 0x1200, cbe_system_error_exception)
+#else /* CONFIG_CBE_RAS */
+EXC_REAL_NONE(0x1200, 0x1300)
+EXC_VIRT_NONE(0x5200, 0x5300)
+#endif
+
+
+EXC_REAL(instruction_breakpoint, 0x1300, 0x1400)
+EXC_VIRT(instruction_breakpoint, 0x5300, 0x5400, 0x1300)
+TRAMP_KVM_SKIP(PACA_EXGEN, 0x1300)
+EXC_COMMON(instruction_breakpoint_common, 0x1300, instruction_breakpoint_exception)
+
+EXC_REAL_NONE(0x1400, 0x1500)
+EXC_VIRT_NONE(0x5400, 0x5500)
+
+EXC_REAL_BEGIN(denorm_exception_hv, 0x1500, 0x1600)
+ mtspr SPRN_SPRG_HSCRATCH0,r13
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0x1500)
+
+#ifdef CONFIG_PPC_DENORMALISATION
+ mfspr r10,SPRN_HSRR1
+ mfspr r11,SPRN_HSRR0 /* save HSRR0 */
+ andis. r10,r10,(HSRR1_DENORM)@h /* denorm? */
+ addi r11,r11,-4 /* HSRR0 is next instruction */
+ bne+ denorm_assist
+#endif
+
+ KVMTEST_PR(0x1500)
+ EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV)
+EXC_REAL_END(denorm_exception_hv, 0x1500, 0x1600)
+
+#ifdef CONFIG_PPC_DENORMALISATION
+EXC_VIRT_BEGIN(denorm_exception, 0x5500, 0x5600)
+ b exc_real_0x1500_denorm_exception_hv
+EXC_VIRT_END(denorm_exception, 0x5500, 0x5600)
+#else
+EXC_VIRT_NONE(0x5500, 0x5600)
+#endif
+
+TRAMP_KVM_SKIP(PACA_EXGEN, 0x1500)
+
+#ifdef CONFIG_PPC_DENORMALISATION
+TRAMP_REAL_BEGIN(denorm_assist)
+BEGIN_FTR_SECTION
+/*
+ * To denormalise we need to move a copy of the register to itself.
+ * For POWER6 do that here for all FP regs.
+ */
+ mfmsr r10
+ ori r10,r10,(MSR_FP|MSR_FE0|MSR_FE1)
+ xori r10,r10,(MSR_FE0|MSR_FE1)
+ mtmsrd r10
+ sync
+
+#define FMR2(n) fmr (n), (n) ; fmr n+1, n+1
+#define FMR4(n) FMR2(n) ; FMR2(n+2)
+#define FMR8(n) FMR4(n) ; FMR4(n+4)
+#define FMR16(n) FMR8(n) ; FMR8(n+8)
+#define FMR32(n) FMR16(n) ; FMR16(n+16)
+ FMR32(0)
+
+FTR_SECTION_ELSE
+/*
+ * To denormalise we need to move a copy of the register to itself.
+ * For POWER7 do that here for the first 32 VSX registers only.
+ */
+ mfmsr r10
+ oris r10,r10,MSR_VSX@h
+ mtmsrd r10
+ sync
+
+#define XVCPSGNDP2(n) XVCPSGNDP(n,n,n) ; XVCPSGNDP(n+1,n+1,n+1)
+#define XVCPSGNDP4(n) XVCPSGNDP2(n) ; XVCPSGNDP2(n+2)
+#define XVCPSGNDP8(n) XVCPSGNDP4(n) ; XVCPSGNDP4(n+4)
+#define XVCPSGNDP16(n) XVCPSGNDP8(n) ; XVCPSGNDP8(n+8)
+#define XVCPSGNDP32(n) XVCPSGNDP16(n) ; XVCPSGNDP16(n+16)
+ XVCPSGNDP32(0)
+
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
+
+BEGIN_FTR_SECTION
+ b denorm_done
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+/*
+ * To denormalise we need to move a copy of the register to itself.
+ * For POWER8 we need to do that for all 64 VSX registers
+ */
+ XVCPSGNDP32(32)
+denorm_done:
+ mtspr SPRN_HSRR0,r11
+ mtcrf 0x80,r9
+ ld r9,PACA_EXGEN+EX_R9(r13)
+ RESTORE_PPR_PACA(PACA_EXGEN, r10)
+BEGIN_FTR_SECTION
+ ld r10,PACA_EXGEN+EX_CFAR(r13)
+ mtspr SPRN_CFAR,r10
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+ ld r10,PACA_EXGEN+EX_R10(r13)
+ ld r11,PACA_EXGEN+EX_R11(r13)
+ ld r12,PACA_EXGEN+EX_R12(r13)
+ ld r13,PACA_EXGEN+EX_R13(r13)
+ HRFID
+ b .
+#endif
+
+EXC_COMMON_HV(denorm_common, 0x1500, unknown_exception)
+
+
+#ifdef CONFIG_CBE_RAS
+EXC_REAL_HV(cbe_maintenance, 0x1600, 0x1700)
+EXC_VIRT_NONE(0x5600, 0x5700)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1600)
+EXC_COMMON(cbe_maintenance_common, 0x1600, cbe_maintenance_exception)
+#else /* CONFIG_CBE_RAS */
+EXC_REAL_NONE(0x1600, 0x1700)
+EXC_VIRT_NONE(0x5600, 0x5700)
+#endif
+
+
+EXC_REAL(altivec_assist, 0x1700, 0x1800)
+EXC_VIRT(altivec_assist, 0x5700, 0x5800, 0x1700)
+TRAMP_KVM(PACA_EXGEN, 0x1700)
+#ifdef CONFIG_ALTIVEC
+EXC_COMMON(altivec_assist_common, 0x1700, altivec_assist_exception)
+#else
+EXC_COMMON(altivec_assist_common, 0x1700, unknown_exception)
+#endif
+
+
+#ifdef CONFIG_CBE_RAS
+EXC_REAL_HV(cbe_thermal, 0x1800, 0x1900)
+EXC_VIRT_NONE(0x5800, 0x5900)
+TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1800)
+EXC_COMMON(cbe_thermal_common, 0x1800, cbe_thermal_exception)
+#else /* CONFIG_CBE_RAS */
+EXC_REAL_NONE(0x1800, 0x1900)
+EXC_VIRT_NONE(0x5800, 0x5900)
+#endif
+
+
+/*
+ * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
+ * - If it was a decrementer interrupt, we bump the dec to max and and return.
+ * - If it was a doorbell we return immediately since doorbells are edge
+ * triggered and won't automatically refire.
+ * - If it was a HMI we return immediately since we handled it in realmode
+ * and it won't refire.
+ * - else we hard disable and return.
+ * This is called with r10 containing the value to OR to the paca field.
+ */
+#define MASKED_INTERRUPT(_H) \
+masked_##_H##interrupt: \
+ std r11,PACA_EXGEN+EX_R11(r13); \
+ lbz r11,PACAIRQHAPPENED(r13); \
+ or r11,r11,r10; \
+ stb r11,PACAIRQHAPPENED(r13); \
+ cmpwi r10,PACA_IRQ_DEC; \
+ bne 1f; \
+ lis r10,0x7fff; \
+ ori r10,r10,0xffff; \
+ mtspr SPRN_DEC,r10; \
+ b 2f; \
+1: cmpwi r10,PACA_IRQ_DBELL; \
+ beq 2f; \
+ cmpwi r10,PACA_IRQ_HMI; \
+ beq 2f; \
+ mfspr r10,SPRN_##_H##SRR1; \
+ rldicl r10,r10,48,1; /* clear MSR_EE */ \
+ rotldi r10,r10,16; \
+ mtspr SPRN_##_H##SRR1,r10; \
+2: mtcrf 0x80,r9; \
+ ld r9,PACA_EXGEN+EX_R9(r13); \
+ ld r10,PACA_EXGEN+EX_R10(r13); \
+ ld r11,PACA_EXGEN+EX_R11(r13); \
+ GET_SCRATCH0(r13); \
+ ##_H##rfid; \
+ b .
+
+/*
+ * Real mode exceptions actually use this too, but alternate
+ * instruction code patches (which end up in the common .text area)
+ * cannot reach these if they are put there.
+ */
+USE_FIXED_SECTION(virt_trampolines)
+ MASKED_INTERRUPT()
+ MASKED_INTERRUPT(H)
+
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+TRAMP_REAL_BEGIN(kvmppc_skip_interrupt)
+ /*
+ * Here all GPRs are unchanged from when the interrupt happened
+ * except for r13, which is saved in SPRG_SCRATCH0.
+ */
+ mfspr r13, SPRN_SRR0
+ addi r13, r13, 4
+ mtspr SPRN_SRR0, r13
+ GET_SCRATCH0(r13)
+ rfid
+ b .
+
+TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt)
+ /*
+ * Here all GPRs are unchanged from when the interrupt happened
+ * except for r13, which is saved in SPRG_SCRATCH0.
+ */
+ mfspr r13, SPRN_HSRR0
+ addi r13, r13, 4
+ mtspr SPRN_HSRR0, r13
+ GET_SCRATCH0(r13)
+ hrfid
+ b .
+#endif
+
+/*
+ * Ensure that any handlers that get invoked from the exception prologs
+ * above are below the first 64KB (0x10000) of the kernel image because
+ * the prologs assemble the addresses of these handlers using the
+ * LOAD_HANDLER macro, which uses an ori instruction.
+ */
+
+/*** Common interrupt handlers ***/
+
+
+ /*
+ * Relocation-on interrupts: A subset of the interrupts can be delivered
+ * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering
+ * it. Addresses are the same as the original interrupt addresses, but
+ * offset by 0xc000000000004000.
+ * It's impossible to receive interrupts below 0x300 via this mechanism.
+ * KVM: None of these traps are from the guest ; anything that escalated
+ * to HV=1 from HV=0 is delivered via real mode handlers.
+ */
+
+ /*
+ * This uses the standard macro, since the original 0x300 vector
+ * only has extra guff for STAB-based processors -- which never
+ * come here.
+ */
+
+EXC_COMMON_BEGIN(ppc64_runlatch_on_trampoline)
+ b __ppc64_runlatch_on
+
+USE_FIXED_SECTION(virt_trampolines)
+ /*
+ * The __end_interrupts marker must be past the out-of-line (OOL)
+ * handlers, so that they are copied to real address 0x100 when running
+ * a relocatable kernel. This ensures they can be reached from the short
+ * trampoline handlers (like 0x4f00, 0x4f20, etc.) which branch
+ * directly, without using LOAD_HANDLER().
+ */
+ .align 7
+ .globl __end_interrupts
+__end_interrupts:
+DEFINE_FIXED_SYMBOL(__end_interrupts)
#ifdef CONFIG_PPC_970_NAP
-power4_fixup_nap:
+TRAMP_REAL_BEGIN(power4_fixup_nap)
andc r9,r9,r10
std r9,TI_LOCAL_FLAGS(r11)
ld r10,_LINK(r1) /* make idle task do the */
@@ -1480,6 +1385,13 @@ power4_fixup_nap:
blr
#endif
+CLOSE_FIXED_SECTION(real_vectors);
+CLOSE_FIXED_SECTION(real_trampolines);
+CLOSE_FIXED_SECTION(virt_vectors);
+CLOSE_FIXED_SECTION(virt_trampolines);
+
+USE_TEXT_SECTION()
+
/*
* Hash table stuff
*/
@@ -1625,3 +1537,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
1: addi r3,r1,STACK_FRAME_OVERHEAD
bl kernel_bad_stack
b 1b
+
+/*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
+ * which kind of interrupt. MSR:EE is already off. We generate a
+ * stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__replay_interrupt)
+ /* We are going to jump to the exception common code which
+ * will retrieve various register values from the PACA which
+ * we don't give a damn about, so we don't bother storing them.
+ */
+ mfmsr r12
+ mflr r11
+ mfcr r9
+ ori r12,r12,MSR_EE
+ cmpwi r3,0x900
+ beq decrementer_common
+ cmpwi r3,0x500
+ beq hardware_interrupt_common
+BEGIN_FTR_SECTION
+ cmpwi r3,0xe80
+ beq h_doorbell_common
+ cmpwi r3,0xea0
+ beq h_virt_irq_common
+ cmpwi r3,0xe60
+ beq hmi_exception_common
+FTR_SECTION_ELSE
+ cmpwi r3,0xa00
+ beq doorbell_super_common
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+ blr
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index b3a663333d36..8f0c7c5d93f2 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -333,6 +333,11 @@ int __init fadump_reserve_mem(void)
return 1;
}
+unsigned long __init arch_reserved_kernel_pages(void)
+{
+ return memblock_reserved_size() / PAGE_SIZE;
+}
+
/* Look for fadump= cmdline option. */
static int __init early_fadump_param(char *p)
{
@@ -778,7 +783,11 @@ static int fadump_init_elfcore_header(char *bufp)
elf->e_entry = 0;
elf->e_phoff = sizeof(struct elfhdr);
elf->e_shoff = 0;
- elf->e_flags = ELF_CORE_EFLAGS;
+#if defined(_CALL_ELF)
+ elf->e_flags = _CALL_ELF;
+#else
+ elf->e_flags = 0;
+#endif
elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = 0;
@@ -1104,7 +1113,9 @@ static ssize_t fadump_release_memory_store(struct kobject *kobj,
* Take away the '/proc/vmcore'. We are releasing the dump
* memory, hence it will not be valid anymore.
*/
+#ifdef CONFIG_PROC_VMCORE
vmcore_cleanup();
+#endif
fadump_invalidate_release_mem();
} else
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 15da2b5df85e..08d14b096eb9 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -50,32 +50,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
#define REST_32FPVSRS(n,c,base) __REST_32FPVSRS(n,__REG_##c,__REG_##base)
#define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-/* void do_load_up_transact_fpu(struct thread_struct *thread)
- *
- * This is similar to load_up_fpu but for the transactional version of the FP
- * register set. It doesn't mess with the task MSR or valid flags.
- * Furthermore, we don't do lazy FP with TM currently.
- */
-_GLOBAL(do_load_up_transact_fpu)
- mfmsr r6
- ori r5,r6,MSR_FP
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
- oris r5,r5,MSR_VSX@h
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
- SYNC
- MTMSRD(r5)
-
- addi r7,r3,THREAD_TRANSACT_FPSTATE
- lfd fr0,FPSTATE_FPSCR(r7)
- MTFSF_L(fr0)
- REST_32FPVSRS(0, R4, R7)
-
- blr
-#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
-
/*
* Load state from memory into FP registers including FPSCR.
* Assumes the caller has enabled FP in the MSR.
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index dc0488b6f6e1..a3f821eb7e9a 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -266,7 +266,6 @@ __secondary_hold_acknowledge:
#define EXCEPTION_PROLOG_2 \
- CLR_TOP32(r11); \
stw r10,_CCR(r11); /* save registers */ \
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
@@ -862,7 +861,6 @@ __secondary_start:
/* ptr to phys current thread */
tophys(r4,r2)
addi r4,r4,THREAD /* phys address of our thread_struct */
- CLR_TOP32(r4)
mtspr SPRN_SPRG_THREAD,r4
li r3,0
mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */
@@ -949,7 +947,6 @@ start_here:
/* ptr to phys current thread */
tophys(r4,r2)
addi r4,r4,THREAD /* init task's THREAD */
- CLR_TOP32(r4)
mtspr SPRN_SPRG_THREAD,r4
li r3,0
mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index f765b0434731..79da0641bae2 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -28,6 +28,7 @@
#include <asm/page.h>
#include <asm/mmu.h>
#include <asm/ppc_asm.h>
+#include <asm/head-64.h>
#include <asm/asm-offsets.h>
#include <asm/bug.h>
#include <asm/cputable.h>
@@ -65,9 +66,14 @@
* 2. The kernel is entered at __start
*/
- .text
- .globl _stext
-_stext:
+OPEN_FIXED_SECTION(first_256B, 0x0, 0x100)
+USE_FIXED_SECTION(first_256B)
+ /*
+ * Offsets are relative from the start of fixed section, and
+ * first_256B starts at 0. Offsets are a bit easier to use here
+ * than the fixed section entry macros.
+ */
+ . = 0x0
_GLOBAL(__start)
/* NOP this out unconditionally */
BEGIN_FTR_SECTION
@@ -104,6 +110,7 @@ __secondary_hold_acknowledge:
. = 0x5c
.globl __run_at_load
__run_at_load:
+DEFINE_FIXED_SYMBOL(__run_at_load)
.long 0x72756e30 /* "run0" -- relocate to 0 by default */
#endif
@@ -133,7 +140,7 @@ __secondary_hold:
/* Tell the master cpu we're here */
/* Relocation is off & we are located at an address less */
/* than 0x100, so only need to grab low order offset. */
- std r24,__secondary_hold_acknowledge-_stext(0)
+ std r24,(ABS_ADDR(__secondary_hold_acknowledge))(0)
sync
li r26,0
@@ -141,7 +148,7 @@ __secondary_hold:
tovirt(r26,r26)
#endif
/* All secondary cpus wait here until told to start. */
-100: ld r12,__secondary_hold_spinloop-_stext(r26)
+100: ld r12,(ABS_ADDR(__secondary_hold_spinloop))(r26)
cmpdi 0,r12,0
beq 100b
@@ -166,12 +173,13 @@ __secondary_hold:
#else
BUG_OPCODE
#endif
+CLOSE_FIXED_SECTION(first_256B)
/* This value is used to mark exception frames on the stack. */
.section ".toc","aw"
exception_marker:
.tc ID_72656773_68657265[TC],0x7265677368657265
- .text
+ .previous
/*
* On server, we include the exception vectors code here as it
@@ -180,8 +188,12 @@ exception_marker:
*/
#ifdef CONFIG_PPC_BOOK3S
#include "exceptions-64s.S"
+#else
+OPEN_TEXT_SECTION(0x100)
#endif
+USE_TEXT_SECTION()
+
#ifdef CONFIG_PPC_BOOK3E
/*
* The booting_thread_hwid holds the thread id we want to boot in cpu
@@ -558,7 +570,7 @@ __after_prom_start:
#if defined(CONFIG_PPC_BOOK3E)
tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */
#endif
- lwz r7,__run_at_load-_stext(r26)
+ lwz r7,(FIXED_SYMBOL_ABS_ADDR(__run_at_load))(r26)
#if defined(CONFIG_PPC_BOOK3E)
tophys(r26,r26)
#endif
@@ -601,7 +613,7 @@ __after_prom_start:
#if defined(CONFIG_PPC_BOOK3E)
tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */
#endif
- lwz r7,__run_at_load-_stext(r26)
+ lwz r7,(FIXED_SYMBOL_ABS_ADDR(__run_at_load))(r26)
cmplwi cr0,r7,1
bne 3f
@@ -611,28 +623,35 @@ __after_prom_start:
sub r5,r5,r11
#else
/* just copy interrupts */
- LOAD_REG_IMMEDIATE(r5, __end_interrupts - _stext)
+ LOAD_REG_IMMEDIATE(r5, FIXED_SYMBOL_ABS_ADDR(__end_interrupts))
#endif
b 5f
3:
#endif
- lis r5,(copy_to_here - _stext)@ha
- addi r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */
+ /* # bytes of memory to copy */
+ lis r5,(ABS_ADDR(copy_to_here))@ha
+ addi r5,r5,(ABS_ADDR(copy_to_here))@l
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 r12,r8,(4f - _stext)@l /* that we just made */
+ /* Jump to the copy of this code that we just made */
+ addis r8,r3,(ABS_ADDR(4f))@ha
+ addi r12,r8,(ABS_ADDR(4f))@l
mtctr r12
bctr
.balign 8
-p_end: .llong _end - _stext
+p_end: .llong _end - copy_to_here
-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 */
+4:
+ /*
+ * Now copy the rest of the kernel up to _end, add
+ * _end - copy_to_here to the copy limit and run again.
+ */
+ addis r8,r26,(ABS_ADDR(p_end))@ha
+ ld r8,(ABS_ADDR(p_end))@l(r8)
+ add r5,r5,r8
5: bl copy_and_flush /* copy the rest */
9: b start_here_multiplatform
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 43ddaae42baf..3a185c51ce8f 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -151,7 +151,6 @@ turn_on_mmu:
#define EXCEPTION_PROLOG_2 \
- CLR_TOP32(r11); \
stw r10,_CCR(r11); /* save registers */ \
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index aec9a1b1d25b..9781c69eae57 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -206,7 +206,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
/*
* Handle debug exception notifications.
*/
-int __kprobes hw_breakpoint_handler(struct die_args *args)
+int hw_breakpoint_handler(struct die_args *args)
{
int rc = NOTIFY_STOP;
struct perf_event *bp;
@@ -290,11 +290,12 @@ out:
rcu_read_unlock();
return rc;
}
+NOKPROBE_SYMBOL(hw_breakpoint_handler);
/*
* Handle single-step exceptions following a DABR hit.
*/
-static int __kprobes single_step_dabr_instruction(struct die_args *args)
+static int single_step_dabr_instruction(struct die_args *args)
{
struct pt_regs *regs = args->regs;
struct perf_event *bp = NULL;
@@ -329,11 +330,12 @@ static int __kprobes single_step_dabr_instruction(struct die_args *args)
return NOTIFY_STOP;
}
+NOKPROBE_SYMBOL(single_step_dabr_instruction);
/*
* Handle debug exception notifications.
*/
-int __kprobes hw_breakpoint_exceptions_notify(
+int hw_breakpoint_exceptions_notify(
struct notifier_block *unused, unsigned long val, void *data)
{
int ret = NOTIFY_DONE;
@@ -349,6 +351,7 @@ int __kprobes hw_breakpoint_exceptions_notify(
return ret;
}
+NOKPROBE_SYMBOL(hw_breakpoint_exceptions_notify);
/*
* Release the user breakpoints used by ptrace
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index c1ca9282f4a0..6ca9a2ffaac7 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -227,7 +227,7 @@ int ibmebus_request_irq(u32 ist, irq_handler_t handler,
{
unsigned int irq = irq_create_mapping(NULL, ist);
- if (irq == NO_IRQ)
+ if (!irq)
return -EINVAL;
return request_irq(irq, handler, irq_flags, devname, dev_id);
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 08887cf2b20e..3c05c311e35e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -67,6 +67,7 @@
#include <asm/smp.h>
#include <asm/debug.h>
#include <asm/livepatch.h>
+#include <asm/asm-prototypes.h>
#ifdef CONFIG_PPC64
#include <asm/paca.h>
@@ -156,6 +157,15 @@ notrace unsigned int __check_irq_replay(void)
}
/*
+ * Check if an hypervisor Maintenance interrupt happened.
+ * This is a higher priority interrupt than the others, so
+ * replay it first.
+ */
+ local_paca->irq_happened &= ~PACA_IRQ_HMI;
+ if (happened & PACA_IRQ_HMI)
+ return 0xe60;
+
+ /*
* We may have missed a decrementer interrupt. We check the
* decrementer itself rather than the paca irq_happened field
* in case we also had a rollover while hard disabled
@@ -190,11 +200,6 @@ notrace unsigned int __check_irq_replay(void)
}
#endif /* CONFIG_PPC_BOOK3E */
- /* Check if an hypervisor Maintenance interrupt happened */
- local_paca->irq_happened &= ~PACA_IRQ_HMI;
- if (happened & PACA_IRQ_HMI)
- return 0xe60;
-
/* There should be nothing left ! */
BUG_ON(local_paca->irq_happened != 0);
@@ -514,7 +519,7 @@ void __do_irq(struct pt_regs *regs)
may_hard_irq_enable();
/* And finally process it */
- if (unlikely(irq == NO_IRQ))
+ if (unlikely(!irq))
__this_cpu_inc(irq_stat.spurious_irqs);
else
generic_handle_irq(irq);
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 7b750c4ed5c7..bc525ea0dc09 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -193,10 +193,10 @@ static int __init add_legacy_soc_port(struct device_node *np,
*/
if (tsi && !strcmp(tsi->type, "tsi-bridge"))
return add_legacy_port(np, -1, UPIO_TSI, addr, addr,
- NO_IRQ, legacy_port_flags, 0);
+ 0, legacy_port_flags, 0);
else
return add_legacy_port(np, -1, UPIO_MEM, addr, addr,
- NO_IRQ, legacy_port_flags, 0);
+ 0, legacy_port_flags, 0);
}
static int __init add_legacy_isa_port(struct device_node *np,
@@ -242,7 +242,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
/* Add port, irq will be dealt with later */
return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]),
- taddr, NO_IRQ, legacy_port_flags, 0);
+ taddr, 0, legacy_port_flags, 0);
}
@@ -314,7 +314,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
/* Add port, irq will be dealt with later. We passed a translated
* IO port value. It will be fixed up later along with the irq
*/
- return add_legacy_port(np, index, iotype, base, addr, NO_IRQ,
+ return add_legacy_port(np, index, iotype, base, addr, 0,
legacy_port_flags, np != pci_dev);
}
#endif
@@ -462,14 +462,14 @@ static void __init fixup_port_irq(int index,
DBG("fixup_port_irq(%d)\n", index);
virq = irq_of_parse_and_map(np, 0);
- if (virq == NO_IRQ && legacy_serial_infos[index].irq_check_parent) {
+ if (!virq && legacy_serial_infos[index].irq_check_parent) {
np = of_get_parent(np);
if (np == NULL)
return;
virq = irq_of_parse_and_map(np, 0);
of_node_put(np);
}
- if (virq == NO_IRQ)
+ if (!virq)
return;
port->irq = virq;
@@ -543,7 +543,7 @@ static int __init serial_dev_init(void)
struct plat_serial8250_port *port = &legacy_serial_ports[i];
struct device_node *np = legacy_serial_infos[i].np;
- if (port->irq == NO_IRQ)
+ if (!port->irq)
fixup_port_irq(i, np, port);
if (port->iotype == UPIO_PORT)
fixup_port_pio(i, np, port);
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 4c780a342282..a205fa3d9bf3 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -23,6 +23,7 @@
#include <asm/current.h>
#include <asm/machdep.h>
#include <asm/cacheflush.h>
+#include <asm/firmware.h>
#include <asm/paca.h>
#include <asm/mmu.h>
#include <asm/sections.h> /* _end */
@@ -31,21 +32,6 @@
#include <asm/hw_breakpoint.h>
#include <asm/asm-prototypes.h>
-#ifdef CONFIG_PPC_BOOK3E
-int default_machine_kexec_prepare(struct kimage *image)
-{
- int i;
- /*
- * Since we use the kernel fault handlers and paging code to
- * handle the virtual mode, we must make sure no destination
- * overlaps kernel static data or bss.
- */
- for (i = 0; i < image->nr_segments; i++)
- if (image->segment[i].mem < __pa(_end))
- return -ETXTBSY;
- return 0;
-}
-#else
int default_machine_kexec_prepare(struct kimage *image)
{
int i;
@@ -55,9 +41,6 @@ int default_machine_kexec_prepare(struct kimage *image)
const unsigned long *basep;
const unsigned int *sizep;
- if (!mmu_hash_ops.hpte_clear_all)
- return -ENOENT;
-
/*
* Since we use the kernel fault handlers and paging code to
* handle the virtual mode, we must make sure no destination
@@ -67,31 +50,6 @@ int default_machine_kexec_prepare(struct kimage *image)
if (image->segment[i].mem < __pa(_end))
return -ETXTBSY;
- /*
- * For non-LPAR, we absolutely can not overwrite the mmu hash
- * table, since we are still using the bolted entries in it to
- * do the copy. Check that here.
- *
- * It is safe if the end is below the start of the blocked
- * region (end <= low), or if the beginning is after the
- * end of the blocked region (begin >= high). Use the
- * boolean identity !(a || b) === (!a && !b).
- */
-#ifdef CONFIG_PPC_STD_MMU_64
- if (htab_address) {
- low = __pa(htab_address);
- high = low + htab_size_bytes;
-
- for (i = 0; i < image->nr_segments; i++) {
- begin = image->segment[i].mem;
- end = begin + image->segment[i].memsz;
-
- if ((begin < high) && (end > low))
- return -ETXTBSY;
- }
- }
-#endif /* CONFIG_PPC_STD_MMU_64 */
-
/* We also should not overwrite the tce tables */
for_each_node_by_type(node, "pci") {
basep = of_get_property(node, "linux,tce-base", NULL);
@@ -113,7 +71,6 @@ int default_machine_kexec_prepare(struct kimage *image)
return 0;
}
-#endif /* !CONFIG_PPC_BOOK3E */
static void copy_segments(unsigned long ind)
{
@@ -332,11 +289,14 @@ struct paca_struct kexec_paca;
/* Our assembly helper, in misc_64.S */
extern void kexec_sequence(void *newstack, unsigned long start,
void *image, void *control,
- void (*clear_all)(void)) __noreturn;
+ void (*clear_all)(void),
+ bool copy_with_mmu_off) __noreturn;
/* too late to fail here */
void default_machine_kexec(struct kimage *image)
{
+ bool copy_with_mmu_off;
+
/* prepare control code if any */
/*
@@ -374,18 +334,29 @@ void default_machine_kexec(struct kimage *image)
/* XXX: If anyone does 'dynamic lppacas' this will also need to be
* switched to a static version!
*/
+ /*
+ * On Book3S, the copy must happen with the MMU off if we are either
+ * using Radix page tables or we are not in an LPAR since we can
+ * overwrite the page tables while copying.
+ *
+ * In an LPAR, we keep the MMU on otherwise we can't access beyond
+ * the RMA. On BookE there is no real MMU off mode, so we have to
+ * keep it enabled as well (but then we have bolted TLB entries).
+ */
+#ifdef CONFIG_PPC_BOOK3E
+ copy_with_mmu_off = false;
+#else
+ copy_with_mmu_off = radix_enabled() ||
+ !(firmware_has_feature(FW_FEATURE_LPAR) ||
+ firmware_has_feature(FW_FEATURE_PS3_LV1));
+#endif
/* Some things are best done in assembly. Finding globals with
* a toc is easier in C, so pass in what we can.
*/
kexec_sequence(&kexec_stack, image->start, image,
- page_address(image->control_code_page),
-#ifdef CONFIG_PPC_STD_MMU
- mmu_hash_ops.hpte_clear_all
-#else
- NULL
-#endif
- );
+ page_address(image->control_code_page),
+ mmu_cleanup_all, copy_with_mmu_off);
/* NOTREACHED */
}
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index d9c912b6e632..03756ffdcd71 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -328,7 +328,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
*
* flush_icache_range(unsigned long start, unsigned long stop)
*/
-_KPROBE(flush_icache_range)
+_GLOBAL(flush_icache_range)
BEGIN_FTR_SECTION
PURGE_PREFETCHED_INS
blr /* for 601, do nothing */
@@ -358,6 +358,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
sync /* additional sync needed on g4 */
isync
blr
+_ASM_NOKPROBE_SYMBOL(flush_icache_range)
+
/*
* Flush a particular page from the data cache to RAM.
* Note: this is necessary because the instruction cache does *not*
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index cb195157b318..9f0bed214bcb 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -66,7 +66,7 @@ PPC64_CACHES:
* flush all bytes from start through stop-1 inclusive
*/
-_KPROBE(flush_icache_range)
+_GLOBAL(flush_icache_range)
BEGIN_FTR_SECTION
PURGE_PREFETCHED_INS
blr
@@ -109,7 +109,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
bdnz 2b
isync
blr
- .previous .text
+_ASM_NOKPROBE_SYMBOL(flush_icache_range)
+
/*
* Like above, but only do the D-cache.
*
@@ -591,7 +592,8 @@ real_mode: /* assume normal blr return */
#endif
/*
- * kexec_sequence(newstack, start, image, control, clear_all())
+ * kexec_sequence(newstack, start, image, control, clear_all(),
+ copy_with_mmu_off)
*
* does the grungy work with stack switching and real mode switches
* also does simple calls to other code
@@ -627,7 +629,7 @@ _GLOBAL(kexec_sequence)
mr r29,r5 /* image (virt) */
mr r28,r6 /* control, unused */
mr r27,r7 /* clear_all() fn desc */
- mr r26,r8 /* spare */
+ mr r26,r8 /* copy_with_mmu_off */
lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */
/* disable interrupts, we are overwriting kernel data next */
@@ -639,15 +641,24 @@ _GLOBAL(kexec_sequence)
mtmsrd r3,1
#endif
+ /* We need to turn the MMU off unless we are in hash mode
+ * under a hypervisor
+ */
+ cmpdi r26,0
+ beq 1f
+ bl real_mode
+1:
/* copy dest pages, flush whole dest image */
mr r3,r29
bl kexec_copy_flush /* (image) */
- /* turn off mmu */
+ /* turn off mmu now if not done earlier */
+ cmpdi r26,0
+ bne 1f
bl real_mode
/* copy 0x100 bytes starting at start to 0 */
- li r3,0
+1: li r3,0
mr r4,r30 /* start, aka phys mem offset */
li r5,0x100
li r6,0
@@ -659,7 +670,9 @@ _GLOBAL(kexec_sequence)
li r6,1
stw r6,kexec_flag-1b(5)
-#ifndef CONFIG_PPC_BOOK3E
+ cmpdi r27,0
+ beq 1f
+
/* clear out hardware hash page table and tlb */
#ifdef PPC64_ELF_ABI_v1
ld r12,0(r27) /* deref function descriptor */
@@ -668,7 +681,6 @@ _GLOBAL(kexec_sequence)
#endif
mtctr r12
bctrl /* mmu_hash_ops.hpte_clear_all(void); */
-#endif /* !CONFIG_PPC_BOOK3E */
/*
* kexec image calling is:
@@ -695,7 +707,7 @@ _GLOBAL(kexec_sequence)
* are the boot cpu ?????
* other device tree differences (prop sizes, va vs pa, etc)...
*/
- mr r3,r25 # my phys cpu
+1: mr r3,r25 # my phys cpu
mr r4,r30 # start, aka phys mem offset
mtlr 4
li r5,0
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c
index d1f1b35bf0c7..30b89d5cbb03 100644
--- a/arch/powerpc/kernel/module.c
+++ b/arch/powerpc/kernel/module.c
@@ -27,7 +27,7 @@
#include <linux/sort.h>
#include <asm/setup.h>
-LIST_HEAD(module_bug_list);
+static LIST_HEAD(module_bug_list);
static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 64174bf95611..34d2c595de23 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -542,9 +542,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
time->tv_nsec = 0;
}
*buf = kmemdup(buff + hdr_size, length, GFP_KERNEL);
+ kfree(buff);
if (*buf == NULL)
return -ENOMEM;
- kfree(buff);
*ecc_notice_size = 0;
if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
@@ -851,7 +851,7 @@ static long dev_nvram_ioctl(struct file *file, unsigned int cmd,
}
}
-const struct file_operations nvram_fops = {
+static const struct file_operations nvram_fops = {
.owner = THIS_MODULE,
.llseek = dev_nvram_llseek,
.read = dev_nvram_read,
@@ -956,7 +956,7 @@ int __init nvram_remove_partition(const char *name, int sig,
/* Make partition a free partition */
part->header.signature = NVRAM_SIG_FREE;
- strncpy(part->header.name, "wwwwwwwwwwww", 12);
+ memset(part->header.name, 'w', 12);
part->header.checksum = nvram_checksum(&part->header);
rc = nvram_write_header(part);
if (rc <= 0) {
@@ -974,8 +974,8 @@ int __init nvram_remove_partition(const char *name, int sig,
}
if (prev) {
prev->header.length += part->header.length;
- prev->header.checksum = nvram_checksum(&part->header);
- rc = nvram_write_header(part);
+ prev->header.checksum = nvram_checksum(&prev->header);
+ rc = nvram_write_header(prev);
if (rc <= 0) {
printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc);
return rc;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index e58908066b0e..95d3769a2e26 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -360,7 +360,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
line, pin);
virq = irq_create_mapping(NULL, line);
- if (virq != NO_IRQ)
+ if (virq)
irq_set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
} else {
pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
@@ -369,7 +369,8 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
virq = irq_create_of_mapping(&oirq);
}
- if(virq == NO_IRQ) {
+
+ if (!virq) {
pr_debug(" Failed to map !\n");
return -1;
}
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 526ac6750e4d..ea3d98115b88 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -178,7 +178,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS;
/* Maybe do a default OF mapping here */
- dev->irq = NO_IRQ;
+ dev->irq = 0;
}
of_pci_parse_addrs(node, dev);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 9ee2623e0f67..9e7c10fe205f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -59,6 +59,7 @@
#include <asm/exec.h>
#include <asm/livepatch.h>
#include <asm/cpu_has_feature.h>
+#include <asm/asm-prototypes.h>
#include <linux/kprobes.h>
#include <linux/kdebug.h>
@@ -88,7 +89,13 @@ static void check_if_tm_restore_required(struct task_struct *tsk)
set_thread_flag(TIF_RESTORE_TM);
}
}
+
+static inline bool msr_tm_active(unsigned long msr)
+{
+ return MSR_TM_ACTIVE(msr);
+}
#else
+static inline bool msr_tm_active(unsigned long msr) { return false; }
static inline void check_if_tm_restore_required(struct task_struct *tsk) { }
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
@@ -104,7 +111,7 @@ static int __init enable_strict_msr_control(char *str)
}
early_param("ppc_strict_facility_enable", enable_strict_msr_control);
-void msr_check_and_set(unsigned long bits)
+unsigned long msr_check_and_set(unsigned long bits)
{
unsigned long oldmsr = mfmsr();
unsigned long newmsr;
@@ -118,6 +125,8 @@ void msr_check_and_set(unsigned long bits)
if (oldmsr != newmsr)
mtmsr_isync(newmsr);
+
+ return newmsr;
}
void __msr_check_and_clear(unsigned long bits)
@@ -196,19 +205,30 @@ EXPORT_SYMBOL_GPL(flush_fp_to_thread);
void enable_kernel_fp(void)
{
+ unsigned long cpumsr;
+
WARN_ON(preemptible());
- msr_check_and_set(MSR_FP);
+ cpumsr = msr_check_and_set(MSR_FP);
if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) {
check_if_tm_restore_required(current);
+ /*
+ * If a thread has already been reclaimed then the
+ * checkpointed registers are on the CPU but have definitely
+ * been saved by the reclaim code. Don't need to and *cannot*
+ * giveup as this would save to the 'live' structure not the
+ * checkpointed structure.
+ */
+ if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
+ return;
__giveup_fpu(current);
}
}
EXPORT_SYMBOL(enable_kernel_fp);
static int restore_fp(struct task_struct *tsk) {
- if (tsk->thread.load_fp) {
+ if (tsk->thread.load_fp || msr_tm_active(tsk->thread.regs->msr)) {
load_fp_state(&current->thread.fp_state);
current->thread.load_fp++;
return 1;
@@ -248,12 +268,23 @@ EXPORT_SYMBOL(giveup_altivec);
void enable_kernel_altivec(void)
{
+ unsigned long cpumsr;
+
WARN_ON(preemptible());
- msr_check_and_set(MSR_VEC);
+ cpumsr = msr_check_and_set(MSR_VEC);
if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) {
check_if_tm_restore_required(current);
+ /*
+ * If a thread has already been reclaimed then the
+ * checkpointed registers are on the CPU but have definitely
+ * been saved by the reclaim code. Don't need to and *cannot*
+ * giveup as this would save to the 'live' structure not the
+ * checkpointed structure.
+ */
+ if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
+ return;
__giveup_altivec(current);
}
}
@@ -278,7 +309,8 @@ EXPORT_SYMBOL_GPL(flush_altivec_to_thread);
static int restore_altivec(struct task_struct *tsk)
{
- if (cpu_has_feature(CPU_FTR_ALTIVEC) && tsk->thread.load_vec) {
+ if (cpu_has_feature(CPU_FTR_ALTIVEC) &&
+ (tsk->thread.load_vec || msr_tm_active(tsk->thread.regs->msr))) {
load_vr_state(&tsk->thread.vr_state);
tsk->thread.used_vr = 1;
tsk->thread.load_vec++;
@@ -321,12 +353,23 @@ static void save_vsx(struct task_struct *tsk)
void enable_kernel_vsx(void)
{
+ unsigned long cpumsr;
+
WARN_ON(preemptible());
- msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
+ cpumsr = msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) {
check_if_tm_restore_required(current);
+ /*
+ * If a thread has already been reclaimed then the
+ * checkpointed registers are on the CPU but have definitely
+ * been saved by the reclaim code. Don't need to and *cannot*
+ * giveup as this would save to the 'live' structure not the
+ * checkpointed structure.
+ */
+ if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr))
+ return;
if (current->thread.regs->msr & MSR_FP)
__giveup_fpu(current);
if (current->thread.regs->msr & MSR_VEC)
@@ -438,6 +481,7 @@ void giveup_all(struct task_struct *tsk)
return;
msr_check_and_set(msr_all_available);
+ check_if_tm_restore_required(tsk);
#ifdef CONFIG_PPC_FPU
if (usermsr & MSR_FP)
@@ -464,7 +508,8 @@ void restore_math(struct pt_regs *regs)
{
unsigned long msr;
- if (!current->thread.load_fp && !loadvec(current->thread))
+ if (!msr_tm_active(regs->msr) &&
+ !current->thread.load_fp && !loadvec(current->thread))
return;
msr = regs->msr;
@@ -767,29 +812,15 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+
+static inline bool tm_enabled(struct task_struct *tsk)
+{
+ return tsk && tsk->thread.regs && (tsk->thread.regs->msr & MSR_TM);
+}
+
static void tm_reclaim_thread(struct thread_struct *thr,
struct thread_info *ti, uint8_t cause)
{
- unsigned long msr_diff = 0;
-
- /*
- * If FP/VSX registers have been already saved to the
- * thread_struct, move them to the transact_fp array.
- * We clear the TIF_RESTORE_TM bit since after the reclaim
- * the thread will no longer be transactional.
- */
- if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) {
- msr_diff = thr->ckpt_regs.msr & ~thr->regs->msr;
- if (msr_diff & MSR_FP)
- memcpy(&thr->transact_fp, &thr->fp_state,
- sizeof(struct thread_fp_state));
- if (msr_diff & MSR_VEC)
- memcpy(&thr->transact_vr, &thr->vr_state,
- sizeof(struct thread_vr_state));
- clear_ti_thread_flag(ti, TIF_RESTORE_TM);
- msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1;
- }
-
/*
* Use the current MSR TM suspended bit to track if we have
* checkpointed state outstanding.
@@ -808,15 +839,9 @@ static void tm_reclaim_thread(struct thread_struct *thr,
if (!MSR_TM_SUSPENDED(mfmsr()))
return;
- tm_reclaim(thr, thr->regs->msr, cause);
+ giveup_all(container_of(thr, struct task_struct, thread));
- /* Having done the reclaim, we now have the checkpointed
- * FP/VSX values in the registers. These might be valid
- * even if we have previously called enable_kernel_fp() or
- * flush_fp_to_thread(), so update thr->regs->msr to
- * indicate their current validity.
- */
- thr->regs->msr |= msr_diff;
+ tm_reclaim(thr, thr->ckpt_regs.msr, cause);
}
void tm_reclaim_current(uint8_t cause)
@@ -832,8 +857,8 @@ static inline void tm_reclaim_task(struct task_struct *tsk)
*
* In switching we need to maintain a 2nd register state as
* oldtask->thread.ckpt_regs. We tm_reclaim(oldproc); this saves the
- * checkpointed (tbegin) state in ckpt_regs and saves the transactional
- * (current) FPRs into oldtask->thread.transact_fpr[].
+ * checkpointed (tbegin) state in ckpt_regs, ckfp_state and
+ * ckvr_state
*
* We also context switch (save) TFHAR/TEXASR/TFIAR in here.
*/
@@ -845,14 +870,6 @@ static inline void tm_reclaim_task(struct task_struct *tsk)
if (!MSR_TM_ACTIVE(thr->regs->msr))
goto out_and_saveregs;
- /* Stash the original thread MSR, as giveup_fpu et al will
- * modify it. We hold onto it to see whether the task used
- * FP & vector regs. If the TIF_RESTORE_TM flag is set,
- * ckpt_regs.msr is already set.
- */
- if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM))
- thr->ckpt_regs.msr = thr->regs->msr;
-
TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, "
"ccr=%lx, msr=%lx, trap=%lx)\n",
tsk->pid, thr->regs->nip,
@@ -881,6 +898,9 @@ void tm_recheckpoint(struct thread_struct *thread,
{
unsigned long flags;
+ if (!(thread->regs->msr & MSR_TM))
+ return;
+
/* We really can't be interrupted here as the TEXASR registers can't
* change and later in the trecheckpoint code, we have a userspace R1.
* So let's hard disable over this region.
@@ -910,10 +930,10 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
* If the task was using FP, we non-lazily reload both the original and
* the speculative FP register states. This is because the kernel
* doesn't see if/when a TM rollback occurs, so if we take an FP
- * unavoidable later, we are unable to determine which set of FP regs
+ * unavailable later, we are unable to determine which set of FP regs
* need to be restored.
*/
- if (!new->thread.regs)
+ if (!tm_enabled(new))
return;
if (!MSR_TM_ACTIVE(new->thread.regs->msr)){
@@ -926,35 +946,35 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
"(new->msr 0x%lx, new->origmsr 0x%lx)\n",
new->pid, new->thread.regs->msr, msr);
- /* This loads the checkpointed FP/VEC state, if used */
tm_recheckpoint(&new->thread, msr);
- /* This loads the speculative FP/VEC state, if used */
- if (msr & MSR_FP) {
- do_load_up_transact_fpu(&new->thread);
- new->thread.regs->msr |=
- (MSR_FP | new->thread.fpexc_mode);
- }
-#ifdef CONFIG_ALTIVEC
- if (msr & MSR_VEC) {
- do_load_up_transact_altivec(&new->thread);
- new->thread.regs->msr |= MSR_VEC;
- }
-#endif
- /* We may as well turn on VSX too since all the state is restored now */
- if (msr & MSR_VSX)
- new->thread.regs->msr |= MSR_VSX;
+ /*
+ * The checkpointed state has been restored but the live state has
+ * not, ensure all the math functionality is turned off to trigger
+ * restore_math() to reload.
+ */
+ new->thread.regs->msr &= ~(MSR_FP | MSR_VEC | MSR_VSX);
TM_DEBUG("*** tm_recheckpoint of pid %d complete "
"(kernel msr 0x%lx)\n",
new->pid, mfmsr());
}
-static inline void __switch_to_tm(struct task_struct *prev)
+static inline void __switch_to_tm(struct task_struct *prev,
+ struct task_struct *new)
{
if (cpu_has_feature(CPU_FTR_TM)) {
- tm_enable();
- tm_reclaim_task(prev);
+ if (tm_enabled(prev) || tm_enabled(new))
+ tm_enable();
+
+ if (tm_enabled(prev)) {
+ prev->thread.load_tm++;
+ tm_reclaim_task(prev);
+ if (!MSR_TM_ACTIVE(prev->thread.regs->msr) && prev->thread.load_tm == 0)
+ prev->thread.regs->msr &= ~MSR_TM;
+ }
+
+ tm_recheckpoint_new_task(new);
}
}
@@ -976,6 +996,12 @@ void restore_tm_state(struct pt_regs *regs)
{
unsigned long msr_diff;
+ /*
+ * This is the only moment we should clear TIF_RESTORE_TM as
+ * it is here that ckpt_regs.msr and pt_regs.msr become the same
+ * again, anything else could lead to an incorrect ckpt_msr being
+ * saved and therefore incorrect signal contexts.
+ */
clear_thread_flag(TIF_RESTORE_TM);
if (!MSR_TM_ACTIVE(regs->msr))
return;
@@ -983,6 +1009,13 @@ void restore_tm_state(struct pt_regs *regs)
msr_diff = current->thread.ckpt_regs.msr & ~regs->msr;
msr_diff &= MSR_FP | MSR_VEC | MSR_VSX;
+ /* Ensure that restore_math() will restore */
+ if (msr_diff & MSR_FP)
+ current->thread.load_fp = 1;
+#ifdef CONFIG_ALIVEC
+ if (cpu_has_feature(CPU_FTR_ALTIVEC) && msr_diff & MSR_VEC)
+ current->thread.load_vec = 1;
+#endif
restore_math(regs);
regs->msr |= msr_diff;
@@ -990,7 +1023,7 @@ void restore_tm_state(struct pt_regs *regs)
#else
#define tm_recheckpoint_new_task(new)
-#define __switch_to_tm(prev)
+#define __switch_to_tm(prev, new)
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
static inline void save_sprs(struct thread_struct *t)
@@ -1131,11 +1164,11 @@ struct task_struct *__switch_to(struct task_struct *prev,
*/
save_sprs(&prev->thread);
- __switch_to_tm(prev);
-
/* Save FPU, Altivec, VSX and SPE state */
giveup_all(prev);
+ __switch_to_tm(prev, new);
+
/*
* We can't take a PMU exception inside _switch() since there is a
* window where the kernel stack SLB and the kernel stack are out
@@ -1143,8 +1176,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
*/
hard_irq_disable();
- tm_recheckpoint_new_task(new);
-
/*
* Call restore_sprs() before calling _switch(). If we move it after
* _switch() then we miss out on calling it for new tasks. The reason
@@ -1379,9 +1410,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
* transitions the CPU out of TM mode. Hence we need to call
* tm_recheckpoint_new_task() (on the same task) to restore the
* checkpointed state back and the TM mode.
+ *
+ * Can't pass dst because it isn't ready. Doesn't matter, passing
+ * dst is only important for __switch_to()
*/
- __switch_to_tm(src);
- tm_recheckpoint_new_task(src);
+ __switch_to_tm(src, src);
*dst = *src;
@@ -1623,8 +1656,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
current->thread.used_spe = 0;
#endif /* CONFIG_SPE */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (cpu_has_feature(CPU_FTR_TM))
- regs->msr |= MSR_TM;
current->thread.tm_tfhar = 0;
current->thread.tm_texasr = 0;
current->thread.tm_tfiar = 0;
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index d3eff99e938c..88ac964f4858 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -42,6 +42,7 @@
#include <asm/sections.h>
#include <asm/machdep.h>
#include <asm/opal.h>
+#include <asm/asm-prototypes.h>
#include <linux/linux_logo.h>
@@ -2643,6 +2644,86 @@ static void __init fixup_device_tree_efika(void)
#define fixup_device_tree_efika()
#endif
+#ifdef CONFIG_PPC_PASEMI_NEMO
+/*
+ * CFE supplied on Nemo is broken in several ways, biggest
+ * problem is that it reassigns ISA interrupts to unused mpic ints.
+ * Add an interrupt-controller property for the io-bridge to use
+ * and correct the ints so we can attach them to an irq_domain
+ */
+static void __init fixup_device_tree_pasemi(void)
+{
+ u32 interrupts[2], parent, rval, val = 0;
+ char *name, *pci_name;
+ phandle iob, node;
+
+ /* Find the root pci node */
+ name = "/pxp@0,e0000000";
+ iob = call_prom("finddevice", 1, 1, ADDR(name));
+ if (!PHANDLE_VALID(iob))
+ return;
+
+ /* check if interrupt-controller node set yet */
+ if (prom_getproplen(iob, "interrupt-controller") !=PROM_ERROR)
+ return;
+
+ prom_printf("adding interrupt-controller property for SB600...\n");
+
+ prom_setprop(iob, name, "interrupt-controller", &val, 0);
+
+ pci_name = "/pxp@0,e0000000/pci@11";
+ node = call_prom("finddevice", 1, 1, ADDR(pci_name));
+ parent = ADDR(iob);
+
+ for( ; prom_next_node(&node); ) {
+ /* scan each node for one with an interrupt */
+ if (!PHANDLE_VALID(node))
+ continue;
+
+ rval = prom_getproplen(node, "interrupts");
+ if (rval == 0 || rval == PROM_ERROR)
+ continue;
+
+ prom_getprop(node, "interrupts", &interrupts, sizeof(interrupts));
+ if ((interrupts[0] < 212) || (interrupts[0] > 222))
+ continue;
+
+ /* found a node, update both interrupts and interrupt-parent */
+ if ((interrupts[0] >= 212) && (interrupts[0] <= 215))
+ interrupts[0] -= 203;
+ if ((interrupts[0] >= 216) && (interrupts[0] <= 220))
+ interrupts[0] -= 213;
+ if (interrupts[0] == 221)
+ interrupts[0] = 14;
+ if (interrupts[0] == 222)
+ interrupts[0] = 8;
+
+ prom_setprop(node, pci_name, "interrupts", interrupts,
+ sizeof(interrupts));
+ prom_setprop(node, pci_name, "interrupt-parent", &parent,
+ sizeof(parent));
+ }
+
+ /*
+ * The io-bridge has device_type set to 'io-bridge' change it to 'isa'
+ * so that generic isa-bridge code can add the SB600 and its on-board
+ * peripherals.
+ */
+ name = "/pxp@0,e0000000/io-bridge@0";
+ iob = call_prom("finddevice", 1, 1, ADDR(name));
+ if (!PHANDLE_VALID(iob))
+ return;
+
+ /* device_type is already set, just change it. */
+
+ prom_printf("Changing device_type of SB600 node...\n");
+
+ prom_setprop(iob, name, "device_type", "isa", sizeof("isa"));
+}
+#else /* !CONFIG_PPC_PASEMI_NEMO */
+static inline void fixup_device_tree_pasemi(void) { }
+#endif
+
static void __init fixup_device_tree(void)
{
fixup_device_tree_maple();
@@ -2650,6 +2731,7 @@ static void __init fixup_device_tree(void)
fixup_device_tree_chrp();
fixup_device_tree_pmac();
fixup_device_tree_efika();
+ fixup_device_tree_pasemi();
}
static void __init prom_find_boot_cpu(void)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index bf91658a8a40..b1ec62f2cc31 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -39,6 +39,7 @@
#include <asm/pgtable.h>
#include <asm/switch_to.h>
#include <asm/tm.h>
+#include <asm/asm-prototypes.h>
#define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h>
@@ -402,13 +403,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
}
/*
- * When the transaction is active, 'transact_fp' holds the current running
- * value of all FPR registers and 'fp_state' holds the last checkpointed
- * value of all FPR registers for the current transaction. When transaction
- * is not active 'fp_state' holds the current running state of all the FPR
- * registers. So this function which returns the current running values of
- * all the FPR registers, needs to know whether any transaction is active
- * or not.
+ * Regardless of transactions, 'fp_state' holds the current running
+ * value of all FPR registers and 'ckfp_state' holds the last checkpointed
+ * value of all FPR registers for the current transaction.
*
* Userspace interface buffer layout:
*
@@ -416,13 +413,6 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
* u64 fpr[32];
* u64 fpscr;
* };
- *
- * There are two config options CONFIG_VSX and CONFIG_PPC_TRANSACTIONAL_MEM
- * which determines the final code in this function. All the combinations of
- * these two config options are possible except the one below as transactional
- * memory config pulls in CONFIG_VSX automatically.
- *
- * !defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
*/
static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
@@ -431,50 +421,29 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
#ifdef CONFIG_VSX
u64 buf[33];
int i;
-#endif
- flush_fp_to_thread(target);
-#if defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
- /* copy to local buffer then write that out */
- if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
- flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
- for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.TS_TRANS_FPR(i);
- buf[32] = target->thread.transact_fp.fpscr;
- } else {
- for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.TS_FPR(i);
- buf[32] = target->thread.fp_state.fpscr;
- }
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
-#endif
+ flush_fp_to_thread(target);
-#if defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
/* copy to local buffer then write that out */
for (i = 0; i < 32 ; i++)
buf[i] = target->thread.TS_FPR(i);
buf[32] = target->thread.fp_state.fpscr;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
-#endif
-
-#if !defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
+#else
BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
offsetof(struct thread_fp_state, fpr[32]));
+ flush_fp_to_thread(target);
+
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fp_state, 0, -1);
#endif
}
/*
- * When the transaction is active, 'transact_fp' holds the current running
- * value of all FPR registers and 'fp_state' holds the last checkpointed
- * value of all FPR registers for the current transaction. When transaction
- * is not active 'fp_state' holds the current running state of all the FPR
- * registers. So this function which setss the current running values of
- * all the FPR registers, needs to know whether any transaction is active
- * or not.
+ * Regardless of transactions, 'fp_state' holds the current running
+ * value of all FPR registers and 'ckfp_state' holds the last checkpointed
+ * value of all FPR registers for the current transaction.
*
* Userspace interface buffer layout:
*
@@ -483,12 +452,6 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
* u64 fpscr;
* };
*
- * There are two config options CONFIG_VSX and CONFIG_PPC_TRANSACTIONAL_MEM
- * which determines the final code in this function. All the combinations of
- * these two config options are possible except the one below as transactional
- * memory config pulls in CONFIG_VSX automatically.
- *
- * !defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
*/
static int fpr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
@@ -497,44 +460,24 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
#ifdef CONFIG_VSX
u64 buf[33];
int i;
-#endif
+
flush_fp_to_thread(target);
-#if defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
/* copy to local buffer then write that out */
i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
if (i)
return i;
- if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
- flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
- for (i = 0; i < 32 ; i++)
- target->thread.TS_TRANS_FPR(i) = buf[i];
- target->thread.transact_fp.fpscr = buf[32];
- } else {
- for (i = 0; i < 32 ; i++)
- target->thread.TS_FPR(i) = buf[i];
- target->thread.fp_state.fpscr = buf[32];
- }
- return 0;
-#endif
-
-#if defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
- /* copy to local buffer then write that out */
- i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
- if (i)
- return i;
for (i = 0; i < 32 ; i++)
target->thread.TS_FPR(i) = buf[i];
target->thread.fp_state.fpscr = buf[32];
return 0;
-#endif
-
-#if !defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
+#else
BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
offsetof(struct thread_fp_state, fpr[32]));
+ flush_fp_to_thread(target);
+
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fp_state, 0, -1);
#endif
@@ -562,13 +505,10 @@ static int vr_active(struct task_struct *target,
}
/*
- * When the transaction is active, 'transact_vr' holds the current running
- * value of all the VMX registers and 'vr_state' holds the last checkpointed
- * value of all the VMX registers for the current transaction to fall back
- * on in case it aborts. When transaction is not active 'vr_state' holds
- * the current running state of all the VMX registers. So this function which
- * gets the current running values of all the VMX registers, needs to know
- * whether any transaction is active or not.
+ * Regardless of transactions, 'vr_state' holds the current running
+ * value of all the VMX registers and 'ckvr_state' holds the last
+ * checkpointed value of all the VMX registers for the current
+ * transaction to fall back on in case it aborts.
*
* Userspace interface buffer layout:
*
@@ -582,7 +522,6 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- struct thread_vr_state *addr;
int ret;
flush_altivec_to_thread(target);
@@ -590,19 +529,8 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32]));
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
- flush_fp_to_thread(target);
- flush_tmregs_to_thread(target);
- addr = &target->thread.transact_vr;
- } else {
- addr = &target->thread.vr_state;
- }
-#else
- addr = &target->thread.vr_state;
-#endif
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- addr, 0,
+ &target->thread.vr_state, 0,
33 * sizeof(vector128));
if (!ret) {
/*
@@ -614,14 +542,7 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr))
- vrsave.word = target->thread.transact_vrsave;
- else
- vrsave.word = target->thread.vrsave;
-#else
vrsave.word = target->thread.vrsave;
-#endif
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
@@ -631,13 +552,10 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
}
/*
- * When the transaction is active, 'transact_vr' holds the current running
- * value of all the VMX registers and 'vr_state' holds the last checkpointed
- * value of all the VMX registers for the current transaction to fall back
- * on in case it aborts. When transaction is not active 'vr_state' holds
- * the current running state of all the VMX registers. So this function which
- * sets the current running values of all the VMX registers, needs to know
- * whether any transaction is active or not.
+ * Regardless of transactions, 'vr_state' holds the current running
+ * value of all the VMX registers and 'ckvr_state' holds the last
+ * checkpointed value of all the VMX registers for the current
+ * transaction to fall back on in case it aborts.
*
* Userspace interface buffer layout:
*
@@ -651,7 +569,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- struct thread_vr_state *addr;
int ret;
flush_altivec_to_thread(target);
@@ -659,19 +576,8 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32]));
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
- flush_fp_to_thread(target);
- flush_tmregs_to_thread(target);
- addr = &target->thread.transact_vr;
- } else {
- addr = &target->thread.vr_state;
- }
-#else
- addr = &target->thread.vr_state;
-#endif
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- addr, 0,
+ &target->thread.vr_state, 0,
33 * sizeof(vector128));
if (!ret && count > 0) {
/*
@@ -683,27 +589,12 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr))
- vrsave.word = target->thread.transact_vrsave;
- else
- vrsave.word = target->thread.vrsave;
-#else
vrsave.word = target->thread.vrsave;
-#endif
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
- if (!ret) {
-
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr))
- target->thread.transact_vrsave = vrsave.word;
- else
- target->thread.vrsave = vrsave.word;
-#else
+ if (!ret)
target->thread.vrsave = vrsave.word;
-#endif
- }
}
return ret;
@@ -725,13 +616,10 @@ static int vsr_active(struct task_struct *target,
}
/*
- * When the transaction is active, 'transact_fp' holds the current running
- * value of all FPR registers and 'fp_state' holds the last checkpointed
- * value of all FPR registers for the current transaction. When transaction
- * is not active 'fp_state' holds the current running state of all the FPR
- * registers. So this function which returns the current running values of
- * all the FPR registers, needs to know whether any transaction is active
- * or not.
+ * Regardless of transactions, 'fp_state' holds the current running
+ * value of all FPR registers and 'ckfp_state' holds the last
+ * checkpointed value of all FPR registers for the current
+ * transaction.
*
* Userspace interface buffer layout:
*
@@ -746,27 +634,14 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset,
u64 buf[32];
int ret, i;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
-#endif
flush_vsx_to_thread(target);
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
- for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.
- transact_fp.fpr[i][TS_VSRLOWOFFSET];
- } else {
- for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.
- fp_state.fpr[i][TS_VSRLOWOFFSET];
- }
-#else
for (i = 0; i < 32 ; i++)
buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
-#endif
+
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
@@ -774,12 +649,10 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset,
}
/*
- * When the transaction is active, 'transact_fp' holds the current running
- * value of all FPR registers and 'fp_state' holds the last checkpointed
- * value of all FPR registers for the current transaction. When transaction
- * is not active 'fp_state' holds the current running state of all the FPR
- * registers. So this function which sets the current running values of all
- * the FPR registers, needs to know whether any transaction is active or not.
+ * Regardless of transactions, 'fp_state' holds the current running
+ * value of all FPR registers and 'ckfp_state' holds the last
+ * checkpointed value of all FPR registers for the current
+ * transaction.
*
* Userspace interface buffer layout:
*
@@ -794,31 +667,16 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset,
u64 buf[32];
int ret,i;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
-#endif
flush_vsx_to_thread(target);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
-
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
- for (i = 0; i < 32 ; i++)
- target->thread.transact_fp.
- fpr[i][TS_VSRLOWOFFSET] = buf[i];
- } else {
+ if (!ret)
for (i = 0; i < 32 ; i++)
- target->thread.fp_state.
- fpr[i][TS_VSRLOWOFFSET] = buf[i];
- }
-#else
- for (i = 0; i < 32 ; i++)
- target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
-#endif
-
+ target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return ret;
}
@@ -944,9 +802,9 @@ static int tm_cgpr_get(struct task_struct *target,
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA;
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.ckpt_regs,
@@ -1009,9 +867,9 @@ static int tm_cgpr_set(struct task_struct *target,
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA;
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.ckpt_regs,
@@ -1087,7 +945,7 @@ static int tm_cfpr_active(struct task_struct *target,
*
* This function gets in transaction checkpointed FPR registers.
*
- * When the transaction is active 'fp_state' holds the checkpointed
+ * When the transaction is active 'ckfp_state' holds the checkpointed
* values for the current transaction to fall back on if it aborts
* in between. This function gets those checkpointed FPR registers.
* The userspace interface buffer layout is as follows.
@@ -1111,14 +969,14 @@ static int tm_cfpr_get(struct task_struct *target,
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA;
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
/* copy to local buffer then write that out */
for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.TS_FPR(i);
- buf[32] = target->thread.fp_state.fpscr;
+ buf[i] = target->thread.TS_CKFPR(i);
+ buf[32] = target->thread.ckfp_state.fpscr;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
}
@@ -1133,7 +991,7 @@ static int tm_cfpr_get(struct task_struct *target,
*
* This function sets in transaction checkpointed FPR registers.
*
- * When the transaction is active 'fp_state' holds the checkpointed
+ * When the transaction is active 'ckfp_state' holds the checkpointed
* FPR register values for the current transaction to fall back on
* if it aborts in between. This function sets these checkpointed
* FPR registers. The userspace interface buffer layout is as follows.
@@ -1157,17 +1015,17 @@ static int tm_cfpr_set(struct task_struct *target,
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA;
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
/* copy to local buffer then write that out */
i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
if (i)
return i;
for (i = 0; i < 32 ; i++)
- target->thread.TS_FPR(i) = buf[i];
- target->thread.fp_state.fpscr = buf[32];
+ target->thread.TS_CKFPR(i) = buf[i];
+ target->thread.ckfp_state.fpscr = buf[32];
return 0;
}
@@ -1202,7 +1060,7 @@ static int tm_cvmx_active(struct task_struct *target,
*
* This function gets in transaction checkpointed VMX registers.
*
- * When the transaction is active 'vr_state' and 'vr_save' hold
+ * When the transaction is active 'ckvr_state' and 'ckvrsave' hold
* the checkpointed values for the current transaction to fall
* back on if it aborts in between. The userspace interface buffer
* layout is as follows.
@@ -1229,12 +1087,12 @@ static int tm_cvmx_get(struct task_struct *target,
return -ENODATA;
/* Flush the state */
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr_state, 0,
+ &target->thread.ckvr_state, 0,
33 * sizeof(vector128));
if (!ret) {
/*
@@ -1245,7 +1103,7 @@ static int tm_cvmx_get(struct task_struct *target,
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
+ vrsave.word = target->thread.ckvrsave;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
}
@@ -1264,7 +1122,7 @@ static int tm_cvmx_get(struct task_struct *target,
*
* This function sets in transaction checkpointed VMX registers.
*
- * When the transaction is active 'vr_state' and 'vr_save' hold
+ * When the transaction is active 'ckvr_state' and 'ckvrsave' hold
* the checkpointed values for the current transaction to fall
* back on if it aborts in between. The userspace interface buffer
* layout is as follows.
@@ -1290,12 +1148,12 @@ static int tm_cvmx_set(struct task_struct *target,
if (!MSR_TM_ACTIVE(target->thread.regs->msr))
return -ENODATA;
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr_state, 0,
+ &target->thread.ckvr_state, 0,
33 * sizeof(vector128));
if (!ret && count > 0) {
/*
@@ -1306,11 +1164,11 @@ static int tm_cvmx_set(struct task_struct *target,
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
+ vrsave.word = target->thread.ckvrsave;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
if (!ret)
- target->thread.vrsave = vrsave.word;
+ target->thread.ckvrsave = vrsave.word;
}
return ret;
@@ -1348,7 +1206,7 @@ static int tm_cvsx_active(struct task_struct *target,
*
* This function gets in transaction checkpointed VSX registers.
*
- * When the transaction is active 'fp_state' holds the checkpointed
+ * When the transaction is active 'ckfp_state' holds the checkpointed
* values for the current transaction to fall back on if it aborts
* in between. This function gets those checkpointed VSX registers.
* The userspace interface buffer layout is as follows.
@@ -1372,13 +1230,13 @@ static int tm_cvsx_get(struct task_struct *target,
return -ENODATA;
/* Flush the state */
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
flush_vsx_to_thread(target);
for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
+ buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
@@ -1396,7 +1254,7 @@ static int tm_cvsx_get(struct task_struct *target,
*
* This function sets in transaction checkpointed VSX registers.
*
- * When the transaction is active 'fp_state' holds the checkpointed
+ * When the transaction is active 'ckfp_state' holds the checkpointed
* VSX register values for the current transaction to fall back on
* if it aborts in between. This function sets these checkpointed
* FPR registers. The userspace interface buffer layout is as follows.
@@ -1420,15 +1278,16 @@ static int tm_cvsx_set(struct task_struct *target,
return -ENODATA;
/* Flush the state */
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
flush_vsx_to_thread(target);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
- for (i = 0; i < 32 ; i++)
- target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+ if (!ret)
+ for (i = 0; i < 32 ; i++)
+ target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return ret;
}
@@ -1484,9 +1343,9 @@ static int tm_spr_get(struct task_struct *target,
return -ENODEV;
/* Flush the states */
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
/* TFHAR register */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
@@ -1540,9 +1399,9 @@ static int tm_spr_set(struct task_struct *target,
return -ENODEV;
/* Flush the states */
+ flush_tmregs_to_thread(target);
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
- flush_tmregs_to_thread(target);
/* TFHAR register */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -2065,33 +1924,12 @@ static const struct user_regset_view user_ppc_native_view = {
static int gpr32_get_common(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf, bool tm_active)
+ void *kbuf, void __user *ubuf,
+ unsigned long *regs)
{
- const unsigned long *regs = &target->thread.regs->gpr[0];
- const unsigned long *ckpt_regs;
compat_ulong_t *k = kbuf;
compat_ulong_t __user *u = ubuf;
compat_ulong_t reg;
- int i;
-
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- ckpt_regs = &target->thread.ckpt_regs.gpr[0];
-#endif
- if (tm_active) {
- regs = ckpt_regs;
- } else {
- if (target->thread.regs == NULL)
- return -EIO;
-
- if (!FULL_REGS(target->thread.regs)) {
- /*
- * We have a partial register set.
- * Fill 14-31 with bogus values.
- */
- for (i = 14; i < 32; i++)
- target->thread.regs->gpr[i] = NV_REG_POISON;
- }
- }
pos /= sizeof(reg);
count /= sizeof(reg);
@@ -2133,29 +1971,13 @@ static int gpr32_get_common(struct task_struct *target,
static int gpr32_set_common(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf, bool tm_active)
+ const void *kbuf, const void __user *ubuf,
+ unsigned long *regs)
{
- unsigned long *regs = &target->thread.regs->gpr[0];
- unsigned long *ckpt_regs;
const compat_ulong_t *k = kbuf;
const compat_ulong_t __user *u = ubuf;
compat_ulong_t reg;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- ckpt_regs = &target->thread.ckpt_regs.gpr[0];
-#endif
-
- if (tm_active) {
- regs = ckpt_regs;
- } else {
- regs = &target->thread.regs->gpr[0];
-
- if (target->thread.regs == NULL)
- return -EIO;
-
- CHECK_FULL_REGS(target->thread.regs);
- }
-
pos /= sizeof(reg);
count /= sizeof(reg);
@@ -2220,7 +2042,8 @@ static int tm_cgpr32_get(struct task_struct *target,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, 1);
+ return gpr32_get_common(target, regset, pos, count, kbuf, ubuf,
+ &target->thread.ckpt_regs.gpr[0]);
}
static int tm_cgpr32_set(struct task_struct *target,
@@ -2228,7 +2051,8 @@ static int tm_cgpr32_set(struct task_struct *target,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 1);
+ return gpr32_set_common(target, regset, pos, count, kbuf, ubuf,
+ &target->thread.ckpt_regs.gpr[0]);
}
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
@@ -2237,7 +2061,21 @@ static int gpr32_get(struct task_struct *target,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, 0);
+ int i;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ if (!FULL_REGS(target->thread.regs)) {
+ /*
+ * We have a partial register set.
+ * Fill 14-31 with bogus values.
+ */
+ for (i = 14; i < 32; i++)
+ target->thread.regs->gpr[i] = NV_REG_POISON;
+ }
+ return gpr32_get_common(target, regset, pos, count, kbuf, ubuf,
+ &target->thread.regs->gpr[0]);
}
static int gpr32_set(struct task_struct *target,
@@ -2245,7 +2083,12 @@ static int gpr32_set(struct task_struct *target,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 0);
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+ return gpr32_set_common(target, regset, pos, count, kbuf, ubuf,
+ &target->thread.regs->gpr[0]);
}
/*
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index cb64d6feb45a..bbe77aed198d 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -99,22 +99,24 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
}
}
-static void do_signal(struct pt_regs *regs)
+static void do_signal(struct task_struct *tsk)
{
sigset_t *oldset = sigmask_to_save();
struct ksignal ksig;
int ret;
int is32 = is_32bit_task();
+ BUG_ON(tsk != current);
+
get_signal(&ksig);
/* Is there any syscall restart business here ? */
- check_syscall_restart(regs, &ksig.ka, ksig.sig > 0);
+ check_syscall_restart(tsk->thread.regs, &ksig.ka, ksig.sig > 0);
if (ksig.sig <= 0) {
/* No signal to deliver -- put the saved sigmask back */
restore_saved_sigmask();
- regs->trap = 0;
+ tsk->thread.regs->trap = 0;
return; /* no signals delivered */
}
@@ -124,23 +126,22 @@ static void do_signal(struct pt_regs *regs)
* user space. The DABR will have been cleared if it
* triggered inside the kernel.
*/
- if (current->thread.hw_brk.address &&
- current->thread.hw_brk.type)
- __set_breakpoint(&current->thread.hw_brk);
+ if (tsk->thread.hw_brk.address && tsk->thread.hw_brk.type)
+ __set_breakpoint(&tsk->thread.hw_brk);
#endif
/* Re-enable the breakpoints for the signal stack */
- thread_change_pc(current, regs);
+ thread_change_pc(tsk, tsk->thread.regs);
if (is32) {
if (ksig.ka.sa.sa_flags & SA_SIGINFO)
- ret = handle_rt_signal32(&ksig, oldset, regs);
+ ret = handle_rt_signal32(&ksig, oldset, tsk);
else
- ret = handle_signal32(&ksig, oldset, regs);
+ ret = handle_signal32(&ksig, oldset, tsk);
} else {
- ret = handle_rt_signal64(&ksig, oldset, regs);
+ ret = handle_rt_signal64(&ksig, oldset, tsk);
}
- regs->trap = 0;
+ tsk->thread.regs->trap = 0;
signal_setup_done(ret, &ksig, test_thread_flag(TIF_SINGLESTEP));
}
@@ -151,8 +152,10 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
if (thread_info_flags & _TIF_UPROBE)
uprobe_notify_resume(regs);
- if (thread_info_flags & _TIF_SIGPENDING)
- do_signal(regs);
+ if (thread_info_flags & _TIF_SIGPENDING) {
+ BUG_ON(regs != current->thread.regs);
+ do_signal(current);
+ }
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
@@ -162,7 +165,7 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
user_enter();
}
-unsigned long get_tm_stackpointer(struct pt_regs *regs)
+unsigned long get_tm_stackpointer(struct task_struct *tsk)
{
/* When in an active transaction that takes a signal, we need to be
* careful with the stack. It's possible that the stack has moved back
@@ -187,11 +190,13 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs)
*/
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- if (MSR_TM_ACTIVE(regs->msr)) {
+ BUG_ON(tsk != current);
+
+ if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
tm_reclaim_current(TM_CAUSE_SIGNAL);
- if (MSR_TM_TRANSACTIONAL(regs->msr))
- return current->thread.ckpt_regs.gpr[1];
+ if (MSR_TM_TRANSACTIONAL(tsk->thread.regs->msr))
+ return tsk->thread.ckpt_regs.gpr[1];
}
#endif
- return regs->gpr[1];
+ return tsk->thread.regs->gpr[1];
}
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
index be305c858e51..7c59d88b9d86 100644
--- a/arch/powerpc/kernel/signal.h
+++ b/arch/powerpc/kernel/signal.h
@@ -16,39 +16,41 @@ extern void __user *get_sigframe(struct ksignal *ksig, unsigned long sp,
size_t frame_size, int is_32);
extern int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
- struct pt_regs *regs);
+ struct task_struct *tsk);
extern int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
- struct pt_regs *regs);
+ struct task_struct *tsk);
extern unsigned long copy_fpr_to_user(void __user *to,
struct task_struct *task);
-extern unsigned long copy_transact_fpr_to_user(void __user *to,
+extern unsigned long copy_ckfpr_to_user(void __user *to,
struct task_struct *task);
extern unsigned long copy_fpr_from_user(struct task_struct *task,
void __user *from);
-extern unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+extern unsigned long copy_ckfpr_from_user(struct task_struct *task,
void __user *from);
+extern unsigned long get_tm_stackpointer(struct task_struct *tsk);
+
#ifdef CONFIG_VSX
extern unsigned long copy_vsx_to_user(void __user *to,
struct task_struct *task);
-extern unsigned long copy_transact_vsx_to_user(void __user *to,
+extern unsigned long copy_ckvsx_to_user(void __user *to,
struct task_struct *task);
extern unsigned long copy_vsx_from_user(struct task_struct *task,
void __user *from);
-extern unsigned long copy_transact_vsx_from_user(struct task_struct *task,
+extern unsigned long copy_ckvsx_from_user(struct task_struct *task,
void __user *from);
#endif
#ifdef CONFIG_PPC64
extern int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
- struct pt_regs *regs);
+ struct task_struct *tsk);
#else /* CONFIG_PPC64 */
static inline int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
- struct pt_regs *regs)
+ struct task_struct *tsk)
{
return -EFAULT;
}
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index a7daf749b97f..27aa913ac91d 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -44,6 +44,7 @@
#include <asm/vdso.h>
#include <asm/switch_to.h>
#include <asm/tm.h>
+#include <asm/asm-prototypes.h>
#ifdef CONFIG_PPC64
#include "ppc32.h"
#include <asm/unistd.h>
@@ -315,7 +316,7 @@ unsigned long copy_vsx_from_user(struct task_struct *task,
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-unsigned long copy_transact_fpr_to_user(void __user *to,
+unsigned long copy_ckfpr_to_user(void __user *to,
struct task_struct *task)
{
u64 buf[ELF_NFPREG];
@@ -323,12 +324,12 @@ unsigned long copy_transact_fpr_to_user(void __user *to,
/* save FPR copy to local buffer then write to the thread_struct */
for (i = 0; i < (ELF_NFPREG - 1) ; i++)
- buf[i] = task->thread.TS_TRANS_FPR(i);
- buf[i] = task->thread.transact_fp.fpscr;
+ buf[i] = task->thread.TS_CKFPR(i);
+ buf[i] = task->thread.ckfp_state.fpscr;
return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
}
-unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+unsigned long copy_ckfpr_from_user(struct task_struct *task,
void __user *from)
{
u64 buf[ELF_NFPREG];
@@ -337,13 +338,13 @@ unsigned long copy_transact_fpr_from_user(struct task_struct *task,
if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
return 1;
for (i = 0; i < (ELF_NFPREG - 1) ; i++)
- task->thread.TS_TRANS_FPR(i) = buf[i];
- task->thread.transact_fp.fpscr = buf[i];
+ task->thread.TS_CKFPR(i) = buf[i];
+ task->thread.ckfp_state.fpscr = buf[i];
return 0;
}
-unsigned long copy_transact_vsx_to_user(void __user *to,
+unsigned long copy_ckvsx_to_user(void __user *to,
struct task_struct *task)
{
u64 buf[ELF_NVSRHALFREG];
@@ -351,11 +352,11 @@ unsigned long copy_transact_vsx_to_user(void __user *to,
/* save FPR copy to local buffer then write to the thread_struct */
for (i = 0; i < ELF_NVSRHALFREG; i++)
- buf[i] = task->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET];
+ buf[i] = task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
}
-unsigned long copy_transact_vsx_from_user(struct task_struct *task,
+unsigned long copy_ckvsx_from_user(struct task_struct *task,
void __user *from)
{
u64 buf[ELF_NVSRHALFREG];
@@ -364,7 +365,7 @@ unsigned long copy_transact_vsx_from_user(struct task_struct *task,
if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
return 1;
for (i = 0; i < ELF_NVSRHALFREG ; i++)
- task->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+ task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return 0;
}
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
@@ -384,17 +385,17 @@ inline unsigned long copy_fpr_from_user(struct task_struct *task,
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-inline unsigned long copy_transact_fpr_to_user(void __user *to,
+inline unsigned long copy_ckfpr_to_user(void __user *to,
struct task_struct *task)
{
- return __copy_to_user(to, task->thread.transact_fp.fpr,
+ return __copy_to_user(to, task->thread.ckfp_state.fpr,
ELF_NFPREG * sizeof(double));
}
-inline unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+inline unsigned long copy_ckfpr_from_user(struct task_struct *task,
void __user *from)
{
- return __copy_from_user(task->thread.transact_fp.fpr, from,
+ return __copy_from_user(task->thread.ckfp_state.fpr, from,
ELF_NFPREG * sizeof(double));
}
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
@@ -525,9 +526,6 @@ static int save_tm_user_regs(struct pt_regs *regs,
*/
regs->msr &= ~MSR_TS_MASK;
- /* Make sure floating point registers are stored in regs */
- flush_fp_to_thread(current);
-
/* Save both sets of general registers */
if (save_general_regs(&current->thread.ckpt_regs, frame)
|| save_general_regs(regs, tm_frame))
@@ -545,18 +543,17 @@ static int save_tm_user_regs(struct pt_regs *regs,
#ifdef CONFIG_ALTIVEC
/* save altivec registers */
if (current->thread.used_vr) {
- flush_altivec_to_thread(current);
- if (__copy_to_user(&frame->mc_vregs, &current->thread.vr_state,
+ if (__copy_to_user(&frame->mc_vregs, &current->thread.ckvr_state,
ELF_NVRREG * sizeof(vector128)))
return 1;
if (msr & MSR_VEC) {
if (__copy_to_user(&tm_frame->mc_vregs,
- &current->thread.transact_vr,
+ &current->thread.vr_state,
ELF_NVRREG * sizeof(vector128)))
return 1;
} else {
if (__copy_to_user(&tm_frame->mc_vregs,
- &current->thread.vr_state,
+ &current->thread.ckvr_state,
ELF_NVRREG * sizeof(vector128)))
return 1;
}
@@ -573,28 +570,28 @@ static int save_tm_user_regs(struct pt_regs *regs,
* most significant bits of that same vector. --BenH
*/
if (cpu_has_feature(CPU_FTR_ALTIVEC))
- current->thread.vrsave = mfspr(SPRN_VRSAVE);
- if (__put_user(current->thread.vrsave,
+ current->thread.ckvrsave = mfspr(SPRN_VRSAVE);
+ if (__put_user(current->thread.ckvrsave,
(u32 __user *)&frame->mc_vregs[32]))
return 1;
if (msr & MSR_VEC) {
- if (__put_user(current->thread.transact_vrsave,
+ if (__put_user(current->thread.vrsave,
(u32 __user *)&tm_frame->mc_vregs[32]))
return 1;
} else {
- if (__put_user(current->thread.vrsave,
+ if (__put_user(current->thread.ckvrsave,
(u32 __user *)&tm_frame->mc_vregs[32]))
return 1;
}
#endif /* CONFIG_ALTIVEC */
- if (copy_fpr_to_user(&frame->mc_fregs, current))
+ if (copy_ckfpr_to_user(&frame->mc_fregs, current))
return 1;
if (msr & MSR_FP) {
- if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current))
+ if (copy_fpr_to_user(&tm_frame->mc_fregs, current))
return 1;
} else {
- if (copy_fpr_to_user(&tm_frame->mc_fregs, current))
+ if (copy_ckfpr_to_user(&tm_frame->mc_fregs, current))
return 1;
}
@@ -606,15 +603,14 @@ static int save_tm_user_regs(struct pt_regs *regs,
* contains valid data
*/
if (current->thread.used_vsr) {
- flush_vsx_to_thread(current);
- if (copy_vsx_to_user(&frame->mc_vsregs, current))
+ if (copy_ckvsx_to_user(&frame->mc_vsregs, current))
return 1;
if (msr & MSR_VSX) {
- if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs,
+ if (copy_vsx_to_user(&tm_frame->mc_vsregs,
current))
return 1;
} else {
- if (copy_vsx_to_user(&tm_frame->mc_vsregs, current))
+ if (copy_ckvsx_to_user(&tm_frame->mc_vsregs, current))
return 1;
}
@@ -698,6 +694,7 @@ static long restore_user_regs(struct pt_regs *regs,
if (__copy_from_user(&current->thread.vr_state, &sr->mc_vregs,
sizeof(sr->mc_vregs)))
return 1;
+ current->thread.used_vr = true;
} else if (current->thread.used_vr)
memset(&current->thread.vr_state, 0,
ELF_NVRREG * sizeof(vector128));
@@ -724,6 +721,7 @@ static long restore_user_regs(struct pt_regs *regs,
*/
if (copy_vsx_from_user(current, &sr->mc_vsregs))
return 1;
+ current->thread.used_vsr = true;
} else if (current->thread.used_vsr)
for (i = 0; i < 32 ; i++)
current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
@@ -743,6 +741,7 @@ static long restore_user_regs(struct pt_regs *regs,
if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
ELF_NEVRREG * sizeof(u32)))
return 1;
+ current->thread.used_spe = true;
} else if (current->thread.used_spe)
memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
@@ -793,33 +792,34 @@ static long restore_tm_user_regs(struct pt_regs *regs,
regs->msr &= ~MSR_VEC;
if (msr & MSR_VEC) {
/* restore altivec registers from the stack */
- if (__copy_from_user(&current->thread.vr_state, &sr->mc_vregs,
+ if (__copy_from_user(&current->thread.ckvr_state, &sr->mc_vregs,
sizeof(sr->mc_vregs)) ||
- __copy_from_user(&current->thread.transact_vr,
+ __copy_from_user(&current->thread.vr_state,
&tm_sr->mc_vregs,
sizeof(sr->mc_vregs)))
return 1;
+ current->thread.used_vr = true;
} else if (current->thread.used_vr) {
memset(&current->thread.vr_state, 0,
ELF_NVRREG * sizeof(vector128));
- memset(&current->thread.transact_vr, 0,
+ memset(&current->thread.ckvr_state, 0,
ELF_NVRREG * sizeof(vector128));
}
/* Always get VRSAVE back */
- if (__get_user(current->thread.vrsave,
+ if (__get_user(current->thread.ckvrsave,
(u32 __user *)&sr->mc_vregs[32]) ||
- __get_user(current->thread.transact_vrsave,
+ __get_user(current->thread.vrsave,
(u32 __user *)&tm_sr->mc_vregs[32]))
return 1;
if (cpu_has_feature(CPU_FTR_ALTIVEC))
- mtspr(SPRN_VRSAVE, current->thread.vrsave);
+ mtspr(SPRN_VRSAVE, current->thread.ckvrsave);
#endif /* CONFIG_ALTIVEC */
regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
if (copy_fpr_from_user(current, &sr->mc_fregs) ||
- copy_transact_fpr_from_user(current, &tm_sr->mc_fregs))
+ copy_ckfpr_from_user(current, &tm_sr->mc_fregs))
return 1;
#ifdef CONFIG_VSX
@@ -829,13 +829,14 @@ static long restore_tm_user_regs(struct pt_regs *regs,
* Restore altivec registers from the stack to a local
* buffer, then write this out to the thread_struct
*/
- if (copy_vsx_from_user(current, &sr->mc_vsregs) ||
- copy_transact_vsx_from_user(current, &tm_sr->mc_vsregs))
+ if (copy_vsx_from_user(current, &tm_sr->mc_vsregs) ||
+ copy_ckvsx_from_user(current, &sr->mc_vsregs))
return 1;
+ current->thread.used_vsr = true;
} else if (current->thread.used_vsr)
for (i = 0; i < 32 ; i++) {
current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
- current->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = 0;
+ current->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
}
#endif /* CONFIG_VSX */
@@ -848,6 +849,7 @@ static long restore_tm_user_regs(struct pt_regs *regs,
if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
ELF_NEVRREG * sizeof(u32)))
return 1;
+ current->thread.used_spe = true;
} else if (current->thread.used_spe)
memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
@@ -877,13 +879,14 @@ static long restore_tm_user_regs(struct pt_regs *regs,
tm_recheckpoint(&current->thread, msr);
/* This loads the speculative FP/VEC state, if used */
+ msr_check_and_set(msr & (MSR_FP | MSR_VEC));
if (msr & MSR_FP) {
- do_load_up_transact_fpu(&current->thread);
+ load_fp_state(&current->thread.fp_state);
regs->msr |= (MSR_FP | current->thread.fpexc_mode);
}
#ifdef CONFIG_ALTIVEC
if (msr & MSR_VEC) {
- do_load_up_transact_altivec(&current->thread);
+ load_vr_state(&current->thread.vr_state);
regs->msr |= MSR_VEC;
}
#endif
@@ -971,7 +974,7 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
* (one which gets siginfo).
*/
int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
- struct pt_regs *regs)
+ struct task_struct *tsk)
{
struct rt_sigframe __user *rt_sf;
struct mcontext __user *frame;
@@ -980,10 +983,13 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
unsigned long newsp = 0;
int sigret;
unsigned long tramp;
+ struct pt_regs *regs = tsk->thread.regs;
+
+ BUG_ON(tsk != current);
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
- rt_sf = get_sigframe(ksig, get_tm_stackpointer(regs), sizeof(*rt_sf), 1);
+ rt_sf = get_sigframe(ksig, get_tm_stackpointer(tsk), sizeof(*rt_sf), 1);
addr = rt_sf;
if (unlikely(rt_sf == NULL))
goto badframe;
@@ -1000,9 +1006,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
/* Save user registers on the stack */
frame = &rt_sf->uc.uc_mcontext;
addr = frame;
- if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
+ if (vdso32_rt_sigtramp && tsk->mm->context.vdso_base) {
sigret = 0;
- tramp = current->mm->context.vdso_base + vdso32_rt_sigtramp;
+ tramp = tsk->mm->context.vdso_base + vdso32_rt_sigtramp;
} else {
sigret = __NR_rt_sigreturn;
tramp = (unsigned long) frame->tramp;
@@ -1029,7 +1035,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
}
regs->link = tramp;
- current->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
+ tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
/* create a stack frame for the caller of the handler */
newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
@@ -1054,7 +1060,7 @@ badframe:
printk_ratelimited(KERN_INFO
"%s[%d]: bad frame in handle_rt_signal32: "
"%p nip %08lx lr %08lx\n",
- current->comm, current->pid,
+ tsk->comm, tsk->pid,
addr, regs->nip, regs->link);
return 1;
@@ -1410,7 +1416,8 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
/*
* OK, we're invoking a handler
*/
-int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs)
+int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
+ struct task_struct *tsk)
{
struct sigcontext __user *sc;
struct sigframe __user *frame;
@@ -1418,9 +1425,12 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs
unsigned long newsp = 0;
int sigret;
unsigned long tramp;
+ struct pt_regs *regs = tsk->thread.regs;
+
+ BUG_ON(tsk != current);
/* Set up Signal Frame */
- frame = get_sigframe(ksig, get_tm_stackpointer(regs), sizeof(*frame), 1);
+ frame = get_sigframe(ksig, get_tm_stackpointer(tsk), sizeof(*frame), 1);
if (unlikely(frame == NULL))
goto badframe;
sc = (struct sigcontext __user *) &frame->sctx;
@@ -1439,9 +1449,9 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs
|| __put_user(ksig->sig, &sc->signal))
goto badframe;
- if (vdso32_sigtramp && current->mm->context.vdso_base) {
+ if (vdso32_sigtramp && tsk->mm->context.vdso_base) {
sigret = 0;
- tramp = current->mm->context.vdso_base + vdso32_sigtramp;
+ tramp = tsk->mm->context.vdso_base + vdso32_sigtramp;
} else {
sigret = __NR_sigreturn;
tramp = (unsigned long) frame->mctx.tramp;
@@ -1463,7 +1473,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs
regs->link = tramp;
- current->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
+ tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
/* create a stack frame for the caller of the handler */
newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
@@ -1483,7 +1493,7 @@ badframe:
printk_ratelimited(KERN_INFO
"%s[%d]: bad frame in handle_signal32: "
"%p nip %08lx lr %08lx\n",
- current->comm, current->pid,
+ tsk->comm, tsk->pid,
frame, regs->nip, regs->link);
return 1;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 70409bb90a95..96698fdf93b4 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -35,6 +35,7 @@
#include <asm/vdso.h>
#include <asm/switch_to.h>
#include <asm/tm.h>
+#include <asm/asm-prototypes.h>
#include "signal.h"
@@ -90,9 +91,9 @@ static elf_vrreg_t __user *sigcontext_vmx_regs(struct sigcontext __user *sc)
* Set up the sigcontext for the signal frame.
*/
-static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
- int signr, sigset_t *set, unsigned long handler,
- int ctx_has_vsx_region)
+static long setup_sigcontext(struct sigcontext __user *sc,
+ struct task_struct *tsk, int signr, sigset_t *set,
+ unsigned long handler, int ctx_has_vsx_region)
{
/* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the
* process never used altivec yet (MSR_VEC is zero in pt_regs of
@@ -106,17 +107,20 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc);
unsigned long vrsave;
#endif
+ struct pt_regs *regs = tsk->thread.regs;
unsigned long msr = regs->msr;
long err = 0;
+ BUG_ON(tsk != current);
+
#ifdef CONFIG_ALTIVEC
err |= __put_user(v_regs, &sc->v_regs);
/* save altivec registers */
- if (current->thread.used_vr) {
- flush_altivec_to_thread(current);
+ if (tsk->thread.used_vr) {
+ flush_altivec_to_thread(tsk);
/* Copy 33 vec registers (vr0..31 and vscr) to the stack */
- err |= __copy_to_user(v_regs, &current->thread.vr_state,
+ err |= __copy_to_user(v_regs, &tsk->thread.vr_state,
33 * sizeof(vector128));
/* set MSR_VEC in the MSR value in the frame to indicate that sc->v_reg)
* contains valid data.
@@ -129,16 +133,16 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
vrsave = 0;
if (cpu_has_feature(CPU_FTR_ALTIVEC)) {
vrsave = mfspr(SPRN_VRSAVE);
- current->thread.vrsave = vrsave;
+ tsk->thread.vrsave = vrsave;
}
err |= __put_user(vrsave, (u32 __user *)&v_regs[33]);
#else /* CONFIG_ALTIVEC */
err |= __put_user(0, &sc->v_regs);
#endif /* CONFIG_ALTIVEC */
- flush_fp_to_thread(current);
+ flush_fp_to_thread(tsk);
/* copy fpr regs and fpscr */
- err |= copy_fpr_to_user(&sc->fp_regs, current);
+ err |= copy_fpr_to_user(&sc->fp_regs, tsk);
/*
* Clear the MSR VSX bit to indicate there is no valid state attached
@@ -151,10 +155,10 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
* then out to userspace. Update v_regs to point after the
* VMX data.
*/
- if (current->thread.used_vsr && ctx_has_vsx_region) {
- flush_vsx_to_thread(current);
+ if (tsk->thread.used_vsr && ctx_has_vsx_region) {
+ flush_vsx_to_thread(tsk);
v_regs += ELF_NVRREG;
- err |= copy_vsx_to_user(v_regs, current);
+ err |= copy_vsx_to_user(v_regs, tsk);
/* set MSR_VSX in the MSR value in the frame to
* indicate that sc->vs_reg) contains valid data.
*/
@@ -187,7 +191,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
*/
static long setup_tm_sigcontexts(struct sigcontext __user *sc,
struct sigcontext __user *tm_sc,
- struct pt_regs *regs,
+ struct task_struct *tsk,
int signr, sigset_t *set, unsigned long handler)
{
/* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the
@@ -202,9 +206,12 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc);
elf_vrreg_t __user *tm_v_regs = sigcontext_vmx_regs(tm_sc);
#endif
- unsigned long msr = regs->msr;
+ struct pt_regs *regs = tsk->thread.regs;
+ unsigned long msr = tsk->thread.ckpt_regs.msr;
long err = 0;
+ BUG_ON(tsk != current);
+
BUG_ON(!MSR_TM_ACTIVE(regs->msr));
/* Remove TM bits from thread's MSR. The MSR in the sigcontext
@@ -214,28 +221,25 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
*/
regs->msr &= ~MSR_TS_MASK;
- flush_fp_to_thread(current);
-
#ifdef CONFIG_ALTIVEC
err |= __put_user(v_regs, &sc->v_regs);
err |= __put_user(tm_v_regs, &tm_sc->v_regs);
/* save altivec registers */
- if (current->thread.used_vr) {
- flush_altivec_to_thread(current);
+ if (tsk->thread.used_vr) {
/* Copy 33 vec registers (vr0..31 and vscr) to the stack */
- err |= __copy_to_user(v_regs, &current->thread.vr_state,
+ err |= __copy_to_user(v_regs, &tsk->thread.ckvr_state,
33 * sizeof(vector128));
/* If VEC was enabled there are transactional VRs valid too,
* else they're a copy of the checkpointed VRs.
*/
if (msr & MSR_VEC)
err |= __copy_to_user(tm_v_regs,
- &current->thread.transact_vr,
+ &tsk->thread.vr_state,
33 * sizeof(vector128));
else
err |= __copy_to_user(tm_v_regs,
- &current->thread.vr_state,
+ &tsk->thread.ckvr_state,
33 * sizeof(vector128));
/* set MSR_VEC in the MSR value in the frame to indicate
@@ -247,13 +251,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
* use altivec.
*/
if (cpu_has_feature(CPU_FTR_ALTIVEC))
- current->thread.vrsave = mfspr(SPRN_VRSAVE);
- err |= __put_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);
+ tsk->thread.ckvrsave = mfspr(SPRN_VRSAVE);
+ err |= __put_user(tsk->thread.ckvrsave, (u32 __user *)&v_regs[33]);
if (msr & MSR_VEC)
- err |= __put_user(current->thread.transact_vrsave,
+ err |= __put_user(tsk->thread.vrsave,
(u32 __user *)&tm_v_regs[33]);
else
- err |= __put_user(current->thread.vrsave,
+ err |= __put_user(tsk->thread.ckvrsave,
(u32 __user *)&tm_v_regs[33]);
#else /* CONFIG_ALTIVEC */
@@ -262,11 +266,11 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
#endif /* CONFIG_ALTIVEC */
/* copy fpr regs and fpscr */
- err |= copy_fpr_to_user(&sc->fp_regs, current);
+ err |= copy_ckfpr_to_user(&sc->fp_regs, tsk);
if (msr & MSR_FP)
- err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, current);
+ err |= copy_fpr_to_user(&tm_sc->fp_regs, tsk);
else
- err |= copy_fpr_to_user(&tm_sc->fp_regs, current);
+ err |= copy_ckfpr_to_user(&tm_sc->fp_regs, tsk);
#ifdef CONFIG_VSX
/*
@@ -274,17 +278,16 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
* then out to userspace. Update v_regs to point after the
* VMX data.
*/
- if (current->thread.used_vsr) {
- flush_vsx_to_thread(current);
+ if (tsk->thread.used_vsr) {
v_regs += ELF_NVRREG;
tm_v_regs += ELF_NVRREG;
- err |= copy_vsx_to_user(v_regs, current);
+ err |= copy_ckvsx_to_user(v_regs, tsk);
if (msr & MSR_VSX)
- err |= copy_transact_vsx_to_user(tm_v_regs, current);
+ err |= copy_vsx_to_user(tm_v_regs, tsk);
else
- err |= copy_vsx_to_user(tm_v_regs, current);
+ err |= copy_ckvsx_to_user(tm_v_regs, tsk);
/* set MSR_VSX in the MSR value in the frame to
* indicate that sc->vs_reg) contains valid data.
@@ -298,7 +301,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
WARN_ON(!FULL_REGS(regs));
err |= __copy_to_user(&tm_sc->gp_regs, regs, GP_REGS_SIZE);
err |= __copy_to_user(&sc->gp_regs,
- &current->thread.ckpt_regs, GP_REGS_SIZE);
+ &tsk->thread.ckpt_regs, GP_REGS_SIZE);
err |= __put_user(msr, &tm_sc->gp_regs[PT_MSR]);
err |= __put_user(msr, &sc->gp_regs[PT_MSR]);
err |= __put_user(signr, &sc->signal);
@@ -314,7 +317,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
* Restore the sigcontext from the signal frame.
*/
-static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
+static long restore_sigcontext(struct task_struct *tsk, sigset_t *set, int sig,
struct sigcontext __user *sc)
{
#ifdef CONFIG_ALTIVEC
@@ -323,10 +326,13 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
unsigned long err = 0;
unsigned long save_r13 = 0;
unsigned long msr;
+ struct pt_regs *regs = tsk->thread.regs;
#ifdef CONFIG_VSX
int i;
#endif
+ BUG_ON(tsk != current);
+
/* If this is not a signal return, we preserve the TLS in r13 */
if (!sig)
save_r13 = regs->gpr[13];
@@ -356,7 +362,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
/*
* Force reload of FP/VEC.
- * This has to be done before copying stuff into current->thread.fpr/vr
+ * This has to be done before copying stuff into tsk->thread.fpr/vr
* for the reasons explained in the previous comment.
*/
regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX);
@@ -368,21 +374,23 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128)))
return -EFAULT;
/* Copy 33 vec registers (vr0..31 and vscr) from the stack */
- if (v_regs != NULL && (msr & MSR_VEC) != 0)
- err |= __copy_from_user(&current->thread.vr_state, v_regs,
+ if (v_regs != NULL && (msr & MSR_VEC) != 0) {
+ err |= __copy_from_user(&tsk->thread.vr_state, v_regs,
33 * sizeof(vector128));
- else if (current->thread.used_vr)
- memset(&current->thread.vr_state, 0, 33 * sizeof(vector128));
+ tsk->thread.used_vr = true;
+ } else if (tsk->thread.used_vr) {
+ memset(&tsk->thread.vr_state, 0, 33 * sizeof(vector128));
+ }
/* Always get VRSAVE back */
if (v_regs != NULL)
- err |= __get_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);
+ err |= __get_user(tsk->thread.vrsave, (u32 __user *)&v_regs[33]);
else
- current->thread.vrsave = 0;
+ tsk->thread.vrsave = 0;
if (cpu_has_feature(CPU_FTR_ALTIVEC))
- mtspr(SPRN_VRSAVE, current->thread.vrsave);
+ mtspr(SPRN_VRSAVE, tsk->thread.vrsave);
#endif /* CONFIG_ALTIVEC */
/* restore floating point */
- err |= copy_fpr_from_user(current, &sc->fp_regs);
+ err |= copy_fpr_from_user(tsk, &sc->fp_regs);
#ifdef CONFIG_VSX
/*
* Get additional VSX data. Update v_regs to point after the
@@ -390,11 +398,13 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
* buffer for formatting, then into the taskstruct.
*/
v_regs += ELF_NVRREG;
- if ((msr & MSR_VSX) != 0)
- err |= copy_vsx_from_user(current, v_regs);
- else
+ if ((msr & MSR_VSX) != 0) {
+ err |= copy_vsx_from_user(tsk, v_regs);
+ tsk->thread.used_vsr = true;
+ } else {
for (i = 0; i < 32 ; i++)
- current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
+ tsk->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
+ }
#endif
return err;
}
@@ -404,7 +414,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
* Restore the two sigcontexts from the frame of a transactional processes.
*/
-static long restore_tm_sigcontexts(struct pt_regs *regs,
+static long restore_tm_sigcontexts(struct task_struct *tsk,
struct sigcontext __user *sc,
struct sigcontext __user *tm_sc)
{
@@ -413,12 +423,16 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
#endif
unsigned long err = 0;
unsigned long msr;
+ struct pt_regs *regs = tsk->thread.regs;
#ifdef CONFIG_VSX
int i;
#endif
+
+ BUG_ON(tsk != current);
+
/* copy the GPRs */
err |= __copy_from_user(regs->gpr, tm_sc->gp_regs, sizeof(regs->gpr));
- err |= __copy_from_user(&current->thread.ckpt_regs, sc->gp_regs,
+ err |= __copy_from_user(&tsk->thread.ckpt_regs, sc->gp_regs,
sizeof(regs->gpr));
/*
@@ -430,7 +444,7 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
* we don't need to re-copy them here.
*/
err |= __get_user(regs->nip, &tm_sc->gp_regs[PT_NIP]);
- err |= __get_user(current->thread.tm_tfhar, &sc->gp_regs[PT_NIP]);
+ err |= __get_user(tsk->thread.tm_tfhar, &sc->gp_regs[PT_NIP]);
/* get MSR separately, transfer the LE bit if doing signal return */
err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
@@ -449,13 +463,13 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
err |= __get_user(regs->link, &tm_sc->gp_regs[PT_LNK]);
err |= __get_user(regs->xer, &tm_sc->gp_regs[PT_XER]);
err |= __get_user(regs->ccr, &tm_sc->gp_regs[PT_CCR]);
- err |= __get_user(current->thread.ckpt_regs.ctr,
+ err |= __get_user(tsk->thread.ckpt_regs.ctr,
&sc->gp_regs[PT_CTR]);
- err |= __get_user(current->thread.ckpt_regs.link,
+ err |= __get_user(tsk->thread.ckpt_regs.link,
&sc->gp_regs[PT_LNK]);
- err |= __get_user(current->thread.ckpt_regs.xer,
+ err |= __get_user(tsk->thread.ckpt_regs.xer,
&sc->gp_regs[PT_XER]);
- err |= __get_user(current->thread.ckpt_regs.ccr,
+ err |= __get_user(tsk->thread.ckpt_regs.ccr,
&sc->gp_regs[PT_CCR]);
/* These regs are not checkpointed; they can go in 'regs'. */
@@ -466,7 +480,7 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
/*
* Force reload of FP/VEC.
- * This has to be done before copying stuff into current->thread.fpr/vr
+ * This has to be done before copying stuff into tsk->thread.fpr/vr
* for the reasons explained in the previous comment.
*/
regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX);
@@ -483,32 +497,33 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
return -EFAULT;
/* Copy 33 vec registers (vr0..31 and vscr) from the stack */
if (v_regs != NULL && tm_v_regs != NULL && (msr & MSR_VEC) != 0) {
- err |= __copy_from_user(&current->thread.vr_state, v_regs,
+ err |= __copy_from_user(&tsk->thread.ckvr_state, v_regs,
33 * sizeof(vector128));
- err |= __copy_from_user(&current->thread.transact_vr, tm_v_regs,
+ err |= __copy_from_user(&tsk->thread.vr_state, tm_v_regs,
33 * sizeof(vector128));
+ current->thread.used_vr = true;
}
- else if (current->thread.used_vr) {
- memset(&current->thread.vr_state, 0, 33 * sizeof(vector128));
- memset(&current->thread.transact_vr, 0, 33 * sizeof(vector128));
+ else if (tsk->thread.used_vr) {
+ memset(&tsk->thread.vr_state, 0, 33 * sizeof(vector128));
+ memset(&tsk->thread.ckvr_state, 0, 33 * sizeof(vector128));
}
/* Always get VRSAVE back */
if (v_regs != NULL && tm_v_regs != NULL) {
- err |= __get_user(current->thread.vrsave,
+ err |= __get_user(tsk->thread.ckvrsave,
(u32 __user *)&v_regs[33]);
- err |= __get_user(current->thread.transact_vrsave,
+ err |= __get_user(tsk->thread.vrsave,
(u32 __user *)&tm_v_regs[33]);
}
else {
- current->thread.vrsave = 0;
- current->thread.transact_vrsave = 0;
+ tsk->thread.vrsave = 0;
+ tsk->thread.ckvrsave = 0;
}
if (cpu_has_feature(CPU_FTR_ALTIVEC))
- mtspr(SPRN_VRSAVE, current->thread.vrsave);
+ mtspr(SPRN_VRSAVE, tsk->thread.vrsave);
#endif /* CONFIG_ALTIVEC */
/* restore floating point */
- err |= copy_fpr_from_user(current, &sc->fp_regs);
- err |= copy_transact_fpr_from_user(current, &tm_sc->fp_regs);
+ err |= copy_fpr_from_user(tsk, &tm_sc->fp_regs);
+ err |= copy_ckfpr_from_user(tsk, &sc->fp_regs);
#ifdef CONFIG_VSX
/*
* Get additional VSX data. Update v_regs to point after the
@@ -518,32 +533,31 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
if (v_regs && ((msr & MSR_VSX) != 0)) {
v_regs += ELF_NVRREG;
tm_v_regs += ELF_NVRREG;
- err |= copy_vsx_from_user(current, v_regs);
- err |= copy_transact_vsx_from_user(current, tm_v_regs);
+ err |= copy_vsx_from_user(tsk, tm_v_regs);
+ err |= copy_ckvsx_from_user(tsk, v_regs);
+ tsk->thread.used_vsr = true;
} else {
for (i = 0; i < 32 ; i++) {
- current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
- current->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = 0;
+ tsk->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
+ tsk->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
}
}
#endif
tm_enable();
/* Make sure the transaction is marked as failed */
- current->thread.tm_texasr |= TEXASR_FS;
+ tsk->thread.tm_texasr |= TEXASR_FS;
/* This loads the checkpointed FP/VEC state, if used */
- tm_recheckpoint(&current->thread, msr);
+ tm_recheckpoint(&tsk->thread, msr);
- /* This loads the speculative FP/VEC state, if used */
+ msr_check_and_set(msr & (MSR_FP | MSR_VEC));
if (msr & MSR_FP) {
- do_load_up_transact_fpu(&current->thread);
- regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+ load_fp_state(&tsk->thread.fp_state);
+ regs->msr |= (MSR_FP | tsk->thread.fpexc_mode);
}
-#ifdef CONFIG_ALTIVEC
if (msr & MSR_VEC) {
- do_load_up_transact_altivec(&current->thread);
+ load_vr_state(&tsk->thread.vr_state);
regs->msr |= MSR_VEC;
}
-#endif
return err;
}
@@ -594,6 +608,8 @@ int sys_swapcontext(struct ucontext __user *old_ctx,
unsigned long new_msr = 0;
int ctx_has_vsx_region = 0;
+ BUG_ON(regs != current->thread.regs);
+
if (new_ctx &&
get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR]))
return -EFAULT;
@@ -616,7 +632,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx,
if (old_ctx != NULL) {
if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size)
- || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0,
+ || setup_sigcontext(&old_ctx->uc_mcontext, current, 0, NULL, 0,
ctx_has_vsx_region)
|| __copy_to_user(&old_ctx->uc_sigmask,
&current->blocked, sizeof(sigset_t)))
@@ -644,7 +660,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx,
if (__copy_from_user(&set, &new_ctx->uc_sigmask, sizeof(set)))
do_exit(SIGSEGV);
set_current_blocked(&set);
- if (restore_sigcontext(regs, NULL, 0, &new_ctx->uc_mcontext))
+ if (restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext))
do_exit(SIGSEGV);
/* This returns like rt_sigreturn */
@@ -667,6 +683,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long msr;
#endif
+ BUG_ON(current->thread.regs != regs);
+
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
@@ -698,14 +716,14 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
struct ucontext __user *uc_transact;
if (__get_user(uc_transact, &uc->uc_link))
goto badframe;
- if (restore_tm_sigcontexts(regs, &uc->uc_mcontext,
+ if (restore_tm_sigcontexts(current, &uc->uc_mcontext,
&uc_transact->uc_mcontext))
goto badframe;
}
else
/* Fall through, for non-TM restore */
#endif
- if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext))
+ if (restore_sigcontext(current, NULL, 1, &uc->uc_mcontext))
goto badframe;
if (restore_altstack(&uc->uc_stack))
@@ -724,13 +742,17 @@ badframe:
return 0;
}
-int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
+int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
+ struct task_struct *tsk)
{
struct rt_sigframe __user *frame;
unsigned long newsp = 0;
long err = 0;
+ struct pt_regs *regs = tsk->thread.regs;
+
+ BUG_ON(tsk != current);
- frame = get_sigframe(ksig, get_tm_stackpointer(regs), sizeof(*frame), 0);
+ frame = get_sigframe(ksig, get_tm_stackpointer(tsk), sizeof(*frame), 0);
if (unlikely(frame == NULL))
goto badframe;
@@ -751,14 +773,13 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs
err |= __put_user(&frame->uc_transact, &frame->uc.uc_link);
err |= setup_tm_sigcontexts(&frame->uc.uc_mcontext,
&frame->uc_transact.uc_mcontext,
- regs, ksig->sig,
- NULL,
+ tsk, ksig->sig, NULL,
(unsigned long)ksig->ka.sa.sa_handler);
} else
#endif
{
err |= __put_user(0, &frame->uc.uc_link);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, ksig->sig,
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, tsk, ksig->sig,
NULL, (unsigned long)ksig->ka.sa.sa_handler,
1);
}
@@ -767,11 +788,11 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs
goto badframe;
/* Make sure signal handler doesn't get spurious FP exceptions */
- current->thread.fp_state.fpscr = 0;
+ tsk->thread.fp_state.fpscr = 0;
/* Set up to return from userspace. */
- if (vdso64_rt_sigtramp && current->mm->context.vdso_base) {
- regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp;
+ if (vdso64_rt_sigtramp && tsk->mm->context.vdso_base) {
+ regs->link = tsk->mm->context.vdso_base + vdso64_rt_sigtramp;
} else {
err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
if (err)
@@ -821,7 +842,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs
badframe:
if (show_unhandled_signals)
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
- current->comm, current->pid, "setup_rt_frame",
+ tsk->comm, tsk->pid, "setup_rt_frame",
(long)frame, regs->nip, regs->link);
return 1;
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index 5fa92706444b..644cce3d8dce 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -40,6 +40,7 @@
#include <asm/syscalls.h>
#include <asm/time.h>
#include <asm/unistd.h>
+#include <asm/asm-prototypes.h>
static inline unsigned long do_mmap2(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags,
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 3efbedefba6a..67859b7d1c97 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -73,6 +73,7 @@
#include <asm/vdso_datapage.h>
#include <asm/firmware.h>
#include <asm/cputime.h>
+#include <asm/asm-prototypes.h>
/* powerpc clocksource/clockevent code */
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
index 298afcf3bf2a..3a2d04134da9 100644
--- a/arch/powerpc/kernel/tm.S
+++ b/arch/powerpc/kernel/tm.S
@@ -108,6 +108,7 @@ _GLOBAL(tm_reclaim)
/* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. */
std r3, STK_PARAM(R3)(r1)
+ std r4, STK_PARAM(R4)(r1)
SAVE_NVGPRS(r1)
/* We need to setup MSR for VSX register save instructions. */
@@ -126,43 +127,6 @@ _GLOBAL(tm_reclaim)
mtmsrd r15
std r14, TM_FRAME_L0(r1)
- /* Stash the stack pointer away for use after reclaim */
- std r1, PACAR1(r13)
-
- /* ******************** FPR/VR/VSRs ************
- * Before reclaiming, capture the current/transactional FPR/VR
- * versions /if used/.
- *
- * (If VSX used, FP and VMX are implied. Or, we don't need to look
- * at MSR.VSX as copying FP regs if .FP, vector regs if .VMX covers it.)
- *
- * We're passed the thread's MSR as parameter 2.
- *
- * We enabled VEC/FP/VSX in the msr above, so we can execute these
- * instructions!
- */
- andis. r0, r4, MSR_VEC@h
- beq dont_backup_vec
-
- addi r7, r3, THREAD_TRANSACT_VRSTATE
- SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */
- mfvscr v0
- li r6, VRSTATE_VSCR
- stvx v0, r7, r6
-dont_backup_vec:
- mfspr r0, SPRN_VRSAVE
- std r0, THREAD_TRANSACT_VRSAVE(r3)
-
- andi. r0, r4, MSR_FP
- beq dont_backup_fp
-
- addi r7, r3, THREAD_TRANSACT_FPSTATE
- SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 transact fp state */
-
- mffs fr0
- 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
@@ -170,6 +134,9 @@ dont_backup_fp:
1: tdeqi r6, 0
EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0
+ /* Stash the stack pointer away for use after reclaim */
+ std r1, PACAR1(r13)
+
/* Clear MSR RI since we are about to change r1, EE is already off. */
li r4, 0
mtmsrd r4, 1
@@ -273,6 +240,43 @@ dont_backup_fp:
* MSR.
*/
+
+ /* ******************** FPR/VR/VSRs ************
+ * After reclaiming, capture the checkpointed FPRs/VRs /if used/.
+ *
+ * (If VSX used, FP and VMX are implied. Or, we don't need to look
+ * at MSR.VSX as copying FP regs if .FP, vector regs if .VMX covers it.)
+ *
+ * We're passed the thread's MSR as the second parameter
+ *
+ * We enabled VEC/FP/VSX in the msr above, so we can execute these
+ * instructions!
+ */
+ ld r4, STK_PARAM(R4)(r1) /* Second parameter, MSR * */
+ mr r3, r12
+ andis. r0, r4, MSR_VEC@h
+ beq dont_backup_vec
+
+ addi r7, r3, THREAD_CKVRSTATE
+ SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */
+ mfvscr v0
+ li r6, VRSTATE_VSCR
+ stvx v0, r7, r6
+dont_backup_vec:
+ mfspr r0, SPRN_VRSAVE
+ std r0, THREAD_CKVRSAVE(r3)
+
+ andi. r0, r4, MSR_FP
+ beq dont_backup_fp
+
+ addi r7, r3, THREAD_CKFPSTATE
+ SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 transact fp state */
+
+ mffs fr0
+ stfd fr0,FPSTATE_FPSCR(r7)
+
+dont_backup_fp:
+
/* TM regs, incl TEXASR -- these live in thread_struct. Note they've
* been updated by the treclaim, to explain to userland the failure
* cause (aborted).
@@ -288,6 +292,7 @@ dont_backup_fp:
/* Restore original MSR/IRQ state & clear TM mode */
ld r14, TM_FRAME_L0(r1) /* Orig MSR */
+
li r15, 0
rldimi r14, r15, MSR_TS_LG, (63-MSR_TS_LG)-1
mtmsrd r14
@@ -356,28 +361,29 @@ _GLOBAL(__tm_recheckpoint)
mtmsr r5
#ifdef CONFIG_ALTIVEC
- /* FP and VEC registers: These are recheckpointed from thread.fpr[]
- * and thread.vr[] respectively. The thread.transact_fpr[] version
- * is more modern, and will be loaded subsequently by any FPUnavailable
- * trap.
+ /*
+ * FP and VEC registers: These are recheckpointed from
+ * thread.ckfp_state and thread.ckvr_state respectively. The
+ * thread.fp_state[] version holds the 'live' (transactional)
+ * and will be loaded subsequently by any FPUnavailable trap.
*/
andis. r0, r4, MSR_VEC@h
beq dont_restore_vec
- addi r8, r3, THREAD_VRSTATE
+ addi r8, r3, THREAD_CKVRSTATE
li r5, VRSTATE_VSCR
lvx v0, r8, r5
mtvscr v0
REST_32VRS(0, r5, r8) /* r5 scratch, r8 ptr */
dont_restore_vec:
- ld r5, THREAD_VRSAVE(r3)
+ ld r5, THREAD_CKVRSAVE(r3)
mtspr SPRN_VRSAVE, r5
#endif
andi. r0, r4, MSR_FP
beq dont_restore_fp
- addi r8, r3, THREAD_FPSTATE
+ addi r8, r3, THREAD_CKFPSTATE
lfd fr0, FPSTATE_FPSCR(r8)
MTFSF_L(fr0)
REST_32FPRS_VSRS(0, R4, R8)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 62859ebe0062..a1f8f5641e9e 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -117,7 +117,7 @@ static int die_owner = -1;
static unsigned int die_nest_count;
static int die_counter;
-static unsigned __kprobes long oops_begin(struct pt_regs *regs)
+static unsigned long oops_begin(struct pt_regs *regs)
{
int cpu;
unsigned long flags;
@@ -144,8 +144,9 @@ static unsigned __kprobes long oops_begin(struct pt_regs *regs)
pmac_backlight_unblank();
return flags;
}
+NOKPROBE_SYMBOL(oops_begin);
-static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
+static void oops_end(unsigned long flags, struct pt_regs *regs,
int signr)
{
bust_spinlocks(0);
@@ -196,8 +197,9 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
panic("Fatal exception");
do_exit(signr);
}
+NOKPROBE_SYMBOL(oops_end);
-static int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+static int __die(const char *str, struct pt_regs *regs, long err)
{
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
@@ -221,6 +223,7 @@ static int __kprobes __die(const char *str, struct pt_regs *regs, long err)
return 0;
}
+NOKPROBE_SYMBOL(__die);
void die(const char *str, struct pt_regs *regs, long err)
{
@@ -802,7 +805,7 @@ void RunModeException(struct pt_regs *regs)
_exception(SIGTRAP, regs, 0, 0);
}
-void __kprobes single_step_exception(struct pt_regs *regs)
+void single_step_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
@@ -819,6 +822,7 @@ void __kprobes single_step_exception(struct pt_regs *regs)
bail:
exception_exit(prev_state);
}
+NOKPROBE_SYMBOL(single_step_exception);
/*
* After we have successfully emulated an instruction, we have to
@@ -1140,7 +1144,7 @@ static int emulate_math(struct pt_regs *regs)
static inline int emulate_math(struct pt_regs *regs) { return -1; }
#endif
-void __kprobes program_check_exception(struct pt_regs *regs)
+void program_check_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
unsigned int reason = get_reason(regs);
@@ -1260,16 +1264,18 @@ sigill:
bail:
exception_exit(prev_state);
}
+NOKPROBE_SYMBOL(program_check_exception);
/*
* This occurs when running in hypervisor mode on POWER6 or later
* and an illegal instruction is encountered.
*/
-void __kprobes emulation_assist_interrupt(struct pt_regs *regs)
+void emulation_assist_interrupt(struct pt_regs *regs)
{
regs->msr |= REASON_ILLEGAL;
program_check_exception(regs);
}
+NOKPROBE_SYMBOL(emulation_assist_interrupt);
void alignment_exception(struct pt_regs *regs)
{
@@ -1310,6 +1316,18 @@ bail:
exception_exit(prev_state);
}
+void slb_miss_bad_addr(struct pt_regs *regs)
+{
+ enum ctx_state prev_state = exception_enter();
+
+ if (user_mode(regs))
+ _exception(SIGSEGV, regs, SEGV_BNDERR, regs->dar);
+ else
+ bad_page_fault(regs, regs->dar, SIGSEGV);
+
+ exception_exit(prev_state);
+}
+
void StackOverflow(struct pt_regs *regs)
{
printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
@@ -1372,6 +1390,22 @@ void vsx_unavailable_exception(struct pt_regs *regs)
}
#ifdef CONFIG_PPC64
+static void tm_unavailable(struct pt_regs *regs)
+{
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (user_mode(regs)) {
+ current->thread.load_tm++;
+ regs->msr |= MSR_TM;
+ tm_enable();
+ tm_restore_sprs(&current->thread);
+ return;
+ }
+#endif
+ pr_emerg("Unrecoverable TM Unavailable Exception "
+ "%lx at %lx\n", regs->trap, regs->nip);
+ die("Unrecoverable TM Unavailable Exception", regs, SIGABRT);
+}
+
void facility_unavailable_exception(struct pt_regs *regs)
{
static char *facility_strings[] = {
@@ -1451,6 +1485,27 @@ void facility_unavailable_exception(struct pt_regs *regs)
return;
}
+ if (status == FSCR_TM_LG) {
+ /*
+ * If we're here then the hardware is TM aware because it
+ * generated an exception with FSRM_TM set.
+ *
+ * If cpu_has_feature(CPU_FTR_TM) is false, then either firmware
+ * told us not to do TM, or the kernel is not built with TM
+ * support.
+ *
+ * If both of those things are true, then userspace can spam the
+ * console by triggering the printk() below just by continually
+ * doing tbegin (or any TM instruction). So in that case just
+ * send the process a SIGILL immediately.
+ */
+ if (!cpu_has_feature(CPU_FTR_TM))
+ goto out;
+
+ tm_unavailable(regs);
+ return;
+ }
+
if ((status < ARRAY_SIZE(facility_strings)) &&
facility_strings[status])
facility = facility_strings[status];
@@ -1463,6 +1518,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
"%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
+out:
if (user_mode(regs)) {
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
@@ -1504,7 +1560,8 @@ void fp_unavailable_tm(struct pt_regs *regs)
/* If VMX is in use, get the transactional values back */
if (regs->msr & MSR_VEC) {
- do_load_up_transact_altivec(&current->thread);
+ msr_check_and_set(MSR_VEC);
+ load_vr_state(&current->thread.vr_state);
/* At this point all the VSX state is loaded, so enable it */
regs->msr |= MSR_VSX;
}
@@ -1525,7 +1582,8 @@ void altivec_unavailable_tm(struct pt_regs *regs)
current->thread.used_vr = 1;
if (regs->msr & MSR_FP) {
- do_load_up_transact_fpu(&current->thread);
+ msr_check_and_set(MSR_FP);
+ load_fp_state(&current->thread.fp_state);
regs->msr |= MSR_VSX;
}
}
@@ -1564,10 +1622,12 @@ void vsx_unavailable_tm(struct pt_regs *regs)
*/
tm_recheckpoint(&current->thread, regs->msr & ~orig_msr);
+ msr_check_and_set(orig_msr & (MSR_FP | MSR_VEC));
+
if (orig_msr & MSR_FP)
- do_load_up_transact_fpu(&current->thread);
+ load_fp_state(&current->thread.fp_state);
if (orig_msr & MSR_VEC)
- do_load_up_transact_altivec(&current->thread);
+ load_vr_state(&current->thread.vr_state);
}
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
@@ -1656,7 +1716,7 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
mtspr(SPRN_DBCR0, current->thread.debug.dbcr0);
}
-void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
+void DebugException(struct pt_regs *regs, unsigned long debug_status)
{
current->thread.debug.dbsr = debug_status;
@@ -1717,6 +1777,7 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
} else
handle_debug(regs, debug_status);
}
+NOKPROBE_SYMBOL(DebugException);
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
#if !defined(CONFIG_TAU_INT)
diff --git a/arch/powerpc/kernel/vdso64/Makefile b/arch/powerpc/kernel/vdso64/Makefile
index 366ae09b14c1..31107bf5a61f 100644
--- a/arch/powerpc/kernel/vdso64/Makefile
+++ b/arch/powerpc/kernel/vdso64/Makefile
@@ -31,15 +31,9 @@ $(obj)/%.so: OBJCOPYFLAGS := -S
$(obj)/%.so: $(obj)/%.so.dbg FORCE
$(call if_changed,objcopy)
-# assembly rules for the .S files
-$(obj-vdso64): %.o: %.S FORCE
- $(call if_changed_dep,vdso64as)
-
# actual build commands
quiet_cmd_vdso64ld = VDSO64L $@
cmd_vdso64ld = $(CC) $(c_flags) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^)
-quiet_cmd_vdso64as = VDSO64A $@
- cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
# install commands for the unstripped file
quiet_cmd_vdso_install = INSTALL $@
diff --git a/arch/powerpc/kernel/vdso64/datapage.S b/arch/powerpc/kernel/vdso64/datapage.S
index 184a6ba7f283..abf17feffe40 100644
--- a/arch/powerpc/kernel/vdso64/datapage.S
+++ b/arch/powerpc/kernel/vdso64/datapage.S
@@ -59,7 +59,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map)
bl V_LOCAL_FUNC(__get_datapage)
mtlr r12
addi r3,r3,CFG_SYSCALL_MAP64
- cmpli cr0,r4,0
+ cmpldi cr0,r4,0
crclr cr0*4+so
beqlr
li r0,NR_syscalls
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
index a76b4af37ef2..382021324883 100644
--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -145,7 +145,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
bne cr0,99f
li r3,0
- cmpli cr0,r4,0
+ cmpldi cr0,r4,0
crclr cr0*4+so
beqlr
lis r5,CLOCK_REALTIME_RES@h
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 616a6d854638..bc85bdff4e01 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -7,31 +7,6 @@
#include <asm/page.h>
#include <asm/ptrace.h>
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-/* void do_load_up_transact_altivec(struct thread_struct *thread)
- *
- * This is similar to load_up_altivec but for the transactional version of the
- * vector regs. It doesn't mess with the task MSR or valid flags.
- * Furthermore, VEC laziness is not supported with TM currently.
- */
-_GLOBAL(do_load_up_transact_altivec)
- mfmsr r6
- oris r5,r6,MSR_VEC@h
- MTMSRD(r5)
- isync
-
- li r4,1
- stw r4,THREAD_USED_VR(r3)
-
- li r10,THREAD_TRANSACT_VRSTATE+VRSTATE_VSCR
- lvx v0,r10,r3
- mtvscr v0
- addi r10,r3,THREAD_TRANSACT_VRSTATE
- REST_32VRS(0,r4,r10)
-
- blr
-#endif
-
/*
* Load state from memory into VMX registers including VSCR.
* Assumes the caller has enabled VMX in the MSR.
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index b5fba689fca6..8295f51c1a5f 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -44,18 +44,68 @@ SECTIONS
* Text, read only data and other permanent read-only sections
*/
- /* Text and gots */
+ _text = .;
+ _stext = .;
+
+ /*
+ * Head text.
+ * This needs to be in its own output section to avoid ld placing
+ * branch trampoline stubs randomly throughout the fixed sections,
+ * which it will do (even if the branch comes from another section)
+ * in order to optimize stub generation.
+ */
+ .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) {
+#ifdef CONFIG_PPC64
+ KEEP(*(.head.text.first_256B));
+#ifdef CONFIG_PPC_BOOK3E
+# define END_FIXED 0x100
+#else
+ KEEP(*(.head.text.real_vectors));
+ *(.head.text.real_trampolines);
+ KEEP(*(.head.text.virt_vectors));
+ *(.head.text.virt_trampolines);
+# if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
+ KEEP(*(.head.data.fwnmi_page));
+# define END_FIXED 0x8000
+# else
+# define END_FIXED 0x7000
+# endif
+#endif
+ ASSERT((. == END_FIXED), "vmlinux.lds.S: fixed section overflow error");
+#else /* !CONFIG_PPC64 */
+ HEAD_TEXT
+#endif
+ } :kernel
+
+ /*
+ * If the build dies here, it's likely code in head_64.S is referencing
+ * labels it can't reach, and the linker inserting stubs without the
+ * assembler's knowledge. To debug, remove the above assert and
+ * rebuild. Look for branch stubs in the fixed section region.
+ *
+ * Linker stub generation could be allowed in "trampoline"
+ * sections if absolutely necessary, but this would require
+ * some rework of the fixed sections. Before resorting to this,
+ * consider references that have sufficient addressing range,
+ * (e.g., hand coded trampolines) so the linker does not have
+ * to add stubs.
+ *
+ * Linker stubs at the top of the main text section are currently not
+ * detected, and will result in a crash at boot due to offsets being
+ * wrong.
+ */
.text : AT(ADDR(.text) - LOAD_OFFSET) {
ALIGN_FUNCTION();
- HEAD_TEXT
- _text = .;
/* careful! __ftr_alt_* sections need to be close to .text */
*(.text .fixup __ftr_alt_* .ref.text)
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
+ MEM_KEEP(init.text)
+ MEM_KEEP(exit.text)
#ifdef CONFIG_PPC32
*(.got1)
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index ba21be15310f..ad5290005ca4 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -22,7 +22,7 @@ obj64-$(CONFIG_SMP) += locks.o
obj64-$(CONFIG_ALTIVEC) += vmx-helper.o
ifeq ($(CONFIG_GENERIC_CSUM),)
-obj-y += checksum_$(CONFIG_WORD_SIZE).o checksum_wrappers.o
+obj-y += checksum_$(BITS).o checksum_wrappers.o
endif
obj-$(CONFIG_PPC_EMULATE_SSTEP) += sstep.o ldstfp.o
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
index 43435c6892fb..eda7a96161ab 100644
--- a/arch/powerpc/lib/mem_64.S
+++ b/arch/powerpc/lib/mem_64.S
@@ -37,6 +37,7 @@ _GLOBAL(memset)
clrldi r5,r5,58
mtctr r0
beq 5f
+ .balign 16
4: std r4,0(r6)
std r4,8(r6)
std r4,16(r6)
@@ -90,6 +91,7 @@ _GLOBAL(backwards_memcpy)
andi. r0,r6,3
mtctr r7
bne 5f
+ .balign 16
1: lwz r7,-4(r4)
lwzu r8,-8(r4)
stw r7,-4(r6)
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index f2cea6d5e764..1a4e570f7894 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -7,17 +7,16 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
obj-y := fault.o mem.o pgtable.o mmap.o \
- init_$(CONFIG_WORD_SIZE).o \
- pgtable_$(CONFIG_WORD_SIZE).o
+ init_$(BITS).o pgtable_$(BITS).o
obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \
tlb_nohash_low.o
-obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(CONFIG_WORD_SIZE)e.o
+obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(BITS)e.o
hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC_BOOK3E_64) += pgtable-book3e.o
obj-$(CONFIG_PPC_STD_MMU_64) += pgtable-hash64.o hash_utils_64.o slb_low.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o
obj-$(CONFIG_PPC_RADIX_MMU) += pgtable-radix.o tlb-radix.o
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o mmu_context_hash32.o
-obj-$(CONFIG_PPC_STD_MMU) += tlb_hash$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_PPC_STD_MMU) += tlb_hash$(BITS).o
ifeq ($(CONFIG_PPC_STD_MMU_64),y)
obj-$(CONFIG_PPC_4K_PAGES) += hash64_4k.o
obj-$(CONFIG_PPC_64K_PAGES) += hash64_64k.o
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index bb1ffc559f38..d0b137d96df1 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -205,7 +205,7 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
* The return value is 0 if the fault was handled, or the signal
* number if this is a kernel fault that can't be handled here.
*/
-int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
+int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
enum ctx_state prev_state = exception_enter();
@@ -498,8 +498,8 @@ bad_area_nosemaphore:
bail:
exception_exit(prev_state);
return rc;
-
}
+NOKPROBE_SYMBOL(do_page_fault);
/*
* bad_page_fault is called when we have a bad access from the kernel.
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index ef3ae891a3db..90480e23fd2c 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -766,6 +766,29 @@ int remove_section_mapping(unsigned long start, unsigned long end)
}
#endif /* CONFIG_MEMORY_HOTPLUG */
+static void update_hid_for_hash(void)
+{
+ unsigned long hid0;
+ unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */
+
+ asm volatile("ptesync": : :"memory");
+ /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */
+ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+ : : "r"(rb), "i"(0), "i"(0), "i"(2), "r"(0) : "memory");
+ asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory");
+ /*
+ * now switch the HID
+ */
+ hid0 = mfspr(SPRN_HID0);
+ hid0 &= ~HID0_POWER9_RADIX;
+ mtspr(SPRN_HID0, hid0);
+ asm volatile("isync": : :"memory");
+
+ /* Wait for it to happen */
+ while ((mfspr(SPRN_HID0) & HID0_POWER9_RADIX))
+ cpu_relax();
+}
+
static void __init hash_init_partition_table(phys_addr_t hash_table,
unsigned long htab_size)
{
@@ -792,6 +815,8 @@ static void __init hash_init_partition_table(phys_addr_t hash_table,
*/
partition_tb->patb1 = 0;
pr_info("Partition table %p\n", partition_tb);
+ if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+ update_hid_for_hash();
/*
* update partition table control register,
* 64 K size.
@@ -1515,6 +1540,29 @@ out_exit:
local_irq_restore(flags);
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static inline void tm_flush_hash_page(int local)
+{
+ /*
+ * Transactions are not aborted by tlbiel, only tlbie. Without, syncing a
+ * page back to a block device w/PIO could pick up transactional data
+ * (bad!) so we force an abort here. Before the sync the page will be
+ * made read-only, which will flush_hash_page. BIG ISSUE here: if the
+ * kernel uses a page from userspace without unmapping it first, it may
+ * see the speculated version.
+ */
+ if (local && cpu_has_feature(CPU_FTR_TM) && current->thread.regs &&
+ MSR_TM_ACTIVE(current->thread.regs->msr)) {
+ tm_enable();
+ tm_abort(TM_CAUSE_TLBI);
+ }
+}
+#else
+static inline void tm_flush_hash_page(int local)
+{
+}
+#endif
+
/* WARNING: This is called from hash_low_64.S, if you change this prototype,
* do not forget to update the assembly call site !
*/
@@ -1541,21 +1589,7 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
ssize, local);
} pte_iterate_hashed_end();
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- /* Transactions are not aborted by tlbiel, only tlbie.
- * Without, syncing a page back to a block device w/ PIO could pick up
- * transactional data (bad!) so we force an abort here. Before the
- * sync the page will be made read-only, which will flush_hash_page.
- * BIG ISSUE here: if the kernel uses a page from userspace without
- * unmapping it first, it may see the speculated version.
- */
- if (local && cpu_has_feature(CPU_FTR_TM) &&
- current->thread.regs &&
- MSR_TM_ACTIVE(current->thread.regs->msr)) {
- tm_enable();
- tm_abort(TM_CAUSE_TLBI);
- }
-#endif
+ tm_flush_hash_page(local);
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -1612,22 +1646,7 @@ void flush_hash_hugepage(unsigned long vsid, unsigned long addr,
MMU_PAGE_16M, ssize, local);
}
tm_abort:
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- /* Transactions are not aborted by tlbiel, only tlbie.
- * Without, syncing a page back to a block device w/ PIO could pick up
- * transactional data (bad!) so we force an abort here. Before the
- * sync the page will be made read-only, which will flush_hash_page.
- * BIG ISSUE here: if the kernel uses a page from userspace without
- * unmapping it first, it may see the speculated version.
- */
- if (local && cpu_has_feature(CPU_FTR_TM) &&
- current->thread.regs &&
- MSR_TM_ACTIVE(current->thread.regs->msr)) {
- tm_enable();
- tm_abort(TM_CAUSE_TLBI);
- }
-#endif
- return;
+ tm_flush_hash_page(local);
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 7372ee13eb1e..a5d3ecdabc44 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -1019,8 +1019,15 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
pte = READ_ONCE(*ptep);
mask = _PAGE_PRESENT | _PAGE_READ;
+
+ /*
+ * On some CPUs like the 8xx, _PAGE_RW hence _PAGE_WRITE is defined
+ * as 0 and _PAGE_RO has to be set when a page is not writable
+ */
if (write)
mask |= _PAGE_WRITE;
+ else
+ mask |= _PAGE_RO;
if ((pte_val(pte) & mask) != mask)
return 0;
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 448685fbf27c..8a7c38b8d335 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -137,7 +137,7 @@ void __init MMU_init(void)
if (memblock.memory.cnt > 1) {
#ifndef CONFIG_WII
memblock_enforce_memory_limit(memblock.memory.regions[0].size);
- printk(KERN_WARNING "Only using first contiguous memory region");
+ pr_warn("Only using first contiguous memory region\n");
#else
wii_memory_fixups();
#endif
diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c
index da6a2168ae9e..e0f1c33601dd 100644
--- a/arch/powerpc/mm/mmu_context_iommu.c
+++ b/arch/powerpc/mm/mmu_context_iommu.c
@@ -15,6 +15,9 @@
#include <linux/rculist.h>
#include <linux/vmalloc.h>
#include <linux/mutex.h>
+#include <linux/migrate.h>
+#include <linux/hugetlb.h>
+#include <linux/swap.h>
#include <asm/mmu_context.h>
static DEFINE_MUTEX(mem_list_mutex);
@@ -72,6 +75,55 @@ bool mm_iommu_preregistered(void)
}
EXPORT_SYMBOL_GPL(mm_iommu_preregistered);
+/*
+ * Taken from alloc_migrate_target with changes to remove CMA allocations
+ */
+struct page *new_iommu_non_cma_page(struct page *page, unsigned long private,
+ int **resultp)
+{
+ gfp_t gfp_mask = GFP_USER;
+ struct page *new_page;
+
+ if (PageHuge(page) || PageTransHuge(page) || PageCompound(page))
+ return NULL;
+
+ if (PageHighMem(page))
+ gfp_mask |= __GFP_HIGHMEM;
+
+ /*
+ * We don't want the allocation to force an OOM if possibe
+ */
+ new_page = alloc_page(gfp_mask | __GFP_NORETRY | __GFP_NOWARN);
+ return new_page;
+}
+
+static int mm_iommu_move_page_from_cma(struct page *page)
+{
+ int ret = 0;
+ LIST_HEAD(cma_migrate_pages);
+
+ /* Ignore huge pages for now */
+ if (PageHuge(page) || PageTransHuge(page) || PageCompound(page))
+ return -EBUSY;
+
+ lru_add_drain();
+ ret = isolate_lru_page(page);
+ if (ret)
+ return ret;
+
+ list_add(&page->lru, &cma_migrate_pages);
+ put_page(page); /* Drop the gup reference */
+
+ ret = migrate_pages(&cma_migrate_pages, new_iommu_non_cma_page,
+ NULL, 0, MIGRATE_SYNC, MR_CMA);
+ if (ret) {
+ if (!list_empty(&cma_migrate_pages))
+ putback_movable_pages(&cma_migrate_pages);
+ }
+
+ return 0;
+}
+
long mm_iommu_get(unsigned long ua, unsigned long entries,
struct mm_iommu_table_group_mem_t **pmem)
{
@@ -124,15 +176,36 @@ long mm_iommu_get(unsigned long ua, unsigned long entries,
for (i = 0; i < entries; ++i) {
if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT),
1/* pages */, 1/* iswrite */, &page)) {
+ ret = -EFAULT;
for (j = 0; j < i; ++j)
- put_page(pfn_to_page(
- mem->hpas[j] >> PAGE_SHIFT));
+ put_page(pfn_to_page(mem->hpas[j] >>
+ PAGE_SHIFT));
vfree(mem->hpas);
kfree(mem);
- ret = -EFAULT;
goto unlock_exit;
}
-
+ /*
+ * If we get a page from the CMA zone, since we are going to
+ * be pinning these entries, we might as well move them out
+ * of the CMA zone if possible. NOTE: faulting in + migration
+ * can be expensive. Batching can be considered later
+ */
+ if (get_pageblock_migratetype(page) == MIGRATE_CMA) {
+ if (mm_iommu_move_page_from_cma(page))
+ goto populate;
+ if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT),
+ 1/* pages */, 1/* iswrite */,
+ &page)) {
+ ret = -EFAULT;
+ for (j = 0; j < i; ++j)
+ put_page(pfn_to_page(mem->hpas[j] >>
+ PAGE_SHIFT));
+ vfree(mem->hpas);
+ kfree(mem);
+ goto unlock_exit;
+ }
+ }
+populate:
mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
}
diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c
index 34079302cc17..f4f437cbabf1 100644
--- a/arch/powerpc/mm/pgtable-book3s64.c
+++ b/arch/powerpc/mm/pgtable-book3s64.c
@@ -35,7 +35,7 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
#endif
changed = !pmd_same(*(pmdp), entry);
if (changed) {
- __ptep_set_access_flags(pmdp_ptep(pmdp), pmd_pte(entry));
+ __ptep_set_access_flags(vma->vm_mm, pmdp_ptep(pmdp), pmd_pte(entry));
flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
}
return changed;
@@ -116,3 +116,12 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
return;
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+/* For use by kexec */
+void mmu_cleanup_all(void)
+{
+ if (radix_enabled())
+ radix__mmu_cleanup_all();
+ else if (mmu_hash_ops.hpte_clear_all)
+ mmu_hash_ops.hpte_clear_all();
+}
diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
index af897d91d09f..ed7bddc456b7 100644
--- a/arch/powerpc/mm/pgtable-radix.c
+++ b/arch/powerpc/mm/pgtable-radix.c
@@ -294,6 +294,32 @@ found:
return;
}
+static void update_hid_for_radix(void)
+{
+ unsigned long hid0;
+ unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */
+
+ asm volatile("ptesync": : :"memory");
+ /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */
+ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+ : : "r"(rb), "i"(1), "i"(0), "i"(2), "r"(0) : "memory");
+ /* prs = 1, ric = 2, rs = 0, r = 1 is = 3 */
+ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+ : : "r"(rb), "i"(1), "i"(1), "i"(2), "r"(0) : "memory");
+ asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory");
+ /*
+ * now switch the HID
+ */
+ hid0 = mfspr(SPRN_HID0);
+ hid0 |= HID0_POWER9_RADIX;
+ mtspr(SPRN_HID0, hid0);
+ asm volatile("isync": : :"memory");
+
+ /* Wait for it to happen */
+ while (!(mfspr(SPRN_HID0) & HID0_POWER9_RADIX))
+ cpu_relax();
+}
+
void __init radix__early_init_mmu(void)
{
unsigned long lpcr;
@@ -345,6 +371,8 @@ void __init radix__early_init_mmu(void)
if (!firmware_has_feature(FW_FEATURE_LPAR)) {
radix_init_native();
+ if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+ update_hid_for_radix();
lpcr = mfspr(SPRN_LPCR);
mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR);
radix_init_partition_table();
@@ -368,6 +396,18 @@ void radix__early_init_mmu_secondary(void)
}
}
+void radix__mmu_cleanup_all(void)
+{
+ unsigned long lpcr;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ lpcr = mfspr(SPRN_LPCR);
+ mtspr(SPRN_LPCR, lpcr & ~LPCR_UPRT);
+ mtspr(SPRN_PTCR, 0);
+ radix__flush_tlb_all();
+ }
+}
+
void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size)
{
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 0b6fb244d0a1..911fdfb63ec1 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -224,7 +224,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
if (changed) {
if (!is_vm_hugetlb_page(vma))
assert_pte_locked(vma->vm_mm, address);
- __ptep_set_access_flags(ptep, entry);
+ __ptep_set_access_flags(vma->vm_mm, ptep, entry);
flush_tlb_page(vma, address);
}
return changed;
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 9f1983404e1a..e2974fcd20f1 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -178,11 +178,9 @@ BEGIN_FTR_SECTION
END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
b slb_finish_load
-8: /* invalid EA */
- li r10,0 /* BAD_VSID */
- li r9,0 /* BAD_VSID */
- li r11,SLB_VSID_USER /* flags don't much matter */
- b slb_finish_load
+8: /* invalid EA - return an error indication */
+ crset 4*cr0+eq /* indicate failure */
+ blr
/*
* Finish loading of an SLB entry and return
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c
index 48df05ef5231..0e49ec541ab5 100644
--- a/arch/powerpc/mm/tlb-radix.c
+++ b/arch/powerpc/mm/tlb-radix.c
@@ -400,3 +400,27 @@ void radix__flush_pmd_tlb_range(struct vm_area_struct *vma,
radix__flush_tlb_range_psize(vma->vm_mm, start, end, MMU_PAGE_2M);
}
EXPORT_SYMBOL(radix__flush_pmd_tlb_range);
+
+void radix__flush_tlb_all(void)
+{
+ unsigned long rb,prs,r,rs;
+ unsigned long ric = RIC_FLUSH_ALL;
+
+ rb = 0x3 << PPC_BITLSHIFT(53); /* IS = 3 */
+ prs = 0; /* partition scoped */
+ r = 1; /* raidx format */
+ rs = 1 & ((1UL << 32) - 1); /* any LPID value to flush guest mappings */
+
+ asm volatile("ptesync": : :"memory");
+ /*
+ * now flush guest entries by passing PRS = 1 and LPID != 0
+ */
+ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+ : : "r"(rb), "i"(r), "i"(1), "i"(ric), "r"(rs) : "memory");
+ /*
+ * now flush host entires by passing PRS = 0 and LPID == 0
+ */
+ asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+ : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(0) : "memory");
+ asm volatile("eieio; tlbsync; ptesync": : :"memory");
+}
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index d5301b6f20d0..89f70073dec8 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -40,6 +40,8 @@
#define PPC_BLR() EMIT(PPC_INST_BLR)
#define PPC_BLRL() EMIT(PPC_INST_BLRL)
#define PPC_MTLR(r) EMIT(PPC_INST_MTLR | ___PPC_RT(r))
+#define PPC_BCTR() EMIT(PPC_INST_BCTR)
+#define PPC_MTCTR(r) EMIT(PPC_INST_MTCTR | ___PPC_RT(r))
#define PPC_ADDI(d, a, i) EMIT(PPC_INST_ADDI | ___PPC_RT(d) | \
___PPC_RA(a) | IMM_L(i))
#define PPC_MR(d, a) PPC_OR(d, a, a)
diff --git a/arch/powerpc/net/bpf_jit64.h b/arch/powerpc/net/bpf_jit64.h
index 5046d6f65c02..62fa7589db2b 100644
--- a/arch/powerpc/net/bpf_jit64.h
+++ b/arch/powerpc/net/bpf_jit64.h
@@ -16,30 +16,33 @@
/*
* Stack layout:
+ * Ensure the top half (upto local_tmp_var) stays consistent
+ * with our redzone usage.
*
* [ prev sp ] <-------------
* [ nv gpr save area ] 8*8 |
+ * [ tail_call_cnt ] 8 |
+ * [ local_tmp_var ] 8 |
* fp (r31) --> [ ebpf stack space ] 512 |
- * [ local/tmp var space ] 16 |
* [ frame header ] 32/112 |
* sp (r1) ---> [ stack pointer ] --------------
*/
-/* for bpf JIT code internal usage */
-#define BPF_PPC_STACK_LOCALS 16
/* for gpr non volatile registers BPG_REG_6 to 10, plus skb cache registers */
#define BPF_PPC_STACK_SAVE (8*8)
+/* for bpf JIT code internal usage */
+#define BPF_PPC_STACK_LOCALS 16
/* Ensure this is quadword aligned */
-#define BPF_PPC_STACKFRAME (STACK_FRAME_MIN_SIZE + BPF_PPC_STACK_LOCALS + \
- MAX_BPF_STACK + BPF_PPC_STACK_SAVE)
+#define BPF_PPC_STACKFRAME (STACK_FRAME_MIN_SIZE + MAX_BPF_STACK + \
+ BPF_PPC_STACK_LOCALS + BPF_PPC_STACK_SAVE)
#ifndef __ASSEMBLY__
/* BPF register usage */
-#define SKB_HLEN_REG (MAX_BPF_REG + 0)
-#define SKB_DATA_REG (MAX_BPF_REG + 1)
-#define TMP_REG_1 (MAX_BPF_REG + 2)
-#define TMP_REG_2 (MAX_BPF_REG + 3)
+#define SKB_HLEN_REG (MAX_BPF_JIT_REG + 0)
+#define SKB_DATA_REG (MAX_BPF_JIT_REG + 1)
+#define TMP_REG_1 (MAX_BPF_JIT_REG + 2)
+#define TMP_REG_2 (MAX_BPF_JIT_REG + 3)
/* BPF to ppc register mappings */
static const int b2p[] = {
@@ -59,12 +62,16 @@ static const int b2p[] = {
/* frame pointer aka BPF_REG_10 */
[BPF_REG_FP] = 31,
/* eBPF jit internal registers */
+ [BPF_REG_AX] = 2,
[SKB_HLEN_REG] = 25,
[SKB_DATA_REG] = 26,
[TMP_REG_1] = 9,
[TMP_REG_2] = 10
};
+/* PPC NVR range -- update this if we ever use NVRs below r24 */
+#define BPF_PPC_NVR_MIN 24
+
/* Assembly helpers */
#define DECLARE_LOAD_FUNC(func) u64 func(u64 r3, u64 r4); \
u64 func##_negative_offset(u64 r3, u64 r4); \
@@ -82,6 +89,7 @@ DECLARE_LOAD_FUNC(sk_load_byte);
#define SEEN_FUNC 0x1000 /* might call external helpers */
#define SEEN_STACK 0x2000 /* uses BPF stack */
#define SEEN_SKB 0x4000 /* uses sk_buff */
+#define SEEN_TAILCALL 0x8000 /* uses tail calls */
struct codegen_context {
/*
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index 6073b78516f6..0fe98a567125 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -17,6 +17,7 @@
#include <linux/filter.h>
#include <linux/if_vlan.h>
#include <asm/kprobes.h>
+#include <linux/bpf.h>
#include "bpf_jit64.h"
@@ -58,6 +59,40 @@ static inline bool bpf_has_stack_frame(struct codegen_context *ctx)
return ctx->seen & SEEN_FUNC || bpf_is_seen_register(ctx, BPF_REG_FP);
}
+/*
+ * When not setting up our own stackframe, the redzone usage is:
+ *
+ * [ prev sp ] <-------------
+ * [ ... ] |
+ * sp (r1) ---> [ stack pointer ] --------------
+ * [ nv gpr save area ] 8*8
+ * [ tail_call_cnt ] 8
+ * [ local_tmp_var ] 8
+ * [ unused red zone ] 208 bytes protected
+ */
+static int bpf_jit_stack_local(struct codegen_context *ctx)
+{
+ if (bpf_has_stack_frame(ctx))
+ return STACK_FRAME_MIN_SIZE + MAX_BPF_STACK;
+ else
+ return -(BPF_PPC_STACK_SAVE + 16);
+}
+
+static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx)
+{
+ return bpf_jit_stack_local(ctx) + 8;
+}
+
+static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg)
+{
+ if (reg >= BPF_PPC_NVR_MIN && reg < 32)
+ return (bpf_has_stack_frame(ctx) ? BPF_PPC_STACKFRAME : 0)
+ - (8 * (32 - reg));
+
+ pr_err("BPF JIT is asking about unknown registers");
+ BUG();
+}
+
static void bpf_jit_emit_skb_loads(u32 *image, struct codegen_context *ctx)
{
/*
@@ -73,36 +108,27 @@ static void bpf_jit_emit_skb_loads(u32 *image, struct codegen_context *ctx)
PPC_BPF_LL(b2p[SKB_DATA_REG], 3, offsetof(struct sk_buff, data));
}
-static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func)
+static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
{
-#ifdef PPC64_ELF_ABI_v1
- /* func points to the function descriptor */
- PPC_LI64(b2p[TMP_REG_2], func);
- /* Load actual entry point from function descriptor */
- PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
- /* ... and move it to LR */
- PPC_MTLR(b2p[TMP_REG_1]);
+ int i;
+
/*
- * Load TOC from function descriptor at offset 8.
- * We can clobber r2 since we get called through a
- * function pointer (so caller will save/restore r2)
- * and since we don't use a TOC ourself.
+ * Initialize tail_call_cnt if we do tail calls.
+ * Otherwise, put in NOPs so that it can be skipped when we are
+ * invoked through a tail call.
*/
- PPC_BPF_LL(2, b2p[TMP_REG_2], 8);
-#else
- /* We can clobber r12 */
- PPC_FUNC_ADDR(12, func);
- PPC_MTLR(12);
-#endif
- PPC_BLRL();
-}
+ if (ctx->seen & SEEN_TAILCALL) {
+ PPC_LI(b2p[TMP_REG_1], 0);
+ /* this goes in the redzone */
+ PPC_BPF_STL(b2p[TMP_REG_1], 1, -(BPF_PPC_STACK_SAVE + 8));
+ } else {
+ PPC_NOP();
+ PPC_NOP();
+ }
-static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
-{
- int i;
- bool new_stack_frame = bpf_has_stack_frame(ctx);
+#define BPF_TAILCALL_PROLOGUE_SIZE 8
- if (new_stack_frame) {
+ if (bpf_has_stack_frame(ctx)) {
/*
* We need a stack frame, but we don't necessarily need to
* save/restore LR unless we call other functions
@@ -122,9 +148,7 @@ static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
*/
for (i = BPF_REG_6; i <= BPF_REG_10; i++)
if (bpf_is_seen_register(ctx, i))
- PPC_BPF_STL(b2p[i], 1,
- (new_stack_frame ? BPF_PPC_STACKFRAME : 0) -
- (8 * (32 - b2p[i])));
+ PPC_BPF_STL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i]));
/*
* Save additional non-volatile regs if we cache skb
@@ -132,53 +156,142 @@ static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
*/
if (ctx->seen & SEEN_SKB) {
PPC_BPF_STL(b2p[SKB_HLEN_REG], 1,
- BPF_PPC_STACKFRAME - (8 * (32 - b2p[SKB_HLEN_REG])));
+ bpf_jit_stack_offsetof(ctx, b2p[SKB_HLEN_REG]));
PPC_BPF_STL(b2p[SKB_DATA_REG], 1,
- BPF_PPC_STACKFRAME - (8 * (32 - b2p[SKB_DATA_REG])));
+ bpf_jit_stack_offsetof(ctx, b2p[SKB_DATA_REG]));
bpf_jit_emit_skb_loads(image, ctx);
}
/* Setup frame pointer to point to the bpf stack area */
if (bpf_is_seen_register(ctx, BPF_REG_FP))
PPC_ADDI(b2p[BPF_REG_FP], 1,
- BPF_PPC_STACKFRAME - BPF_PPC_STACK_SAVE);
+ STACK_FRAME_MIN_SIZE + MAX_BPF_STACK);
}
-static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
+static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx)
{
int i;
- bool new_stack_frame = bpf_has_stack_frame(ctx);
-
- /* Move result to r3 */
- PPC_MR(3, b2p[BPF_REG_0]);
/* Restore NVRs */
for (i = BPF_REG_6; i <= BPF_REG_10; i++)
if (bpf_is_seen_register(ctx, i))
- PPC_BPF_LL(b2p[i], 1,
- (new_stack_frame ? BPF_PPC_STACKFRAME : 0) -
- (8 * (32 - b2p[i])));
+ PPC_BPF_LL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i]));
/* Restore non-volatile registers used for skb cache */
if (ctx->seen & SEEN_SKB) {
PPC_BPF_LL(b2p[SKB_HLEN_REG], 1,
- BPF_PPC_STACKFRAME - (8 * (32 - b2p[SKB_HLEN_REG])));
+ bpf_jit_stack_offsetof(ctx, b2p[SKB_HLEN_REG]));
PPC_BPF_LL(b2p[SKB_DATA_REG], 1,
- BPF_PPC_STACKFRAME - (8 * (32 - b2p[SKB_DATA_REG])));
+ bpf_jit_stack_offsetof(ctx, b2p[SKB_DATA_REG]));
}
/* Tear down our stack frame */
- if (new_stack_frame) {
+ if (bpf_has_stack_frame(ctx)) {
PPC_ADDI(1, 1, BPF_PPC_STACKFRAME);
if (ctx->seen & SEEN_FUNC) {
PPC_BPF_LL(0, 1, PPC_LR_STKOFF);
PPC_MTLR(0);
}
}
+}
+
+static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
+{
+ bpf_jit_emit_common_epilogue(image, ctx);
+
+ /* Move result to r3 */
+ PPC_MR(3, b2p[BPF_REG_0]);
PPC_BLR();
}
+static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func)
+{
+#ifdef PPC64_ELF_ABI_v1
+ /* func points to the function descriptor */
+ PPC_LI64(b2p[TMP_REG_2], func);
+ /* Load actual entry point from function descriptor */
+ PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
+ /* ... and move it to LR */
+ PPC_MTLR(b2p[TMP_REG_1]);
+ /*
+ * Load TOC from function descriptor at offset 8.
+ * We can clobber r2 since we get called through a
+ * function pointer (so caller will save/restore r2)
+ * and since we don't use a TOC ourself.
+ */
+ PPC_BPF_LL(2, b2p[TMP_REG_2], 8);
+#else
+ /* We can clobber r12 */
+ PPC_FUNC_ADDR(12, func);
+ PPC_MTLR(12);
+#endif
+ PPC_BLRL();
+}
+
+static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out)
+{
+ /*
+ * By now, the eBPF program has already setup parameters in r3, r4 and r5
+ * r3/BPF_REG_1 - pointer to ctx -- passed as is to the next bpf program
+ * r4/BPF_REG_2 - pointer to bpf_array
+ * r5/BPF_REG_3 - index in bpf_array
+ */
+ int b2p_bpf_array = b2p[BPF_REG_2];
+ int b2p_index = b2p[BPF_REG_3];
+
+ /*
+ * if (index >= array->map.max_entries)
+ * goto out;
+ */
+ PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries));
+ PPC_CMPLW(b2p_index, b2p[TMP_REG_1]);
+ PPC_BCC(COND_GE, out);
+
+ /*
+ * if (tail_call_cnt > MAX_TAIL_CALL_CNT)
+ * goto out;
+ */
+ PPC_LD(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx));
+ PPC_CMPLWI(b2p[TMP_REG_1], MAX_TAIL_CALL_CNT);
+ PPC_BCC(COND_GT, out);
+
+ /*
+ * tail_call_cnt++;
+ */
+ PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 1);
+ PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx));
+
+ /* prog = array->ptrs[index]; */
+ PPC_MULI(b2p[TMP_REG_1], b2p_index, 8);
+ PPC_ADD(b2p[TMP_REG_1], b2p[TMP_REG_1], b2p_bpf_array);
+ PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_array, ptrs));
+
+ /*
+ * if (prog == NULL)
+ * goto out;
+ */
+ PPC_CMPLDI(b2p[TMP_REG_1], 0);
+ PPC_BCC(COND_EQ, out);
+
+ /* goto *(prog->bpf_func + prologue_size); */
+ PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_prog, bpf_func));
+#ifdef PPC64_ELF_ABI_v1
+ /* skip past the function descriptor */
+ PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1],
+ FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE);
+#else
+ PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], BPF_TAILCALL_PROLOGUE_SIZE);
+#endif
+ PPC_MTCTR(b2p[TMP_REG_1]);
+
+ /* tear down stack, restore NVRs, ... */
+ bpf_jit_emit_common_epilogue(image, ctx);
+
+ PPC_BCTR();
+ /* out: */
+}
+
/* Assemble the body code between the prologue & epilogue */
static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
struct codegen_context *ctx,
@@ -200,7 +313,6 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
u64 imm64;
u8 *func;
u32 true_cond;
- int stack_local_off;
/*
* addrs[] maps a BPF bytecode address into a real offset from
@@ -219,9 +331,9 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
* optimization but everything else should work without
* any issues.
*/
- if (dst_reg >= 24 && dst_reg <= 31)
+ if (dst_reg >= BPF_PPC_NVR_MIN && dst_reg < 32)
bpf_set_seen_register(ctx, insn[i].dst_reg);
- if (src_reg >= 24 && src_reg <= 31)
+ if (src_reg >= BPF_PPC_NVR_MIN && src_reg < 32)
bpf_set_seen_register(ctx, insn[i].src_reg);
switch (code) {
@@ -490,25 +602,12 @@ bpf_alu32_trunc:
* Way easier and faster(?) to store the value
* into stack and then use ldbrx
*
- * First, determine where in stack we can store
- * this:
- * - if we have allotted a stack frame, then we
- * will utilize the area set aside by
- * BPF_PPC_STACK_LOCALS
- * - else, we use the area beneath the NV GPR
- * save area
- *
* ctx->seen will be reliable in pass2, but
* the instructions generated will remain the
* same across all passes
*/
- if (bpf_has_stack_frame(ctx))
- stack_local_off = STACK_FRAME_MIN_SIZE;
- else
- stack_local_off = -(BPF_PPC_STACK_SAVE + 8);
-
- PPC_STD(dst_reg, 1, stack_local_off);
- PPC_ADDI(b2p[TMP_REG_1], 1, stack_local_off);
+ PPC_STD(dst_reg, 1, bpf_jit_stack_local(ctx));
+ PPC_ADDI(b2p[TMP_REG_1], 1, bpf_jit_stack_local(ctx));
PPC_LDBRX(dst_reg, 0, b2p[TMP_REG_1]);
break;
}
@@ -668,7 +767,7 @@ emit_clear:
/* Save skb pointer if we need to re-cache skb data */
if (bpf_helper_changes_skb_data(func))
- PPC_BPF_STL(3, 1, STACK_FRAME_MIN_SIZE);
+ PPC_BPF_STL(3, 1, bpf_jit_stack_local(ctx));
bpf_jit_emit_func_call(image, ctx, (u64)func);
@@ -678,7 +777,7 @@ emit_clear:
/* refresh skb cache */
if (bpf_helper_changes_skb_data(func)) {
/* reload skb pointer to r3 */
- PPC_BPF_LL(3, 1, STACK_FRAME_MIN_SIZE);
+ PPC_BPF_LL(3, 1, bpf_jit_stack_local(ctx));
bpf_jit_emit_skb_loads(image, ctx);
}
break;
@@ -837,9 +936,12 @@ common_load:
break;
/*
- * TODO: Tail call
+ * Tail call
*/
case BPF_JMP | BPF_CALL | BPF_X:
+ ctx->seen |= SEEN_TAILCALL;
+ bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]);
+ break;
default:
/*
@@ -872,21 +974,37 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
int pass;
int flen;
struct bpf_binary_header *bpf_hdr;
+ struct bpf_prog *org_fp = fp;
+ struct bpf_prog *tmp_fp;
+ bool bpf_blinded = false;
if (!bpf_jit_enable)
- return fp;
+ return org_fp;
+
+ tmp_fp = bpf_jit_blind_constants(org_fp);
+ if (IS_ERR(tmp_fp))
+ return org_fp;
+
+ if (tmp_fp != org_fp) {
+ bpf_blinded = true;
+ fp = tmp_fp;
+ }
flen = fp->len;
addrs = kzalloc((flen+1) * sizeof(*addrs), GFP_KERNEL);
- if (addrs == NULL)
- return fp;
+ if (addrs == NULL) {
+ fp = org_fp;
+ goto out;
+ }
+
+ memset(&cgctx, 0, sizeof(struct codegen_context));
- cgctx.idx = 0;
- cgctx.seen = 0;
/* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs))
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
/* We hit something illegal or unsupported. */
+ fp = org_fp;
goto out;
+ }
/*
* Pretend to build prologue, given the features we've seen. This will
@@ -901,8 +1019,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4,
bpf_jit_fill_ill_insns);
- if (!bpf_hdr)
+ if (!bpf_hdr) {
+ fp = org_fp;
goto out;
+ }
code_base = (u32 *)(image + FUNCTION_DESCR_SIZE);
@@ -939,6 +1059,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
out:
kfree(addrs);
+
+ if (bpf_blinded)
+ bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp);
+
return fp;
}
diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c
index b129d007e7fe..b19265de9178 100644
--- a/arch/powerpc/oprofile/cell/spu_profiler.c
+++ b/arch/powerpc/oprofile/cell/spu_profiler.c
@@ -43,7 +43,7 @@ static unsigned int profiling_interval;
#define SPU_PC_MASK 0xFFFF
DEFINE_SPINLOCK(oprof_spu_smpl_arry_lck);
-unsigned long oprof_spu_smpl_arry_lck_flags;
+static unsigned long oprof_spu_smpl_arry_lck_flags;
void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset)
{
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
index ef2142ff7dbd..83d2b4ef7f0d 100644
--- a/arch/powerpc/oprofile/cell/spu_task_sync.c
+++ b/arch/powerpc/oprofile/cell/spu_task_sync.c
@@ -36,7 +36,7 @@
static DEFINE_SPINLOCK(buffer_lock);
static DEFINE_SPINLOCK(cache_lock);
static int num_spu_nodes;
-int spu_prof_num_nodes;
+static int spu_prof_num_nodes;
struct spu_buffer spu_buff[MAX_NUMNODES * SPUS_PER_NODE];
struct delayed_work spu_work;
@@ -88,7 +88,7 @@ static void spu_buff_add(unsigned long int value, int spu)
/* This function copies the per SPU buffers to the
* OProfile kernel buffer.
*/
-void sync_spu_buff(void)
+static void sync_spu_buff(void)
{
int spu;
unsigned long flags;
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 4ed377f0f7b2..72c27b8d2cf3 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -2158,7 +2158,7 @@ static void perf_event_interrupt(struct pt_regs *regs)
irq_exit();
}
-int power_pmu_prepare_cpu(unsigned int cpu)
+static int power_pmu_prepare_cpu(unsigned int cpu)
{
struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
index 7aa37236bb70..43fabb3cae0f 100644
--- a/arch/powerpc/perf/hv-gpci.c
+++ b/arch/powerpc/perf/hv-gpci.c
@@ -131,7 +131,7 @@ static const struct attribute_group *attr_groups[] = {
#define HGPCI_MAX_DATA_BYTES \
(HGPCI_REQ_BUFFER_SIZE - sizeof(struct hv_get_perf_counter_info_params))
-DEFINE_PER_CPU(char, hv_gpci_reqb[HGPCI_REQ_BUFFER_SIZE]) __aligned(sizeof(uint64_t));
+static DEFINE_PER_CPU(char, hv_gpci_reqb[HGPCI_REQ_BUFFER_SIZE]) __aligned(sizeof(uint64_t));
struct hv_gpci_request_buffer {
struct hv_get_perf_counter_info_params params;
diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c
index a383c23a9070..7963658dbc22 100644
--- a/arch/powerpc/perf/power7-pmu.c
+++ b/arch/powerpc/perf/power7-pmu.c
@@ -416,7 +416,7 @@ static struct attribute *power7_pmu_format_attr[] = {
NULL,
};
-struct attribute_group power7_pmu_format_group = {
+static struct attribute_group power7_pmu_format_group = {
.name = "format",
.attrs = power7_pmu_format_attr,
};
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 5fde2b192fec..ab830d106ec5 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -204,7 +204,7 @@ static struct attribute *power8_pmu_format_attr[] = {
NULL,
};
-struct attribute_group power8_pmu_format_group = {
+static struct attribute_group power8_pmu_format_group = {
.name = "format",
.attrs = power8_pmu_format_attr,
};
diff --git a/arch/powerpc/perf/power9-pmu.c b/arch/powerpc/perf/power9-pmu.c
index 788346303852..8e9a81967ff8 100644
--- a/arch/powerpc/perf/power9-pmu.c
+++ b/arch/powerpc/perf/power9-pmu.c
@@ -119,7 +119,7 @@ static struct attribute *power9_pmu_format_attr[] = {
NULL,
};
-struct attribute_group power9_pmu_format_group = {
+static struct attribute_group power9_pmu_format_group = {
.name = "format",
.attrs = power9_pmu_format_attr,
};
diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c
index 5ecce543103e..a886c2c22097 100644
--- a/arch/powerpc/platforms/44x/warp.c
+++ b/arch/powerpc/platforms/44x/warp.c
@@ -204,7 +204,7 @@ static void pika_setup_critical_temp(struct device_node *np,
i2c_smbus_write_byte_data(client, 3, 0); /* Tlow */
irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n");
return;
}
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
index 0035d146df73..fe4d4eac7427 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
@@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,
status |= (ignore | mask);
if (status == 0xff)
- return NO_IRQ;
+ return 0;
cpld_irq = ffz(status) + offset;
@@ -110,14 +110,14 @@ static void cpld_pic_cascade(struct irq_desc *desc)
irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,
&cpld_regs->pci_mask);
- if (irq != NO_IRQ) {
+ if (irq) {
generic_handle_irq(irq);
return;
}
irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,
&cpld_regs->misc_mask);
- if (irq != NO_IRQ) {
+ if (irq) {
generic_handle_irq(irq);
return;
}
@@ -177,7 +177,7 @@ mpc5121_ads_cpld_pic_init(void)
goto end;
cascade_irq = irq_of_parse_and_map(np, 0);
- if (cascade_irq == NO_IRQ)
+ if (!cascade_irq)
goto end;
/*
diff --git a/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c b/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c
index d93dd4acf40b..cec3f88f153d 100644
--- a/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c
+++ b/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c
@@ -473,7 +473,7 @@ static int mpc512x_lpbfifo_probe(struct platform_device *pdev)
}
lpbfifo.irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
- if (lpbfifo.irq == NO_IRQ) {
+ if (!lpbfifo.irq) {
dev_err(&pdev->dev, "mapping irq failed\n");
ret = -ENODEV;
goto err0;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index 4fe2074c88cb..fc98912f42cf 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -511,7 +511,7 @@ unsigned int mpc52xx_get_irq(void)
irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
}
} else {
- return NO_IRQ;
+ return 0;
}
return irq_linear_revmap(mpc52xx_irqhost, irq);
diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
index 60e89fc9c753..8b065bdf7412 100644
--- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
+++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
@@ -131,7 +131,7 @@ int __init pq2ads_pci_init_irq(void)
}
irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
printk(KERN_ERR "No interrupt in pci pic node.\n");
of_node_put(np);
goto out;
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index 2ef03e7d248c..0d6a62fc5864 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -89,7 +89,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
goto err;
ret = of_irq_to_resource(np, 0, &res[1]);
- if (ret == NO_IRQ)
+ if (!ret)
goto err;
pdev = platform_device_alloc("mpc83xx_spi", i);
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index fcbea4b51a78..24717d060008 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -352,7 +352,7 @@ static int pmc_probe(struct platform_device *ofdev)
return -ENODEV;
pmc_irq = irq_of_parse_and_map(np, 0);
- if (pmc_irq != NO_IRQ) {
+ if (pmc_irq) {
ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED,
"pmc", ofdev);
@@ -400,7 +400,7 @@ out_syscr:
out_pmc:
iounmap(pmc_regs);
out:
- if (pmc_irq != NO_IRQ)
+ if (pmc_irq)
free_irq(pmc_irq, ofdev);
return ret;
diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
index 28720a4ded7b..954e5e8b14ef 100644
--- a/arch/powerpc/platforms/85xx/common.c
+++ b/arch/powerpc/platforms/85xx/common.c
@@ -76,7 +76,7 @@ void __init mpc85xx_cpm2_pic_init(void)
return;
}
irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
of_node_put(np);
printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n");
return;
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 62f171c71c4c..86f20156178e 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -196,7 +196,7 @@ static void mpc85xx_8259_cascade_handler(struct irq_desc *desc)
{
unsigned int cascade_irq = i8259_irq();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
/* handle an interrupt from the 8259 */
generic_handle_irq(cascade_irq);
@@ -247,7 +247,7 @@ static int mpc85xx_cds_8259_attach(void)
}
cascade_irq = irq_of_parse_and_map(cascade_node, 0);
- if (cascade_irq == NO_IRQ) {
+ if (!cascade_irq) {
printk(KERN_ERR "Failed to map cascade interrupt\n");
return -ENXIO;
}
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 6bc07d837b1c..ed69c7ee1829 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -51,7 +51,7 @@ static void mpc85xx_8259_cascade(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
- if (cascade_irq != NO_IRQ) {
+ if (cascade_irq) {
generic_handle_irq(cascade_irq);
}
chip->irq_eoi(&desc->irq_data);
@@ -96,7 +96,7 @@ void __init mpc85xx_ds_pic_init(void)
}
cascade_irq = irq_of_parse_and_map(cascade_node, 0);
- if (cascade_irq == NO_IRQ) {
+ if (!cascade_irq) {
printk(KERN_ERR "Failed to map cascade interrupt\n");
return;
}
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
index b02d6a5bb035..82f8490b5aa7 100644
--- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
@@ -78,7 +78,7 @@ static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
break;
}
if (i == 3)
- return NO_IRQ;
+ return 0;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
@@ -103,7 +103,7 @@ static void socrates_fpga_pic_cascade(struct irq_desc *desc)
*/
cascade_irq = socrates_fpga_pic_get_irq(irq);
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
}
@@ -292,7 +292,7 @@ void socrates_fpga_pic_init(struct device_node *pic)
for (i = 0; i < 3; i++) {
socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
- if (socrates_fpga_irqs[i] == NO_IRQ) {
+ if (!socrates_fpga_irqs[i]) {
pr_warning("FPGA PIC: can't get irq%d.\n", i);
continue;
}
diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c
index 845defa1fd19..a6c695fa4da0 100644
--- a/arch/powerpc/platforms/86xx/pic.c
+++ b/arch/powerpc/platforms/86xx/pic.c
@@ -22,7 +22,7 @@ static void mpc86xx_8259_cascade(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
@@ -58,7 +58,7 @@ void __init mpc86xx_init_irq(void)
}
cascade_irq = irq_of_parse_and_map(cascade_node, 0);
- if (cascade_irq == NO_IRQ) {
+ if (!cascade_irq) {
printk(KERN_ERR "Failed to map cascade interrupt\n");
return;
}
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index b1ab6e96cb31..f81069f79a94 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -241,6 +241,6 @@ void __init mpc8xx_pics_init(void)
}
irq = cpm_pic_init();
- if (irq != NO_IRQ)
+ if (irq)
irq_set_chained_handler(irq, cpm_cascade);
}
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index f32edec13fd1..ca2da30ad2ab 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -74,6 +74,7 @@ config PPC_BOOK3S_64
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
select ARCH_SUPPORTS_NUMA_BALANCING
select IRQ_WORK
+ select HAVE_KERNEL_XZ
config PPC_BOOK3E_64
bool "Embedded processors"
@@ -86,6 +87,7 @@ endchoice
choice
prompt "CPU selection"
depends on PPC64
+ default POWER8_CPU if CPU_LITTLE_ENDIAN
default GENERIC_CPU
help
This will create a kernel which is optimised for a particular CPU.
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index aed7714495c1..8b55c5f19d4c 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -271,7 +271,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
for_each_pci_msi_entry(entry, dev) {
virq = irq_create_direct_mapping(msic->irq_domain);
- if (virq == NO_IRQ) {
+ if (!virq) {
dev_warn(&dev->dev,
"axon_msi: virq allocation failed!\n");
return -1;
@@ -293,7 +293,7 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n");
for_each_pci_msi_entry(entry, dev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
irq_set_msi_desc(entry->irq, NULL);
@@ -375,7 +375,7 @@ static int axon_msi_probe(struct platform_device *device)
}
virq = irq_of_parse_and_map(dn, 0);
- if (virq == NO_IRQ) {
+ if (!virq) {
printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
dn->full_name);
goto out_free_fifo;
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 1428d583c238..b926438d73af 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -189,7 +189,7 @@ static struct device_node *cbe_get_be_node(int cpu_id)
return NULL;
}
-void __init cbe_fill_regs_map(struct cbe_regs_map *map)
+static void __init cbe_fill_regs_map(struct cbe_regs_map *map)
{
if(map->be_node) {
struct device_node *be, *np;
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 9f609fc8d331..a6bbbaba14a3 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -123,7 +123,7 @@ static void iic_ioexc_cascade(struct irq_desc *desc)
unsigned int cirq =
irq_linear_revmap(iic_host,
base | cascade);
- if (cirq != NO_IRQ)
+ if (cirq)
generic_handle_irq(cirq);
}
/* post-ack level interrupts */
@@ -153,10 +153,10 @@ static unsigned int iic_get_irq(void)
*(unsigned long *) &pending =
in_be64((u64 __iomem *) &iic->regs->pending_destr);
if (!(pending.flags & CBE_IIC_IRQ_VALID))
- return NO_IRQ;
+ return 0;
virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending));
- if (virq == NO_IRQ)
- return NO_IRQ;
+ if (!virq)
+ return 0;
iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
BUG_ON(iic->eoi_ptr > 15);
return virq;
@@ -187,18 +187,12 @@ void iic_message_pass(int cpu, int msg)
out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);
}
-struct irq_domain *iic_get_irq_host(int node)
-{
- return iic_host;
-}
-EXPORT_SYMBOL_GPL(iic_get_irq_host);
-
static void iic_request_ipi(int msg)
{
int virq;
virq = irq_create_mapping(iic_host, iic_msg_to_irq(msg));
- if (virq == NO_IRQ) {
+ if (!virq) {
printk(KERN_ERR
"iic: failed to map IPI %s\n", smp_ipi_name[msg]);
return;
@@ -353,7 +347,7 @@ static int __init setup_iic(void)
cascade |= 1 << IIC_IRQ_CLASS_SHIFT;
cascade |= IIC_UNIT_IIC;
cascade = irq_create_mapping(iic_host, cascade);
- if (cascade == NO_IRQ)
+ if (!cascade)
continue;
/*
* irq_data is a generic pointer that gets passed back
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index f7d1a4953ea0..7ff51f96a00e 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -411,7 +411,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu)
virq = irq_create_mapping(NULL,
IIC_IRQ_IOEX_ATI | (iommu->nid << IIC_IRQ_NODE_SHIFT));
- BUG_ON(virq == NO_IRQ);
+ BUG_ON(!virq);
ret = request_irq(virq, ioc_interrupt, 0, iommu->name, iommu);
BUG_ON(ret);
@@ -651,7 +651,7 @@ static int dma_fixed_dma_supported(struct device *dev, u64 mask)
static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask);
-struct dma_map_ops dma_iommu_fixed_ops = {
+static struct dma_map_ops dma_iommu_fixed_ops = {
.alloc = dma_fixed_alloc_coherent,
.free = dma_fixed_free_coherent,
.map_sg = dma_fixed_map_sg,
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c
index 348a27b12512..e3ad0c38f017 100644
--- a/arch/powerpc/platforms/cell/pmu.c
+++ b/arch/powerpc/platforms/cell/pmu.c
@@ -385,7 +385,7 @@ static int __init cbe_init_pm_irq(void)
for_each_online_node(node) {
irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
(node << IIC_IRQ_NODE_SHIFT));
- if (irq == NO_IRQ) {
+ if (!irq) {
printk("ERROR: Unable to allocate irq for node %d\n",
node);
return -EINVAL;
@@ -412,7 +412,7 @@ void cbe_sync_irq(int node)
IIC_IRQ_IOEX_PMI
| (node << IIC_IRQ_NODE_SHIFT));
- if (irq == NO_IRQ) {
+ if (!irq) {
printk(KERN_WARNING "ERROR, unable to get existing irq %d " \
"for node %d\n", irq, node);
return;
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 2d4f60c0119a..460ab392f0e7 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -298,7 +298,7 @@ int cbe_sysreset_hack(void)
}
#endif /* CONFIG_PPC_IBM_CELL_RESETBUTTON */
-int __init cbe_ptcal_init(void)
+static int __init cbe_ptcal_init(void)
{
int ret;
ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index d06dcac66fcb..ff924af00e78 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -207,11 +207,11 @@ static void spider_irq_cascade(struct irq_desc *desc)
cs = in_be32(pic->regs + TIR_CS) >> 24;
if (cs == SPIDER_IRQ_INVALID)
- virq = NO_IRQ;
+ virq = 0;
else
virq = irq_linear_revmap(pic->host, cs);
- if (virq != NO_IRQ)
+ if (virq)
generic_handle_irq(virq);
chip->irq_eoi(&desc->irq_data);
@@ -245,19 +245,19 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
/* Now do the horrible hacks */
tmp = of_get_property(of_node, "#interrupt-cells", NULL);
if (tmp == NULL)
- return NO_IRQ;
+ return 0;
intsize = *tmp;
imap = of_get_property(of_node, "interrupt-map", &imaplen);
if (imap == NULL || imaplen < (intsize + 1))
- return NO_IRQ;
+ return 0;
iic = of_find_node_by_phandle(imap[intsize]);
if (iic == NULL)
- return NO_IRQ;
+ return 0;
imap += intsize + 1;
tmp = of_get_property(iic, "#interrupt-cells", NULL);
if (tmp == NULL) {
of_node_put(iic);
- return NO_IRQ;
+ return 0;
}
intsize = *tmp;
/* Assume unit is last entry of interrupt specifier */
@@ -266,7 +266,7 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL);
if (tmp == NULL) {
of_node_put(iic);
- return NO_IRQ;
+ return 0;
}
/* ugly as hell but works for now */
pic->node_id = (*tmp) >> 1;
@@ -281,7 +281,7 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
(pic->node_id << IIC_IRQ_NODE_SHIFT) |
(2 << IIC_IRQ_CLASS_SHIFT) |
unit);
- if (virq == NO_IRQ)
+ if (!virq)
printk(KERN_ERR "spider_pic: failed to map cascade !");
return virq;
}
@@ -318,7 +318,7 @@ static void __init spider_init_one(struct device_node *of_node, int chip,
/* Hook up the cascade interrupt to the iic and nodeid */
virq = spider_find_cascade_and_node(pic);
- if (virq == NO_IRQ)
+ if (!virq)
return;
irq_set_handler_data(virq, pic);
irq_set_chained_handler(virq, spider_irq_cascade);
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index bb4a8e07c229..e84d8fbc2e21 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -402,7 +402,7 @@ static int spu_request_irqs(struct spu *spu)
{
int ret = 0;
- if (spu->irqs[0] != NO_IRQ) {
+ if (spu->irqs[0]) {
snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0",
spu->number);
ret = request_irq(spu->irqs[0], spu_irq_class_0,
@@ -410,7 +410,7 @@ static int spu_request_irqs(struct spu *spu)
if (ret)
goto bail0;
}
- if (spu->irqs[1] != NO_IRQ) {
+ if (spu->irqs[1]) {
snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1",
spu->number);
ret = request_irq(spu->irqs[1], spu_irq_class_1,
@@ -418,7 +418,7 @@ static int spu_request_irqs(struct spu *spu)
if (ret)
goto bail1;
}
- if (spu->irqs[2] != NO_IRQ) {
+ if (spu->irqs[2]) {
snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2",
spu->number);
ret = request_irq(spu->irqs[2], spu_irq_class_2,
@@ -429,10 +429,10 @@ static int spu_request_irqs(struct spu *spu)
return 0;
bail2:
- if (spu->irqs[1] != NO_IRQ)
+ if (spu->irqs[1])
free_irq(spu->irqs[1], spu);
bail1:
- if (spu->irqs[0] != NO_IRQ)
+ if (spu->irqs[0])
free_irq(spu->irqs[0], spu);
bail0:
return ret;
@@ -440,11 +440,11 @@ bail0:
static void spu_free_irqs(struct spu *spu)
{
- if (spu->irqs[0] != NO_IRQ)
+ if (spu->irqs[0])
free_irq(spu->irqs[0], spu);
- if (spu->irqs[1] != NO_IRQ)
+ if (spu->irqs[1])
free_irq(spu->irqs[1], spu);
- if (spu->irqs[2] != NO_IRQ)
+ if (spu->irqs[2])
free_irq(spu->irqs[2], spu);
}
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
index 21b4bfb97200..672d310dcf14 100644
--- a/arch/powerpc/platforms/cell/spu_manage.c
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -105,7 +105,10 @@ static int __init spu_map_interrupts_old(struct spu *spu,
spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
/* Right now, we only fail if class 2 failed */
- return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
+ if (!spu->irqs[2])
+ return -EINVAL;
+
+ return 0;
}
static void __iomem * __init spu_map_prop_old(struct spu *spu,
@@ -191,7 +194,7 @@ static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
pr_debug(" irq %d no 0x%x on %s\n", i, oirq.args[0],
oirq.np->full_name);
spu->irqs[i] = irq_create_of_mapping(&oirq);
- if (spu->irqs[i] == NO_IRQ) {
+ if (!spu->irqs[i]) {
pr_debug("spu_new: failed to map it !\n");
goto err;
}
@@ -202,7 +205,7 @@ err:
pr_debug("failed to map irq %x for spu %s\n", *oirq.args,
spu->name);
for (; i >= 0; i--) {
- if (spu->irqs[i] != NO_IRQ)
+ if (spu->irqs[i])
irq_dispose_mapping(spu->irqs[i]);
}
return ret;
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 2975754c65ea..5364d4a54249 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -103,7 +103,7 @@ spufs_new_inode(struct super_block *sb, umode_t mode)
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
out:
return inode;
}
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index bfb300633dfe..0ce1b45f02a8 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -368,7 +368,7 @@ static void chrp_8259_cascade(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
@@ -514,7 +514,7 @@ static void __init chrp_find_8259(void)
}
if (chrp_mpic != NULL) {
cascade_irq = irq_of_parse_and_map(pic, 0);
- if (cascade_irq == NO_IRQ)
+ if (!cascade_irq)
printk(KERN_ERR "i8259: failed to map cascade irq\n");
else
irq_set_chained_handler(cascade_irq,
diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
index b7866e01483d..ade83829d5e8 100644
--- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
@@ -181,7 +181,7 @@ unsigned int flipper_pic_get_irq(void)
irq_status = in_be32(io_base + FLIPPER_ICR) &
in_be32(io_base + FLIPPER_IMR);
if (irq_status == 0)
- return NO_IRQ; /* no more IRQs pending */
+ return 0; /* no more IRQs pending */
irq = __ffs(irq_status);
return irq_linear_revmap(flipper_irq_host, irq);
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
index 9b7975706bfc..89c54de88b7a 100644
--- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -114,7 +114,7 @@ static unsigned int __hlwd_pic_get_irq(struct irq_domain *h)
irq_status = in_be32(io_base + HW_BROADWAY_ICR) &
in_be32(io_base + HW_BROADWAY_IMR);
if (irq_status == 0)
- return NO_IRQ; /* no more IRQs pending */
+ return 0; /* no more IRQs pending */
irq = __ffs(irq_status);
return irq_linear_revmap(h, irq);
@@ -131,7 +131,7 @@ static void hlwd_pic_irq_cascade(struct irq_desc *desc)
raw_spin_unlock(&desc->lock);
virq = __hlwd_pic_get_irq(irq_domain);
- if (virq != NO_IRQ)
+ if (virq)
generic_handle_irq(virq);
else
pr_err("spurious interrupt!\n");
diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c
index ed7321d6772e..8e3590941960 100644
--- a/arch/powerpc/platforms/embedded6xx/mvme5100.c
+++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c
@@ -47,7 +47,7 @@ static void mvme5100_8259_cascade(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
@@ -84,7 +84,7 @@ static void __init mvme5100_pic_init(void)
}
cirq = irq_of_parse_and_map(cp, 0);
- if (cirq == NO_IRQ) {
+ if (!cirq) {
pr_warn("mvme5100_pic_init: no cascade interrupt?\n");
return;
}
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index a2f89e6326ce..a0589aac4163 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -552,7 +552,7 @@ void maple_pci_irq_fixup(struct pci_dev *dev)
pci_bus_to_host(dev->bus) == u4_pcie) {
printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
dev->irq = irq_create_mapping(NULL, 1);
- if (dev->irq != NO_IRQ)
+ if (dev->irq)
irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
}
@@ -562,7 +562,7 @@ void maple_pci_irq_fixup(struct pci_dev *dev)
if (dev->vendor == PCI_VENDOR_ID_AMD &&
dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
(dev->class & 5) != 5) {
- dev->irq = NO_IRQ;
+ dev->irq = 0;
}
DBG(" <- maple_pci_irq_fixup\n");
@@ -648,7 +648,7 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
return defirq;
}
irq = irq_of_parse_and_map(np, channel & 0x1);
- if (irq == NO_IRQ) {
+ if (!irq) {
printk("Failed to map onboard IDE interrupt for channel %d\n",
channel);
return defirq;
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 3c30c7a4534d..b7f937563827 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -156,7 +156,7 @@ static void __noreturn maple_halt(void)
}
#ifdef CONFIG_SMP
-struct smp_ops_t maple_smp_ops = {
+static struct smp_ops_t maple_smp_ops = {
.probe = smp_mpic_probe,
.message_pass = smp_mpic_message_pass,
.kick_cpu = smp_generic_kick_cpu,
@@ -176,7 +176,7 @@ static void __init maple_use_rtas_reboot_and_halt_if_present(void)
}
}
-void __init maple_setup_arch(void)
+static void __init maple_setup_arch(void)
{
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000;
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
index 00d4b28cbb60..c7f1dbe94de7 100644
--- a/arch/powerpc/platforms/pasemi/Kconfig
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -14,6 +14,16 @@ config PPC_PASEMI
menu "PA Semi PWRficient options"
depends on PPC_PASEMI
+config PPC_PASEMI_NEMO
+ bool "Nemo motherboard Support"
+ depends on PPC_PASEMI
+ select PPC_I8259
+ help
+ This option enables support for the 'Nemo' motherboard
+ used in A-Eons's Amigaone X1000. This consists of some
+ device tree patches and workarounds for the SB600 South
+ Bridge that provides SATA/USB/Audio.
+
config PPC_PASEMI_IOMMU
bool "PA Semi IOMMU support"
depends on PPC_PASEMI
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
index ddf635000c6b..c23e60959aa8 100644
--- a/arch/powerpc/platforms/pasemi/gpio_mdio.c
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -306,7 +306,7 @@ static struct platform_driver gpio_mdio_driver =
},
};
-int gpio_mdio_init(void)
+static int gpio_mdio_init(void)
{
struct device_node *np;
@@ -326,7 +326,7 @@ int gpio_mdio_init(void)
}
module_init(gpio_mdio_init);
-void gpio_mdio_exit(void)
+static void gpio_mdio_exit(void)
{
platform_driver_unregister(&gpio_mdio_driver);
if (gpio_regs)
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
index c61667e8bb06..e74adc4e7fd8 100644
--- a/arch/powerpc/platforms/pasemi/iommu.c
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -199,7 +199,7 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)
set_iommu_table_base(&dev->dev, &iommu_table_iobmap);
}
-int __init iob_init(struct device_node *dn)
+static int __init iob_init(struct device_node *dn)
{
unsigned long tmp;
u32 regword;
diff --git a/arch/powerpc/platforms/pasemi/misc.c b/arch/powerpc/platforms/pasemi/misc.c
index e0ab299763c1..8571e7bf78b6 100644
--- a/arch/powerpc/platforms/pasemi/misc.c
+++ b/arch/powerpc/platforms/pasemi/misc.c
@@ -76,7 +76,7 @@ static int __init pasemi_register_i2c_devices(void)
}
info.irq = irq_of_parse_and_map(node, 0);
- if (info.irq == NO_IRQ)
+ if (!info.irq)
info.irq = -1;
if (find_i2c_driver(node, &info) < 0)
diff --git a/arch/powerpc/platforms/pasemi/msi.c b/arch/powerpc/platforms/pasemi/msi.c
index d9af76342d99..d9cd510c8865 100644
--- a/arch/powerpc/platforms/pasemi/msi.c
+++ b/arch/powerpc/platforms/pasemi/msi.c
@@ -68,7 +68,7 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev);
for_each_pci_msi_entry(entry, pdev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
hwirq = virq_to_hw(entry->irq);
@@ -109,7 +109,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
}
virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n",
hwirq);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq,
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index e86c1bd08f1f..3182400cf48f 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -59,7 +59,7 @@ struct mce_regs {
static struct mce_regs mce_regs[MAX_MCE_REGS];
static int num_mce_regs;
-static int nmi_virq = NO_IRQ;
+static int nmi_virq = 0;
static void __noreturn pas_restart(char *cmd)
@@ -105,7 +105,7 @@ static void pas_take_timebase(void)
arch_spin_unlock(&timebase_lock);
}
-struct smp_ops_t pas_smp_ops = {
+static struct smp_ops_t pas_smp_ops = {
.probe = smp_mpic_probe,
.message_pass = smp_mpic_message_pass,
.kick_cpu = smp_generic_kick_cpu,
@@ -115,7 +115,7 @@ struct smp_ops_t pas_smp_ops = {
};
#endif /* CONFIG_SMP */
-void __init pas_setup_arch(void)
+static void __init pas_setup_arch(void)
{
#ifdef CONFIG_SMP
/* Setup SMP callback */
@@ -264,7 +264,7 @@ static int pas_machine_check_handler(struct pt_regs *regs)
srr0 = regs->nip;
srr1 = regs->msr;
- if (nmi_virq != NO_IRQ && mpic_get_mcirq() == nmi_virq) {
+ if (nmi_virq && mpic_get_mcirq() == nmi_virq) {
printk(KERN_ERR "NMI delivered\n");
debugger(regs);
mpic_end_irq(irq_get_irq_data(nmi_virq));
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 6d6f277477aa..c8c217b7dd33 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -401,7 +401,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
{
struct pmac_i2c_host_kw *host = bus->hostdata;
u8 mode_reg = host->speed;
- int use_irq = host->irq != NO_IRQ && !bus->polled;
+ int use_irq = host->irq && !bus->polled;
/* Setup mode & subaddress if any */
switch(bus->mode) {
@@ -535,7 +535,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
break;
}
host->irq = irq_of_parse_and_map(np, 0);
- if (host->irq == NO_IRQ)
+ if (!host->irq)
printk(KERN_WARNING
"low_i2c: Failed to map interrupt for %s\n",
np->full_name);
@@ -557,7 +557,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
*/
if (request_irq(host->irq, kw_i2c_irq, IRQF_NO_SUSPEND,
"keywest i2c", host))
- host->irq = NO_IRQ;
+ host->irq = 0;
printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
*addrp, host->irq, np->full_name);
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index e49d07f3d542..459138ed4571 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -26,7 +26,7 @@ static irqreturn_t macio_gpio_irq(int irq, void *data)
static int macio_do_gpio_irq_enable(struct pmf_function *func)
{
unsigned int irq = irq_of_parse_and_map(func->node, 0);
- if (irq == NO_IRQ)
+ if (!irq)
return -EINVAL;
return request_irq(irq, macio_gpio_irq, 0, func->node->name, func);
}
@@ -34,7 +34,7 @@ static int macio_do_gpio_irq_enable(struct pmf_function *func)
static int macio_do_gpio_irq_disable(struct pmf_function *func)
{
unsigned int irq = irq_of_parse_and_map(func->node, 0);
- if (irq == NO_IRQ)
+ if (!irq)
return -EINVAL;
free_irq(irq, func);
return 0;
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
index 43075081721f..695e8c4d4224 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -804,7 +804,7 @@ void pmf_unregister_driver(struct device_node *np)
}
EXPORT_SYMBOL_GPL(pmf_unregister_driver);
-struct pmf_function *__pmf_find_function(struct device_node *target,
+static struct pmf_function *__pmf_find_function(struct device_node *target,
const char *name, u32 flags)
{
struct device_node *actor = of_node_get(target);
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 981546345033..f5f9ad7c3398 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -251,7 +251,7 @@ static unsigned int pmac_pic_get_irq(void)
}
raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
if (unlikely(irq < 0))
- return NO_IRQ;
+ return 0;
return irq_linear_revmap(pmac_pic_host, irq);
}
@@ -389,7 +389,7 @@ static void __init pmac_pic_probe_oldstyle(void)
out_le32(&pmac_irq_hw[i]->enable, 0);
/* Hookup cascade irq */
- if (slave && pmac_irq_cascade != NO_IRQ)
+ if (slave && pmac_irq_cascade)
setup_irq(pmac_irq_cascade, &gatwick_cascade_action);
printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
@@ -444,7 +444,7 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
pswitch = of_find_node_by_name(NULL, "programmer-switch");
if (pswitch) {
nmi_irq = irq_of_parse_and_map(pswitch, 0);
- if (nmi_irq != NO_IRQ) {
+ if (nmi_irq) {
mpic_irq_set_priority(nmi_irq, 9);
setup_irq(nmi_irq, &xmon_action);
}
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 366e4f510fcf..c9eb7d6540ea 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -979,7 +979,7 @@ static void pmac_cpu_die(void)
#endif /* CONFIG_HOTPLUG_CPU */
/* Core99 Macs (dual G4s and G5s) */
-struct smp_ops_t core99_smp_ops = {
+static struct smp_ops_t core99_smp_ops = {
.message_pass = smp_mpic_message_pass,
.probe = smp_core99_probe,
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index 86544ea85dc3..2354ea51e871 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -763,7 +763,8 @@ int pnv_eeh_phb_reset(struct pci_controller *hose, int option)
* reset followed by hot reset on root bus. So we also
* need the PCI bus settlement delay.
*/
- rc = pnv_eeh_poll(phb->opal_id);
+ if (rc > 0)
+ rc = pnv_eeh_poll(phb->opal_id);
if (option == EEH_RESET_DEACTIVATE) {
if (system_state < SYSTEM_RUNNING)
udelay(1000 * EEH_PE_RST_SETTLE_TIME);
@@ -806,7 +807,8 @@ static int pnv_eeh_root_reset(struct pci_controller *hose, int option)
goto out;
/* Poll state of the PHB until the request is done */
- rc = pnv_eeh_poll(phb->opal_id);
+ if (rc > 0)
+ rc = pnv_eeh_poll(phb->opal_id);
if (option == EEH_RESET_DEACTIVATE)
msleep(EEH_PE_RST_SETTLE_TIME);
out:
@@ -1090,10 +1092,16 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option)
}
}
- bus = eeh_pe_bus_get(pe);
if (pe->type & EEH_PE_VF)
return pnv_eeh_reset_vf_pe(pe, option);
+ bus = eeh_pe_bus_get(pe);
+ if (!bus) {
+ pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n",
+ __func__, pe->phb->global_number, pe->addr);
+ return -EIO;
+ }
+
if (pci_is_root_bus(bus) ||
pci_is_root_bus(bus->parent))
return pnv_eeh_root_reset(hose, option);
@@ -1306,7 +1314,7 @@ static void pnv_eeh_get_and_dump_hub_diag(struct pci_controller *hose)
return;
}
- switch (data->type) {
+ switch (be16_to_cpu(data->type)) {
case OPAL_P7IOC_DIAG_TYPE_RGC:
pr_info("P7IOC diag-data for RGC\n\n");
pnv_eeh_dump_hub_diag_common(data);
@@ -1538,7 +1546,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
/* Try best to clear it */
opal_pci_eeh_freeze_clear(phb->opal_id,
- frozen_pe_no,
+ be64_to_cpu(frozen_pe_no),
OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
ret = EEH_NEXT_ERR_NONE;
} else if ((*pe)->state & EEH_PE_ISOLATED ||
diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
index 00e1a0195c78..aec85e778028 100644
--- a/arch/powerpc/platforms/powernv/npu-dma.c
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -115,7 +115,7 @@ static u64 dma_npu_get_required_mask(struct device *dev)
return 0;
}
-struct dma_map_ops dma_npu_ops = {
+static struct dma_map_ops dma_npu_ops = {
.map_page = dma_npu_map_page,
.map_sg = dma_npu_map_sg,
.alloc = dma_npu_alloc,
diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c
index ed8bba68a162..998316bf2dad 100644
--- a/arch/powerpc/platforms/powernv/opal-irqchip.c
+++ b/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -222,7 +222,7 @@ int __init opal_event_init(void)
/* Get hardware and virtual IRQ */
irq = be32_to_cpup(irqs);
virq = irq_create_mapping(NULL, irq);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_warn("Failed to map irq 0x%x\n", irq);
continue;
}
@@ -260,7 +260,7 @@ machine_arch_initcall(powernv, opal_event_init);
int opal_event_request(unsigned int opal_event_nr)
{
if (WARN_ON_ONCE(!opal_event_irqchip.domain))
- return NO_IRQ;
+ return 0;
return irq_create_mapping(opal_event_irqchip.domain, opal_event_nr);
}
diff --git a/arch/powerpc/platforms/powernv/pci-cxl.c b/arch/powerpc/platforms/powernv/pci-cxl.c
index 1349a099c74c..94498a04558b 100644
--- a/arch/powerpc/platforms/powernv/pci-cxl.c
+++ b/arch/powerpc/platforms/powernv/pci-cxl.c
@@ -344,7 +344,7 @@ int pnv_cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return (hwirq ? hwirq : -ENOMEM);
virq = irq_create_mapping(NULL, hwirq);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_warn("%s: Failed to map cxl mode MSI to linux irq\n",
pci_name(pdev));
return -ENOMEM;
@@ -374,7 +374,7 @@ void pnv_cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev)
return;
for_each_pci_msi_entry(entry, pdev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
hwirq = virq_to_hw(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index d314eccd075b..d4b33dd2d9e7 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -133,9 +133,22 @@ static inline bool pnv_pci_is_m64_flags(unsigned long resource_flags)
static struct pnv_ioda_pe *pnv_ioda_init_pe(struct pnv_phb *phb, int pe_no)
{
+ s64 rc;
+
phb->ioda.pe_array[pe_no].phb = phb;
phb->ioda.pe_array[pe_no].pe_number = pe_no;
+ /*
+ * Clear the PE frozen state as it might be put into frozen state
+ * in the last PCI remove path. It's not harmful to do so when the
+ * PE is already in unfrozen state.
+ */
+ rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
+ OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+ if (rc != OPAL_SUCCESS)
+ pr_warn("%s: Error %lld unfreezing PHB#%d-PE#%d\n",
+ __func__, rc, phb->hose->global_number, pe_no);
+
return &phb->ioda.pe_array[pe_no];
}
@@ -417,7 +430,7 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
struct device_node *dn = hose->dn;
struct resource *res;
u32 m64_range[2], i;
- const u32 *r;
+ const __be32 *r;
u64 pci_addr;
if (phb->type != PNV_PHB_IODA1 && phb->type != PNV_PHB_IODA2) {
@@ -3049,6 +3062,38 @@ static void pnv_ioda_setup_pe_seg(struct pnv_ioda_pe *pe)
}
}
+#ifdef CONFIG_DEBUG_FS
+static int pnv_pci_diag_data_set(void *data, u64 val)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ s64 ret;
+
+ if (val != 1ULL)
+ return -EINVAL;
+
+ hose = (struct pci_controller *)data;
+ if (!hose || !hose->private_data)
+ return -ENODEV;
+
+ phb = hose->private_data;
+
+ /* Retrieve the diag data from firmware */
+ ret = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+ PNV_PCI_DIAG_BUF_SIZE);
+ if (ret != OPAL_SUCCESS)
+ return -EIO;
+
+ /* Print the diag data to the kernel log */
+ pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(pnv_pci_diag_data_fops, NULL,
+ pnv_pci_diag_data_set, "%llu\n");
+
+#endif /* CONFIG_DEBUG_FS */
+
static void pnv_pci_ioda_create_dbgfs(void)
{
#ifdef CONFIG_DEBUG_FS
@@ -3064,9 +3109,14 @@ static void pnv_pci_ioda_create_dbgfs(void)
sprintf(name, "PCI%04x", hose->global_number);
phb->dbgfs = debugfs_create_dir(name, powerpc_debugfs_root);
- if (!phb->dbgfs)
+ if (!phb->dbgfs) {
pr_warning("%s: Error on creating debugfs on PHB#%x\n",
__func__, hose->global_number);
+ continue;
+ }
+
+ debugfs_create_file("dump_diag_regs", 0200, phb->dbgfs, hose,
+ &pnv_pci_diag_data_fops);
}
#endif /* CONFIG_DEBUG_FS */
}
@@ -3779,10 +3829,11 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
if (rc)
pr_warning(" OPAL Error %ld performing IODA table reset !\n", rc);
- /* If we're running in kdump kerenl, the previous kerenl never
+ /*
+ * If we're running in kdump kernel, the previous kernel 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.
+ * transactions from previous kernel.
*/
if (is_kdump_kernel()) {
pr_info(" Issue PHB reset ...\n");
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index a21d831c1114..db7b8020f68e 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -186,7 +186,7 @@ int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return -ENOSPC;
}
virq = irq_create_mapping(NULL, phb->msi_base + hwirq);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_warn("%s: Failed to map MSI to linux irq\n",
pci_name(pdev));
msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 1);
@@ -217,7 +217,7 @@ void pnv_teardown_msi_irqs(struct pci_dev *pdev)
return;
for_each_pci_msi_entry(entry, pdev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
hwirq = virq_to_hw(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
@@ -309,8 +309,8 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
be64_to_cpu(data->dma1ErrorLog1));
for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
- if ((data->pestA[i] >> 63) == 0 &&
- (data->pestB[i] >> 63) == 0)
+ if ((be64_to_cpu(data->pestA[i]) >> 63) == 0 &&
+ (be64_to_cpu(data->pestB[i]) >> 63) == 0)
continue;
pr_info("PE[%3d] A/B: %016llx %016llx\n",
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c
index 57caaf11a83f..e48462447ff0 100644
--- a/arch/powerpc/platforms/ps3/device-init.c
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -62,7 +62,7 @@ static int __init ps3_register_lpm_devices(void)
&dev->lpm.rights);
if (result) {
- pr_debug("%s:%d: ps3_repository_read_lpm_privleges failed \n",
+ pr_debug("%s:%d: ps3_repository_read_lpm_privileges failed\n",
__func__, __LINE__);
goto fail_read_repo;
}
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index b831638e6f4a..98f8c3611133 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -192,7 +192,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
*virq = irq_create_mapping(NULL, outlet);
- if (*virq == NO_IRQ) {
+ if (!*virq) {
FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n",
__func__, __LINE__, outlet);
result = -ENOMEM;
@@ -339,7 +339,7 @@ int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
if (result) {
FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n",
__func__, __LINE__, ps3_result(result));
- *virq = NO_IRQ;
+ *virq = 0;
return result;
}
@@ -418,7 +418,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
" failed: %s\n", __func__, __LINE__,
ps3_result(result));
ps3_event_receive_port_destroy(*virq);
- *virq = NO_IRQ;
+ *virq = 0;
return result;
}
@@ -724,12 +724,12 @@ static unsigned int ps3_get_irq(void)
asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
plug &= 0x3f;
- if (unlikely(plug == NO_IRQ)) {
+ if (unlikely(!plug)) {
DBG("%s:%d: no plug found: thread_id %llu\n", __func__,
__LINE__, pd->thread_id);
dump_bmp(&per_cpu(ps3_private, 0));
dump_bmp(&per_cpu(ps3_private, 1));
- return NO_IRQ;
+ return 0;
}
#if defined(DEBUG)
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 3c7707af3384..60154d08debf 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -91,7 +91,7 @@ static void __init ps3_smp_probe(void)
result = smp_request_message_ipi(virqs[i], i);
if (result)
- virqs[i] = NO_IRQ;
+ virqs[i] = 0;
else
ps3_register_ipi_irq(cpu, virqs[i]);
}
@@ -112,7 +112,7 @@ void ps3_smp_cleanup_cpu(int cpu)
for (i = 0; i < MSG_COUNT; i++) {
/* Can't call free_irq from interrupt context. */
ps3_event_receive_port_destroy(virqs[i]);
- virqs[i] = NO_IRQ;
+ virqs[i] = 0;
}
DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 492b2575e0d2..b54850845466 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -284,7 +284,7 @@ fail_alloc_2:
fail_alloc_1:
ps3_spe_irq_destroy(spu->irqs[0]);
fail_alloc_0:
- spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
+ spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = 0;
return result;
}
@@ -334,7 +334,7 @@ static int ps3_destroy_spu(struct spu *spu)
ps3_spe_irq_destroy(spu->irqs[1]);
ps3_spe_irq_destroy(spu->irqs[0]);
- spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
+ spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = 0;
spu_unmap(spu);
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 4748124faa10..423e450efe07 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -27,7 +27,7 @@
#include <asm/uaccess.h>
#include <asm/rtas.h>
-struct workqueue_struct *pseries_hp_wq;
+static struct workqueue_struct *pseries_hp_wq;
struct pseries_hp_work {
struct work_struct work;
@@ -377,7 +377,7 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
return rc;
}
-void pseries_hp_work_fn(struct work_struct *work)
+static void pseries_hp_work_fn(struct work_struct *work)
{
struct pseries_hp_work *hp_work =
container_of(work, struct pseries_hp_work, work);
@@ -413,6 +413,7 @@ void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog,
queue_work(pseries_hp_wq, (struct work_struct *)work);
} else {
*rc = -ENOMEM;
+ kfree(hp_errlog_copy);
complete(hotplug_done);
}
}
diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c
index a6ddca833119..32187dc76730 100644
--- a/arch/powerpc/platforms/pseries/event_sources.c
+++ b/arch/powerpc/platforms/pseries/event_sources.c
@@ -34,7 +34,7 @@ void request_event_sources_irqs(struct device_node *np,
if (count > 15)
break;
virqs[count] = irq_create_of_mapping(&oirq);
- if (virqs[count] == NO_IRQ) {
+ if (!virqs[count]) {
pr_err("event-sources: Unable to allocate "
"interrupt number for %s\n",
np->full_name);
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index 543a6386f3eb..326ef0dd6038 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -119,7 +119,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
struct msi_desc *entry;
for_each_pci_msi_entry(entry, pdev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
irq_set_msi_desc(entry->irq, NULL);
@@ -471,7 +471,7 @@ again:
virq = irq_create_mapping(NULL, hwirq);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
return -ENOSPC;
}
@@ -490,7 +490,7 @@ again:
static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
{
/* No LSI -> leave MSIs (if any) configured */
- if (pdev->irq == NO_IRQ) {
+ if (!pdev->irq) {
dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n");
return;
}
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c
index b502ab61aafa..7d28cabf1206 100644
--- a/arch/powerpc/platforms/pseries/scanlog.c
+++ b/arch/powerpc/platforms/pseries/scanlog.c
@@ -156,7 +156,7 @@ static int scanlog_release(struct inode * inode, struct file * file)
return 0;
}
-const struct file_operations scanlog_fops = {
+static const struct file_operations scanlog_fops = {
.owner = THIS_MODULE,
.read = scanlog_read,
.write = scanlog_write,
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index a39d20e8623d..97aa3f332f24 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -114,7 +114,7 @@ static void pseries_8259_cascade(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
@@ -141,7 +141,7 @@ static void __init pseries_setup_i8259_cascade(void)
}
cascade = irq_of_parse_and_map(found, 0);
- if (cascade == NO_IRQ) {
+ if (!cascade) {
printk(KERN_ERR "pic: failed to map cascade interrupt");
return;
}
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 9144204442eb..ada29eaed6e2 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -240,7 +240,7 @@ static int axon_ram_probe(struct platform_device *device)
device_add_disk(&device->dev, bank->disk);
bank->irq_id = irq_of_parse_and_map(device->dev.of_node, 0);
- if (bank->irq_id == NO_IRQ) {
+ if (!bank->irq_id) {
dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
rc = -EFAULT;
goto failed;
@@ -250,7 +250,7 @@ static int axon_ram_probe(struct platform_device *device)
AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
if (rc != 0) {
dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
- bank->irq_id = NO_IRQ;
+ bank->irq_id = 0;
rc = -EFAULT;
goto failed;
}
@@ -268,7 +268,7 @@ static int axon_ram_probe(struct platform_device *device)
failed:
if (bank != NULL) {
- if (bank->irq_id != NO_IRQ)
+ if (bank->irq_id)
free_irq(bank->irq_id, device);
if (bank->disk != NULL) {
if (bank->disk->major > 0)
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 81d49476c47e..3c0eb9b25535 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -132,7 +132,7 @@ unsigned int cpm_pic_init(void)
{
struct device_node *np = NULL;
struct resource res;
- unsigned int sirq = NO_IRQ, hwirq, eirq;
+ unsigned int sirq = 0, hwirq, eirq;
int ret;
pr_debug("cpm_pic_init\n");
@@ -154,7 +154,7 @@ unsigned int cpm_pic_init(void)
goto end;
sirq = irq_of_parse_and_map(np, 0);
- if (sirq == NO_IRQ)
+ if (!sirq)
goto end;
/* Initialize the CPM interrupt controller. */
@@ -168,7 +168,7 @@ unsigned int cpm_pic_init(void)
cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);
if (cpm_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
- sirq = NO_IRQ;
+ sirq = 0;
goto end;
}
@@ -182,7 +182,7 @@ unsigned int cpm_pic_init(void)
}
eirq = irq_of_parse_and_map(np, 0);
- if (eirq == NO_IRQ)
+ if (!eirq)
goto end;
if (setup_irq(eirq, &cpm_error_irqaction))
diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c
index bffcc7a486a1..48866e6c1efb 100644
--- a/arch/powerpc/sysdev/ehv_pic.c
+++ b/arch/powerpc/sysdev/ehv_pic.c
@@ -155,7 +155,7 @@ static struct irq_chip ehv_pic_direct_eoi_irq_chip = {
.irq_set_type = ehv_pic_set_irq_type,
};
-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+/* Return an interrupt vector or 0 if no interrupt is pending. */
unsigned int ehv_pic_get_irq(void)
{
int irq;
@@ -168,7 +168,7 @@ unsigned int ehv_pic_get_irq(void)
ev_int_iack(0, &irq); /* legacy mode */
if (irq == 0xFFFF) /* 0xFFFF --> no irq is pending */
- return NO_IRQ;
+ return 0;
/*
* this will also setup revmap[] in the slow path for the first
diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c
index 06ac3c61b3d0..a6f0b96ce2c9 100644
--- a/arch/powerpc/sysdev/fsl_gtm.c
+++ b/arch/powerpc/sysdev/fsl_gtm.c
@@ -406,7 +406,7 @@ static int __init fsl_gtm_init(void)
unsigned int irq;
irq = irq_of_parse_and_map(np, i);
- if (irq == NO_IRQ) {
+ if (!irq) {
pr_err("%s: not enough interrupts specified\n",
np->full_name);
goto err;
diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c
index b83f32562a37..488ec453038a 100644
--- a/arch/powerpc/sysdev/fsl_mpic_err.c
+++ b/arch/powerpc/sysdev/fsl_mpic_err.c
@@ -115,8 +115,8 @@ static irqreturn_t fsl_error_int_handler(int irq, void *data)
errint = __builtin_clz(eisr);
cascade_irq = irq_linear_revmap(mpic->irqhost,
mpic->err_int_vecs[errint]);
- WARN_ON(cascade_irq == NO_IRQ);
- if (cascade_irq != NO_IRQ) {
+ WARN_ON(!cascade_irq);
+ if (cascade_irq) {
generic_handle_irq(cascade_irq);
} else {
eimr |= 1 << (31 - errint);
@@ -134,7 +134,7 @@ void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
int ret;
virq = irq_create_mapping(mpic->irqhost, irqnum);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_err("Error interrupt setup failed\n");
return;
}
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 3a2be3676f43..8a244828782e 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -131,7 +131,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
irq_hw_number_t hwirq;
for_each_pci_msi_entry(entry, pdev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
hwirq = virq_to_hw(entry->irq);
msi_data = irq_get_chip_data(entry->irq);
@@ -250,7 +250,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
virq = irq_create_mapping(msi_data->irqhost, hwirq);
- if (virq == NO_IRQ) {
+ if (!virq) {
dev_err(&pdev->dev, "fail mapping hwirq %i\n", hwirq);
msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
rc = -ENOSPC;
@@ -285,7 +285,7 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data)
msir_index = cascade_data->index;
if (msir_index >= NR_MSI_REG_MAX)
- cascade_irq = NO_IRQ;
+ cascade_irq = 0;
switch (msi_data->feature & FSL_PIC_IP_MASK) {
case FSL_PIC_IP_MPIC:
@@ -315,7 +315,7 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data)
cascade_irq = irq_linear_revmap(msi_data->irqhost,
msi_hwirq(msi_data, msir_index,
intr_index + have_shift));
- if (cascade_irq != NO_IRQ) {
+ if (cascade_irq) {
generic_handle_irq(cascade_irq);
ret = IRQ_HANDLED;
}
@@ -337,7 +337,7 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
if (msi->cascade_array[i]) {
virq = msi->cascade_array[i]->virq;
- BUG_ON(virq == NO_IRQ);
+ BUG_ON(!virq);
free_irq(virq, msi->cascade_array[i]);
kfree(msi->cascade_array[i]);
@@ -362,7 +362,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
int virt_msir, i, ret;
virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index);
- if (virt_msir == NO_IRQ) {
+ if (!virt_msir) {
dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n",
__func__, irq_index);
return 0;
diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c
index d57b77573068..02553a8ce191 100644
--- a/arch/powerpc/sysdev/ge/ge_pic.c
+++ b/arch/powerpc/sysdev/ge/ge_pic.c
@@ -102,7 +102,7 @@ static void gef_pic_cascade(struct irq_desc *desc)
*/
cascade_irq = gef_pic_get_irq();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
@@ -206,7 +206,7 @@ void __init gef_pic_init(struct device_node *np)
/* Map controller */
gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
- if (gef_pic_cascade_irq == NO_IRQ) {
+ if (!gef_pic_cascade_irq) {
printk(KERN_ERR "SBC610: failed to map cascade interrupt");
return;
}
@@ -223,12 +223,12 @@ void __init gef_pic_init(struct device_node *np)
/*
* This is called when we receive an interrupt with apparently comes from this
- * chip - check, returning the highest interrupt generated or return NO_IRQ
+ * chip - check, returning the highest interrupt generated or return 0.
*/
unsigned int gef_pic_get_irq(void)
{
u32 cause, mask, active;
- unsigned int virq = NO_IRQ;
+ unsigned int virq = 0;
int hwirq;
cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index aa2c186d3115..bafb014e1a7e 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -68,9 +68,9 @@ unsigned int i8259_irq(void)
if (!pci_intack)
outb(0x0B, 0x20); /* ISR register */
if(~inb(0x20) & 0x80)
- irq = NO_IRQ;
+ irq = 0;
} else if (irq == 0xff)
- irq = NO_IRQ;
+ irq = 0;
if (lock)
raw_spin_unlock(&i8259_lock);
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index f76ee39cb337..f267ee0afc08 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -853,7 +853,7 @@ void ipic_clear_mcp_status(u32 mask)
ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
}
-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+/* Return an interrupt vector or 0 if no interrupt is pending. */
unsigned int ipic_get_irq(void)
{
int irq;
@@ -864,7 +864,7 @@ unsigned int ipic_get_irq(void)
irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK;
if (irq == 0) /* 0 --> no irq is pending */
- return NO_IRQ;
+ return 0;
return irq_linear_revmap(primary_ipic->irqhost, irq);
}
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c
index 69f5814ae6d4..c31f634f1973 100644
--- a/arch/powerpc/sysdev/mmio_nvram.c
+++ b/arch/powerpc/sysdev/mmio_nvram.c
@@ -89,7 +89,7 @@ static ssize_t mmio_nvram_write(char *buf, size_t count, loff_t *index)
return count;
}
-void mmio_nvram_write_val(int addr, unsigned char val)
+static void mmio_nvram_write_val(int addr, unsigned char val)
{
unsigned long flags;
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index b7cf7abff2eb..3e828b20c21e 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -79,7 +79,7 @@ unsigned int mpc8xx_get_irq(void)
irq = in_be32(&siu_reg->sc_sivec) >> 26;
if (irq == PIC_VEC_SPURRIOUS)
- irq = NO_IRQ;
+ irq = 0;
return irq_linear_revmap(mpc8xx_pic_host, irq);
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 7de45b2df366..4d48cecfedd1 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1649,7 +1649,7 @@ void __init mpic_init(struct mpic *mpic)
/* Check if this MPIC is chained from a parent interrupt controller */
if (mpic->flags & MPIC_SECONDARY) {
int virq = irq_of_parse_and_map(mpic->node, 0);
- if (virq != NO_IRQ) {
+ if (virq) {
printk(KERN_INFO "%s: hooking up to IRQ %d\n",
mpic->node->full_name, virq);
irq_set_handler_data(virq, mpic);
@@ -1778,13 +1778,13 @@ static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg)
if (unlikely(src == mpic->spurious_vec)) {
if (mpic->flags & MPIC_SPV_EOI)
mpic_eoi(mpic);
- return NO_IRQ;
+ return 0;
}
if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n",
mpic->name, (int)src);
mpic_eoi(mpic);
- return NO_IRQ;
+ return 0;
}
return irq_linear_revmap(mpic->irqhost, src);
@@ -1817,17 +1817,17 @@ unsigned int mpic_get_coreint_irq(void)
if (unlikely(src == mpic->spurious_vec)) {
if (mpic->flags & MPIC_SPV_EOI)
mpic_eoi(mpic);
- return NO_IRQ;
+ return 0;
}
if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n",
mpic->name, (int)src);
- return NO_IRQ;
+ return 0;
}
return irq_linear_revmap(mpic->irqhost, src);
#else
- return NO_IRQ;
+ return 0;
#endif
}
@@ -1852,7 +1852,7 @@ void mpic_request_ipis(void)
for (i = 0; i < 4; i++) {
unsigned int vipi = irq_create_mapping(mpic->irqhost,
mpic->ipi_vecs[0] + i);
- if (vipi == NO_IRQ) {
+ if (!vipi) {
printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]);
continue;
}
diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c
index 3f165d972a0e..db2286be5d9a 100644
--- a/arch/powerpc/sysdev/mpic_msgr.c
+++ b/arch/powerpc/sysdev/mpic_msgr.c
@@ -238,7 +238,7 @@ static int mpic_msgr_probe(struct platform_device *dev)
if (receive_mask & (1 << i)) {
msgr->irq = irq_of_parse_and_map(np, irq_index);
- if (msgr->irq == NO_IRQ) {
+ if (!msgr->irq) {
dev_err(&dev->dev,
"Missing interrupt specifier");
kfree(msgr);
@@ -246,7 +246,7 @@ static int mpic_msgr_probe(struct platform_device *dev)
}
irq_index += 1;
} else {
- msgr->irq = NO_IRQ;
+ msgr->irq = 0;
}
mpic_msgrs[reg_number] = msgr;
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index 2cbc7e29b85f..cfc1c57d760f 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -110,7 +110,7 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
irq_hw_number_t hwirq;
for_each_pci_msi_entry(entry, pdev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
hwirq = virq_to_hw(entry->irq);
@@ -155,7 +155,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
msg.address_hi = addr >> 32;
virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
- if (virq == NO_IRQ) {
+ if (!virq) {
pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq);
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
return -ENOSPC;
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c
index 0f842dd16bcd..a79953deb489 100644
--- a/arch/powerpc/sysdev/mv64x60_pic.c
+++ b/arch/powerpc/sysdev/mv64x60_pic.c
@@ -272,7 +272,7 @@ unsigned int mv64x60_get_irq(void)
u32 cause;
int level1;
irq_hw_number_t hwirq;
- int virq = NO_IRQ;
+ int virq = 0;
cause = in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_SELECT_CAUSE);
if (cause & MV64X60_SELECT_CAUSE_HIGH) {
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index 8a0b77a3ec0c..9ea6a221d9d5 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -158,7 +158,7 @@ static int pmi_of_probe(struct platform_device *dev)
data->dev = dev;
data->irq = irq_of_parse_and_map(np, 0);
- if (data->irq == NO_IRQ) {
+ if (!data->irq) {
printk(KERN_ERR "pmi: invalid interrupt.\n");
rc = -EFAULT;
goto error_cleanup_iomap;
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
index 52a93dcae262..9926ad67af76 100644
--- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
@@ -60,7 +60,7 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
}
hwirq = ppc4xx_hsta_msi.irq_map[irq];
- if (hwirq == NO_IRQ) {
+ if (!hwirq) {
pr_err("%s: Failed mapping irq %d\n", __func__, irq);
return -EINVAL;
}
@@ -110,7 +110,7 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev)
int irq;
for_each_pci_msi_entry(entry, dev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
irq = hsta_find_hwirq_offset(entry->irq);
@@ -166,7 +166,7 @@ static int hsta_msi_probe(struct platform_device *pdev)
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) {
+ if (!ppc4xx_hsta_msi.irq_map[irq]) {
dev_err(dev, "Unable to map IRQ\n");
ret = -EINVAL;
goto out2;
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
index 8fb806135043..590dab4f47d6 100644
--- a/arch/powerpc/sysdev/ppc4xx_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -102,7 +102,7 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
__func__);
}
virq = irq_of_parse_and_map(msi_data->msi_dev, int_no);
- if (virq == NO_IRQ) {
+ if (!virq) {
dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1);
return -ENOSPC;
@@ -129,7 +129,7 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
for_each_pci_msi_entry(entry, dev) {
- if (entry->irq == NO_IRQ)
+ if (!entry->irq)
continue;
hwirq = virq_to_hw(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
@@ -201,7 +201,7 @@ static int ppc4xx_of_msi_remove(struct platform_device *dev)
for (i = 0; i < msi_irqs; i++) {
virq = msi->msi_virqs[i];
- if (virq != NO_IRQ)
+ if (virq)
irq_dispose_mapping(virq);
}
diff --git a/arch/powerpc/sysdev/ppc4xx_soc.c b/arch/powerpc/sysdev/ppc4xx_soc.c
index 5c77c9ba33aa..d41134d2f786 100644
--- a/arch/powerpc/sysdev/ppc4xx_soc.c
+++ b/arch/powerpc/sysdev/ppc4xx_soc.c
@@ -109,7 +109,7 @@ static int __init ppc4xx_l2c_probe(void)
/* Get and map irq number from device tree */
irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
printk(KERN_ERR "irq_of_parse_and_map failed\n");
of_node_put(np);
return -ENODEV;
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 379de955aae3..57c971b7839c 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -433,7 +433,7 @@ void tsi108_irq_cascade(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = get_pci_source();
- if (cascade_irq != NO_IRQ)
+ if (cascade_irq)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 6893d8f236df..a00949f3e378 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -319,7 +319,7 @@ void __init uic_init_tree(void)
}
}
-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+/* Return an interrupt vector or 0 if no interrupt is pending. */
unsigned int uic_get_irq(void)
{
u32 msr;
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c
index c1917cf67c3d..e7fa26c4ff73 100644
--- a/arch/powerpc/sysdev/xics/icp-hv.c
+++ b/arch/powerpc/sysdev/xics/icp-hv.c
@@ -112,10 +112,10 @@ static unsigned int icp_hv_get_irq(void)
unsigned int irq;
if (vec == XICS_IRQ_SPURIOUS)
- return NO_IRQ;
+ return 0;
irq = irq_find_mapping(xics_host, vec);
- if (likely(irq != NO_IRQ)) {
+ if (likely(irq)) {
xics_push_cppr(vec);
return irq;
}
@@ -126,7 +126,7 @@ static unsigned int icp_hv_get_irq(void)
/* We might learn about it later, so EOI it */
icp_hv_set_xirr(xirr);
- return NO_IRQ;
+ return 0;
}
static void icp_hv_set_cpu_priority(unsigned char cppr)
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
index afdf62f2a695..8a6a043e239b 100644
--- a/arch/powerpc/sysdev/xics/icp-native.c
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -124,10 +124,10 @@ static unsigned int icp_native_get_irq(void)
unsigned int irq;
if (vec == XICS_IRQ_SPURIOUS)
- return NO_IRQ;
+ return 0;
irq = irq_find_mapping(xics_host, vec);
- if (likely(irq != NO_IRQ)) {
+ if (likely(irq)) {
xics_push_cppr(vec);
return irq;
}
@@ -138,7 +138,7 @@ static unsigned int icp_native_get_irq(void)
/* We might learn about it later, so EOI it */
icp_native_set_xirr(xirr);
- return NO_IRQ;
+ return 0;
}
#ifdef CONFIG_SMP
diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c
index 9114243fa1b5..d38e86fd5720 100644
--- a/arch/powerpc/sysdev/xics/icp-opal.c
+++ b/arch/powerpc/sysdev/xics/icp-opal.c
@@ -51,14 +51,14 @@ static unsigned int icp_opal_get_irq(void)
rc = opal_int_get_xirr(&xirr, false);
if (rc < 0)
- return NO_IRQ;
+ return 0;
xirr = be32_to_cpu(xirr);
vec = xirr & 0x00ffffff;
if (vec == XICS_IRQ_SPURIOUS)
- return NO_IRQ;
+ return 0;
irq = irq_find_mapping(xics_host, vec);
- if (likely(irq != NO_IRQ)) {
+ if (likely(irq)) {
xics_push_cppr(vec);
return irq;
}
@@ -69,7 +69,7 @@ static unsigned int icp_opal_get_irq(void)
/* We might learn about it later, so EOI it */
opal_int_eoi(xirr);
- return NO_IRQ;
+ return 0;
}
static void icp_opal_set_cpu_priority(unsigned char cppr)
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
index 9d530f479588..69d858e51ac7 100644
--- a/arch/powerpc/sysdev/xics/xics-common.c
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -131,7 +131,7 @@ static void xics_request_ipi(void)
unsigned int ipi;
ipi = irq_create_mapping(xics_host, XICS_IPI);
- BUG_ON(ipi == NO_IRQ);
+ BUG_ON(!ipi);
/*
* IPIs are marked IRQF_PERCPU. The handler was set in map.
diff --git a/arch/powerpc/xmon/spr_access.S b/arch/powerpc/xmon/spr_access.S
index 84ad74213c83..7d8b0e8ed6d9 100644
--- a/arch/powerpc/xmon/spr_access.S
+++ b/arch/powerpc/xmon/spr_access.S
@@ -2,12 +2,12 @@
/* unsigned long xmon_mfspr(sprn, default_value) */
_GLOBAL(xmon_mfspr)
- ld r5, .Lmfspr_table@got(r2)
+ PPC_LL r5, .Lmfspr_table@got(r2)
b xmon_mxspr
/* void xmon_mtspr(sprn, new_value) */
_GLOBAL(xmon_mtspr)
- ld r5, .Lmtspr_table@got(r2)
+ PPC_LL r5, .Lmtspr_table@got(r2)
b xmon_mxspr
/*
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index deeadfa291ba..426481d4cc86 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -67,10 +67,10 @@ config DEBUG_RODATA
config S390
def_bool y
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
+ select ARCH_HAS_GIGANTIC_PAGE
select ARCH_HAS_KCOV
select ARCH_HAS_SG_CHAIN
select ARCH_HAS_UBSAN_SANITIZE_ALL
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 255c7eec4481..09bccb224d03 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -51,7 +51,7 @@ static void hypfs_update_update(struct super_block *sb)
struct inode *inode = d_inode(sb_info->update_file);
sb_info->last_update = get_seconds();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
}
/* directory tree removal functions */
@@ -99,7 +99,7 @@ static struct inode *hypfs_make_inode(struct super_block *sb, umode_t mode)
ret->i_mode = mode;
ret->i_uid = hypfs_info->uid;
ret->i_gid = hypfs_info->gid;
- ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
if (S_ISDIR(mode))
set_nlink(ret, 2);
}
diff --git a/arch/s390/include/asm/uprobes.h b/arch/s390/include/asm/uprobes.h
index 1411dff7fea7..658393c65d7e 100644
--- a/arch/s390/include/asm/uprobes.h
+++ b/arch/s390/include/asm/uprobes.h
@@ -29,14 +29,4 @@ struct arch_uprobe {
struct arch_uprobe_task {
};
-int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm,
- unsigned long addr);
-int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
-int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
-bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
-int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val,
- void *data);
-void arch_uprobe_abort_xol(struct arch_uprobe *ap, struct pt_regs *regs);
-unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
- struct pt_regs *regs);
#endif /* _ASM_UPROBES_H */
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 437e61159279..0f9cd90c11af 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -189,7 +189,7 @@ static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info
kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
- kgid = GROUP_AT(group_info, i);
+ kgid = group_info->gid[i];
group = (u16)from_kgid_munged(user_ns, kgid);
if (put_user(group, grouplist+i))
return -EFAULT;
@@ -213,7 +213,7 @@ static int groups16_from_user(struct group_info *group_info, u16 __user *groupli
if (!gid_valid(kgid))
return -EINVAL;
- GROUP_AT(group_info, i) = kgid;
+ group_info->gid[i] = kgid;
}
return 0;
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 429bfd111961..000e6e91f6a0 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -35,6 +35,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/score/kernel/vmlinux.lds.S b/arch/score/kernel/vmlinux.lds.S
index 7274b5c4287e..4117890b1db1 100644
--- a/arch/score/kernel/vmlinux.lds.S
+++ b/arch/score/kernel/vmlinux.lds.S
@@ -40,6 +40,7 @@ SECTIONS
_text = .; /* Text and read-only data */
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.text.*)
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 235a4101999f..5b9a3cc90c58 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -36,6 +36,7 @@ SECTIONS
TEXT_TEXT
EXTRA_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index f5d60f14a0bc..b23c76b42d6e 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -22,7 +22,6 @@ config SPARC
select HAVE_ARCH_TRACEHOOK
select HAVE_EXIT_THREAD
select SYSCTL_EXCEPTION_TRACE
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select RTC_CLASS
select RTC_DRV_M48T59
select RTC_SYSTOHC
diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index 3f70f900e834..1d51a11fb261 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -86,8 +86,9 @@ static inline unsigned long get_softint(void)
return retval;
}
-void arch_trigger_all_cpu_backtrace(bool);
-#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
+ bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
extern void *hardirq_stack[NR_CPUS];
extern void *softirq_stack[NR_CPUS];
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index fa14402b33f9..47ff5588e521 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -239,7 +239,7 @@ static void __global_reg_poll(struct global_reg_snapshot *gp)
}
}
-void arch_trigger_all_cpu_backtrace(bool include_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
{
struct thread_info *tp = current_thread_info();
struct pt_regs *regs = get_irq_regs();
@@ -255,15 +255,15 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot));
- if (include_self)
+ if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
__global_reg_self(tp, regs, this_cpu);
smp_fetch_global_regs();
- for_each_online_cpu(cpu) {
+ for_each_cpu(cpu, mask) {
struct global_reg_snapshot *gp;
- if (!include_self && cpu == this_cpu)
+ if (exclude_self && cpu == this_cpu)
continue;
gp = &global_cpu_snapshot[cpu].reg;
@@ -300,7 +300,7 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
static void sysrq_handle_globreg(int key)
{
- arch_trigger_all_cpu_backtrace(true);
+ trigger_all_cpu_backtrace();
}
static struct sysrq_key_op sparc_globalreg_op = {
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index d79b3b734245..572db686f845 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -49,6 +49,7 @@ SECTIONS
HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 78da75b670bc..4583c0320059 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -3,7 +3,6 @@
config TILE
def_bool y
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_WANT_FRAME_POINTERS
diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h
index 84a924034bdb..1fa1f2544ff9 100644
--- a/arch/tile/include/asm/irq.h
+++ b/arch/tile/include/asm/irq.h
@@ -79,8 +79,9 @@ void tile_irq_activate(unsigned int irq, int tile_irq_type);
void setup_irq_regs(void);
#ifdef __tilegx__
-void arch_trigger_all_cpu_backtrace(bool self);
-#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
+ bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
#endif
#endif /* _ASM_TILE_IRQ_H */
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index 670a3569450f..101de132e363 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -50,7 +50,7 @@ STD_ENTRY(smp_nap)
* When interrupted at _cpu_idle_nap, we bump the PC forward 8, and
* as a result return to the function that called _cpu_idle().
*/
-STD_ENTRY(_cpu_idle)
+STD_ENTRY_SECTION(_cpu_idle, .cpuidle.text)
movei r1, 1
IRQ_ENABLE_LOAD(r2, r3)
mtspr INTERRUPT_CRITICAL_SECTION, r1
diff --git a/arch/tile/kernel/pmc.c b/arch/tile/kernel/pmc.c
index db62cc34b955..81cf8743a3f3 100644
--- a/arch/tile/kernel/pmc.c
+++ b/arch/tile/kernel/pmc.c
@@ -16,7 +16,6 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/atomic.h>
-#include <linux/interrupt.h>
#include <asm/processor.h>
#include <asm/pmc.h>
@@ -29,9 +28,7 @@ int handle_perf_interrupt(struct pt_regs *regs, int fault)
if (!perf_irq)
panic("Unexpected PERF_COUNT interrupt %d\n", fault);
- nmi_enter();
retval = perf_irq(regs, fault);
- nmi_exit();
return retval;
}
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index a465d8372edd..9f37106ef93a 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -22,7 +22,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/compat.h>
-#include <linux/hardirq.h>
+#include <linux/nmi.h>
#include <linux/syscalls.h>
#include <linux/kernel.h>
#include <linux/tracehook.h>
@@ -594,66 +594,18 @@ void show_regs(struct pt_regs *regs)
tile_show_stack(&kbt);
}
-/* To ensure stack dump on tiles occurs one by one. */
-static DEFINE_SPINLOCK(backtrace_lock);
-/* To ensure no backtrace occurs before all of the stack dump are done. */
-static atomic_t backtrace_cpus;
-/* The cpu mask to avoid reentrance. */
-static struct cpumask backtrace_mask;
-
-void do_nmi_dump_stack(struct pt_regs *regs)
-{
- int is_idle = is_idle_task(current) && !in_interrupt();
- int cpu;
-
- nmi_enter();
- cpu = smp_processor_id();
- if (WARN_ON_ONCE(!cpumask_test_and_clear_cpu(cpu, &backtrace_mask)))
- goto done;
-
- spin_lock(&backtrace_lock);
- if (is_idle)
- pr_info("CPU: %d idle\n", cpu);
- else
- show_regs(regs);
- spin_unlock(&backtrace_lock);
- atomic_dec(&backtrace_cpus);
-done:
- nmi_exit();
-}
-
#ifdef __tilegx__
-void arch_trigger_all_cpu_backtrace(bool self)
+void nmi_raise_cpu_backtrace(struct cpumask *in_mask)
{
struct cpumask mask;
HV_Coord tile;
unsigned int timeout;
int cpu;
- int ongoing;
HV_NMI_Info info[NR_CPUS];
- ongoing = atomic_cmpxchg(&backtrace_cpus, 0, num_online_cpus() - 1);
- if (ongoing != 0) {
- pr_err("Trying to do all-cpu backtrace.\n");
- pr_err("But another all-cpu backtrace is ongoing (%d cpus left)\n",
- ongoing);
- if (self) {
- pr_err("Reporting the stack on this cpu only.\n");
- dump_stack();
- }
- return;
- }
-
- cpumask_copy(&mask, cpu_online_mask);
- cpumask_clear_cpu(smp_processor_id(), &mask);
- cpumask_copy(&backtrace_mask, &mask);
-
- /* Backtrace for myself first. */
- if (self)
- dump_stack();
-
/* Tentatively dump stack on remote tiles via NMI. */
timeout = 100;
+ cpumask_copy(&mask, in_mask);
while (!cpumask_empty(&mask) && timeout) {
for_each_cpu(cpu, &mask) {
tile.x = cpu_x(cpu);
@@ -664,12 +616,17 @@ void arch_trigger_all_cpu_backtrace(bool self)
}
mdelay(10);
+ touch_softlockup_watchdog();
timeout--;
}
- /* Warn about cpus stuck in ICS and decrement their counts here. */
+ /* Warn about cpus stuck in ICS. */
if (!cpumask_empty(&mask)) {
for_each_cpu(cpu, &mask) {
+
+ /* Clear the bit as if nmi_cpu_backtrace() ran. */
+ cpumask_clear_cpu(cpu, in_mask);
+
switch (info[cpu].result) {
case HV_NMI_RESULT_FAIL_ICS:
pr_warn("Skipping stack dump of cpu %d in ICS at pc %#llx\n",
@@ -680,16 +637,20 @@ void arch_trigger_all_cpu_backtrace(bool self)
cpu);
break;
case HV_ENOSYS:
- pr_warn("Hypervisor too old to allow remote stack dumps.\n");
- goto skip_for_each;
+ WARN_ONCE(1, "Hypervisor too old to allow remote stack dumps.\n");
+ break;
default: /* should not happen */
pr_warn("Skipping stack dump of cpu %d [%d,%#llx]\n",
cpu, info[cpu].result, info[cpu].pc);
break;
}
}
-skip_for_each:
- atomic_sub(cpumask_weight(&mask), &backtrace_cpus);
}
}
+
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+{
+ nmi_trigger_cpumask_backtrace(mask, exclude_self,
+ nmi_raise_cpu_backtrace);
+}
#endif /* __tilegx_ */
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 4d9651c5b1ad..39f427bb0de2 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -20,6 +20,8 @@
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/nmi.h>
#include <asm/stack.h>
#include <asm/traps.h>
#include <asm/setup.h>
@@ -392,14 +394,17 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
void do_nmi(struct pt_regs *regs, int fault_num, unsigned long reason)
{
+ nmi_enter();
switch (reason) {
+#ifdef arch_trigger_cpumask_backtrace
case TILE_NMI_DUMP_STACK:
- do_nmi_dump_stack(regs);
+ nmi_cpu_backtrace(regs);
break;
+#endif
default:
panic("Unexpected do_nmi type %ld", reason);
- return;
}
+ nmi_exit();
}
/* Deprecated function currently only used here. */
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S
index 9d449caf8910..e1baf094fba4 100644
--- a/arch/tile/kernel/vmlinux.lds.S
+++ b/arch/tile/kernel/vmlinux.lds.S
@@ -42,6 +42,7 @@ SECTIONS
.text : AT (ADDR(.text) - LOAD_OFFSET) {
HEAD_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index adde088aeeff..4fdbcf958cd5 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -68,6 +68,7 @@ SECTIONS
_stext = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.stub .text.* .gnu.linkonce.t.*)
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 6899195602b7..1840f55ed042 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -28,6 +28,7 @@ SECTIONS
_stext = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
/* .gnu.warning sections are handled specially by elf32.em. */
diff --git a/arch/unicore32/kernel/vmlinux.lds.S b/arch/unicore32/kernel/vmlinux.lds.S
index 77e407e49a63..56e788e8ee83 100644
--- a/arch/unicore32/kernel/vmlinux.lds.S
+++ b/arch/unicore32/kernel/vmlinux.lds.S
@@ -37,6 +37,7 @@ SECTIONS
.text : { /* Real text segment */
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 9b2d50a73a11..bada636d1065 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -23,11 +23,11 @@ config X86
select ARCH_CLOCKSOURCE_DATA
select ARCH_DISCARD_MEMBLOCK
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FAST_MULTIPLIER
select ARCH_HAS_GCOV_PROFILE_ALL
+ select ARCH_HAS_GIGANTIC_PAGE if X86_64
select ARCH_HAS_KCOV if X86_64
select ARCH_HAS_PMEM_API if X86_64
select ARCH_HAS_MMIO_FLUSH
@@ -2757,19 +2757,6 @@ config PMC_ATOM
def_bool y
depends on PCI
-config VMD
- depends on PCI_MSI
- tristate "Volume Management Device Driver"
- default N
- ---help---
- Adds support for the Intel Volume Management Device (VMD). VMD is a
- secondary PCI host bridge that allows PCI Express root ports,
- and devices attached to them, to be removed from the default
- PCI domain and placed within the VMD domain. This provides
- more bus resources than are otherwise possible with a
- single domain. If you know your system provides one of these and
- has devices attached to it, say Y; if you are not sure, say N.
-
source "net/Kconfig"
source "drivers/Kconfig"
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 830ed391e7ef..2d449337a360 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -163,11 +163,12 @@ asinstr += $(call as-instr,pshufb %xmm0$(comma)%xmm0,-DCONFIG_AS_SSSE3=1)
asinstr += $(call as-instr,crc32l %eax$(comma)%eax,-DCONFIG_AS_CRC32=1)
avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
+avx512_instr :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,-DCONFIG_AS_AVX512=1)
sha1_ni_instr :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA1_NI=1)
sha256_ni_instr :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA256_NI=1)
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(sha1_ni_instr) $(sha256_ni_instr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(sha1_ni_instr) $(sha256_ni_instr)
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr)
LDFLAGS := -m elf_$(UTS_MACHINE)
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index fee1d95902b5..c98ec2efd750 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -1148,7 +1148,7 @@ END(error_entry)
/*
- * On entry, EBS is a "return to kernel mode" flag:
+ * On entry, EBX is a "return to kernel mode" flag:
* 1: already in kernel mode, don't need SWAPGS
* 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
*/
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index f848572169ea..ff6ef7b30822 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -386,3 +386,8 @@
377 i386 copy_file_range sys_copy_file_range
378 i386 preadv2 sys_preadv2 compat_sys_preadv2
379 i386 pwritev2 sys_pwritev2 compat_sys_pwritev2
+380 i386 pkey_mprotect sys_pkey_mprotect
+381 i386 pkey_alloc sys_pkey_alloc
+382 i386 pkey_free sys_pkey_free
+#383 i386 pkey_get sys_pkey_get
+#384 i386 pkey_set sys_pkey_set
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index e9ce9c7c39b4..2f024d02511d 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -335,6 +335,11 @@
326 common copy_file_range sys_copy_file_range
327 64 preadv2 sys_preadv2
328 64 pwritev2 sys_pwritev2
+329 common pkey_mprotect sys_pkey_mprotect
+330 common pkey_alloc sys_pkey_alloc
+331 common pkey_free sys_pkey_free
+#332 common pkey_get sys_pkey_get
+#333 common pkey_set sys_pkey_set
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/arch/x86/entry/syscalls/syscalltbl.sh b/arch/x86/entry/syscalls/syscalltbl.sh
index cd3d3015d7df..751d1f992630 100644
--- a/arch/x86/entry/syscalls/syscalltbl.sh
+++ b/arch/x86/entry/syscalls/syscalltbl.sh
@@ -10,8 +10,11 @@ syscall_macro() {
# Entry can be either just a function name or "function/qualifier"
real_entry="${entry%%/*}"
- qualifier="${entry:${#real_entry}}" # Strip the function name
- qualifier="${qualifier:1}" # Strip the slash, if any
+ if [ "$entry" = "$real_entry" ]; then
+ qualifier=
+ else
+ qualifier=${entry#*/}
+ fi
echo "__SYSCALL_${abi}($nr, $real_entry, $qualifier)"
}
@@ -22,7 +25,7 @@ emit() {
entry="$3"
compat="$4"
- if [ "$abi" == "64" -a -n "$compat" ]; then
+ if [ "$abi" = "64" -a -n "$compat" ]; then
echo "a compat entry for a 64-bit syscall makes no sense" >&2
exit 1
fi
@@ -45,17 +48,17 @@ emit() {
grep '^[0-9]' "$in" | sort -n | (
while read nr abi name entry compat; do
abi=`echo "$abi" | tr '[a-z]' '[A-Z]'`
- if [ "$abi" == "COMMON" -o "$abi" == "64" ]; then
+ if [ "$abi" = "COMMON" -o "$abi" = "64" ]; then
# COMMON is the same as 64, except that we don't expect X32
# programs to use it. Our expectation has nothing to do with
# any generated code, so treat them the same.
emit 64 "$nr" "$entry" "$compat"
- elif [ "$abi" == "X32" ]; then
+ elif [ "$abi" = "X32" ]; then
# X32 is equivalent to 64 on an X32-compatible kernel.
echo "#ifdef CONFIG_X86_X32_ABI"
emit 64 "$nr" "$entry" "$compat"
echo "#endif"
- elif [ "$abi" == "I386" ]; then
+ elif [ "$abi" = "I386" ]; then
emit "$abi" "$nr" "$entry" "$compat"
else
echo "Unknown abi $abi" >&2
diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h
index d4957ac72b48..430bacf73074 100644
--- a/arch/x86/include/asm/fpu/xstate.h
+++ b/arch/x86/include/asm/fpu/xstate.h
@@ -27,11 +27,12 @@
XFEATURE_MASK_YMM | \
XFEATURE_MASK_OPMASK | \
XFEATURE_MASK_ZMM_Hi256 | \
- XFEATURE_MASK_Hi16_ZMM | \
- XFEATURE_MASK_PKRU)
+ XFEATURE_MASK_Hi16_ZMM)
/* Supported features which require eager state saving */
-#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)
+#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | \
+ XFEATURE_MASK_BNDCSR | \
+ XFEATURE_MASK_PKRU)
/* All currently supported features */
#define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER)
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index e7de5c9a4fbd..16d3fa211962 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -50,8 +50,9 @@ extern int vector_used_by_percpu_irq(unsigned int vector);
extern void init_ISA_irqs(void);
#ifdef CONFIG_X86_LOCAL_APIC
-void arch_trigger_all_cpu_backtrace(bool);
-#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+void arch_trigger_cpumask_backtrace(const struct cpumask *mask,
+ bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
#endif
#endif /* _ASM_X86_IRQ_H */
diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h
index b77f5edb03b0..ac7692dcfa2e 100644
--- a/arch/x86/include/asm/irqflags.h
+++ b/arch/x86/include/asm/irqflags.h
@@ -4,6 +4,10 @@
#include <asm/processor-flags.h>
#ifndef __ASSEMBLY__
+
+/* Provide __cpuidle; we can't safely include <linux/cpu.h> */
+#define __cpuidle __attribute__((__section__(".cpuidle.text")))
+
/*
* Interrupt control:
*/
@@ -44,12 +48,12 @@ static inline void native_irq_enable(void)
asm volatile("sti": : :"memory");
}
-static inline void native_safe_halt(void)
+static inline __cpuidle void native_safe_halt(void)
{
asm volatile("sti; hlt": : :"memory");
}
-static inline void native_halt(void)
+static inline __cpuidle void native_halt(void)
{
asm volatile("hlt": : :"memory");
}
@@ -86,7 +90,7 @@ static inline notrace void arch_local_irq_enable(void)
* Used in the idle loop; sti takes one instruction cycle
* to complete:
*/
-static inline void arch_safe_halt(void)
+static inline __cpuidle void arch_safe_halt(void)
{
native_safe_halt();
}
@@ -95,7 +99,7 @@ static inline void arch_safe_halt(void)
* Used when interrupts are already enabled or to
* shutdown the processor:
*/
-static inline void halt(void)
+static inline __cpuidle void halt(void)
{
native_halt();
}
diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h
index 1ea0baef1175..72198c64e646 100644
--- a/arch/x86/include/asm/mmu.h
+++ b/arch/x86/include/asm/mmu.h
@@ -23,6 +23,14 @@ typedef struct {
const struct vdso_image *vdso_image; /* vdso image in use */
atomic_t perf_rdpmc_allowed; /* nonzero if rdpmc is allowed */
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+ /*
+ * One bit per protection key says whether userspace can
+ * use it or not. protected by mmap_sem.
+ */
+ u16 pkey_allocation_map;
+ s16 execute_only_pkey;
+#endif
} mm_context_t;
#ifdef CONFIG_SMP
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index d8abfcf524d1..8e0a9fe86de4 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -4,6 +4,7 @@
#include <asm/desc.h>
#include <linux/atomic.h>
#include <linux/mm_types.h>
+#include <linux/pkeys.h>
#include <trace/events/tlb.h>
@@ -107,7 +108,16 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
static inline int init_new_context(struct task_struct *tsk,
struct mm_struct *mm)
{
+ #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+ if (cpu_feature_enabled(X86_FEATURE_OSPKE)) {
+ /* pkey 0 is the default and always allocated */
+ mm->context.pkey_allocation_map = 0x1;
+ /* -1 means unallocated or invalid */
+ mm->context.execute_only_pkey = -1;
+ }
+ #endif
init_new_context_ldt(tsk, mm);
+
return 0;
}
static inline void destroy_context(struct mm_struct *mm)
@@ -195,16 +205,20 @@ static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
mpx_notify_unmap(mm, vma, start, end);
}
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
static inline int vma_pkey(struct vm_area_struct *vma)
{
- u16 pkey = 0;
-#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 |
VM_PKEY_BIT2 | VM_PKEY_BIT3;
- pkey = (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
-#endif
- return pkey;
+
+ return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
+}
+#else
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+ return 0;
}
+#endif
static inline bool __pkru_allows_pkey(u16 pkey, bool write)
{
@@ -258,5 +272,4 @@ static inline bool arch_pte_access_permitted(pte_t pte, bool write)
{
return __pkru_allows_pkey(pte_flags_pkey(pte_flags(pte)), write);
}
-
#endif /* _ASM_X86_MMU_CONTEXT_H */
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 9ab7507ca1c2..1411dbed5e5e 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -23,6 +23,9 @@ struct pci_sysdata {
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
void *fwnode; /* IRQ domain for MSI assignment */
#endif
+#if IS_ENABLED(CONFIG_VMD)
+ bool vmd_domain; /* True if in Intel VMD domain */
+#endif
};
extern int pci_routeirq;
@@ -56,6 +59,17 @@ static inline void *_pci_root_bus_fwnode(struct pci_bus *bus)
#define pci_root_bus_fwnode _pci_root_bus_fwnode
#endif
+static inline bool is_vmd(struct pci_bus *bus)
+{
+#if IS_ENABLED(CONFIG_VMD)
+ struct pci_sysdata *sd = bus->sysdata;
+
+ return sd->vmd_domain;
+#else
+ return false;
+#endif
+}
+
/* Can be used to override the logic in pci_scan_bus for skipping
already-configured bus numbers - to be used for buggy BIOSes
or architectures with incomplete PCI setup by the loader */
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index f1218f512f62..8b4de22d6429 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -439,8 +439,6 @@ extern pgprot_t pgprot_writethrough(pgprot_t prot);
struct file;
pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot);
-int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
- unsigned long size, pgprot_t *vma_prot);
/* Install a pte for a particular vaddr in kernel space. */
void set_pte_vaddr(unsigned long vaddr, pte_t pte);
diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h
index 7b84565c916c..34684adb6899 100644
--- a/arch/x86/include/asm/pkeys.h
+++ b/arch/x86/include/asm/pkeys.h
@@ -10,7 +10,6 @@ extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
* Try to dedicate one of the protection keys to be used as an
* execute-only protection key.
*/
-#define PKEY_DEDICATED_EXECUTE_ONLY 15
extern int __execute_only_pkey(struct mm_struct *mm);
static inline int execute_only_pkey(struct mm_struct *mm)
{
@@ -31,4 +30,76 @@ static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
return __arch_override_mprotect_pkey(vma, prot, pkey);
}
+extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val);
+
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | VM_PKEY_BIT3)
+
+#define mm_pkey_allocation_map(mm) (mm->context.pkey_allocation_map)
+#define mm_set_pkey_allocated(mm, pkey) do { \
+ mm_pkey_allocation_map(mm) |= (1U << pkey); \
+} while (0)
+#define mm_set_pkey_free(mm, pkey) do { \
+ mm_pkey_allocation_map(mm) &= ~(1U << pkey); \
+} while (0)
+
+static inline
+bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
+{
+ return mm_pkey_allocation_map(mm) & (1U << pkey);
+}
+
+/*
+ * Returns a positive, 4-bit key on success, or -1 on failure.
+ */
+static inline
+int mm_pkey_alloc(struct mm_struct *mm)
+{
+ /*
+ * Note: this is the one and only place we make sure
+ * that the pkey is valid as far as the hardware is
+ * concerned. The rest of the kernel trusts that
+ * only good, valid pkeys come out of here.
+ */
+ u16 all_pkeys_mask = ((1U << arch_max_pkey()) - 1);
+ int ret;
+
+ /*
+ * Are we out of pkeys? We must handle this specially
+ * because ffz() behavior is undefined if there are no
+ * zeros.
+ */
+ if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
+ return -1;
+
+ ret = ffz(mm_pkey_allocation_map(mm));
+
+ mm_set_pkey_allocated(mm, ret);
+
+ return ret;
+}
+
+static inline
+int mm_pkey_free(struct mm_struct *mm, int pkey)
+{
+ /*
+ * pkey 0 is special, always allocated and can never
+ * be freed.
+ */
+ if (!pkey)
+ return -EINVAL;
+ if (!mm_pkey_is_allocated(mm, pkey))
+ return -EINVAL;
+
+ mm_set_pkey_free(mm, pkey);
+
+ return 0;
+}
+
+extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val);
+extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val);
+extern void copy_init_pkru_to_fpregs(void);
+
#endif /*_ASM_X86_PKEYS_H */
diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h
index c4b6d1cafa46..46de9ac4b990 100644
--- a/arch/x86/include/asm/unwind.h
+++ b/arch/x86/include/asm/unwind.h
@@ -23,6 +23,8 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
bool unwind_next_frame(struct unwind_state *state);
+unsigned long unwind_get_return_address(struct unwind_state *state);
+
static inline bool unwind_done(struct unwind_state *state)
{
return state->stack_info.type == STACK_TYPE_UNKNOWN;
@@ -48,8 +50,6 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
return state->bp + 1;
}
-unsigned long unwind_get_return_address(struct unwind_state *state);
-
#else /* !CONFIG_FRAME_POINTER */
static inline
@@ -58,16 +58,6 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
return NULL;
}
-static inline
-unsigned long unwind_get_return_address(struct unwind_state *state)
-{
- if (unwind_done(state))
- return 0;
-
- return ftrace_graph_ret_addr(state->task, &state->graph_idx,
- *state->sp, state->sp);
-}
-
#endif /* CONFIG_FRAME_POINTER */
#endif /* _ASM_X86_UNWIND_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 45257cf84370..4dd5d500eb60 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o
obj-y += apic/
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
+obj-$(CONFIG_LIVEPATCH) += livepatch.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_X86_TSC) += trace_clock.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 32a7d70913ac..8a5abaa7d453 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -233,6 +233,10 @@ acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
acpi_table_print_madt_entry(header);
+ /* Ignore invalid ID */
+ if (processor->id == 0xff)
+ return 0;
+
/*
* We need to register disabled CPU as well to permit
* counting disabled CPUs. This allows us to size
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index bdfad642123f..af15f4444330 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -152,7 +152,7 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu,
}
EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
-void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
+void __cpuidle acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
{
unsigned int cpu = smp_processor_id();
struct cstate_entry *percpu_entry;
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index f266b8a92a9e..88c657b057e2 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2128,9 +2128,11 @@ int __generic_processor_info(int apicid, int version, bool enabled)
if (num_processors >= nr_cpu_ids) {
int thiscpu = max + disabled_cpus;
- pr_warning(
- "APIC: NR_CPUS/possible_cpus limit of %i reached."
- " Processor %d/0x%x ignored.\n", max, thiscpu, apicid);
+ if (enabled) {
+ pr_warning("APIC: NR_CPUS/possible_cpus limit of %i "
+ "reached. Processor %d/0x%x ignored.\n",
+ max, thiscpu, apicid);
+ }
disabled_cpus++;
return -EINVAL;
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
index f29501e1a5c1..c73c9fb281e1 100644
--- a/arch/x86/kernel/apic/hw_nmi.c
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -26,32 +26,32 @@ u64 hw_nmi_get_sample_period(int watchdog_thresh)
}
#endif
-#ifdef arch_trigger_all_cpu_backtrace
+#ifdef arch_trigger_cpumask_backtrace
static void nmi_raise_cpu_backtrace(cpumask_t *mask)
{
apic->send_IPI_mask(mask, NMI_VECTOR);
}
-void arch_trigger_all_cpu_backtrace(bool include_self)
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
{
- nmi_trigger_all_cpu_backtrace(include_self, nmi_raise_cpu_backtrace);
+ nmi_trigger_cpumask_backtrace(mask, exclude_self,
+ nmi_raise_cpu_backtrace);
}
-static int
-arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
+static int nmi_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
{
if (nmi_cpu_backtrace(regs))
return NMI_HANDLED;
return NMI_DONE;
}
-NOKPROBE_SYMBOL(arch_trigger_all_cpu_backtrace_handler);
+NOKPROBE_SYMBOL(nmi_cpu_backtrace_handler);
-static int __init register_trigger_all_cpu_backtrace(void)
+static int __init register_nmi_cpu_backtrace_handler(void)
{
- register_nmi_handler(NMI_LOCAL, arch_trigger_all_cpu_backtrace_handler,
+ register_nmi_handler(NMI_LOCAL, nmi_cpu_backtrace_handler,
0, "arch_bt");
return 0;
}
-early_initcall(register_trigger_all_cpu_backtrace);
+early_initcall(register_nmi_cpu_backtrace_handler);
#endif
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 6066d945c40e..5d30c5e42bb1 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -661,11 +661,28 @@ void irq_complete_move(struct irq_cfg *cfg)
*/
void irq_force_complete_move(struct irq_desc *desc)
{
- struct irq_data *irqdata = irq_desc_get_irq_data(desc);
- struct apic_chip_data *data = apic_chip_data(irqdata);
- struct irq_cfg *cfg = data ? &data->cfg : NULL;
+ struct irq_data *irqdata;
+ struct apic_chip_data *data;
+ struct irq_cfg *cfg;
unsigned int cpu;
+ /*
+ * The function is called for all descriptors regardless of which
+ * irqdomain they belong to. For example if an IRQ is provided by
+ * an irq_chip as part of a GPIO driver, the chip data for that
+ * descriptor is specific to the irq_chip in question.
+ *
+ * Check first that the chip_data is what we expect
+ * (apic_chip_data) before touching it any further.
+ */
+ irqdata = irq_domain_get_irq_data(x86_vector_domain,
+ irq_desc_get_irq(desc));
+ if (!irqdata)
+ return;
+
+ data = apic_chip_data(irqdata);
+ cfg = data ? &data->cfg : NULL;
+
if (!cfg)
return;
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 1ff0598d309c..81160578b91a 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -27,6 +27,7 @@
#include <asm/div64.h>
#include <asm/x86_init.h>
#include <asm/hypervisor.h>
+#include <asm/apic.h>
#define CPUID_VMWARE_INFO_LEAF 0x40000000
#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
@@ -82,10 +83,17 @@ static void __init vmware_platform_setup(void)
VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
- if (ebx != UINT_MAX)
+ if (ebx != UINT_MAX) {
x86_platform.calibrate_tsc = vmware_get_tsc_khz;
- else
+#ifdef CONFIG_X86_LOCAL_APIC
+ /* Skip lapic calibration since we know the bus frequency. */
+ lapic_timer_frequency = ecx / HZ;
+ pr_info("Host bus clock speed read from hypervisor : %u Hz\n",
+ ecx);
+#endif
+ } else {
pr_warn("Failed to get TSC freq from the hypervisor\n");
+ }
}
/*
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 3fc03a09a93b..47004010ad5d 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -12,6 +12,7 @@
#include <asm/traps.h>
#include <linux/hardirq.h>
+#include <linux/pkeys.h>
#define CREATE_TRACE_POINTS
#include <asm/trace/fpu.h>
@@ -505,6 +506,9 @@ static inline void copy_init_fpstate_to_fpregs(void)
copy_kernel_to_fxregs(&init_fpstate.fxsave);
else
copy_kernel_to_fregs(&init_fpstate.fsave);
+
+ if (boot_cpu_has(X86_FEATURE_OSPKE))
+ copy_init_pkru_to_fpregs();
}
/*
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 01567aa87503..124aa5c593f8 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -5,6 +5,7 @@
*/
#include <linux/compat.h>
#include <linux/cpu.h>
+#include <linux/mman.h>
#include <linux/pkeys.h>
#include <asm/fpu/api.h>
@@ -866,9 +867,10 @@ const void *get_xsave_field_ptr(int xsave_state)
return get_xsave_addr(&fpu->state.xsave, xsave_state);
}
+#ifdef CONFIG_ARCH_HAS_PKEYS
+
#define NR_VALID_PKRU_BITS (CONFIG_NR_PROTECTION_KEYS * 2)
#define PKRU_VALID_MASK (NR_VALID_PKRU_BITS - 1)
-
/*
* This will go out and modify PKRU register to set the access
* rights for @pkey to @init_val.
@@ -914,6 +916,7 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
return 0;
}
+#endif /* ! CONFIG_ARCH_HAS_PKEYS */
/*
* This is similar to user_regset_copyout(), but will not add offset to
diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c
new file mode 100644
index 000000000000..e9d252d873aa
--- /dev/null
+++ b/arch/x86/kernel/livepatch.c
@@ -0,0 +1,65 @@
+/*
+ * livepatch.c - x86-specific Kernel Live Patching Core
+ *
+ * This program is free software; 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/livepatch.h>
+#include <asm/text-patching.h>
+
+/* Apply per-object alternatives. Based on x86 module_finalize() */
+void arch_klp_init_object_loaded(struct klp_patch *patch,
+ struct klp_object *obj)
+{
+ int cnt;
+ struct klp_modinfo *info;
+ Elf_Shdr *s, *alt = NULL, *para = NULL;
+ void *aseg, *pseg;
+ const char *objname;
+ char sec_objname[MODULE_NAME_LEN];
+ char secname[KSYM_NAME_LEN];
+
+ info = patch->mod->klp_info;
+ objname = obj->name ? obj->name : "vmlinux";
+
+ /* See livepatch core code for BUILD_BUG_ON() explanation */
+ BUILD_BUG_ON(MODULE_NAME_LEN < 56 || KSYM_NAME_LEN != 128);
+
+ for (s = info->sechdrs; s < info->sechdrs + info->hdr.e_shnum; s++) {
+ /* Apply per-object .klp.arch sections */
+ cnt = sscanf(info->secstrings + s->sh_name,
+ ".klp.arch.%55[^.].%127s",
+ sec_objname, secname);
+ if (cnt != 2)
+ continue;
+ if (strcmp(sec_objname, objname))
+ continue;
+ if (!strcmp(".altinstructions", secname))
+ alt = s;
+ if (!strcmp(".parainstructions", secname))
+ para = s;
+ }
+
+ if (alt) {
+ aseg = (void *) alt->sh_addr;
+ apply_alternatives(aseg, aseg + alt->sh_size);
+ }
+
+ if (para) {
+ pseg = (void *) para->sh_addr;
+ apply_paravirt(pseg, pseg + para->sh_size);
+ }
+}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 4002b475171c..28cea7802ecb 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -302,7 +302,7 @@ void arch_cpu_idle(void)
/*
* We use this if we don't have any better idle routine..
*/
-void default_idle(void)
+void __cpuidle default_idle(void)
{
trace_cpu_idle_rcuidle(1, smp_processor_id());
safe_halt();
@@ -417,7 +417,7 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
* with interrupts enabled and no flags, which is backwards compatible with the
* original MWAIT implementation.
*/
-static void mwait_idle(void)
+static __cpuidle void mwait_idle(void)
{
if (!current_set_polling_and_test()) {
trace_cpu_idle_rcuidle(1, smp_processor_id());
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index ee944bd2310d..b3760b3c1ca0 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -109,12 +109,13 @@ void __show_regs(struct pt_regs *regs, int all)
get_debugreg(d7, 7);
/* Only print out debug registers if they are in their non-default state. */
- if ((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
- (d6 == DR6_RESERVED) && (d7 == 0x400))
- return;
-
- printk(KERN_DEFAULT "DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
- printk(KERN_DEFAULT "DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
+ if (!((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
+ (d6 == DR6_RESERVED) && (d7 == 0x400))) {
+ printk(KERN_DEFAULT "DR0: %016lx DR1: %016lx DR2: %016lx\n",
+ d0, d1, d2);
+ printk(KERN_DEFAULT "DR3: %016lx DR6: %016lx DR7: %016lx\n",
+ d3, d6, d7);
+ }
if (boot_cpu_has(X86_FEATURE_OSPKE))
printk(KERN_DEFAULT "PKRU: %08x\n", read_pkru());
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 42a93621f5b0..951f093a96fe 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1407,9 +1407,21 @@ __init void prefill_possible_map(void)
{
int i, possible;
- /* no processor from mptable or madt */
- if (!num_processors)
- num_processors = 1;
+ /* No boot processor was found in mptable or ACPI MADT */
+ if (!num_processors) {
+ int apicid = boot_cpu_physical_apicid;
+ int cpu = hard_smp_processor_id();
+
+ pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu);
+
+ /* Make sure boot cpu is enumerated */
+ if (apic->cpu_present_to_apicid(0) == BAD_APICID &&
+ apic->apic_id_valid(apicid))
+ generic_processor_info(apicid, boot_cpu_apic_version);
+
+ if (!num_processors)
+ num_processors = 1;
+ }
i = setup_max_cpus ?: 1;
if (setup_possible_cpus == -1) {
diff --git a/arch/x86/kernel/unwind_guess.c b/arch/x86/kernel/unwind_guess.c
index b5a834c93065..9298993dc8b7 100644
--- a/arch/x86/kernel/unwind_guess.c
+++ b/arch/x86/kernel/unwind_guess.c
@@ -5,6 +5,16 @@
#include <asm/stacktrace.h>
#include <asm/unwind.h>
+unsigned long unwind_get_return_address(struct unwind_state *state)
+{
+ if (unwind_done(state))
+ return 0;
+
+ return ftrace_graph_ret_addr(state->task, &state->graph_idx,
+ *state->sp, state->sp);
+}
+EXPORT_SYMBOL_GPL(unwind_get_return_address);
+
bool unwind_next_frame(struct unwind_state *state)
{
struct stack_info *info = &state->stack_info;
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 9297a002d8e5..dbf67f64d5ec 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -97,6 +97,7 @@ SECTIONS
_stext = .;
TEXT_TEXT
SCHED_TEXT
+ CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
ENTRY_TEXT
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 1e525122cbe4..4dc13340653e 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1144,6 +1144,15 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)
{
/* This is only called for the current mm, so: */
bool foreign = false;
+
+ /*
+ * Read or write was blocked by protection keys. This is
+ * always an unconditional error and can never result in
+ * a follow-up action to resolve the fault, like a COW.
+ */
+ if (error_code & PF_PK)
+ return 1;
+
/*
* Make sure to check the VMA so that we do not perform
* faults just to hit a PF_PK as soon as we fill in a
diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c
index e8c474451928..f88ce0e5efd9 100644
--- a/arch/x86/mm/pkeys.c
+++ b/arch/x86/mm/pkeys.c
@@ -11,6 +11,7 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
+#include <linux/debugfs.h> /* debugfs_create_u32() */
#include <linux/mm_types.h> /* mm_struct, vma, etc... */
#include <linux/pkeys.h> /* PKEY_* */
#include <uapi/asm-generic/mman-common.h>
@@ -21,8 +22,19 @@
int __execute_only_pkey(struct mm_struct *mm)
{
+ bool need_to_set_mm_pkey = false;
+ int execute_only_pkey = mm->context.execute_only_pkey;
int ret;
+ /* Do we need to assign a pkey for mm's execute-only maps? */
+ if (execute_only_pkey == -1) {
+ /* Go allocate one to use, which might fail */
+ execute_only_pkey = mm_pkey_alloc(mm);
+ if (execute_only_pkey < 0)
+ return -1;
+ need_to_set_mm_pkey = true;
+ }
+
/*
* We do not want to go through the relatively costly
* dance to set PKRU if we do not need to. Check it
@@ -32,22 +44,33 @@ int __execute_only_pkey(struct mm_struct *mm)
* can make fpregs inactive.
*/
preempt_disable();
- if (fpregs_active() &&
- !__pkru_allows_read(read_pkru(), PKEY_DEDICATED_EXECUTE_ONLY)) {
+ if (!need_to_set_mm_pkey &&
+ fpregs_active() &&
+ !__pkru_allows_read(read_pkru(), execute_only_pkey)) {
preempt_enable();
- return PKEY_DEDICATED_EXECUTE_ONLY;
+ return execute_only_pkey;
}
preempt_enable();
- ret = arch_set_user_pkey_access(current, PKEY_DEDICATED_EXECUTE_ONLY,
+
+ /*
+ * Set up PKRU so that it denies access for everything
+ * other than execution.
+ */
+ ret = arch_set_user_pkey_access(current, execute_only_pkey,
PKEY_DISABLE_ACCESS);
/*
* If the PKRU-set operation failed somehow, just return
* 0 and effectively disable execute-only support.
*/
- if (ret)
- return 0;
+ if (ret) {
+ mm_set_pkey_free(mm, execute_only_pkey);
+ return -1;
+ }
- return PKEY_DEDICATED_EXECUTE_ONLY;
+ /* We got one, store it and use it from here on out */
+ if (need_to_set_mm_pkey)
+ mm->context.execute_only_pkey = execute_only_pkey;
+ return execute_only_pkey;
}
static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
@@ -55,7 +78,7 @@ static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
/* Do this check first since the vm_flags should be hot */
if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
return false;
- if (vma_pkey(vma) != PKEY_DEDICATED_EXECUTE_ONLY)
+ if (vma_pkey(vma) != vma->vm_mm->context.execute_only_pkey)
return false;
return true;
@@ -99,3 +122,106 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey
*/
return vma_pkey(vma);
}
+
+#define PKRU_AD_KEY(pkey) (PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
+
+/*
+ * Make the default PKRU value (at execve() time) as restrictive
+ * as possible. This ensures that any threads clone()'d early
+ * in the process's lifetime will not accidentally get access
+ * to data which is pkey-protected later on.
+ */
+u32 init_pkru_value = PKRU_AD_KEY( 1) | PKRU_AD_KEY( 2) | PKRU_AD_KEY( 3) |
+ PKRU_AD_KEY( 4) | PKRU_AD_KEY( 5) | PKRU_AD_KEY( 6) |
+ PKRU_AD_KEY( 7) | PKRU_AD_KEY( 8) | PKRU_AD_KEY( 9) |
+ PKRU_AD_KEY(10) | PKRU_AD_KEY(11) | PKRU_AD_KEY(12) |
+ PKRU_AD_KEY(13) | PKRU_AD_KEY(14) | PKRU_AD_KEY(15);
+
+/*
+ * Called from the FPU code when creating a fresh set of FPU
+ * registers. This is called from a very specific context where
+ * we know the FPU regstiers are safe for use and we can use PKRU
+ * directly. The fact that PKRU is only available when we are
+ * using eagerfpu mode makes this possible.
+ */
+void copy_init_pkru_to_fpregs(void)
+{
+ u32 init_pkru_value_snapshot = READ_ONCE(init_pkru_value);
+ /*
+ * Any write to PKRU takes it out of the XSAVE 'init
+ * state' which increases context switch cost. Avoid
+ * writing 0 when PKRU was already 0.
+ */
+ if (!init_pkru_value_snapshot && !read_pkru())
+ return;
+ /*
+ * Override the PKRU state that came from 'init_fpstate'
+ * with the baseline from the process.
+ */
+ write_pkru(init_pkru_value_snapshot);
+}
+
+static ssize_t init_pkru_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "0x%x\n", init_pkru_value);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t init_pkru_write_file(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ ssize_t len;
+ u32 new_init_pkru;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ /* Make the buffer a valid string that we can not overrun */
+ buf[len] = '\0';
+ if (kstrtouint(buf, 0, &new_init_pkru))
+ return -EINVAL;
+
+ /*
+ * Don't allow insane settings that will blow the system
+ * up immediately if someone attempts to disable access
+ * or writes to pkey 0.
+ */
+ if (new_init_pkru & (PKRU_AD_BIT|PKRU_WD_BIT))
+ return -EINVAL;
+
+ WRITE_ONCE(init_pkru_value, new_init_pkru);
+ return count;
+}
+
+static const struct file_operations fops_init_pkru = {
+ .read = init_pkru_read_file,
+ .write = init_pkru_write_file,
+ .llseek = default_llseek,
+};
+
+static int __init create_init_pkru_value(void)
+{
+ debugfs_create_file("init_pkru", S_IRUSR | S_IWUSR,
+ arch_debugfs_dir, NULL, &fops_init_pkru);
+ return 0;
+}
+late_initcall(create_init_pkru_value);
+
+static __init int setup_init_pkru(char *opt)
+{
+ u32 new_init_pkru;
+
+ if (kstrtouint(opt, 0, &new_init_pkru))
+ return 1;
+
+ WRITE_ONCE(init_pkru_value, new_init_pkru);
+
+ return 1;
+}
+__setup("init_pkru=", setup_init_pkru);
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index 97062a635b77..5c6fc3577a49 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -23,8 +23,6 @@ obj-y += bus_numa.o
obj-$(CONFIG_AMD_NB) += amd_bus.o
obj-$(CONFIG_PCI_CNB20LE_QUIRK) += broadcom_bus.o
-obj-$(CONFIG_VMD) += vmd.o
-
ifeq ($(CONFIG_PCI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 7b6a9d14c8c0..a4fdfa7dcc1b 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -677,6 +677,12 @@ static void set_dma_domain_ops(struct pci_dev *pdev)
static void set_dma_domain_ops(struct pci_dev *pdev) {}
#endif
+static void set_dev_domain_options(struct pci_dev *pdev)
+{
+ if (is_vmd(pdev->bus))
+ pdev->hotplug_user_indicators = 1;
+}
+
int pcibios_add_device(struct pci_dev *dev)
{
struct setup_data *data;
@@ -707,6 +713,7 @@ int pcibios_add_device(struct pci_dev *dev)
iounmap(data);
}
set_dma_domain_ops(dev);
+ set_dev_domain_options(dev);
return 0;
}
diff --git a/arch/xtensa/include/uapi/asm/mman.h b/arch/xtensa/include/uapi/asm/mman.h
index 9e079d49e7f2..24365b30aae9 100644
--- a/arch/xtensa/include/uapi/asm/mman.h
+++ b/arch/xtensa/include/uapi/asm/mman.h
@@ -117,4 +117,9 @@
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
#endif /* _XTENSA_MMAN_H */
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index 72cfe3587dd8..31411fc82662 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -89,6 +89,9 @@ SECTIONS
VMLINUX_SYMBOL(__sched_text_start) = .;
*(.sched.literal .sched.text)
VMLINUX_SYMBOL(__sched_text_end) = .;
+ VMLINUX_SYMBOL(__cpuidle_text_start) = .;
+ *(.cpuidle.literal .cpuidle.text)
+ VMLINUX_SYMBOL(__cpuidle_text_end) = .;
VMLINUX_SYMBOL(__lock_text_start) = .;
*(.spinlock.literal .spinlock.text)
VMLINUX_SYMBOL(__lock_text_end) = .;
diff --git a/block/Kconfig b/block/Kconfig
index 161491d0a879..1d4d624492fc 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -4,6 +4,7 @@
menuconfig BLOCK
bool "Enable the block layer" if EXPERT
default y
+ select SBITMAP
help
Provide block layer support for the kernel.
@@ -124,4 +125,9 @@ config BLOCK_COMPAT
depends on BLOCK && COMPAT
default y
+config BLK_MQ_PCI
+ bool
+ depends on BLOCK && PCI
+ default y
+
source block/Kconfig.iosched
diff --git a/block/Makefile b/block/Makefile
index 9eda2322b2d4..36acdd7545be 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \
blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
blk-lib.o blk-mq.o blk-mq-tag.o \
- blk-mq-sysfs.o blk-mq-cpu.o blk-mq-cpumap.o ioctl.o \
+ blk-mq-sysfs.o blk-mq-cpumap.o ioctl.o \
genhd.o scsi_ioctl.o partition-generic.o ioprio.o \
badblocks.o partitions/
@@ -22,4 +22,4 @@ obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
obj-$(CONFIG_BLK_CMDLINE_PARSER) += cmdline-parser.o
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
-
+obj-$(CONFIG_BLK_MQ_PCI) += blk-mq-pci.o
diff --git a/block/bio.c b/block/bio.c
index aa7354088008..db85c5753a76 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1068,7 +1068,7 @@ static int bio_copy_to_iter(struct bio *bio, struct iov_iter iter)
return 0;
}
-static void bio_free_pages(struct bio *bio)
+void bio_free_pages(struct bio *bio)
{
struct bio_vec *bvec;
int i;
@@ -1076,6 +1076,7 @@ static void bio_free_pages(struct bio *bio)
bio_for_each_segment_all(bvec, bio, i)
__free_page(bvec->bv_page);
}
+EXPORT_SYMBOL(bio_free_pages);
/**
* bio_uncopy_user - finish previously mapped bio
@@ -1274,7 +1275,7 @@ struct bio *bio_map_user_iov(struct request_queue *q,
nr_pages += end - start;
/*
- * buffer must be aligned to at least hardsector size for now
+ * buffer must be aligned to at least logical block size for now
*/
if (uaddr & queue_dma_alignment(q))
return ERR_PTR(-EINVAL);
diff --git a/block/blk-core.c b/block/blk-core.c
index 36c7ac328d8c..14d7c0740dc0 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -288,7 +288,7 @@ void blk_sync_queue(struct request_queue *q)
int i;
queue_for_each_hw_ctx(q, hctx, i) {
- cancel_delayed_work_sync(&hctx->run_work);
+ cancel_work_sync(&hctx->run_work);
cancel_delayed_work_sync(&hctx->delay_work);
}
} else {
@@ -3097,6 +3097,12 @@ int kblockd_schedule_work(struct work_struct *work)
}
EXPORT_SYMBOL(kblockd_schedule_work);
+int kblockd_schedule_work_on(int cpu, struct work_struct *work)
+{
+ return queue_work_on(cpu, kblockd_workqueue, work);
+}
+EXPORT_SYMBOL(kblockd_schedule_work_on);
+
int kblockd_schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
{
@@ -3301,19 +3307,23 @@ bool blk_poll(struct request_queue *q, blk_qc_t cookie)
{
struct blk_plug *plug;
long state;
+ unsigned int queue_num;
+ struct blk_mq_hw_ctx *hctx;
if (!q->mq_ops || !q->mq_ops->poll || !blk_qc_t_valid(cookie) ||
!test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
return false;
+ queue_num = blk_qc_t_to_queue_num(cookie);
+ hctx = q->queue_hw_ctx[queue_num];
+ hctx->poll_considered++;
+
plug = current->plug;
if (plug)
blk_flush_plug_list(plug, false);
state = current->state;
while (!need_resched()) {
- unsigned int queue_num = blk_qc_t_to_queue_num(cookie);
- struct blk_mq_hw_ctx *hctx = q->queue_hw_ctx[queue_num];
int ret;
hctx->poll_invoked++;
diff --git a/block/blk-flush.c b/block/blk-flush.c
index d308def812db..6a14b68b9135 100644
--- a/block/blk-flush.c
+++ b/block/blk-flush.c
@@ -232,7 +232,7 @@ static void flush_end_io(struct request *flush_rq, int error)
/* release the tag's ownership to the req cloned from */
spin_lock_irqsave(&fq->mq_flush_lock, flags);
- hctx = q->mq_ops->map_queue(q, flush_rq->mq_ctx->cpu);
+ hctx = blk_mq_map_queue(q, flush_rq->mq_ctx->cpu);
blk_mq_tag_set_rq(hctx, flush_rq->tag, fq->orig_rq);
flush_rq->tag = -1;
}
@@ -325,7 +325,7 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq)
flush_rq->tag = first_rq->tag;
fq->orig_rq = first_rq;
- hctx = q->mq_ops->map_queue(q, first_rq->mq_ctx->cpu);
+ hctx = blk_mq_map_queue(q, first_rq->mq_ctx->cpu);
blk_mq_tag_set_rq(hctx, first_rq->tag, flush_rq);
}
@@ -358,7 +358,7 @@ static void mq_flush_data_end_io(struct request *rq, int error)
unsigned long flags;
struct blk_flush_queue *fq = blk_get_flush_queue(q, ctx);
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
+ hctx = blk_mq_map_queue(q, ctx->cpu);
/*
* After populating an empty queue, kick it to avoid stall. Read
diff --git a/block/blk-mq-cpu.c b/block/blk-mq-cpu.c
deleted file mode 100644
index bb3ed488f7b5..000000000000
--- a/block/blk-mq-cpu.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * CPU notifier helper code for blk-mq
- *
- * Copyright (C) 2013-2014 Jens Axboe
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/list.h>
-#include <linux/llist.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-
-#include <linux/blk-mq.h>
-#include "blk-mq.h"
-
-static LIST_HEAD(blk_mq_cpu_notify_list);
-static DEFINE_RAW_SPINLOCK(blk_mq_cpu_notify_lock);
-
-static int blk_mq_main_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- unsigned int cpu = (unsigned long) hcpu;
- struct blk_mq_cpu_notifier *notify;
- int ret = NOTIFY_OK;
-
- raw_spin_lock(&blk_mq_cpu_notify_lock);
-
- list_for_each_entry(notify, &blk_mq_cpu_notify_list, list) {
- ret = notify->notify(notify->data, action, cpu);
- if (ret != NOTIFY_OK)
- break;
- }
-
- raw_spin_unlock(&blk_mq_cpu_notify_lock);
- return ret;
-}
-
-void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
-{
- BUG_ON(!notifier->notify);
-
- raw_spin_lock(&blk_mq_cpu_notify_lock);
- list_add_tail(&notifier->list, &blk_mq_cpu_notify_list);
- raw_spin_unlock(&blk_mq_cpu_notify_lock);
-}
-
-void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
-{
- raw_spin_lock(&blk_mq_cpu_notify_lock);
- list_del(&notifier->list);
- raw_spin_unlock(&blk_mq_cpu_notify_lock);
-}
-
-void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
- int (*fn)(void *, unsigned long, unsigned int),
- void *data)
-{
- notifier->notify = fn;
- notifier->data = data;
-}
-
-void __init blk_mq_cpu_init(void)
-{
- hotcpu_notifier(blk_mq_main_cpu_notify, 0);
-}
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index d0634bcf322f..19b1d9c5f07e 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -31,14 +31,16 @@ static int get_first_sibling(unsigned int cpu)
return cpu;
}
-int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues,
- const struct cpumask *online_mask)
+int blk_mq_map_queues(struct blk_mq_tag_set *set)
{
+ unsigned int *map = set->mq_map;
+ unsigned int nr_queues = set->nr_hw_queues;
+ const struct cpumask *online_mask = cpu_online_mask;
unsigned int i, nr_cpus, nr_uniq_cpus, queue, first_sibling;
cpumask_var_t cpus;
if (!alloc_cpumask_var(&cpus, GFP_ATOMIC))
- return 1;
+ return -ENOMEM;
cpumask_clear(cpus);
nr_cpus = nr_uniq_cpus = 0;
@@ -86,23 +88,6 @@ 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_tag_set *set)
-{
- unsigned int *map;
-
- /* If cpus are offline, map them to first hctx */
- map = kzalloc_node(sizeof(*map) * nr_cpu_ids, GFP_KERNEL,
- set->numa_node);
- if (!map)
- return NULL;
-
- if (!blk_mq_update_queue_map(map, set->nr_hw_queues, cpu_online_mask))
- return map;
-
- kfree(map);
- return NULL;
-}
-
/*
* We have no quick way of doing reverse lookups. This is only used at
* queue init time, so runtime isn't important.
diff --git a/block/blk-mq-pci.c b/block/blk-mq-pci.c
new file mode 100644
index 000000000000..966c2169762e
--- /dev/null
+++ b/block/blk-mq-pci.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 Christoph Hellwig.
+ *
+ * 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.
+ */
+#include <linux/kobject.h>
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/blk-mq-pci.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+
+/**
+ * blk_mq_pci_map_queues - provide a default queue mapping for PCI device
+ * @set: tagset to provide the mapping for
+ * @pdev: PCI device associated with @set.
+ *
+ * This function assumes the PCI device @pdev has at least as many available
+ * interrupt vetors as @set has queues. It will then queuery the vector
+ * corresponding to each queue for it's affinity mask and built queue mapping
+ * that maps a queue to the CPUs that have irq affinity for the corresponding
+ * vector.
+ */
+int blk_mq_pci_map_queues(struct blk_mq_tag_set *set, struct pci_dev *pdev)
+{
+ const struct cpumask *mask;
+ unsigned int queue, cpu;
+
+ for (queue = 0; queue < set->nr_hw_queues; queue++) {
+ mask = pci_irq_get_affinity(pdev, queue);
+ if (!mask)
+ return -EINVAL;
+
+ for_each_cpu(cpu, mask)
+ set->mq_map[cpu] = queue;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(blk_mq_pci_map_queues);
diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c
index fe822aa5b8e4..01fb455d3377 100644
--- a/block/blk-mq-sysfs.c
+++ b/block/blk-mq-sysfs.c
@@ -176,7 +176,17 @@ static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page)
static ssize_t blk_mq_hw_sysfs_poll_show(struct blk_mq_hw_ctx *hctx, char *page)
{
- return sprintf(page, "invoked=%lu, success=%lu\n", hctx->poll_invoked, hctx->poll_success);
+ return sprintf(page, "considered=%lu, invoked=%lu, success=%lu\n",
+ hctx->poll_considered, hctx->poll_invoked,
+ hctx->poll_success);
+}
+
+static ssize_t blk_mq_hw_sysfs_poll_store(struct blk_mq_hw_ctx *hctx,
+ const char *page, size_t size)
+{
+ hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
+
+ return size;
}
static ssize_t blk_mq_hw_sysfs_queued_show(struct blk_mq_hw_ctx *hctx,
@@ -198,12 +208,14 @@ static ssize_t blk_mq_hw_sysfs_dispatched_show(struct blk_mq_hw_ctx *hctx,
page += sprintf(page, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
- for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER; i++) {
- unsigned long d = 1U << (i - 1);
+ for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
+ unsigned int d = 1U << (i - 1);
- page += sprintf(page, "%8lu\t%lu\n", d, hctx->dispatched[i]);
+ page += sprintf(page, "%8u\t%lu\n", d, hctx->dispatched[i]);
}
+ page += sprintf(page, "%8u+\t%lu\n", 1U << (i - 1),
+ hctx->dispatched[i]);
return page - start_page;
}
@@ -301,8 +313,9 @@ static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
.show = blk_mq_hw_sysfs_cpus_show,
};
static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_poll = {
- .attr = {.name = "io_poll", .mode = S_IRUGO },
+ .attr = {.name = "io_poll", .mode = S_IWUSR | S_IRUGO },
.show = blk_mq_hw_sysfs_poll_show,
+ .store = blk_mq_hw_sysfs_poll_store,
};
static struct attribute *default_hw_ctx_attrs[] = {
@@ -380,9 +393,8 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
return ret;
}
-static void __blk_mq_unregister_disk(struct gendisk *disk)
+static void __blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
{
- struct request_queue *q = disk->queue;
struct blk_mq_hw_ctx *hctx;
struct blk_mq_ctx *ctx;
int i, j;
@@ -400,15 +412,15 @@ static void __blk_mq_unregister_disk(struct gendisk *disk)
kobject_del(&q->mq_kobj);
kobject_put(&q->mq_kobj);
- kobject_put(&disk_to_dev(disk)->kobj);
+ kobject_put(&dev->kobj);
q->mq_sysfs_init_done = false;
}
-void blk_mq_unregister_disk(struct gendisk *disk)
+void blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
{
blk_mq_disable_hotplug();
- __blk_mq_unregister_disk(disk);
+ __blk_mq_unregister_dev(dev, q);
blk_mq_enable_hotplug();
}
@@ -430,10 +442,8 @@ static void blk_mq_sysfs_init(struct request_queue *q)
}
}
-int blk_mq_register_disk(struct gendisk *disk)
+int blk_mq_register_dev(struct device *dev, struct request_queue *q)
{
- struct device *dev = disk_to_dev(disk);
- struct request_queue *q = disk->queue;
struct blk_mq_hw_ctx *hctx;
int ret, i;
@@ -454,7 +464,7 @@ int blk_mq_register_disk(struct gendisk *disk)
}
if (ret)
- __blk_mq_unregister_disk(disk);
+ __blk_mq_unregister_dev(dev, q);
else
q->mq_sysfs_init_done = true;
out:
@@ -462,7 +472,7 @@ out:
return ret;
}
-EXPORT_SYMBOL_GPL(blk_mq_register_disk);
+EXPORT_SYMBOL_GPL(blk_mq_register_dev);
void blk_mq_sysfs_unregister(struct request_queue *q)
{
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index 729bac3a673b..dcf5ce3ba4bf 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -1,58 +1,24 @@
/*
- * Fast and scalable bitmap tagging variant. Uses sparser bitmaps spread
- * over multiple cachelines to avoid ping-pong between multiple submitters
- * or submitter and completer. Uses rolling wakeups to avoid falling of
- * the scaling cliff when we run out of tags and have to start putting
- * submitters to sleep.
- *
- * Uses active queue tracking to support fairer distribution of tags
- * between multiple submitters when a shared tag map is used.
+ * Tag allocation using scalable bitmaps. Uses active queue tracking to support
+ * fairer distribution of tags between multiple submitters when a shared tag map
+ * is used.
*
* Copyright (C) 2013-2014 Jens Axboe
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/random.h>
#include <linux/blk-mq.h>
#include "blk.h"
#include "blk-mq.h"
#include "blk-mq-tag.h"
-static bool bt_has_free_tags(struct blk_mq_bitmap_tags *bt)
-{
- int i;
-
- for (i = 0; i < bt->map_nr; i++) {
- struct blk_align_bitmap *bm = &bt->map[i];
- int ret;
-
- ret = find_first_zero_bit(&bm->word, bm->depth);
- if (ret < bm->depth)
- return true;
- }
-
- return false;
-}
-
bool blk_mq_has_free_tags(struct blk_mq_tags *tags)
{
if (!tags)
return true;
- return bt_has_free_tags(&tags->bitmap_tags);
-}
-
-static inline int bt_index_inc(int index)
-{
- return (index + 1) & (BT_WAIT_QUEUES - 1);
-}
-
-static inline void bt_index_atomic_inc(atomic_t *index)
-{
- int old = atomic_read(index);
- int new = bt_index_inc(old);
- atomic_cmpxchg(index, old, new);
+ return sbitmap_any_bit_clear(&tags->bitmap_tags.sb);
}
/*
@@ -72,29 +38,9 @@ bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
*/
void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool include_reserve)
{
- struct blk_mq_bitmap_tags *bt;
- int i, wake_index;
-
- /*
- * Make sure all changes prior to this are visible from other CPUs.
- */
- smp_mb();
- bt = &tags->bitmap_tags;
- wake_index = atomic_read(&bt->wake_index);
- for (i = 0; i < BT_WAIT_QUEUES; i++) {
- struct bt_wait_state *bs = &bt->bs[wake_index];
-
- if (waitqueue_active(&bs->wait))
- wake_up(&bs->wait);
-
- wake_index = bt_index_inc(wake_index);
- }
-
- if (include_reserve) {
- bt = &tags->breserved_tags;
- if (waitqueue_active(&bt->bs[0].wait))
- wake_up(&bt->bs[0].wait);
- }
+ sbitmap_queue_wake_all(&tags->bitmap_tags);
+ if (include_reserve)
+ sbitmap_queue_wake_all(&tags->breserved_tags);
}
/*
@@ -118,7 +64,7 @@ void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
* and attempt to provide a fair share of the tag depth for each of them.
*/
static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
- struct blk_mq_bitmap_tags *bt)
+ struct sbitmap_queue *bt)
{
unsigned int depth, users;
@@ -130,7 +76,7 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
/*
* Don't try dividing an ant
*/
- if (bt->depth == 1)
+ if (bt->sb.depth == 1)
return true;
users = atomic_read(&hctx->tags->active_queues);
@@ -140,142 +86,36 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
/*
* Allow at least some tags
*/
- depth = max((bt->depth + users - 1) / users, 4U);
+ depth = max((bt->sb.depth + users - 1) / users, 4U);
return atomic_read(&hctx->nr_active) < depth;
}
-static int __bt_get_word(struct blk_align_bitmap *bm, unsigned int last_tag,
- bool nowrap)
-{
- int tag, org_last_tag = last_tag;
-
- while (1) {
- tag = find_next_zero_bit(&bm->word, bm->depth, last_tag);
- if (unlikely(tag >= bm->depth)) {
- /*
- * We started with an offset, and we didn't reset the
- * offset to 0 in a failure case, so start from 0 to
- * exhaust the map.
- */
- if (org_last_tag && last_tag && !nowrap) {
- last_tag = org_last_tag = 0;
- continue;
- }
- return -1;
- }
-
- if (!test_and_set_bit(tag, &bm->word))
- break;
-
- last_tag = tag + 1;
- if (last_tag >= bm->depth - 1)
- last_tag = 0;
- }
-
- return tag;
-}
-
-#define BT_ALLOC_RR(tags) (tags->alloc_policy == BLK_TAG_ALLOC_RR)
-
-/*
- * Straight forward bitmap tag implementation, where each bit is a tag
- * (cleared == free, and set == busy). The small twist is using per-cpu
- * last_tag caches, which blk-mq stores in the blk_mq_ctx software queue
- * contexts. This enables us to drastically limit the space searched,
- * without dirtying an extra shared cacheline like we would if we stored
- * the cache value inside the shared blk_mq_bitmap_tags structure. On top
- * of that, each word of tags is in a separate cacheline. This means that
- * multiple users will tend to stick to different cachelines, at least
- * until the map is exhausted.
- */
-static int __bt_get(struct blk_mq_hw_ctx *hctx, struct blk_mq_bitmap_tags *bt,
- unsigned int *tag_cache, struct blk_mq_tags *tags)
+static int __bt_get(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt)
{
- unsigned int last_tag, org_last_tag;
- int index, i, tag;
-
if (!hctx_may_queue(hctx, bt))
return -1;
-
- last_tag = org_last_tag = *tag_cache;
- index = TAG_TO_INDEX(bt, last_tag);
-
- for (i = 0; i < bt->map_nr; i++) {
- tag = __bt_get_word(&bt->map[index], TAG_TO_BIT(bt, last_tag),
- BT_ALLOC_RR(tags));
- if (tag != -1) {
- tag += (index << bt->bits_per_word);
- goto done;
- }
-
- /*
- * Jump to next index, and reset the last tag to be the
- * first tag of that index
- */
- index++;
- last_tag = (index << bt->bits_per_word);
-
- if (index >= bt->map_nr) {
- index = 0;
- last_tag = 0;
- }
- }
-
- *tag_cache = 0;
- return -1;
-
- /*
- * Only update the cache from the allocation path, if we ended
- * up using the specific cached tag.
- */
-done:
- if (tag == org_last_tag || unlikely(BT_ALLOC_RR(tags))) {
- last_tag = tag + 1;
- if (last_tag >= bt->depth - 1)
- last_tag = 0;
-
- *tag_cache = last_tag;
- }
-
- return tag;
+ return __sbitmap_queue_get(bt);
}
-static struct bt_wait_state *bt_wait_ptr(struct blk_mq_bitmap_tags *bt,
- struct blk_mq_hw_ctx *hctx)
+static int bt_get(struct blk_mq_alloc_data *data, struct sbitmap_queue *bt,
+ struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags)
{
- struct bt_wait_state *bs;
- int wait_index;
-
- if (!hctx)
- return &bt->bs[0];
-
- wait_index = atomic_read(&hctx->wait_index);
- bs = &bt->bs[wait_index];
- bt_index_atomic_inc(&hctx->wait_index);
- return bs;
-}
-
-static int bt_get(struct blk_mq_alloc_data *data,
- struct blk_mq_bitmap_tags *bt,
- struct blk_mq_hw_ctx *hctx,
- unsigned int *last_tag, struct blk_mq_tags *tags)
-{
- struct bt_wait_state *bs;
+ struct sbq_wait_state *ws;
DEFINE_WAIT(wait);
int tag;
- tag = __bt_get(hctx, bt, last_tag, tags);
+ tag = __bt_get(hctx, bt);
if (tag != -1)
return tag;
if (data->flags & BLK_MQ_REQ_NOWAIT)
return -1;
- bs = bt_wait_ptr(bt, hctx);
+ ws = bt_wait_ptr(bt, hctx);
do {
- prepare_to_wait(&bs->wait, &wait, TASK_UNINTERRUPTIBLE);
+ prepare_to_wait(&ws->wait, &wait, TASK_UNINTERRUPTIBLE);
- tag = __bt_get(hctx, bt, last_tag, tags);
+ tag = __bt_get(hctx, bt);
if (tag != -1)
break;
@@ -292,7 +132,7 @@ static int bt_get(struct blk_mq_alloc_data *data,
* Retry tag allocation after running the hardware queue,
* as running the queue may also have found completions.
*/
- tag = __bt_get(hctx, bt, last_tag, tags);
+ tag = __bt_get(hctx, bt);
if (tag != -1)
break;
@@ -301,20 +141,18 @@ static int bt_get(struct blk_mq_alloc_data *data,
io_schedule();
data->ctx = blk_mq_get_ctx(data->q);
- data->hctx = data->q->mq_ops->map_queue(data->q,
- data->ctx->cpu);
+ data->hctx = blk_mq_map_queue(data->q, data->ctx->cpu);
if (data->flags & BLK_MQ_REQ_RESERVED) {
bt = &data->hctx->tags->breserved_tags;
} else {
- last_tag = &data->ctx->last_tag;
hctx = data->hctx;
bt = &hctx->tags->bitmap_tags;
}
- finish_wait(&bs->wait, &wait);
- bs = bt_wait_ptr(bt, hctx);
+ finish_wait(&ws->wait, &wait);
+ ws = bt_wait_ptr(bt, hctx);
} while (1);
- finish_wait(&bs->wait, &wait);
+ finish_wait(&ws->wait, &wait);
return tag;
}
@@ -323,7 +161,7 @@ static unsigned int __blk_mq_get_tag(struct blk_mq_alloc_data *data)
int tag;
tag = bt_get(data, &data->hctx->tags->bitmap_tags, data->hctx,
- &data->ctx->last_tag, data->hctx->tags);
+ data->hctx->tags);
if (tag >= 0)
return tag + data->hctx->tags->nr_reserved_tags;
@@ -332,15 +170,15 @@ static unsigned int __blk_mq_get_tag(struct blk_mq_alloc_data *data)
static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_alloc_data *data)
{
- int tag, zero = 0;
+ int tag;
if (unlikely(!data->hctx->tags->nr_reserved_tags)) {
WARN_ON_ONCE(1);
return BLK_MQ_TAG_FAIL;
}
- tag = bt_get(data, &data->hctx->tags->breserved_tags, NULL, &zero,
- data->hctx->tags);
+ tag = bt_get(data, &data->hctx->tags->breserved_tags, NULL,
+ data->hctx->tags);
if (tag < 0)
return BLK_MQ_TAG_FAIL;
@@ -354,55 +192,8 @@ unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data)
return __blk_mq_get_tag(data);
}
-static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt)
-{
- int i, wake_index;
-
- wake_index = atomic_read(&bt->wake_index);
- for (i = 0; i < BT_WAIT_QUEUES; i++) {
- struct bt_wait_state *bs = &bt->bs[wake_index];
-
- if (waitqueue_active(&bs->wait)) {
- int o = atomic_read(&bt->wake_index);
- if (wake_index != o)
- atomic_cmpxchg(&bt->wake_index, o, wake_index);
-
- return bs;
- }
-
- wake_index = bt_index_inc(wake_index);
- }
-
- return NULL;
-}
-
-static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag)
-{
- const int index = TAG_TO_INDEX(bt, tag);
- struct bt_wait_state *bs;
- int wait_cnt;
-
- clear_bit(TAG_TO_BIT(bt, tag), &bt->map[index].word);
-
- /* Ensure that the wait list checks occur after clear_bit(). */
- smp_mb();
-
- bs = bt_wake_ptr(bt);
- if (!bs)
- return;
-
- wait_cnt = atomic_dec_return(&bs->wait_cnt);
- if (unlikely(wait_cnt < 0))
- wait_cnt = atomic_inc_return(&bs->wait_cnt);
- if (wait_cnt == 0) {
- atomic_add(bt->wake_cnt, &bs->wait_cnt);
- bt_index_atomic_inc(&bt->wake_index);
- wake_up(&bs->wait);
- }
-}
-
-void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, unsigned int tag,
- unsigned int *last_tag)
+void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
+ unsigned int tag)
{
struct blk_mq_tags *tags = hctx->tags;
@@ -410,67 +201,92 @@ void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, unsigned int tag,
const int real_tag = tag - tags->nr_reserved_tags;
BUG_ON(real_tag >= tags->nr_tags);
- bt_clear_tag(&tags->bitmap_tags, real_tag);
- if (likely(tags->alloc_policy == BLK_TAG_ALLOC_FIFO))
- *last_tag = real_tag;
+ sbitmap_queue_clear(&tags->bitmap_tags, real_tag, ctx->cpu);
} else {
BUG_ON(tag >= tags->nr_reserved_tags);
- bt_clear_tag(&tags->breserved_tags, tag);
+ sbitmap_queue_clear(&tags->breserved_tags, tag, ctx->cpu);
}
}
-static void bt_for_each(struct blk_mq_hw_ctx *hctx,
- struct blk_mq_bitmap_tags *bt, unsigned int off,
- busy_iter_fn *fn, void *data, bool reserved)
+struct bt_iter_data {
+ struct blk_mq_hw_ctx *hctx;
+ busy_iter_fn *fn;
+ void *data;
+ bool reserved;
+};
+
+static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
{
+ struct bt_iter_data *iter_data = data;
+ struct blk_mq_hw_ctx *hctx = iter_data->hctx;
+ struct blk_mq_tags *tags = hctx->tags;
+ bool reserved = iter_data->reserved;
struct request *rq;
- int bit, i;
- for (i = 0; i < bt->map_nr; i++) {
- struct blk_align_bitmap *bm = &bt->map[i];
+ if (!reserved)
+ bitnr += tags->nr_reserved_tags;
+ rq = tags->rqs[bitnr];
- for (bit = find_first_bit(&bm->word, bm->depth);
- bit < bm->depth;
- bit = find_next_bit(&bm->word, bm->depth, bit + 1)) {
- rq = hctx->tags->rqs[off + bit];
- if (rq->q == hctx->queue)
- fn(hctx, rq, data, reserved);
- }
+ if (rq->q == hctx->queue)
+ iter_data->fn(hctx, rq, iter_data->data, reserved);
+ return true;
+}
- off += (1 << bt->bits_per_word);
- }
+static void bt_for_each(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt,
+ busy_iter_fn *fn, void *data, bool reserved)
+{
+ struct bt_iter_data iter_data = {
+ .hctx = hctx,
+ .fn = fn,
+ .data = data,
+ .reserved = reserved,
+ };
+
+ sbitmap_for_each_set(&bt->sb, bt_iter, &iter_data);
}
-static void bt_tags_for_each(struct blk_mq_tags *tags,
- struct blk_mq_bitmap_tags *bt, unsigned int off,
- busy_tag_iter_fn *fn, void *data, bool reserved)
+struct bt_tags_iter_data {
+ struct blk_mq_tags *tags;
+ busy_tag_iter_fn *fn;
+ void *data;
+ bool reserved;
+};
+
+static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
{
+ struct bt_tags_iter_data *iter_data = data;
+ struct blk_mq_tags *tags = iter_data->tags;
+ bool reserved = iter_data->reserved;
struct request *rq;
- int bit, i;
- if (!tags->rqs)
- return;
- for (i = 0; i < bt->map_nr; i++) {
- struct blk_align_bitmap *bm = &bt->map[i];
-
- for (bit = find_first_bit(&bm->word, bm->depth);
- bit < bm->depth;
- bit = find_next_bit(&bm->word, bm->depth, bit + 1)) {
- rq = tags->rqs[off + bit];
- fn(rq, data, reserved);
- }
+ if (!reserved)
+ bitnr += tags->nr_reserved_tags;
+ rq = tags->rqs[bitnr];
- off += (1 << bt->bits_per_word);
- }
+ iter_data->fn(rq, iter_data->data, reserved);
+ return true;
+}
+
+static void bt_tags_for_each(struct blk_mq_tags *tags, struct sbitmap_queue *bt,
+ busy_tag_iter_fn *fn, void *data, bool reserved)
+{
+ struct bt_tags_iter_data iter_data = {
+ .tags = tags,
+ .fn = fn,
+ .data = data,
+ .reserved = reserved,
+ };
+
+ if (tags->rqs)
+ sbitmap_for_each_set(&bt->sb, bt_tags_iter, &iter_data);
}
static void blk_mq_all_tag_busy_iter(struct blk_mq_tags *tags,
busy_tag_iter_fn *fn, void *priv)
{
if (tags->nr_reserved_tags)
- bt_tags_for_each(tags, &tags->breserved_tags, 0, fn, priv, true);
- bt_tags_for_each(tags, &tags->bitmap_tags, tags->nr_reserved_tags, fn, priv,
- false);
+ bt_tags_for_each(tags, &tags->breserved_tags, fn, priv, true);
+ bt_tags_for_each(tags, &tags->bitmap_tags, fn, priv, false);
}
void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset,
@@ -529,124 +345,40 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
continue;
if (tags->nr_reserved_tags)
- bt_for_each(hctx, &tags->breserved_tags, 0, fn, priv, true);
- bt_for_each(hctx, &tags->bitmap_tags, tags->nr_reserved_tags, fn, priv,
- false);
+ bt_for_each(hctx, &tags->breserved_tags, fn, priv, true);
+ bt_for_each(hctx, &tags->bitmap_tags, fn, priv, false);
}
}
-static unsigned int bt_unused_tags(struct blk_mq_bitmap_tags *bt)
+static unsigned int bt_unused_tags(const struct sbitmap_queue *bt)
{
- unsigned int i, used;
-
- for (i = 0, used = 0; i < bt->map_nr; i++) {
- struct blk_align_bitmap *bm = &bt->map[i];
-
- used += bitmap_weight(&bm->word, bm->depth);
- }
-
- return bt->depth - used;
+ return bt->sb.depth - sbitmap_weight(&bt->sb);
}
-static void bt_update_count(struct blk_mq_bitmap_tags *bt,
- unsigned int depth)
+static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth,
+ bool round_robin, int node)
{
- unsigned int tags_per_word = 1U << bt->bits_per_word;
- unsigned int map_depth = depth;
-
- if (depth) {
- int i;
-
- for (i = 0; i < bt->map_nr; i++) {
- bt->map[i].depth = min(map_depth, tags_per_word);
- map_depth -= bt->map[i].depth;
- }
- }
-
- bt->wake_cnt = BT_WAIT_BATCH;
- if (bt->wake_cnt > depth / BT_WAIT_QUEUES)
- bt->wake_cnt = max(1U, depth / BT_WAIT_QUEUES);
-
- bt->depth = depth;
-}
-
-static int bt_alloc(struct blk_mq_bitmap_tags *bt, unsigned int depth,
- int node, bool reserved)
-{
- int i;
-
- bt->bits_per_word = ilog2(BITS_PER_LONG);
-
- /*
- * Depth can be zero for reserved tags, that's not a failure
- * condition.
- */
- if (depth) {
- unsigned int nr, tags_per_word;
-
- tags_per_word = (1 << bt->bits_per_word);
-
- /*
- * If the tag space is small, shrink the number of tags
- * per word so we spread over a few cachelines, at least.
- * If less than 4 tags, just forget about it, it's not
- * going to work optimally anyway.
- */
- if (depth >= 4) {
- while (tags_per_word * 4 > depth) {
- bt->bits_per_word--;
- tags_per_word = (1 << bt->bits_per_word);
- }
- }
-
- nr = ALIGN(depth, tags_per_word) / tags_per_word;
- bt->map = kzalloc_node(nr * sizeof(struct blk_align_bitmap),
- GFP_KERNEL, node);
- if (!bt->map)
- return -ENOMEM;
-
- bt->map_nr = nr;
- }
-
- bt->bs = kzalloc(BT_WAIT_QUEUES * sizeof(*bt->bs), GFP_KERNEL);
- if (!bt->bs) {
- kfree(bt->map);
- bt->map = NULL;
- return -ENOMEM;
- }
-
- bt_update_count(bt, depth);
-
- for (i = 0; i < BT_WAIT_QUEUES; i++) {
- init_waitqueue_head(&bt->bs[i].wait);
- atomic_set(&bt->bs[i].wait_cnt, bt->wake_cnt);
- }
-
- return 0;
-}
-
-static void bt_free(struct blk_mq_bitmap_tags *bt)
-{
- kfree(bt->map);
- kfree(bt->bs);
+ return sbitmap_queue_init_node(bt, depth, -1, round_robin, GFP_KERNEL,
+ node);
}
static struct blk_mq_tags *blk_mq_init_bitmap_tags(struct blk_mq_tags *tags,
int node, int alloc_policy)
{
unsigned int depth = tags->nr_tags - tags->nr_reserved_tags;
+ bool round_robin = alloc_policy == BLK_TAG_ALLOC_RR;
- tags->alloc_policy = alloc_policy;
-
- if (bt_alloc(&tags->bitmap_tags, depth, node, false))
- goto enomem;
- if (bt_alloc(&tags->breserved_tags, tags->nr_reserved_tags, node, true))
- goto enomem;
+ if (bt_alloc(&tags->bitmap_tags, depth, round_robin, node))
+ goto free_tags;
+ if (bt_alloc(&tags->breserved_tags, tags->nr_reserved_tags, round_robin,
+ node))
+ goto free_bitmap_tags;
return tags;
-enomem:
- bt_free(&tags->bitmap_tags);
+free_bitmap_tags:
+ sbitmap_queue_free(&tags->bitmap_tags);
+free_tags:
kfree(tags);
return NULL;
}
@@ -666,11 +398,6 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
if (!tags)
return NULL;
- if (!zalloc_cpumask_var(&tags->cpumask, GFP_KERNEL)) {
- kfree(tags);
- return NULL;
- }
-
tags->nr_tags = total_tags;
tags->nr_reserved_tags = reserved_tags;
@@ -679,19 +406,11 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
void blk_mq_free_tags(struct blk_mq_tags *tags)
{
- bt_free(&tags->bitmap_tags);
- bt_free(&tags->breserved_tags);
- free_cpumask_var(tags->cpumask);
+ sbitmap_queue_free(&tags->bitmap_tags);
+ sbitmap_queue_free(&tags->breserved_tags);
kfree(tags);
}
-void blk_mq_tag_init_last_tag(struct blk_mq_tags *tags, unsigned int *tag)
-{
- unsigned int depth = tags->nr_tags - tags->nr_reserved_tags;
-
- *tag = prandom_u32() % depth;
-}
-
int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
{
tdepth -= tags->nr_reserved_tags;
@@ -702,7 +421,8 @@ int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
* Don't need (or can't) update reserved tags here, they remain
* static and should never need resizing.
*/
- bt_update_count(&tags->bitmap_tags, tdepth);
+ sbitmap_queue_resize(&tags->bitmap_tags, tdepth);
+
blk_mq_tag_wakeup_all(tags, false);
return 0;
}
@@ -726,7 +446,7 @@ u32 blk_mq_unique_tag(struct request *rq)
int hwq = 0;
if (q->mq_ops) {
- hctx = q->mq_ops->map_queue(q, rq->mq_ctx->cpu);
+ hctx = blk_mq_map_queue(q, rq->mq_ctx->cpu);
hwq = hctx->queue_num;
}
@@ -746,7 +466,7 @@ ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
page += sprintf(page, "nr_tags=%u, reserved_tags=%u, "
"bits_per_word=%u\n",
tags->nr_tags, tags->nr_reserved_tags,
- tags->bitmap_tags.bits_per_word);
+ 1U << tags->bitmap_tags.sb.shift);
free = bt_unused_tags(&tags->bitmap_tags);
res = bt_unused_tags(&tags->breserved_tags);
diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h
index d468a79f2c4a..d1662734dc53 100644
--- a/block/blk-mq-tag.h
+++ b/block/blk-mq-tag.h
@@ -3,31 +3,6 @@
#include "blk-mq.h"
-enum {
- BT_WAIT_QUEUES = 8,
- BT_WAIT_BATCH = 8,
-};
-
-struct bt_wait_state {
- atomic_t wait_cnt;
- wait_queue_head_t wait;
-} ____cacheline_aligned_in_smp;
-
-#define TAG_TO_INDEX(bt, tag) ((tag) >> (bt)->bits_per_word)
-#define TAG_TO_BIT(bt, tag) ((tag) & ((1 << (bt)->bits_per_word) - 1))
-
-struct blk_mq_bitmap_tags {
- unsigned int depth;
- unsigned int wake_cnt;
- unsigned int bits_per_word;
-
- unsigned int map_nr;
- struct blk_align_bitmap *map;
-
- atomic_t wake_index;
- struct bt_wait_state *bs;
-};
-
/*
* Tag address space map.
*/
@@ -37,14 +12,11 @@ struct blk_mq_tags {
atomic_t active_queues;
- struct blk_mq_bitmap_tags bitmap_tags;
- struct blk_mq_bitmap_tags breserved_tags;
+ struct sbitmap_queue bitmap_tags;
+ struct sbitmap_queue breserved_tags;
struct request **rqs;
struct list_head page_list;
-
- int alloc_policy;
- cpumask_var_t cpumask;
};
@@ -52,15 +24,23 @@ extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags, unsigned int r
extern void blk_mq_free_tags(struct blk_mq_tags *tags);
extern unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data);
-extern void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, unsigned int tag, unsigned int *last_tag);
+extern void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
+ unsigned int tag);
extern bool blk_mq_has_free_tags(struct blk_mq_tags *tags);
extern ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page);
-extern void blk_mq_tag_init_last_tag(struct blk_mq_tags *tags, unsigned int *last_tag);
extern int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int depth);
extern void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool);
void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
void *priv);
+static inline struct sbq_wait_state *bt_wait_ptr(struct sbitmap_queue *bt,
+ struct blk_mq_hw_ctx *hctx)
+{
+ if (!hctx)
+ return &bt->ws[0];
+ return sbq_wait_ptr(bt, &hctx->wait_index);
+}
+
enum {
BLK_MQ_TAG_CACHE_MIN = 1,
BLK_MQ_TAG_CACHE_MAX = 64,
diff --git a/block/blk-mq.c b/block/blk-mq.c
index c207fa9870eb..ddc2eed64771 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -22,6 +22,7 @@
#include <linux/sched/sysctl.h>
#include <linux/delay.h>
#include <linux/crash_dump.h>
+#include <linux/prefetch.h>
#include <trace/events/block.h>
@@ -33,49 +34,28 @@
static DEFINE_MUTEX(all_q_mutex);
static LIST_HEAD(all_q_list);
-static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx);
-
/*
* Check if any of the ctx's have pending work in this hardware queue
*/
static bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
{
- unsigned int i;
-
- for (i = 0; i < hctx->ctx_map.size; i++)
- if (hctx->ctx_map.map[i].word)
- return true;
-
- return false;
+ return sbitmap_any_bit_set(&hctx->ctx_map);
}
-static inline struct blk_align_bitmap *get_bm(struct blk_mq_hw_ctx *hctx,
- struct blk_mq_ctx *ctx)
-{
- return &hctx->ctx_map.map[ctx->index_hw / hctx->ctx_map.bits_per_word];
-}
-
-#define CTX_TO_BIT(hctx, ctx) \
- ((ctx)->index_hw & ((hctx)->ctx_map.bits_per_word - 1))
-
/*
* Mark this ctx as having pending work in this hardware queue
*/
static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
struct blk_mq_ctx *ctx)
{
- struct blk_align_bitmap *bm = get_bm(hctx, ctx);
-
- if (!test_bit(CTX_TO_BIT(hctx, ctx), &bm->word))
- set_bit(CTX_TO_BIT(hctx, ctx), &bm->word);
+ if (!sbitmap_test_bit(&hctx->ctx_map, ctx->index_hw))
+ sbitmap_set_bit(&hctx->ctx_map, ctx->index_hw);
}
static void blk_mq_hctx_clear_pending(struct blk_mq_hw_ctx *hctx,
struct blk_mq_ctx *ctx)
{
- struct blk_align_bitmap *bm = get_bm(hctx, ctx);
-
- clear_bit(CTX_TO_BIT(hctx, ctx), &bm->word);
+ sbitmap_clear_bit(&hctx->ctx_map, ctx->index_hw);
}
void blk_mq_freeze_queue_start(struct request_queue *q)
@@ -244,21 +224,11 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
return ERR_PTR(ret);
ctx = blk_mq_get_ctx(q);
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
+ hctx = blk_mq_map_queue(q, ctx->cpu);
blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
-
rq = __blk_mq_alloc_request(&alloc_data, rw, 0);
- if (!rq && !(flags & BLK_MQ_REQ_NOWAIT)) {
- __blk_mq_run_hw_queue(hctx);
- blk_mq_put_ctx(ctx);
-
- ctx = blk_mq_get_ctx(q);
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
- blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
- rq = __blk_mq_alloc_request(&alloc_data, rw, 0);
- ctx = alloc_data.ctx;
- }
blk_mq_put_ctx(ctx);
+
if (!rq) {
blk_queue_exit(q);
return ERR_PTR(-EWOULDBLOCK);
@@ -333,7 +303,7 @@ static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx,
rq->cmd_flags = 0;
clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
- blk_mq_put_tag(hctx, tag, &ctx->last_tag);
+ blk_mq_put_tag(hctx, ctx, tag);
blk_queue_exit(q);
}
@@ -349,11 +319,7 @@ EXPORT_SYMBOL_GPL(blk_mq_free_hctx_request);
void blk_mq_free_request(struct request *rq)
{
- struct blk_mq_hw_ctx *hctx;
- struct request_queue *q = rq->q;
-
- hctx = q->mq_ops->map_queue(q, rq->mq_ctx->cpu);
- blk_mq_free_hctx_request(hctx, rq);
+ blk_mq_free_hctx_request(blk_mq_map_queue(rq->q, rq->mq_ctx->cpu), rq);
}
EXPORT_SYMBOL_GPL(blk_mq_free_request);
@@ -513,7 +479,7 @@ EXPORT_SYMBOL(blk_mq_requeue_request);
static void blk_mq_requeue_work(struct work_struct *work)
{
struct request_queue *q =
- container_of(work, struct request_queue, requeue_work);
+ container_of(work, struct request_queue, requeue_work.work);
LIST_HEAD(rq_list);
struct request *rq, *next;
unsigned long flags;
@@ -568,16 +534,24 @@ EXPORT_SYMBOL(blk_mq_add_to_requeue_list);
void blk_mq_cancel_requeue_work(struct request_queue *q)
{
- cancel_work_sync(&q->requeue_work);
+ cancel_delayed_work_sync(&q->requeue_work);
}
EXPORT_SYMBOL_GPL(blk_mq_cancel_requeue_work);
void blk_mq_kick_requeue_list(struct request_queue *q)
{
- kblockd_schedule_work(&q->requeue_work);
+ kblockd_schedule_delayed_work(&q->requeue_work, 0);
}
EXPORT_SYMBOL(blk_mq_kick_requeue_list);
+void blk_mq_delay_kick_requeue_list(struct request_queue *q,
+ unsigned long msecs)
+{
+ kblockd_schedule_delayed_work(&q->requeue_work,
+ msecs_to_jiffies(msecs));
+}
+EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list);
+
void blk_mq_abort_requeue_list(struct request_queue *q)
{
unsigned long flags;
@@ -600,8 +574,10 @@ EXPORT_SYMBOL(blk_mq_abort_requeue_list);
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag)
{
- if (tag < tags->nr_tags)
+ if (tag < tags->nr_tags) {
+ prefetch(tags->rqs[tag]);
return tags->rqs[tag];
+ }
return NULL;
}
@@ -756,38 +732,44 @@ static bool blk_mq_attempt_merge(struct request_queue *q,
return false;
}
+struct flush_busy_ctx_data {
+ struct blk_mq_hw_ctx *hctx;
+ struct list_head *list;
+};
+
+static bool flush_busy_ctx(struct sbitmap *sb, unsigned int bitnr, void *data)
+{
+ struct flush_busy_ctx_data *flush_data = data;
+ struct blk_mq_hw_ctx *hctx = flush_data->hctx;
+ struct blk_mq_ctx *ctx = hctx->ctxs[bitnr];
+
+ sbitmap_clear_bit(sb, bitnr);
+ spin_lock(&ctx->lock);
+ list_splice_tail_init(&ctx->rq_list, flush_data->list);
+ spin_unlock(&ctx->lock);
+ return true;
+}
+
/*
* Process software queues that have been marked busy, splicing them
* to the for-dispatch
*/
static void flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list)
{
- struct blk_mq_ctx *ctx;
- int i;
-
- for (i = 0; i < hctx->ctx_map.size; i++) {
- struct blk_align_bitmap *bm = &hctx->ctx_map.map[i];
- unsigned int off, bit;
-
- if (!bm->word)
- continue;
+ struct flush_busy_ctx_data data = {
+ .hctx = hctx,
+ .list = list,
+ };
- bit = 0;
- off = i * hctx->ctx_map.bits_per_word;
- do {
- bit = find_next_bit(&bm->word, bm->depth, bit);
- if (bit >= bm->depth)
- break;
+ sbitmap_for_each_set(&hctx->ctx_map, flush_busy_ctx, &data);
+}
- ctx = hctx->ctxs[bit + off];
- clear_bit(bit, &bm->word);
- spin_lock(&ctx->lock);
- list_splice_tail_init(&ctx->rq_list, list);
- spin_unlock(&ctx->lock);
+static inline unsigned int queued_to_index(unsigned int queued)
+{
+ if (!queued)
+ return 0;
- bit++;
- } while (1);
- }
+ return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1);
}
/*
@@ -878,10 +860,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
dptr = &driver_list;
}
- if (!queued)
- hctx->dispatched[0]++;
- else if (queued < (1 << (BLK_MQ_MAX_DISPATCH_ORDER - 1)))
- hctx->dispatched[ilog2(queued) + 1]++;
+ hctx->dispatched[queued_to_index(queued)]++;
/*
* Any items that need requeuing? Stuff them into hctx->dispatch,
@@ -937,7 +916,7 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
!blk_mq_hw_queue_mapped(hctx)))
return;
- if (!async) {
+ if (!async && !(hctx->flags & BLK_MQ_F_BLOCKING)) {
int cpu = get_cpu();
if (cpumask_test_cpu(cpu, hctx->cpumask)) {
__blk_mq_run_hw_queue(hctx);
@@ -948,8 +927,7 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
put_cpu();
}
- kblockd_schedule_delayed_work_on(blk_mq_hctx_next_cpu(hctx),
- &hctx->run_work, 0);
+ kblockd_schedule_work_on(blk_mq_hctx_next_cpu(hctx), &hctx->run_work);
}
void blk_mq_run_hw_queues(struct request_queue *q, bool async)
@@ -970,7 +948,7 @@ EXPORT_SYMBOL(blk_mq_run_hw_queues);
void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx)
{
- cancel_delayed_work(&hctx->run_work);
+ cancel_work(&hctx->run_work);
cancel_delayed_work(&hctx->delay_work);
set_bit(BLK_MQ_S_STOPPED, &hctx->state);
}
@@ -1023,7 +1001,7 @@ 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, run_work.work);
+ hctx = container_of(work, struct blk_mq_hw_ctx, run_work);
__blk_mq_run_hw_queue(hctx);
}
@@ -1076,9 +1054,7 @@ void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
{
struct blk_mq_ctx *ctx = rq->mq_ctx;
struct request_queue *q = rq->q;
- struct blk_mq_hw_ctx *hctx;
-
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
+ struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
spin_lock(&ctx->lock);
__blk_mq_insert_request(hctx, rq, at_head);
@@ -1095,12 +1071,10 @@ static void blk_mq_insert_requests(struct request_queue *q,
bool from_schedule)
{
- struct blk_mq_hw_ctx *hctx;
+ struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
trace_block_unplug(q, depth, !from_schedule);
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
/*
* preemption doesn't flush plug list, so it's possible ctx->cpu is
* offline now
@@ -1234,26 +1208,14 @@ static struct request *blk_mq_map_request(struct request_queue *q,
blk_queue_enter_live(q);
ctx = blk_mq_get_ctx(q);
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
+ hctx = blk_mq_map_queue(q, ctx->cpu);
if (rw_is_sync(bio_op(bio), bio->bi_opf))
op_flags |= REQ_SYNC;
trace_block_getrq(q, bio, op);
- blk_mq_set_alloc_data(&alloc_data, q, BLK_MQ_REQ_NOWAIT, ctx, hctx);
+ blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx);
rq = __blk_mq_alloc_request(&alloc_data, op, op_flags);
- if (unlikely(!rq)) {
- __blk_mq_run_hw_queue(hctx);
- blk_mq_put_ctx(ctx);
- trace_block_sleeprq(q, bio, op);
-
- ctx = blk_mq_get_ctx(q);
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
- blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx);
- rq = __blk_mq_alloc_request(&alloc_data, op, op_flags);
- ctx = alloc_data.ctx;
- hctx = alloc_data.hctx;
- }
hctx->queued++;
data->hctx = hctx;
@@ -1265,8 +1227,7 @@ static int blk_mq_direct_issue_request(struct request *rq, blk_qc_t *cookie)
{
int ret;
struct request_queue *q = rq->q;
- struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q,
- rq->mq_ctx->cpu);
+ struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, rq->mq_ctx->cpu);
struct blk_mq_queue_data bd = {
.rq = rq,
.list = NULL,
@@ -1470,15 +1431,6 @@ run_queue:
return cookie;
}
-/*
- * Default mapping to a software queue, since we use one per CPU.
- */
-struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q, const int cpu)
-{
- return q->queue_hw_ctx[q->mq_map[cpu]];
-}
-EXPORT_SYMBOL(blk_mq_map_queue);
-
static void blk_mq_free_rq_map(struct blk_mq_tag_set *set,
struct blk_mq_tags *tags, unsigned int hctx_idx)
{
@@ -1606,42 +1558,18 @@ fail:
return NULL;
}
-static void blk_mq_free_bitmap(struct blk_mq_ctxmap *bitmap)
-{
- kfree(bitmap->map);
-}
-
-static int blk_mq_alloc_bitmap(struct blk_mq_ctxmap *bitmap, int node)
-{
- unsigned int bpw = 8, total, num_maps, i;
-
- bitmap->bits_per_word = bpw;
-
- num_maps = ALIGN(nr_cpu_ids, bpw) / bpw;
- bitmap->map = kzalloc_node(num_maps * sizeof(struct blk_align_bitmap),
- GFP_KERNEL, node);
- if (!bitmap->map)
- return -ENOMEM;
-
- total = nr_cpu_ids;
- for (i = 0; i < num_maps; i++) {
- bitmap->map[i].depth = min(total, bitmap->bits_per_word);
- total -= bitmap->map[i].depth;
- }
-
- return 0;
-}
-
/*
* 'cpu' is going away. splice any existing rq_list entries from this
* software queue to the hw queue dispatch list, and ensure that it
* gets run.
*/
-static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
+static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node)
{
+ struct blk_mq_hw_ctx *hctx;
struct blk_mq_ctx *ctx;
LIST_HEAD(tmp);
+ hctx = hlist_entry_safe(node, struct blk_mq_hw_ctx, cpuhp_dead);
ctx = __blk_mq_get_ctx(hctx->queue, cpu);
spin_lock(&ctx->lock);
@@ -1652,30 +1580,20 @@ static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
spin_unlock(&ctx->lock);
if (list_empty(&tmp))
- return NOTIFY_OK;
+ return 0;
spin_lock(&hctx->lock);
list_splice_tail_init(&tmp, &hctx->dispatch);
spin_unlock(&hctx->lock);
blk_mq_run_hw_queue(hctx, true);
- return NOTIFY_OK;
+ return 0;
}
-static int blk_mq_hctx_notify(void *data, unsigned long action,
- unsigned int cpu)
+static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx)
{
- struct blk_mq_hw_ctx *hctx = data;
-
- if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
- return blk_mq_hctx_cpu_offline(hctx, cpu);
-
- /*
- * In case of CPU online, tags may be reallocated
- * in blk_mq_map_swqueue() after mapping is updated.
- */
-
- return NOTIFY_OK;
+ cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD,
+ &hctx->cpuhp_dead);
}
/* hctx->ctxs will be freed in queue's release handler */
@@ -1695,9 +1613,9 @@ static void blk_mq_exit_hctx(struct request_queue *q,
if (set->ops->exit_hctx)
set->ops->exit_hctx(hctx, hctx_idx);
- blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
+ blk_mq_remove_cpuhp(hctx);
blk_free_flush_queue(hctx->fq);
- blk_mq_free_bitmap(&hctx->ctx_map);
+ sbitmap_free(&hctx->ctx_map);
}
static void blk_mq_exit_hw_queues(struct request_queue *q,
@@ -1734,7 +1652,7 @@ static int blk_mq_init_hctx(struct request_queue *q,
if (node == NUMA_NO_NODE)
node = hctx->numa_node = set->numa_node;
- INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn);
+ INIT_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);
@@ -1742,9 +1660,7 @@ static int blk_mq_init_hctx(struct request_queue *q,
hctx->queue_num = hctx_idx;
hctx->flags = set->flags & ~BLK_MQ_F_TAG_SHARED;
- blk_mq_init_cpu_notifier(&hctx->cpu_notifier,
- blk_mq_hctx_notify, hctx);
- blk_mq_register_cpu_notifier(&hctx->cpu_notifier);
+ cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead);
hctx->tags = set->tags[hctx_idx];
@@ -1757,7 +1673,8 @@ static int blk_mq_init_hctx(struct request_queue *q,
if (!hctx->ctxs)
goto unregister_cpu_notifier;
- if (blk_mq_alloc_bitmap(&hctx->ctx_map, node))
+ if (sbitmap_init_node(&hctx->ctx_map, nr_cpu_ids, ilog2(8), GFP_KERNEL,
+ node))
goto free_ctxs;
hctx->nr_ctx = 0;
@@ -1784,12 +1701,11 @@ static int blk_mq_init_hctx(struct request_queue *q,
if (set->ops->exit_hctx)
set->ops->exit_hctx(hctx, hctx_idx);
free_bitmap:
- blk_mq_free_bitmap(&hctx->ctx_map);
+ sbitmap_free(&hctx->ctx_map);
free_ctxs:
kfree(hctx->ctxs);
unregister_cpu_notifier:
- blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
-
+ blk_mq_remove_cpuhp(hctx);
return -1;
}
@@ -1812,7 +1728,7 @@ static void blk_mq_init_cpu_queues(struct request_queue *q,
if (!cpu_online(i))
continue;
- hctx = q->mq_ops->map_queue(q, i);
+ hctx = blk_mq_map_queue(q, i);
/*
* Set local node, IFF we have more than one hw queue. If
@@ -1850,7 +1766,7 @@ static void blk_mq_map_swqueue(struct request_queue *q,
continue;
ctx = per_cpu_ptr(q->queue_ctx, i);
- hctx = q->mq_ops->map_queue(q, i);
+ hctx = blk_mq_map_queue(q, i);
cpumask_set_cpu(i, hctx->cpumask);
ctx->index_hw = hctx->nr_ctx;
@@ -1860,8 +1776,6 @@ static void blk_mq_map_swqueue(struct request_queue *q,
mutex_unlock(&q->sysfs_lock);
queue_for_each_hw_ctx(q, hctx, i) {
- struct blk_mq_ctxmap *map = &hctx->ctx_map;
-
/*
* If no software queues are mapped to this hardware queue,
* disable it and free the request entries.
@@ -1881,13 +1795,12 @@ static void blk_mq_map_swqueue(struct request_queue *q,
hctx->tags = set->tags[i];
WARN_ON(!hctx->tags);
- cpumask_copy(hctx->tags->cpumask, hctx->cpumask);
/*
* Set the map size to the number of mapped software queues.
* This is more accurate and more efficient than looping
* over all possibly mapped software queues.
*/
- map->size = DIV_ROUND_UP(hctx->nr_ctx, map->bits_per_word);
+ sbitmap_resize(&hctx->ctx_map, hctx->nr_ctx);
/*
* Initialize batch roundrobin counts
@@ -1975,7 +1888,6 @@ void blk_mq_release(struct request_queue *q)
kfree(hctx);
}
- kfree(q->mq_map);
q->mq_map = NULL;
kfree(q->queue_hw_ctx);
@@ -2074,9 +1986,7 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
if (!q->queue_hw_ctx)
goto err_percpu;
- q->mq_map = blk_mq_make_queue_map(set);
- if (!q->mq_map)
- goto err_map;
+ q->mq_map = set->mq_map;
blk_mq_realloc_hw_ctxs(set, q);
if (!q->nr_hw_queues)
@@ -2094,7 +2004,7 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
q->sg_reserved_size = INT_MAX;
- INIT_WORK(&q->requeue_work, blk_mq_requeue_work);
+ INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work);
INIT_LIST_HEAD(&q->requeue_list);
spin_lock_init(&q->requeue_lock);
@@ -2126,8 +2036,6 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
return q;
err_hctxs:
- kfree(q->mq_map);
-err_map:
kfree(q->queue_hw_ctx);
err_percpu:
free_percpu(q->queue_ctx);
@@ -2159,8 +2067,6 @@ static void blk_mq_queue_reinit(struct request_queue *q,
blk_mq_sysfs_unregister(q);
- blk_mq_update_queue_map(q->mq_map, q->nr_hw_queues, online_mask);
-
/*
* redo blk_mq_init_cpu_queues and blk_mq_init_hw_queues. FIXME: maybe
* we should change hctx numa_node according to new topology (this
@@ -2172,50 +2078,18 @@ static void blk_mq_queue_reinit(struct request_queue *q,
blk_mq_sysfs_register(q);
}
-static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
- unsigned long action, void *hcpu)
+/*
+ * New online cpumask which is going to be set in this hotplug event.
+ * Declare this cpumasks as global as cpu-hotplug operation is invoked
+ * one-by-one and dynamically allocating this could result in a failure.
+ */
+static struct cpumask cpuhp_online_new;
+
+static void blk_mq_queue_reinit_work(void)
{
struct request_queue *q;
- int cpu = (unsigned long)hcpu;
- /*
- * New online cpumask which is going to be set in this hotplug event.
- * Declare this cpumasks as global as cpu-hotplug operation is invoked
- * one-by-one and dynamically allocating this could result in a failure.
- */
- static struct cpumask online_new;
-
- /*
- * Before hotadded cpu starts handling requests, new mappings must
- * be established. Otherwise, these requests in hw queue might
- * never be dispatched.
- *
- * For example, there is a single hw queue (hctx) and two CPU queues
- * (ctx0 for CPU0, and ctx1 for CPU1).
- *
- * Now CPU1 is just onlined and a request is inserted into
- * ctx1->rq_list and set bit0 in pending bitmap as ctx1->index_hw is
- * still zero.
- *
- * And then while running hw queue, flush_busy_ctxs() finds bit0 is
- * set in pending bitmap and tries to retrieve requests in
- * hctx->ctxs[0]->rq_list. But htx->ctxs[0] is a pointer to ctx0,
- * so the request in ctx1->rq_list is ignored.
- */
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_DEAD:
- case CPU_UP_CANCELED:
- cpumask_copy(&online_new, cpu_online_mask);
- break;
- case CPU_UP_PREPARE:
- cpumask_copy(&online_new, cpu_online_mask);
- cpumask_set_cpu(cpu, &online_new);
- break;
- default:
- return NOTIFY_OK;
- }
mutex_lock(&all_q_mutex);
-
/*
* We need to freeze and reinit all existing queues. Freezing
* involves synchronous wait for an RCU grace period and doing it
@@ -2236,13 +2110,43 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
}
list_for_each_entry(q, &all_q_list, all_q_node)
- blk_mq_queue_reinit(q, &online_new);
+ blk_mq_queue_reinit(q, &cpuhp_online_new);
list_for_each_entry(q, &all_q_list, all_q_node)
blk_mq_unfreeze_queue(q);
mutex_unlock(&all_q_mutex);
- return NOTIFY_OK;
+}
+
+static int blk_mq_queue_reinit_dead(unsigned int cpu)
+{
+ cpumask_copy(&cpuhp_online_new, cpu_online_mask);
+ blk_mq_queue_reinit_work();
+ return 0;
+}
+
+/*
+ * Before hotadded cpu starts handling requests, new mappings must be
+ * established. Otherwise, these requests in hw queue might never be
+ * dispatched.
+ *
+ * For example, there is a single hw queue (hctx) and two CPU queues (ctx0
+ * for CPU0, and ctx1 for CPU1).
+ *
+ * Now CPU1 is just onlined and a request is inserted into ctx1->rq_list
+ * and set bit0 in pending bitmap as ctx1->index_hw is still zero.
+ *
+ * And then while running hw queue, flush_busy_ctxs() finds bit0 is set in
+ * pending bitmap and tries to retrieve requests in hctx->ctxs[0]->rq_list.
+ * But htx->ctxs[0] is a pointer to ctx0, so the request in ctx1->rq_list
+ * is ignored.
+ */
+static int blk_mq_queue_reinit_prepare(unsigned int cpu)
+{
+ cpumask_copy(&cpuhp_online_new, cpu_online_mask);
+ cpumask_set_cpu(cpu, &cpuhp_online_new);
+ blk_mq_queue_reinit_work();
+ return 0;
}
static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
@@ -2299,12 +2203,6 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
return 0;
}
-struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags)
-{
- return tags->cpumask;
-}
-EXPORT_SYMBOL_GPL(blk_mq_tags_cpumask);
-
/*
* Alloc a tag set to be associated with one or more request queues.
* May fail with EINVAL for various error conditions. May adjust the
@@ -2313,6 +2211,8 @@ EXPORT_SYMBOL_GPL(blk_mq_tags_cpumask);
*/
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
{
+ int ret;
+
BUILD_BUG_ON(BLK_MQ_MAX_DEPTH > 1 << BLK_MQ_UNIQUE_TAG_BITS);
if (!set->nr_hw_queues)
@@ -2322,7 +2222,7 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN)
return -EINVAL;
- if (!set->ops->queue_rq || !set->ops->map_queue)
+ if (!set->ops->queue_rq)
return -EINVAL;
if (set->queue_depth > BLK_MQ_MAX_DEPTH) {
@@ -2351,17 +2251,35 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
if (!set->tags)
return -ENOMEM;
- if (blk_mq_alloc_rq_maps(set))
- goto enomem;
+ ret = -ENOMEM;
+ set->mq_map = kzalloc_node(sizeof(*set->mq_map) * nr_cpu_ids,
+ GFP_KERNEL, set->numa_node);
+ if (!set->mq_map)
+ goto out_free_tags;
+
+ if (set->ops->map_queues)
+ ret = set->ops->map_queues(set);
+ else
+ ret = blk_mq_map_queues(set);
+ if (ret)
+ goto out_free_mq_map;
+
+ ret = blk_mq_alloc_rq_maps(set);
+ if (ret)
+ goto out_free_mq_map;
mutex_init(&set->tag_list_lock);
INIT_LIST_HEAD(&set->tag_list);
return 0;
-enomem:
+
+out_free_mq_map:
+ kfree(set->mq_map);
+ set->mq_map = NULL;
+out_free_tags:
kfree(set->tags);
set->tags = NULL;
- return -ENOMEM;
+ return ret;
}
EXPORT_SYMBOL(blk_mq_alloc_tag_set);
@@ -2374,6 +2292,9 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
blk_mq_free_rq_map(set, set->tags[i], i);
}
+ kfree(set->mq_map);
+ set->mq_map = NULL;
+
kfree(set->tags);
set->tags = NULL;
}
@@ -2444,10 +2365,12 @@ void blk_mq_enable_hotplug(void)
static int __init blk_mq_init(void)
{
- blk_mq_cpu_init();
-
- hotcpu_notifier(blk_mq_queue_reinit_notify, 0);
+ cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL,
+ blk_mq_hctx_notify_dead);
+ cpuhp_setup_state_nocalls(CPUHP_BLK_MQ_PREPARE, "block/mq:prepare",
+ blk_mq_queue_reinit_prepare,
+ blk_mq_queue_reinit_dead);
return 0;
}
subsys_initcall(blk_mq_init);
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 9087b11037b7..e5d25249028c 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -12,8 +12,6 @@ struct blk_mq_ctx {
unsigned int cpu;
unsigned int index_hw;
- unsigned int last_tag ____cacheline_aligned_in_smp;
-
/* incremented at dispatch time */
unsigned long rq_dispatched[2];
unsigned long rq_merged;
@@ -34,24 +32,21 @@ void blk_mq_wake_waiters(struct request_queue *q);
/*
* CPU hotplug helpers
*/
-struct blk_mq_cpu_notifier;
-void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
- int (*fn)(void *, unsigned long, unsigned int),
- void *data);
-void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier);
-void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier);
-void blk_mq_cpu_init(void);
void blk_mq_enable_hotplug(void);
void blk_mq_disable_hotplug(void);
/*
* CPU -> queue mappings
*/
-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,
- const struct cpumask *online_mask);
+int blk_mq_map_queues(struct blk_mq_tag_set *set);
extern int blk_mq_hw_queue_to_node(unsigned int *map, unsigned int);
+static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q,
+ int cpu)
+{
+ return q->queue_hw_ctx[q->mq_map[cpu]];
+}
+
/*
* sysfs helpers
*/
@@ -63,15 +58,6 @@ extern void blk_mq_rq_timed_out(struct request *req, bool reserved);
void blk_mq_release(struct request_queue *q);
-/*
- * Basic implementation of sparser bitmap, allowing the user to spread
- * the bits over more cachelines.
- */
-struct blk_align_bitmap {
- unsigned long word;
- unsigned long depth;
-} ____cacheline_aligned_in_smp;
-
static inline struct blk_mq_ctx *__blk_mq_get_ctx(struct request_queue *q,
unsigned int cpu)
{
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index f87a7e747d36..9cc8d7c5439a 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -704,7 +704,7 @@ int blk_register_queue(struct gendisk *disk)
kobject_uevent(&q->kobj, KOBJ_ADD);
if (q->mq_ops)
- blk_mq_register_disk(disk);
+ blk_mq_register_dev(dev, q);
if (!q->request_fn)
return 0;
@@ -729,7 +729,7 @@ void blk_unregister_queue(struct gendisk *disk)
return;
if (q->mq_ops)
- blk_mq_unregister_disk(disk);
+ blk_mq_unregister_dev(disk_to_dev(disk), q);
if (q->request_fn)
elv_unregister_queue(q);
diff --git a/block/blk.h b/block/blk.h
index c37492f5edaa..74444c49078f 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -39,14 +39,9 @@ extern struct ida blk_queue_ida;
static inline struct blk_flush_queue *blk_get_flush_queue(
struct request_queue *q, struct blk_mq_ctx *ctx)
{
- struct blk_mq_hw_ctx *hctx;
-
- if (!q->mq_ops)
- return q->fq;
-
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
- return hctx->fq;
+ if (q->mq_ops)
+ return blk_mq_map_queue(q, ctx->cpu)->fq;
+ return q->fq;
}
static inline void __blk_get_queue(struct request_queue *q)
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index cc2f6dbd4303..5e24d880306c 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -3042,7 +3042,6 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
if (ktime_get_ns() < rq->fifo_time)
rq = NULL;
- cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
return rq;
}
@@ -3420,6 +3419,9 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
unsigned int max_dispatch;
+ if (cfq_cfqq_must_dispatch(cfqq))
+ return true;
+
/*
* Drain async requests before we start sync IO
*/
@@ -3511,15 +3513,20 @@ static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
+ rq = cfq_check_fifo(cfqq);
+ if (rq)
+ cfq_mark_cfqq_must_dispatch(cfqq);
+
if (!cfq_may_dispatch(cfqd, cfqq))
return false;
/*
* follow expired path, else get first next available
*/
- rq = cfq_check_fifo(cfqq);
if (!rq)
rq = cfqq->next_rq;
+ else
+ cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
/*
* insert request into driver dispatch list
@@ -3989,7 +3996,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
* if the new request is sync, but the currently running queue is
* not, let the sync request have priority.
*/
- if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
+ if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq) && !cfq_cfqq_must_dispatch(cfqq))
return true;
/*
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index 68a5ceaa04c8..2d8466f9e49b 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -39,6 +39,37 @@ struct algif_hash_tfm {
bool has_key;
};
+static int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx)
+{
+ unsigned ds;
+
+ if (ctx->result)
+ return 0;
+
+ ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
+
+ ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
+ if (!ctx->result)
+ return -ENOMEM;
+
+ memset(ctx->result, 0, ds);
+
+ return 0;
+}
+
+static void hash_free_result(struct sock *sk, struct hash_ctx *ctx)
+{
+ unsigned ds;
+
+ if (!ctx->result)
+ return;
+
+ ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
+
+ sock_kzfree_s(sk, ctx->result, ds);
+ ctx->result = NULL;
+}
+
static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
size_t ignored)
{
@@ -54,6 +85,9 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
lock_sock(sk);
if (!ctx->more) {
+ if ((msg->msg_flags & MSG_MORE))
+ hash_free_result(sk, ctx);
+
err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req),
&ctx->completion);
if (err)
@@ -90,6 +124,10 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
ctx->more = msg->msg_flags & MSG_MORE;
if (!ctx->more) {
+ err = hash_alloc_result(sk, ctx);
+ if (err)
+ goto unlock;
+
ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
&ctx->completion);
@@ -116,6 +154,13 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page,
sg_init_table(ctx->sgl.sg, 1);
sg_set_page(ctx->sgl.sg, page, size, offset);
+ if (!(flags & MSG_MORE)) {
+ err = hash_alloc_result(sk, ctx);
+ if (err)
+ goto unlock;
+ } else if (!ctx->more)
+ hash_free_result(sk, ctx);
+
ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, ctx->result, size);
if (!(flags & MSG_MORE)) {
@@ -153,6 +198,7 @@ static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
struct alg_sock *ask = alg_sk(sk);
struct hash_ctx *ctx = ask->private;
unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
+ bool result;
int err;
if (len > ds)
@@ -161,17 +207,29 @@ static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
msg->msg_flags |= MSG_TRUNC;
lock_sock(sk);
+ result = ctx->result;
+ err = hash_alloc_result(sk, ctx);
+ if (err)
+ goto unlock;
+
+ ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
+
if (ctx->more) {
ctx->more = 0;
- ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
&ctx->completion);
if (err)
goto unlock;
+ } else if (!result) {
+ err = af_alg_wait_for_completion(
+ crypto_ahash_digest(&ctx->req),
+ &ctx->completion);
}
err = memcpy_to_msg(msg, ctx->result, len);
+ hash_free_result(sk, ctx);
+
unlock:
release_sock(sk);
@@ -394,8 +452,7 @@ static void hash_sock_destruct(struct sock *sk)
struct alg_sock *ask = alg_sk(sk);
struct hash_ctx *ctx = ask->private;
- sock_kzfree_s(sk, ctx->result,
- crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)));
+ hash_free_result(sk, ctx);
sock_kfree_s(sk, ctx, ctx->len);
af_alg_release_parent(sk);
}
@@ -407,20 +464,12 @@ static int hash_accept_parent_nokey(void *private, struct sock *sk)
struct algif_hash_tfm *tfm = private;
struct crypto_ahash *hash = tfm->hash;
unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
- unsigned ds = crypto_ahash_digestsize(hash);
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
return -ENOMEM;
- ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
- if (!ctx->result) {
- sock_kfree_s(sk, ctx, len);
- return -ENOMEM;
- }
-
- memset(ctx->result, 0, ds);
-
+ ctx->result = NULL;
ctx->len = len;
ctx->more = 0;
af_alg_init_completion(&ctx->completion);
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index 08b3ac68952b..f83de99d7d71 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -368,8 +368,6 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
dma_set_unmap(tx, unmap);
async_tx_submit(chan, tx, submit);
-
- return tx;
} else {
struct page *p_src = P(blocks, disks);
struct page *q_src = Q(blocks, disks);
@@ -424,9 +422,11 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
submit->cb_param = cb_param_orig;
submit->flags = flags_orig;
async_tx_sync_epilog(submit);
-
- return NULL;
+ tx = NULL;
}
+ dmaengine_unmap_put(unmap);
+
+ return tx;
}
EXPORT_SYMBOL_GPL(async_syndrome_val);
diff --git a/crypto/crct10dif_generic.c b/crypto/crct10dif_generic.c
index c1229614c7e3..8e94e29dc6fc 100644
--- a/crypto/crct10dif_generic.c
+++ b/crypto/crct10dif_generic.c
@@ -107,10 +107,7 @@ static struct shash_alg alg = {
static int __init crct10dif_mod_init(void)
{
- int ret;
-
- ret = crypto_register_shash(&alg);
- return ret;
+ return crypto_register_shash(&alg);
}
static void __exit crct10dif_mod_fini(void)
diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c
index a55c82dd48ef..bfb92ace2c91 100644
--- a/crypto/crypto_engine.c
+++ b/crypto/crypto_engine.c
@@ -14,13 +14,12 @@
#include <linux/err.h>
#include <linux/delay.h>
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
#include "internal.h"
#define CRYPTO_ENGINE_MAX_QLEN 10
-void crypto_finalize_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, int err);
-
/**
* crypto_pump_requests - dequeue one request from engine queue to process
* @engine: the hardware engine
@@ -34,10 +33,11 @@ static void crypto_pump_requests(struct crypto_engine *engine,
bool in_kthread)
{
struct crypto_async_request *async_req, *backlog;
- struct ablkcipher_request *req;
+ struct ahash_request *hreq;
+ struct ablkcipher_request *breq;
unsigned long flags;
bool was_busy = false;
- int ret;
+ int ret, rtype;
spin_lock_irqsave(&engine->queue_lock, flags);
@@ -82,9 +82,7 @@ static void crypto_pump_requests(struct crypto_engine *engine,
if (!async_req)
goto out;
- req = ablkcipher_request_cast(async_req);
-
- engine->cur_req = req;
+ engine->cur_req = async_req;
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
@@ -95,6 +93,7 @@ static void crypto_pump_requests(struct crypto_engine *engine,
spin_unlock_irqrestore(&engine->queue_lock, flags);
+ rtype = crypto_tfm_alg_type(engine->cur_req->tfm);
/* Until here we get the request need to be encrypted successfully */
if (!was_busy && engine->prepare_crypt_hardware) {
ret = engine->prepare_crypt_hardware(engine);
@@ -104,24 +103,55 @@ static void crypto_pump_requests(struct crypto_engine *engine,
}
}
- if (engine->prepare_request) {
- ret = engine->prepare_request(engine, engine->cur_req);
+ switch (rtype) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ hreq = ahash_request_cast(engine->cur_req);
+ if (engine->prepare_hash_request) {
+ ret = engine->prepare_hash_request(engine, hreq);
+ if (ret) {
+ pr_err("failed to prepare request: %d\n", ret);
+ goto req_err;
+ }
+ engine->cur_req_prepared = true;
+ }
+ ret = engine->hash_one_request(engine, hreq);
if (ret) {
- pr_err("failed to prepare request: %d\n", ret);
+ pr_err("failed to hash one request from queue\n");
goto req_err;
}
- engine->cur_req_prepared = true;
- }
-
- ret = engine->crypt_one_request(engine, engine->cur_req);
- if (ret) {
- pr_err("failed to crypt one request from queue\n");
- goto req_err;
+ return;
+ case CRYPTO_ALG_TYPE_ABLKCIPHER:
+ breq = ablkcipher_request_cast(engine->cur_req);
+ if (engine->prepare_cipher_request) {
+ ret = engine->prepare_cipher_request(engine, breq);
+ if (ret) {
+ pr_err("failed to prepare request: %d\n", ret);
+ goto req_err;
+ }
+ engine->cur_req_prepared = true;
+ }
+ ret = engine->cipher_one_request(engine, breq);
+ if (ret) {
+ pr_err("failed to cipher one request from queue\n");
+ goto req_err;
+ }
+ return;
+ default:
+ pr_err("failed to prepare request of unknown type\n");
+ return;
}
- return;
req_err:
- crypto_finalize_request(engine, engine->cur_req, ret);
+ switch (rtype) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ hreq = ahash_request_cast(engine->cur_req);
+ crypto_finalize_hash_request(engine, hreq, ret);
+ break;
+ case CRYPTO_ALG_TYPE_ABLKCIPHER:
+ breq = ablkcipher_request_cast(engine->cur_req);
+ crypto_finalize_cipher_request(engine, breq, ret);
+ break;
+ }
return;
out:
@@ -137,12 +167,14 @@ static void crypto_pump_work(struct kthread_work *work)
}
/**
- * crypto_transfer_request - transfer the new request into the engine queue
+ * crypto_transfer_cipher_request - transfer the new request into the
+ * enginequeue
* @engine: the hardware engine
* @req: the request need to be listed into the engine queue
*/
-int crypto_transfer_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, bool need_pump)
+int crypto_transfer_cipher_request(struct crypto_engine *engine,
+ struct ablkcipher_request *req,
+ bool need_pump)
{
unsigned long flags;
int ret;
@@ -162,46 +194,125 @@ int crypto_transfer_request(struct crypto_engine *engine,
spin_unlock_irqrestore(&engine->queue_lock, flags);
return ret;
}
-EXPORT_SYMBOL_GPL(crypto_transfer_request);
+EXPORT_SYMBOL_GPL(crypto_transfer_cipher_request);
+
+/**
+ * crypto_transfer_cipher_request_to_engine - transfer one request to list
+ * into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_cipher_request_to_engine(struct crypto_engine *engine,
+ struct ablkcipher_request *req)
+{
+ return crypto_transfer_cipher_request(engine, req, true);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_cipher_request_to_engine);
+
+/**
+ * crypto_transfer_hash_request - transfer the new request into the
+ * enginequeue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_hash_request(struct crypto_engine *engine,
+ struct ahash_request *req, bool need_pump)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&engine->queue_lock, flags);
+
+ if (!engine->running) {
+ spin_unlock_irqrestore(&engine->queue_lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ ret = ahash_enqueue_request(&engine->queue, req);
+
+ if (!engine->busy && need_pump)
+ queue_kthread_work(&engine->kworker, &engine->pump_requests);
+
+ spin_unlock_irqrestore(&engine->queue_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_hash_request);
/**
- * crypto_transfer_request_to_engine - transfer one request to list into the
- * engine queue
+ * crypto_transfer_hash_request_to_engine - transfer one request to list
+ * into the engine queue
* @engine: the hardware engine
* @req: the request need to be listed into the engine queue
*/
-int crypto_transfer_request_to_engine(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine,
+ struct ahash_request *req)
{
- return crypto_transfer_request(engine, req, true);
+ return crypto_transfer_hash_request(engine, req, true);
}
-EXPORT_SYMBOL_GPL(crypto_transfer_request_to_engine);
+EXPORT_SYMBOL_GPL(crypto_transfer_hash_request_to_engine);
/**
- * crypto_finalize_request - finalize one request if the request is done
+ * crypto_finalize_cipher_request - finalize one request if the request is done
* @engine: the hardware engine
* @req: the request need to be finalized
* @err: error number
*/
-void crypto_finalize_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, int err)
+void crypto_finalize_cipher_request(struct crypto_engine *engine,
+ struct ablkcipher_request *req, int err)
{
unsigned long flags;
bool finalize_cur_req = false;
int ret;
spin_lock_irqsave(&engine->queue_lock, flags);
- if (engine->cur_req == req)
+ if (engine->cur_req == &req->base)
finalize_cur_req = true;
spin_unlock_irqrestore(&engine->queue_lock, flags);
if (finalize_cur_req) {
- if (engine->cur_req_prepared && engine->unprepare_request) {
- ret = engine->unprepare_request(engine, req);
+ if (engine->cur_req_prepared &&
+ engine->unprepare_cipher_request) {
+ ret = engine->unprepare_cipher_request(engine, req);
if (ret)
pr_err("failed to unprepare request\n");
}
+ spin_lock_irqsave(&engine->queue_lock, flags);
+ engine->cur_req = NULL;
+ engine->cur_req_prepared = false;
+ spin_unlock_irqrestore(&engine->queue_lock, flags);
+ }
+
+ req->base.complete(&req->base, err);
+ queue_kthread_work(&engine->kworker, &engine->pump_requests);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_cipher_request);
+
+/**
+ * crypto_finalize_hash_request - finalize one request if the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_hash_request(struct crypto_engine *engine,
+ struct ahash_request *req, int err)
+{
+ unsigned long flags;
+ bool finalize_cur_req = false;
+ int ret;
+
+ spin_lock_irqsave(&engine->queue_lock, flags);
+ if (engine->cur_req == &req->base)
+ finalize_cur_req = true;
+ spin_unlock_irqrestore(&engine->queue_lock, flags);
+
+ if (finalize_cur_req) {
+ if (engine->cur_req_prepared &&
+ engine->unprepare_hash_request) {
+ ret = engine->unprepare_hash_request(engine, req);
+ if (ret)
+ pr_err("failed to unprepare request\n");
+ }
spin_lock_irqsave(&engine->queue_lock, flags);
engine->cur_req = NULL;
engine->cur_req_prepared = false;
@@ -212,7 +323,7 @@ void crypto_finalize_request(struct crypto_engine *engine,
queue_kthread_work(&engine->kworker, &engine->pump_requests);
}
-EXPORT_SYMBOL_GPL(crypto_finalize_request);
+EXPORT_SYMBOL_GPL(crypto_finalize_hash_request);
/**
* crypto_engine_start - start the hardware engine
@@ -249,7 +360,7 @@ EXPORT_SYMBOL_GPL(crypto_engine_start);
int crypto_engine_stop(struct crypto_engine *engine)
{
unsigned long flags;
- unsigned limit = 500;
+ unsigned int limit = 500;
int ret = 0;
spin_lock_irqsave(&engine->queue_lock, flags);
diff --git a/crypto/drbg.c b/crypto/drbg.c
index f752da3a7c75..fb33f7d3b052 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1178,12 +1178,16 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
goto err;
drbg->Vbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL);
- if (!drbg->Vbuf)
+ if (!drbg->Vbuf) {
+ ret = -ENOMEM;
goto fini;
+ }
drbg->V = PTR_ALIGN(drbg->Vbuf, ret + 1);
drbg->Cbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL);
- if (!drbg->Cbuf)
+ if (!drbg->Cbuf) {
+ ret = -ENOMEM;
goto fini;
+ }
drbg->C = PTR_ALIGN(drbg->Cbuf, ret + 1);
/* scratchpad is only generated for CTR and Hash */
if (drbg->core->flags & DRBG_HMAC)
@@ -1199,8 +1203,10 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
if (0 < sb_size) {
drbg->scratchpadbuf = kzalloc(sb_size + ret, GFP_KERNEL);
- if (!drbg->scratchpadbuf)
+ if (!drbg->scratchpadbuf) {
+ ret = -ENOMEM;
goto fini;
+ }
drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1);
}
@@ -1917,6 +1923,8 @@ static inline int __init drbg_healthcheck_sanity(void)
return -ENOMEM;
mutex_init(&drbg->drbg_mutex);
+ drbg->core = &drbg_cores[coreref];
+ drbg->reseed_threshold = drbg_max_requests(drbg);
/*
* if the following tests fail, it is likely that there is a buffer
@@ -1926,12 +1934,6 @@ static inline int __init drbg_healthcheck_sanity(void)
* grave bug.
*/
- /* get a valid instance of DRBG for following tests */
- ret = drbg_instantiate(drbg, NULL, coreref, pr);
- if (ret) {
- rc = ret;
- goto outbuf;
- }
max_addtllen = drbg_max_addtl(drbg);
max_request_bytes = drbg_max_request_bytes(drbg);
drbg_string_fill(&addtl, buf, max_addtllen + 1);
@@ -1941,10 +1943,9 @@ static inline int __init drbg_healthcheck_sanity(void)
/* overflow max_bits */
len = drbg_generate(drbg, buf, (max_request_bytes + 1), NULL);
BUG_ON(0 < len);
- drbg_uninstantiate(drbg);
/* overflow max addtllen with personalization string */
- ret = drbg_instantiate(drbg, &addtl, coreref, pr);
+ ret = drbg_seed(drbg, &addtl, false);
BUG_ON(0 == ret);
/* all tests passed */
rc = 0;
@@ -1952,9 +1953,7 @@ static inline int __init drbg_healthcheck_sanity(void)
pr_devel("DRBG: Sanity tests for failure code paths successfully "
"completed\n");
- drbg_uninstantiate(drbg);
-outbuf:
- kzfree(drbg);
+ kfree(drbg);
return rc;
}
@@ -2006,7 +2005,7 @@ static int __init drbg_init(void)
{
unsigned int i = 0; /* pointer to drbg_algs */
unsigned int j = 0; /* pointer to drbg_cores */
- int ret = -EFAULT;
+ int ret;
ret = drbg_healthcheck_sanity();
if (ret)
@@ -2016,7 +2015,7 @@ static int __init drbg_init(void)
pr_info("DRBG: Cannot register all DRBG types"
"(slots needed: %zu, slots available: %zu)\n",
ARRAY_SIZE(drbg_cores) * 2, ARRAY_SIZE(drbg_algs));
- return ret;
+ return -EFAULT;
}
/*
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 70a892e87ccb..f624ac98c94e 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -117,7 +117,7 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
struct crypto_skcipher *ctr = ctx->ctr;
struct {
be128 hash;
- u8 iv[8];
+ u8 iv[16];
struct crypto_gcm_setkey_result result;
diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
index bac70995e064..12ad3e3a84e3 100644
--- a/crypto/ghash-generic.c
+++ b/crypto/ghash-generic.c
@@ -14,24 +14,13 @@
#include <crypto/algapi.h>
#include <crypto/gf128mul.h>
+#include <crypto/ghash.h>
#include <crypto/internal/hash.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#define GHASH_BLOCK_SIZE 16
-#define GHASH_DIGEST_SIZE 16
-
-struct ghash_ctx {
- struct gf128mul_4k *gf128;
-};
-
-struct ghash_desc_ctx {
- u8 buffer[GHASH_BLOCK_SIZE];
- u32 bytes;
-};
-
static int ghash_init(struct shash_desc *desc)
{
struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c
index 86fb59b109a9..94ee44acd465 100644
--- a/crypto/mcryptd.c
+++ b/crypto/mcryptd.c
@@ -612,12 +612,7 @@ EXPORT_SYMBOL_GPL(mcryptd_alloc_ahash);
int ahash_mcryptd_digest(struct ahash_request *desc)
{
- int err;
-
- err = crypto_ahash_init(desc) ?:
- ahash_mcryptd_finup(desc);
-
- return err;
+ return crypto_ahash_init(desc) ?: ahash_mcryptd_finup(desc);
}
int ahash_mcryptd_update(struct ahash_request *desc)
diff --git a/crypto/rsa_helper.c b/crypto/rsa_helper.c
index 4df6451e7543..0b66dc824606 100644
--- a/crypto/rsa_helper.c
+++ b/crypto/rsa_helper.c
@@ -35,8 +35,8 @@ int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
n_sz--;
}
- /* In FIPS mode only allow key size 2K & 3K */
- if (n_sz != 256 && n_sz != 384) {
+ /* In FIPS mode only allow key size 2K and higher */
+ if (n_sz < 256) {
pr_err("RSA: key size not allowed in FIPS mode\n");
return -EINVAL;
}
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5c9d5a5e7b65..62dffa0028ac 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -209,16 +209,19 @@ static int ahash_partial_update(struct ahash_request **preq,
char *state;
struct ahash_request *req;
int statesize, ret = -EINVAL;
+ const char guard[] = { 0x00, 0xba, 0xad, 0x00 };
req = *preq;
statesize = crypto_ahash_statesize(
crypto_ahash_reqtfm(req));
- state = kmalloc(statesize, GFP_KERNEL);
+ state = kmalloc(statesize + sizeof(guard), GFP_KERNEL);
if (!state) {
pr_err("alt: hash: Failed to alloc state for %s\n", algo);
goto out_nostate;
}
+ memcpy(state + statesize, guard, sizeof(guard));
ret = crypto_ahash_export(req, state);
+ WARN_ON(memcmp(state + statesize, guard, sizeof(guard)));
if (ret) {
pr_err("alt: hash: Failed to export() for %s\n", algo);
goto out;
@@ -665,7 +668,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
memcpy(key, template[i].key, template[i].klen);
ret = crypto_aead_setkey(tfm, key, template[i].klen);
- if (!ret == template[i].fail) {
+ if (template[i].fail == !ret) {
pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n",
d, j, algo, crypto_aead_get_flags(tfm));
goto out;
@@ -770,7 +773,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
memcpy(key, template[i].key, template[i].klen);
ret = crypto_aead_setkey(tfm, key, template[i].klen);
- if (!ret == template[i].fail) {
+ if (template[i].fail == !ret) {
pr_err("alg: aead%s: setkey failed on chunk test %d for %s: flags=%x\n",
d, j, algo, crypto_aead_get_flags(tfm));
goto out;
@@ -1008,6 +1011,9 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
if (template[i].np)
continue;
+ if (fips_enabled && template[i].fips_skip)
+ continue;
+
j++;
ret = -EINVAL;
@@ -1023,7 +1029,7 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
ret = crypto_cipher_setkey(tfm, template[i].key,
template[i].klen);
- if (!ret == template[i].fail) {
+ if (template[i].fail == !ret) {
printk(KERN_ERR "alg: cipher: setkey failed "
"on test %d for %s: flags=%x\n", j,
algo, crypto_cipher_get_flags(tfm));
@@ -1112,6 +1118,9 @@ static int __test_skcipher(struct crypto_skcipher *tfm, int enc,
if (template[i].np && !template[i].also_non_np)
continue;
+ if (fips_enabled && template[i].fips_skip)
+ continue;
+
if (template[i].iv)
memcpy(iv, template[i].iv, ivsize);
else
@@ -1133,7 +1142,7 @@ static int __test_skcipher(struct crypto_skcipher *tfm, int enc,
ret = crypto_skcipher_setkey(tfm, template[i].key,
template[i].klen);
- if (!ret == template[i].fail) {
+ if (template[i].fail == !ret) {
pr_err("alg: skcipher%s: setkey failed on test %d for %s: flags=%x\n",
d, j, algo, crypto_skcipher_get_flags(tfm));
goto out;
@@ -1198,6 +1207,9 @@ static int __test_skcipher(struct crypto_skcipher *tfm, int enc,
if (!template[i].np)
continue;
+ if (fips_enabled && template[i].fips_skip)
+ continue;
+
if (template[i].iv)
memcpy(iv, template[i].iv, ivsize);
else
@@ -1211,7 +1223,7 @@ static int __test_skcipher(struct crypto_skcipher *tfm, int enc,
ret = crypto_skcipher_setkey(tfm, template[i].key,
template[i].klen);
- if (!ret == template[i].fail) {
+ if (template[i].fail == !ret) {
pr_err("alg: skcipher%s: setkey failed on chunk test %d for %s: flags=%x\n",
d, j, algo, crypto_skcipher_get_flags(tfm));
goto out;
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index acb6bbff781a..e64a4ef9d8ca 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -59,6 +59,7 @@ struct hash_testvec {
* @tap: How to distribute data in @np SGs
* @also_non_np: if set to 1, the test will be also done without
* splitting data in @np SGs
+ * @fips_skip: Skip the test vector in FIPS mode
*/
struct cipher_testvec {
@@ -75,6 +76,7 @@ struct cipher_testvec {
unsigned char klen;
unsigned short ilen;
unsigned short rlen;
+ bool fips_skip;
};
struct aead_testvec {
@@ -18224,6 +18226,7 @@ static struct cipher_testvec aes_xts_enc_tv_template[] = {
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.klen = 32,
+ .fips_skip = 1,
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.input = "\x00\x00\x00\x00\x00\x00\x00\x00"
@@ -18566,6 +18569,7 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = {
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.klen = 32,
+ .fips_skip = 1,
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.input = "\x91\x7c\xf6\x9e\xbd\x68\xb2\xec"
diff --git a/crypto/xor.c b/crypto/xor.c
index 35d6b3adf230..263af9fb45ea 100644
--- a/crypto/xor.c
+++ b/crypto/xor.c
@@ -24,6 +24,10 @@
#include <linux/preempt.h>
#include <asm/xor.h>
+#ifndef XOR_SELECT_TEMPLATE
+#define XOR_SELECT_TEMPLATE(x) (x)
+#endif
+
/* The xor routines to use. */
static struct xor_block_template *active_template;
@@ -109,6 +113,15 @@ calibrate_xor_blocks(void)
void *b1, *b2;
struct xor_block_template *f, *fastest;
+ fastest = XOR_SELECT_TEMPLATE(NULL);
+
+ if (fastest) {
+ printk(KERN_INFO "xor: automatically using best "
+ "checksumming function %-10s\n",
+ fastest->name);
+ goto out;
+ }
+
/*
* Note: Since the memory is not actually used for _anything_ but to
* test the XOR speed, we don't really want kmemcheck to warn about
@@ -126,36 +139,22 @@ calibrate_xor_blocks(void)
* all the possible functions, just test the best one
*/
- fastest = NULL;
-
-#ifdef XOR_SELECT_TEMPLATE
- fastest = XOR_SELECT_TEMPLATE(fastest);
-#endif
-
#define xor_speed(templ) do_xor_speed((templ), b1, b2)
- if (fastest) {
- printk(KERN_INFO "xor: automatically using best "
- "checksumming function:\n");
- xor_speed(fastest);
- goto out;
- } else {
- printk(KERN_INFO "xor: measuring software checksum speed\n");
- XOR_TRY_TEMPLATES;
- fastest = template_list;
- for (f = fastest; f; f = f->next)
- if (f->speed > fastest->speed)
- fastest = f;
- }
+ printk(KERN_INFO "xor: measuring software checksum speed\n");
+ XOR_TRY_TEMPLATES;
+ fastest = template_list;
+ for (f = fastest; f; f = f->next)
+ if (f->speed > fastest->speed)
+ fastest = f;
printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
fastest->name, fastest->speed / 1000, fastest->speed % 1000);
#undef xor_speed
- out:
free_pages((unsigned long)b1, 2);
-
+out:
active_template = fastest;
return 0;
}
diff --git a/crypto/xts.c b/crypto/xts.c
index 26ba5833b994..305343f22a02 100644
--- a/crypto/xts.c
+++ b/crypto/xts.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2007 Rik Snel <rsnel@cube.dyndns.org>
*
- * Based om ecb.c
+ * Based on ecb.c
* Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
*
* This program is free software; you can redistribute it and/or modify it
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 60746ef904e4..f0a029e68d3e 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -457,7 +457,7 @@ static void ghes_do_proc(struct ghes *ghes,
devfn = PCI_DEVFN(pcie_err->device_id.device,
pcie_err->device_id.function);
- aer_severity = cper_severity_to_aer(sev);
+ aer_severity = cper_severity_to_aer(gdata->error_severity);
/*
* If firmware reset the component to contain
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index cea52528aa18..2237d3f24f0e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -31,6 +31,7 @@
#include <linux/sched.h> /* need_resched() */
#include <linux/tick.h>
#include <linux/cpuidle.h>
+#include <linux/cpu.h>
#include <acpi/processor.h>
/*
@@ -115,7 +116,7 @@ static const struct dmi_system_id processor_power_dmi_table[] = {
* Callers should disable interrupts before the call and enable
* interrupts after return.
*/
-static void acpi_safe_halt(void)
+static void __cpuidle acpi_safe_halt(void)
{
if (!tif_need_resched()) {
safe_halt();
@@ -645,7 +646,7 @@ static int acpi_idle_bm_check(void)
*
* Caller disables interrupt before call and enables interrupt after return.
*/
-static void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
if (cx->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index dc75de9059cd..62c63c0c5c22 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -361,8 +361,11 @@ store_mem_state(struct device *dev,
err:
unlock_device_hotplug();
- if (ret)
+ if (ret < 0)
return ret;
+ if (ret)
+ return -EINVAL;
+
return count;
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index c9f2107f7095..cbdb3b162718 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1703,7 +1703,6 @@ static int loop_init_request(void *data, struct request *rq,
static struct blk_mq_ops loop_mq_ops = {
.queue_rq = loop_queue_rq,
- .map_queue = blk_mq_map_queue,
.init_request = loop_init_request,
};
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 2aca98e8e427..3cfd879267b2 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -3686,7 +3686,7 @@ static int mtip_block_open(struct block_device *dev, fmode_t mode)
return -ENODEV;
}
-void mtip_block_release(struct gendisk *disk, fmode_t mode)
+static void mtip_block_release(struct gendisk *disk, fmode_t mode)
{
}
@@ -3895,7 +3895,6 @@ exit_handler:
static struct blk_mq_ops mtip_mq_ops = {
.queue_rq = mtip_queue_rq,
- .map_queue = blk_mq_map_queue,
.init_request = mtip_init_cmd,
.exit_request = mtip_free_cmd,
.complete = mtip_softirq_done_fn,
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index a9e398019f38..ba405b55329f 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -34,33 +34,29 @@
#include <linux/kthread.h>
#include <linux/types.h>
#include <linux/debugfs.h>
+#include <linux/blk-mq.h>
#include <asm/uaccess.h>
#include <asm/types.h>
#include <linux/nbd.h>
+#define NBD_TIMEDOUT 0
+#define NBD_DISCONNECT_REQUESTED 1
+
struct nbd_device {
u32 flags;
+ unsigned long runtime_flags;
struct socket * sock; /* If == NULL, device is not ready, yet */
int magic;
- spinlock_t queue_lock;
- struct list_head queue_head; /* Requests waiting result */
- struct request *active_req;
- wait_queue_head_t active_wq;
- struct list_head waiting_queue; /* Requests to be sent */
- wait_queue_head_t waiting_wq;
+ struct blk_mq_tag_set tag_set;
struct mutex tx_lock;
struct gendisk *disk;
int blksize;
loff_t bytesize;
- int xmit_timeout;
- bool timedout;
- bool disconnect; /* a disconnect has been requested by user */
- struct timer_list timeout_timer;
/* protects initialization and shutdown of the socket */
spinlock_t sock_lock;
struct task_struct *task_recv;
@@ -71,6 +67,11 @@ struct nbd_device {
#endif
};
+struct nbd_cmd {
+ struct nbd_device *nbd;
+ struct list_head list;
+};
+
#if IS_ENABLED(CONFIG_DEBUG_FS)
static struct dentry *nbd_dbg_dir;
#endif
@@ -83,18 +84,6 @@ static unsigned int nbds_max = 16;
static struct nbd_device *nbd_dev;
static int max_part;
-/*
- * Use just one lock (or at most 1 per NIC). Two arguments for this:
- * 1. Each NIC is essentially a synchronization point for all servers
- * accessed through that NIC so there's no need to have more locks
- * than NICs anyway.
- * 2. More locks lead to more "Dirty cache line bouncing" which will slow
- * down each lock to the point where they're actually slower than just
- * a single lock.
- * Thanks go to Jens Axboe and Al Viro for their LKML emails explaining this!
- */
-static DEFINE_SPINLOCK(nbd_lock);
-
static inline struct device *nbd_to_dev(struct nbd_device *nbd)
{
return disk_to_dev(nbd->disk);
@@ -153,18 +142,16 @@ static int nbd_size_set(struct nbd_device *nbd, struct block_device *bdev,
return 0;
}
-static void nbd_end_request(struct nbd_device *nbd, struct request *req)
+static void nbd_end_request(struct nbd_cmd *cmd)
{
+ struct nbd_device *nbd = cmd->nbd;
+ struct request *req = blk_mq_rq_from_pdu(cmd);
int error = req->errors ? -EIO : 0;
- struct request_queue *q = req->q;
- unsigned long flags;
- dev_dbg(nbd_to_dev(nbd), "request %p: %s\n", req,
+ dev_dbg(nbd_to_dev(nbd), "request %p: %s\n", cmd,
error ? "failed" : "done");
- spin_lock_irqsave(q->queue_lock, flags);
- __blk_end_request_all(req, error);
- spin_unlock_irqrestore(q->queue_lock, flags);
+ blk_mq_complete_request(req, error);
}
/*
@@ -172,40 +159,49 @@ static void nbd_end_request(struct nbd_device *nbd, struct request *req)
*/
static void sock_shutdown(struct nbd_device *nbd)
{
- spin_lock_irq(&nbd->sock_lock);
+ struct socket *sock;
+
+ spin_lock(&nbd->sock_lock);
if (!nbd->sock) {
spin_unlock_irq(&nbd->sock_lock);
return;
}
+ sock = nbd->sock;
dev_warn(disk_to_dev(nbd->disk), "shutting down socket\n");
- kernel_sock_shutdown(nbd->sock, SHUT_RDWR);
- sockfd_put(nbd->sock);
nbd->sock = NULL;
- spin_unlock_irq(&nbd->sock_lock);
+ spin_unlock(&nbd->sock_lock);
- del_timer(&nbd->timeout_timer);
+ kernel_sock_shutdown(sock, SHUT_RDWR);
+ sockfd_put(sock);
}
-static void nbd_xmit_timeout(unsigned long arg)
+static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
+ bool reserved)
{
- struct nbd_device *nbd = (struct nbd_device *)arg;
- unsigned long flags;
-
- if (list_empty(&nbd->queue_head))
- return;
+ struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
+ struct nbd_device *nbd = cmd->nbd;
+ struct socket *sock = NULL;
- spin_lock_irqsave(&nbd->sock_lock, flags);
+ spin_lock(&nbd->sock_lock);
- nbd->timedout = true;
+ set_bit(NBD_TIMEDOUT, &nbd->runtime_flags);
- if (nbd->sock)
- kernel_sock_shutdown(nbd->sock, SHUT_RDWR);
+ if (nbd->sock) {
+ sock = nbd->sock;
+ get_file(sock->file);
+ }
- spin_unlock_irqrestore(&nbd->sock_lock, flags);
+ spin_unlock(&nbd->sock_lock);
+ if (sock) {
+ kernel_sock_shutdown(sock, SHUT_RDWR);
+ sockfd_put(sock);
+ }
+ req->errors++;
dev_err(nbd_to_dev(nbd), "Connection timed out, shutting down connection\n");
+ return BLK_EH_HANDLED;
}
/*
@@ -255,9 +251,6 @@ static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size,
tsk_restore_flags(current, pflags, PF_MEMALLOC);
- if (!send && nbd->xmit_timeout)
- mod_timer(&nbd->timeout_timer, jiffies + nbd->xmit_timeout);
-
return result;
}
@@ -273,8 +266,9 @@ static inline int sock_send_bvec(struct nbd_device *nbd, struct bio_vec *bvec,
}
/* always call with the tx_lock held */
-static int nbd_send_req(struct nbd_device *nbd, struct request *req)
+static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd)
{
+ struct request *req = blk_mq_rq_from_pdu(cmd);
int result, flags;
struct nbd_request request;
unsigned long size = blk_rq_bytes(req);
@@ -298,10 +292,10 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
request.len = htonl(size);
}
- memcpy(request.handle, &req, sizeof(req));
+ memcpy(request.handle, &req->tag, sizeof(req->tag));
dev_dbg(nbd_to_dev(nbd), "request %p: sending control (%s@%llu,%uB)\n",
- req, nbdcmd_to_ascii(type),
+ cmd, nbdcmd_to_ascii(type),
(unsigned long long)blk_rq_pos(req) << 9, blk_rq_bytes(req));
result = sock_xmit(nbd, 1, &request, sizeof(request),
(type == NBD_CMD_WRITE) ? MSG_MORE : 0);
@@ -323,7 +317,7 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
if (!rq_iter_last(bvec, iter))
flags = MSG_MORE;
dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
- req, bvec.bv_len);
+ cmd, bvec.bv_len);
result = sock_send_bvec(nbd, &bvec, flags);
if (result <= 0) {
dev_err(disk_to_dev(nbd->disk),
@@ -336,29 +330,6 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
return 0;
}
-static struct request *nbd_find_request(struct nbd_device *nbd,
- struct request *xreq)
-{
- struct request *req, *tmp;
- int err;
-
- err = wait_event_interruptible(nbd->active_wq, nbd->active_req != xreq);
- if (unlikely(err))
- return ERR_PTR(err);
-
- spin_lock(&nbd->queue_lock);
- list_for_each_entry_safe(req, tmp, &nbd->queue_head, queuelist) {
- if (req != xreq)
- continue;
- list_del_init(&req->queuelist);
- spin_unlock(&nbd->queue_lock);
- return req;
- }
- spin_unlock(&nbd->queue_lock);
-
- return ERR_PTR(-ENOENT);
-}
-
static inline int sock_recv_bvec(struct nbd_device *nbd, struct bio_vec *bvec)
{
int result;
@@ -370,11 +341,14 @@ static inline int sock_recv_bvec(struct nbd_device *nbd, struct bio_vec *bvec)
}
/* NULL returned = something went wrong, inform userspace */
-static struct request *nbd_read_stat(struct nbd_device *nbd)
+static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd)
{
int result;
struct nbd_reply reply;
- struct request *req;
+ struct nbd_cmd *cmd;
+ struct request *req = NULL;
+ u16 hwq;
+ int tag;
reply.magic = 0;
result = sock_xmit(nbd, 0, &reply, sizeof(reply), MSG_WAITALL);
@@ -390,25 +364,27 @@ static struct request *nbd_read_stat(struct nbd_device *nbd)
return ERR_PTR(-EPROTO);
}
- req = nbd_find_request(nbd, *(struct request **)reply.handle);
- if (IS_ERR(req)) {
- result = PTR_ERR(req);
- if (result != -ENOENT)
- return ERR_PTR(result);
+ memcpy(&tag, reply.handle, sizeof(int));
- dev_err(disk_to_dev(nbd->disk), "Unexpected reply (%p)\n",
- reply.handle);
- return ERR_PTR(-EBADR);
+ hwq = blk_mq_unique_tag_to_hwq(tag);
+ if (hwq < nbd->tag_set.nr_hw_queues)
+ req = blk_mq_tag_to_rq(nbd->tag_set.tags[hwq],
+ blk_mq_unique_tag_to_tag(tag));
+ if (!req || !blk_mq_request_started(req)) {
+ dev_err(disk_to_dev(nbd->disk), "Unexpected reply (%d) %p\n",
+ tag, req);
+ return ERR_PTR(-ENOENT);
}
+ cmd = blk_mq_rq_to_pdu(req);
if (ntohl(reply.error)) {
dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n",
ntohl(reply.error));
req->errors++;
- return req;
+ return cmd;
}
- dev_dbg(nbd_to_dev(nbd), "request %p: got reply\n", req);
+ dev_dbg(nbd_to_dev(nbd), "request %p: got reply\n", cmd);
if (rq_data_dir(req) != WRITE) {
struct req_iterator iter;
struct bio_vec bvec;
@@ -419,13 +395,13 @@ static struct request *nbd_read_stat(struct nbd_device *nbd)
dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
result);
req->errors++;
- return req;
+ return cmd;
}
dev_dbg(nbd_to_dev(nbd), "request %p: got %d bytes data\n",
- req, bvec.bv_len);
+ cmd, bvec.bv_len);
}
}
- return req;
+ return cmd;
}
static ssize_t pid_show(struct device *dev,
@@ -444,7 +420,7 @@ static struct device_attribute pid_attr = {
static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
{
- struct request *req;
+ struct nbd_cmd *cmd;
int ret;
BUG_ON(nbd->magic != NBD_MAGIC);
@@ -460,13 +436,13 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
nbd_size_update(nbd, bdev);
while (1) {
- req = nbd_read_stat(nbd);
- if (IS_ERR(req)) {
- ret = PTR_ERR(req);
+ cmd = nbd_read_stat(nbd);
+ if (IS_ERR(cmd)) {
+ ret = PTR_ERR(cmd);
break;
}
- nbd_end_request(nbd, req);
+ nbd_end_request(cmd);
}
nbd_size_clear(nbd, bdev);
@@ -475,44 +451,37 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
return ret;
}
-static void nbd_clear_que(struct nbd_device *nbd)
+static void nbd_clear_req(struct request *req, void *data, bool reserved)
{
- struct request *req;
+ struct nbd_cmd *cmd;
+
+ if (!blk_mq_request_started(req))
+ return;
+ cmd = blk_mq_rq_to_pdu(req);
+ req->errors++;
+ nbd_end_request(cmd);
+}
+static void nbd_clear_que(struct nbd_device *nbd)
+{
BUG_ON(nbd->magic != NBD_MAGIC);
/*
* Because we have set nbd->sock to NULL under the tx_lock, all
- * modifications to the list must have completed by now. For
- * the same reason, the active_req must be NULL.
- *
- * As a consequence, we don't need to take the spin lock while
- * purging the list here.
+ * modifications to the list must have completed by now.
*/
BUG_ON(nbd->sock);
- BUG_ON(nbd->active_req);
- while (!list_empty(&nbd->queue_head)) {
- req = list_entry(nbd->queue_head.next, struct request,
- queuelist);
- list_del_init(&req->queuelist);
- req->errors++;
- nbd_end_request(nbd, req);
- }
-
- while (!list_empty(&nbd->waiting_queue)) {
- req = list_entry(nbd->waiting_queue.next, struct request,
- queuelist);
- list_del_init(&req->queuelist);
- req->errors++;
- nbd_end_request(nbd, req);
- }
+ blk_mq_tagset_busy_iter(&nbd->tag_set, nbd_clear_req, NULL);
dev_dbg(disk_to_dev(nbd->disk), "queue cleared\n");
}
-static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
+static void nbd_handle_cmd(struct nbd_cmd *cmd)
{
+ struct request *req = blk_mq_rq_from_pdu(cmd);
+ struct nbd_device *nbd = cmd->nbd;
+
if (req->cmd_type != REQ_TYPE_FS)
goto error_out;
@@ -526,6 +495,7 @@ static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
req->errors = 0;
mutex_lock(&nbd->tx_lock);
+ nbd->task_send = current;
if (unlikely(!nbd->sock)) {
mutex_unlock(&nbd->tx_lock);
dev_err(disk_to_dev(nbd->disk),
@@ -533,106 +503,30 @@ static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
goto error_out;
}
- nbd->active_req = req;
-
- if (nbd->xmit_timeout && list_empty_careful(&nbd->queue_head))
- mod_timer(&nbd->timeout_timer, jiffies + nbd->xmit_timeout);
-
- if (nbd_send_req(nbd, req) != 0) {
+ if (nbd_send_cmd(nbd, cmd) != 0) {
dev_err(disk_to_dev(nbd->disk), "Request send failed\n");
req->errors++;
- nbd_end_request(nbd, req);
- } else {
- spin_lock(&nbd->queue_lock);
- list_add_tail(&req->queuelist, &nbd->queue_head);
- spin_unlock(&nbd->queue_lock);
+ nbd_end_request(cmd);
}
- nbd->active_req = NULL;
+ nbd->task_send = NULL;
mutex_unlock(&nbd->tx_lock);
- wake_up_all(&nbd->active_wq);
return;
error_out:
req->errors++;
- nbd_end_request(nbd, req);
+ nbd_end_request(cmd);
}
-static int nbd_thread_send(void *data)
+static int nbd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct nbd_device *nbd = data;
- struct request *req;
-
- nbd->task_send = current;
-
- set_user_nice(current, MIN_NICE);
- while (!kthread_should_stop() || !list_empty(&nbd->waiting_queue)) {
- /* wait for something to do */
- wait_event_interruptible(nbd->waiting_wq,
- kthread_should_stop() ||
- !list_empty(&nbd->waiting_queue));
-
- /* extract request */
- if (list_empty(&nbd->waiting_queue))
- continue;
-
- spin_lock_irq(&nbd->queue_lock);
- req = list_entry(nbd->waiting_queue.next, struct request,
- queuelist);
- list_del_init(&req->queuelist);
- spin_unlock_irq(&nbd->queue_lock);
-
- /* handle request */
- nbd_handle_req(nbd, req);
- }
+ struct nbd_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
- nbd->task_send = NULL;
-
- return 0;
-}
-
-/*
- * We always wait for result of write, for now. It would be nice to make it optional
- * in future
- * if ((rq_data_dir(req) == WRITE) && (nbd->flags & NBD_WRITE_NOCHK))
- * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
- */
-
-static void nbd_request_handler(struct request_queue *q)
- __releases(q->queue_lock) __acquires(q->queue_lock)
-{
- struct request *req;
-
- while ((req = blk_fetch_request(q)) != NULL) {
- struct nbd_device *nbd;
-
- spin_unlock_irq(q->queue_lock);
-
- nbd = req->rq_disk->private_data;
-
- BUG_ON(nbd->magic != NBD_MAGIC);
-
- dev_dbg(nbd_to_dev(nbd), "request %p: dequeued (flags=%x)\n",
- req, req->cmd_type);
-
- if (unlikely(!nbd->sock)) {
- dev_err_ratelimited(disk_to_dev(nbd->disk),
- "Attempted send on closed socket\n");
- req->errors++;
- nbd_end_request(nbd, req);
- spin_lock_irq(q->queue_lock);
- continue;
- }
-
- spin_lock_irq(&nbd->queue_lock);
- list_add_tail(&req->queuelist, &nbd->waiting_queue);
- spin_unlock_irq(&nbd->queue_lock);
-
- wake_up(&nbd->waiting_wq);
-
- spin_lock_irq(q->queue_lock);
- }
+ blk_mq_start_request(bd->rq);
+ nbd_handle_cmd(cmd);
+ return BLK_MQ_RQ_QUEUE_OK;
}
static int nbd_set_socket(struct nbd_device *nbd, struct socket *sock)
@@ -657,15 +551,13 @@ out:
/* Reset all properties of an NBD device */
static void nbd_reset(struct nbd_device *nbd)
{
- nbd->disconnect = false;
- nbd->timedout = false;
+ nbd->runtime_flags = 0;
nbd->blksize = 1024;
nbd->bytesize = 0;
set_capacity(nbd->disk, 0);
nbd->flags = 0;
- nbd->xmit_timeout = 0;
+ nbd->tag_set.timeout = 0;
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue);
- del_timer_sync(&nbd->timeout_timer);
}
static void nbd_bdev_reset(struct block_device *bdev)
@@ -700,33 +592,37 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
{
switch (cmd) {
case NBD_DISCONNECT: {
- struct request sreq;
+ struct request *sreq;
dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n");
if (!nbd->sock)
return -EINVAL;
+ sreq = blk_mq_alloc_request(bdev_get_queue(bdev), WRITE, 0);
+ if (!sreq)
+ return -ENOMEM;
+
mutex_unlock(&nbd->tx_lock);
fsync_bdev(bdev);
mutex_lock(&nbd->tx_lock);
- blk_rq_init(NULL, &sreq);
- sreq.cmd_type = REQ_TYPE_DRV_PRIV;
+ sreq->cmd_type = REQ_TYPE_DRV_PRIV;
/* Check again after getting mutex back. */
- if (!nbd->sock)
+ if (!nbd->sock) {
+ blk_mq_free_request(sreq);
return -EINVAL;
+ }
- nbd->disconnect = true;
+ set_bit(NBD_DISCONNECT_REQUESTED, &nbd->runtime_flags);
- nbd_send_req(nbd, &sreq);
+ nbd_send_cmd(nbd, blk_mq_rq_to_pdu(sreq));
+ blk_mq_free_request(sreq);
return 0;
}
case NBD_CLEAR_SOCK:
sock_shutdown(nbd);
nbd_clear_que(nbd);
- BUG_ON(!list_empty(&nbd->queue_head));
- BUG_ON(!list_empty(&nbd->waiting_queue));
kill_bdev(bdev);
return 0;
@@ -758,13 +654,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
return nbd_size_set(nbd, bdev, nbd->blksize, arg);
case NBD_SET_TIMEOUT:
- nbd->xmit_timeout = arg * HZ;
- if (arg)
- mod_timer(&nbd->timeout_timer,
- jiffies + nbd->xmit_timeout);
- else
- del_timer_sync(&nbd->timeout_timer);
-
+ nbd->tag_set.timeout = arg * HZ;
return 0;
case NBD_SET_FLAGS:
@@ -772,7 +662,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
return 0;
case NBD_DO_IT: {
- struct task_struct *thread;
int error;
if (nbd->task_recv)
@@ -786,18 +675,9 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
nbd_parse_flags(nbd, bdev);
- thread = kthread_run(nbd_thread_send, nbd, "%s",
- nbd_name(nbd));
- if (IS_ERR(thread)) {
- mutex_lock(&nbd->tx_lock);
- nbd->task_recv = NULL;
- return PTR_ERR(thread);
- }
-
nbd_dev_dbg_init(nbd);
error = nbd_thread_recv(nbd, bdev);
nbd_dev_dbg_close(nbd);
- kthread_stop(thread);
mutex_lock(&nbd->tx_lock);
nbd->task_recv = NULL;
@@ -807,9 +687,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
kill_bdev(bdev);
nbd_bdev_reset(bdev);
- if (nbd->disconnect) /* user requested, ignore socket errors */
+ /* user requested, ignore socket errors */
+ if (test_bit(NBD_DISCONNECT_REQUESTED, &nbd->runtime_flags))
error = 0;
- if (nbd->timedout)
+ if (test_bit(NBD_TIMEDOUT, &nbd->runtime_flags))
error = -ETIMEDOUT;
nbd_reset(nbd);
@@ -825,10 +706,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
return 0;
case NBD_PRINT_DEBUG:
- dev_info(disk_to_dev(nbd->disk),
- "next = %p, prev = %p, head = %p\n",
- nbd->queue_head.next, nbd->queue_head.prev,
- &nbd->queue_head);
+ /*
+ * For compatibility only, we no longer keep a list of
+ * outstanding requests.
+ */
return 0;
}
return -ENOTTY;
@@ -935,7 +816,7 @@ static int nbd_dev_dbg_init(struct nbd_device *nbd)
debugfs_create_file("tasks", 0444, dir, nbd, &nbd_dbg_tasks_ops);
debugfs_create_u64("size_bytes", 0444, dir, &nbd->bytesize);
- debugfs_create_u32("timeout", 0444, dir, &nbd->xmit_timeout);
+ debugfs_create_u32("timeout", 0444, dir, &nbd->tag_set.timeout);
debugfs_create_u32("blocksize", 0444, dir, &nbd->blksize);
debugfs_create_file("flags", 0444, dir, nbd, &nbd_dbg_flags_ops);
@@ -987,6 +868,23 @@ static void nbd_dbg_close(void)
#endif
+static int nbd_init_request(void *data, struct request *rq,
+ unsigned int hctx_idx, unsigned int request_idx,
+ unsigned int numa_node)
+{
+ struct nbd_cmd *cmd = blk_mq_rq_to_pdu(rq);
+
+ cmd->nbd = data;
+ INIT_LIST_HEAD(&cmd->list);
+ return 0;
+}
+
+static struct blk_mq_ops nbd_mq_ops = {
+ .queue_rq = nbd_queue_rq,
+ .init_request = nbd_init_request,
+ .timeout = nbd_xmit_timeout,
+};
+
/*
* And here should be modules and kernel interface
* (Just smiley confuses emacs :-)
@@ -1035,16 +933,34 @@ static int __init nbd_init(void)
if (!disk)
goto out;
nbd_dev[i].disk = disk;
+
+ nbd_dev[i].tag_set.ops = &nbd_mq_ops;
+ nbd_dev[i].tag_set.nr_hw_queues = 1;
+ nbd_dev[i].tag_set.queue_depth = 128;
+ nbd_dev[i].tag_set.numa_node = NUMA_NO_NODE;
+ nbd_dev[i].tag_set.cmd_size = sizeof(struct nbd_cmd);
+ nbd_dev[i].tag_set.flags = BLK_MQ_F_SHOULD_MERGE |
+ BLK_MQ_F_SG_MERGE | BLK_MQ_F_BLOCKING;
+ nbd_dev[i].tag_set.driver_data = &nbd_dev[i];
+
+ err = blk_mq_alloc_tag_set(&nbd_dev[i].tag_set);
+ if (err) {
+ put_disk(disk);
+ goto out;
+ }
+
/*
* The new linux 2.5 block layer implementation requires
* every gendisk to have its very own request_queue struct.
* These structs are big so we dynamically allocate them.
*/
- disk->queue = blk_init_queue(nbd_request_handler, &nbd_lock);
+ disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set);
if (!disk->queue) {
+ blk_mq_free_tag_set(&nbd_dev[i].tag_set);
put_disk(disk);
goto out;
}
+
/*
* Tell the block layer that we are not a rotational device
*/
@@ -1069,16 +985,8 @@ static int __init nbd_init(void)
for (i = 0; i < nbds_max; i++) {
struct gendisk *disk = nbd_dev[i].disk;
nbd_dev[i].magic = NBD_MAGIC;
- INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
- spin_lock_init(&nbd_dev[i].queue_lock);
spin_lock_init(&nbd_dev[i].sock_lock);
- INIT_LIST_HEAD(&nbd_dev[i].queue_head);
mutex_init(&nbd_dev[i].tx_lock);
- init_timer(&nbd_dev[i].timeout_timer);
- nbd_dev[i].timeout_timer.function = nbd_xmit_timeout;
- nbd_dev[i].timeout_timer.data = (unsigned long)&nbd_dev[i];
- init_waitqueue_head(&nbd_dev[i].active_wq);
- init_waitqueue_head(&nbd_dev[i].waiting_wq);
disk->major = NBD_MAJOR;
disk->first_minor = i << part_shift;
disk->fops = &nbd_fops;
@@ -1091,6 +999,7 @@ static int __init nbd_init(void)
return 0;
out:
while (i--) {
+ blk_mq_free_tag_set(&nbd_dev[i].tag_set);
blk_cleanup_queue(nbd_dev[i].disk->queue);
put_disk(nbd_dev[i].disk);
}
@@ -1110,6 +1019,7 @@ static void __exit nbd_cleanup(void)
if (disk) {
del_gendisk(disk);
blk_cleanup_queue(disk->queue);
+ blk_mq_free_tag_set(&nbd_dev[i].tag_set);
put_disk(disk);
}
}
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 75a7f88d6717..ba6f4a2e73db 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -34,6 +34,7 @@ struct nullb {
unsigned int index;
struct request_queue *q;
struct gendisk *disk;
+ struct nvm_dev *ndev;
struct blk_mq_tag_set tag_set;
struct hrtimer timer;
unsigned int queue_depth;
@@ -393,7 +394,6 @@ static int null_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
static struct blk_mq_ops null_mq_ops = {
.queue_rq = null_queue_rq,
- .map_queue = blk_mq_map_queue,
.init_hctx = null_init_hctx,
.complete = null_softirq_done_fn,
};
@@ -414,23 +414,6 @@ static void cleanup_queues(struct nullb *nullb)
kfree(nullb->queues);
}
-static void null_del_dev(struct nullb *nullb)
-{
- list_del_init(&nullb->list);
-
- if (use_lightnvm)
- nvm_unregister(nullb->disk_name);
- else
- del_gendisk(nullb->disk);
- blk_cleanup_queue(nullb->q);
- if (queue_mode == NULL_Q_MQ)
- blk_mq_free_tag_set(&nullb->tag_set);
- if (!use_lightnvm)
- put_disk(nullb->disk);
- cleanup_queues(nullb);
- kfree(nullb);
-}
-
#ifdef CONFIG_NVM
static void null_lnvm_end_io(struct request *rq, int error)
@@ -564,10 +547,58 @@ static struct nvm_dev_ops null_lnvm_dev_ops = {
/* Simulate nvme protocol restriction */
.max_phys_sect = 64,
};
+
+static int null_nvm_register(struct nullb *nullb)
+{
+ struct nvm_dev *dev;
+ int rv;
+
+ dev = nvm_alloc_dev(0);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->q = nullb->q;
+ memcpy(dev->name, nullb->disk_name, DISK_NAME_LEN);
+ dev->ops = &null_lnvm_dev_ops;
+
+ rv = nvm_register(dev);
+ if (rv) {
+ kfree(dev);
+ return rv;
+ }
+ nullb->ndev = dev;
+ return 0;
+}
+
+static void null_nvm_unregister(struct nullb *nullb)
+{
+ nvm_unregister(nullb->ndev);
+}
#else
-static struct nvm_dev_ops null_lnvm_dev_ops;
+static int null_nvm_register(struct nullb *nullb)
+{
+ return -EINVAL;
+}
+static void null_nvm_unregister(struct nullb *nullb) {}
#endif /* CONFIG_NVM */
+static void null_del_dev(struct nullb *nullb)
+{
+ list_del_init(&nullb->list);
+
+ if (use_lightnvm)
+ null_nvm_unregister(nullb);
+ else
+ del_gendisk(nullb->disk);
+ blk_cleanup_queue(nullb->q);
+ if (queue_mode == NULL_Q_MQ)
+ blk_mq_free_tag_set(&nullb->tag_set);
+ if (!use_lightnvm)
+ put_disk(nullb->disk);
+ cleanup_queues(nullb);
+ kfree(nullb);
+}
+
static int null_open(struct block_device *bdev, fmode_t mode)
{
return 0;
@@ -640,11 +671,32 @@ static int init_driver_queues(struct nullb *nullb)
return 0;
}
-static int null_add_dev(void)
+static int null_gendisk_register(struct nullb *nullb)
{
struct gendisk *disk;
- struct nullb *nullb;
sector_t size;
+
+ disk = nullb->disk = alloc_disk_node(1, home_node);
+ if (!disk)
+ return -ENOMEM;
+ size = gb * 1024 * 1024 * 1024ULL;
+ set_capacity(disk, size >> 9);
+
+ disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
+ disk->major = null_major;
+ disk->first_minor = nullb->index;
+ disk->fops = &null_fops;
+ disk->private_data = nullb;
+ disk->queue = nullb->q;
+ strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+
+ add_disk(disk);
+ return 0;
+}
+
+static int null_add_dev(void)
+{
+ struct nullb *nullb;
int rv;
nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, home_node);
@@ -716,42 +768,19 @@ static int null_add_dev(void)
sprintf(nullb->disk_name, "nullb%d", nullb->index);
- if (use_lightnvm) {
- rv = nvm_register(nullb->q, nullb->disk_name,
- &null_lnvm_dev_ops);
- if (rv)
- goto out_cleanup_blk_queue;
- goto done;
- }
-
- disk = nullb->disk = alloc_disk_node(1, home_node);
- if (!disk) {
- rv = -ENOMEM;
- goto out_cleanup_lightnvm;
- }
- size = gb * 1024 * 1024 * 1024ULL;
- set_capacity(disk, size >> 9);
-
- disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
- disk->major = null_major;
- disk->first_minor = nullb->index;
- disk->fops = &null_fops;
- disk->private_data = nullb;
- disk->queue = nullb->q;
- strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+ if (use_lightnvm)
+ rv = null_nvm_register(nullb);
+ else
+ rv = null_gendisk_register(nullb);
- add_disk(disk);
+ if (rv)
+ goto out_cleanup_blk_queue;
-done:
mutex_lock(&lock);
list_add_tail(&nullb->list, &nullb_list);
mutex_unlock(&lock);
return 0;
-
-out_cleanup_lightnvm:
- if (use_lightnvm)
- nvm_unregister(nullb->disk_name);
out_cleanup_blk_queue:
blk_cleanup_queue(nullb->q);
out_cleanup_tags:
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 6c6519f6492a..abb71628ab61 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -31,6 +31,7 @@
#include <linux/ceph/libceph.h>
#include <linux/ceph/osd_client.h>
#include <linux/ceph/mon_client.h>
+#include <linux/ceph/cls_lock_client.h>
#include <linux/ceph/decode.h>
#include <linux/parser.h>
#include <linux/bsearch.h>
@@ -114,12 +115,17 @@ static int atomic_dec_return_safe(atomic_t *v)
#define RBD_OBJ_PREFIX_LEN_MAX 64
+#define RBD_NOTIFY_TIMEOUT 5 /* seconds */
+#define RBD_RETRY_DELAY msecs_to_jiffies(1000)
+
/* Feature bits */
#define RBD_FEATURE_LAYERING (1<<0)
#define RBD_FEATURE_STRIPINGV2 (1<<1)
-#define RBD_FEATURES_ALL \
- (RBD_FEATURE_LAYERING | RBD_FEATURE_STRIPINGV2)
+#define RBD_FEATURE_EXCLUSIVE_LOCK (1<<2)
+#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING | \
+ RBD_FEATURE_STRIPINGV2 | \
+ RBD_FEATURE_EXCLUSIVE_LOCK)
/* Features supported by this (client software) implementation. */
@@ -128,11 +134,8 @@ static int atomic_dec_return_safe(atomic_t *v)
/*
* An RBD device name will be "rbd#", where the "rbd" comes from
* RBD_DRV_NAME above, and # is a unique integer identifier.
- * MAX_INT_FORMAT_WIDTH is used in ensuring DEV_NAME_LEN is big
- * enough to hold all possible device names.
*/
#define DEV_NAME_LEN 32
-#define MAX_INT_FORMAT_WIDTH ((5 * sizeof (int)) / 2 + 1)
/*
* block device image metadata (in-memory version)
@@ -322,6 +325,24 @@ struct rbd_img_request {
#define for_each_obj_request_safe(ireq, oreq, n) \
list_for_each_entry_safe_reverse(oreq, n, &(ireq)->obj_requests, links)
+enum rbd_watch_state {
+ RBD_WATCH_STATE_UNREGISTERED,
+ RBD_WATCH_STATE_REGISTERED,
+ RBD_WATCH_STATE_ERROR,
+};
+
+enum rbd_lock_state {
+ RBD_LOCK_STATE_UNLOCKED,
+ RBD_LOCK_STATE_LOCKED,
+ RBD_LOCK_STATE_RELEASING,
+};
+
+/* WatchNotify::ClientId */
+struct rbd_client_id {
+ u64 gid;
+ u64 handle;
+};
+
struct rbd_mapping {
u64 size;
u64 features;
@@ -349,13 +370,29 @@ struct rbd_device {
unsigned long flags; /* possibly lock protected */
struct rbd_spec *spec;
struct rbd_options *opts;
+ char *config_info; /* add{,_single_major} string */
struct ceph_object_id header_oid;
struct ceph_object_locator header_oloc;
- struct ceph_file_layout layout;
+ struct ceph_file_layout layout; /* used for all rbd requests */
+ struct mutex watch_mutex;
+ enum rbd_watch_state watch_state;
struct ceph_osd_linger_request *watch_handle;
+ u64 watch_cookie;
+ struct delayed_work watch_dwork;
+
+ struct rw_semaphore lock_rwsem;
+ enum rbd_lock_state lock_state;
+ struct rbd_client_id owner_cid;
+ struct work_struct acquired_lock_work;
+ struct work_struct released_lock_work;
+ struct delayed_work lock_dwork;
+ struct work_struct unlock_work;
+ wait_queue_head_t lock_waitq;
+
+ struct workqueue_struct *task_wq;
struct rbd_spec *parent_spec;
u64 parent_overlap;
@@ -439,6 +476,29 @@ static int minor_to_rbd_dev_id(int minor)
return minor >> RBD_SINGLE_MAJOR_PART_SHIFT;
}
+static bool rbd_is_lock_supported(struct rbd_device *rbd_dev)
+{
+ return (rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK) &&
+ rbd_dev->spec->snap_id == CEPH_NOSNAP &&
+ !rbd_dev->mapping.read_only;
+}
+
+static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev)
+{
+ return rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED ||
+ rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING;
+}
+
+static bool rbd_is_lock_owner(struct rbd_device *rbd_dev)
+{
+ bool is_lock_owner;
+
+ down_read(&rbd_dev->lock_rwsem);
+ is_lock_owner = __rbd_is_lock_owner(rbd_dev);
+ up_read(&rbd_dev->lock_rwsem);
+ return is_lock_owner;
+}
+
static BUS_ATTR(add, S_IWUSR, NULL, rbd_add);
static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove);
static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major);
@@ -735,6 +795,7 @@ enum {
/* string args above */
Opt_read_only,
Opt_read_write,
+ Opt_lock_on_read,
Opt_err
};
@@ -746,16 +807,19 @@ static match_table_t rbd_opts_tokens = {
{Opt_read_only, "ro"}, /* Alternate spelling */
{Opt_read_write, "read_write"},
{Opt_read_write, "rw"}, /* Alternate spelling */
+ {Opt_lock_on_read, "lock_on_read"},
{Opt_err, NULL}
};
struct rbd_options {
int queue_depth;
bool read_only;
+ bool lock_on_read;
};
#define RBD_QUEUE_DEPTH_DEFAULT BLKDEV_MAX_RQ
#define RBD_READ_ONLY_DEFAULT false
+#define RBD_LOCK_ON_READ_DEFAULT false
static int parse_rbd_opts_token(char *c, void *private)
{
@@ -791,6 +855,9 @@ static int parse_rbd_opts_token(char *c, void *private)
case Opt_read_write:
rbd_opts->read_only = false;
break;
+ case Opt_lock_on_read:
+ rbd_opts->lock_on_read = true;
+ break;
default:
/* libceph prints "bad option" msg */
return -EINVAL;
@@ -919,7 +986,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
char *snap_names = NULL;
u64 *snap_sizes = NULL;
u32 snap_count;
- size_t size;
int ret = -ENOMEM;
u32 i;
@@ -957,9 +1023,9 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
goto out_err;
/* ...as well as the array of their sizes. */
-
- size = snap_count * sizeof (*header->snap_sizes);
- snap_sizes = kmalloc(size, GFP_KERNEL);
+ snap_sizes = kmalloc_array(snap_count,
+ sizeof(*header->snap_sizes),
+ GFP_KERNEL);
if (!snap_sizes)
goto out_err;
@@ -1551,11 +1617,18 @@ static bool obj_request_type_valid(enum obj_request_type type)
}
}
-static int rbd_obj_request_submit(struct ceph_osd_client *osdc,
- struct rbd_obj_request *obj_request)
+static void rbd_img_obj_callback(struct rbd_obj_request *obj_request);
+
+static void rbd_obj_request_submit(struct rbd_obj_request *obj_request)
{
- dout("%s %p\n", __func__, obj_request);
- return ceph_osdc_start_request(osdc, obj_request->osd_req, false);
+ struct ceph_osd_request *osd_req = obj_request->osd_req;
+
+ dout("%s %p osd_req %p\n", __func__, obj_request, osd_req);
+ if (obj_request_img_data_test(obj_request)) {
+ WARN_ON(obj_request->callback != rbd_img_obj_callback);
+ rbd_img_request_get(obj_request->img_request);
+ }
+ ceph_osdc_start_request(osd_req->r_osdc, osd_req, false);
}
static void rbd_obj_request_end(struct rbd_obj_request *obj_request)
@@ -1745,6 +1818,22 @@ static void rbd_obj_request_complete(struct rbd_obj_request *obj_request)
complete_all(&obj_request->completion);
}
+static void rbd_obj_request_error(struct rbd_obj_request *obj_request, int err)
+{
+ obj_request->result = err;
+ obj_request->xferred = 0;
+ /*
+ * kludge - mirror rbd_obj_request_submit() to match a put in
+ * rbd_img_obj_callback()
+ */
+ if (obj_request_img_data_test(obj_request)) {
+ WARN_ON(obj_request->callback != rbd_img_obj_callback);
+ rbd_img_request_get(obj_request->img_request);
+ }
+ obj_request_done_set(obj_request);
+ rbd_obj_request_complete(obj_request);
+}
+
static void rbd_osd_read_callback(struct rbd_obj_request *obj_request)
{
struct rbd_img_request *img_request = NULL;
@@ -1877,11 +1966,10 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req)
static void rbd_osd_req_format_read(struct rbd_obj_request *obj_request)
{
- struct rbd_img_request *img_request = obj_request->img_request;
struct ceph_osd_request *osd_req = obj_request->osd_req;
- if (img_request)
- osd_req->r_snapid = img_request->snap_id;
+ rbd_assert(obj_request_img_data_test(obj_request));
+ osd_req->r_snapid = obj_request->img_request->snap_id;
}
static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
@@ -2074,7 +2162,9 @@ static void rbd_obj_request_destroy(struct kref *kref)
bio_chain_put(obj_request->bio_list);
break;
case OBJ_REQUEST_PAGES:
- if (obj_request->pages)
+ /* img_data requests don't own their page array */
+ if (obj_request->pages &&
+ !obj_request_img_data_test(obj_request))
ceph_release_page_vector(obj_request->pages,
obj_request->page_count);
break;
@@ -2295,13 +2385,6 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request)
xferred = obj_request->length;
}
- /* Image object requests don't own their page array */
-
- if (obj_request->type == OBJ_REQUEST_PAGES) {
- obj_request->pages = NULL;
- obj_request->page_count = 0;
- }
-
if (img_request_child_test(img_request)) {
rbd_assert(img_request->obj_request != NULL);
more = obj_request->which < img_request->obj_request_count - 1;
@@ -2520,8 +2603,6 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
rbd_img_obj_request_fill(obj_request, osd_req, op_type, 0);
- rbd_img_request_get(img_request);
-
img_offset += length;
resid -= length;
}
@@ -2579,7 +2660,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
{
struct rbd_obj_request *orig_request;
struct ceph_osd_request *osd_req;
- struct ceph_osd_client *osdc;
struct rbd_device *rbd_dev;
struct page **pages;
enum obj_operation_type op_type;
@@ -2603,7 +2683,7 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
rbd_assert(obj_request_type_valid(orig_request->type));
img_result = img_request->result;
parent_length = img_request->length;
- rbd_assert(parent_length == img_request->xferred);
+ rbd_assert(img_result || parent_length == img_request->xferred);
rbd_img_request_put(img_request);
rbd_assert(orig_request->img_request);
@@ -2616,13 +2696,9 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
* and re-submit the original write request.
*/
if (!rbd_dev->parent_overlap) {
- struct ceph_osd_client *osdc;
-
ceph_release_page_vector(pages, page_count);
- osdc = &rbd_dev->rbd_client->client->osdc;
- img_result = rbd_obj_request_submit(osdc, orig_request);
- if (!img_result)
- return;
+ rbd_obj_request_submit(orig_request);
+ return;
}
if (img_result)
@@ -2656,17 +2732,12 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
/* All set, send it off. */
- osdc = &rbd_dev->rbd_client->client->osdc;
- img_result = rbd_obj_request_submit(osdc, orig_request);
- if (!img_result)
- return;
-out_err:
- /* Record the error code and complete the request */
+ rbd_obj_request_submit(orig_request);
+ return;
- orig_request->result = img_result;
- orig_request->xferred = 0;
- obj_request_done_set(orig_request);
- rbd_obj_request_complete(orig_request);
+out_err:
+ ceph_release_page_vector(pages, page_count);
+ rbd_obj_request_error(orig_request, img_result);
}
/*
@@ -2680,26 +2751,19 @@ out_err:
* When the read completes, this page array will be transferred to
* the original object request for the copyup operation.
*
- * If an error occurs, record it as the result of the original
- * object request and mark it done so it gets completed.
+ * If an error occurs, it is recorded as the result of the original
+ * object request in rbd_img_obj_exists_callback().
*/
static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
{
- struct rbd_img_request *img_request = NULL;
+ struct rbd_device *rbd_dev = obj_request->img_request->rbd_dev;
struct rbd_img_request *parent_request = NULL;
- struct rbd_device *rbd_dev;
u64 img_offset;
u64 length;
struct page **pages = NULL;
u32 page_count;
int result;
- rbd_assert(obj_request_img_data_test(obj_request));
- rbd_assert(obj_request_type_valid(obj_request->type));
-
- img_request = obj_request->img_request;
- rbd_assert(img_request != NULL);
- rbd_dev = img_request->rbd_dev;
rbd_assert(rbd_dev->parent != NULL);
/*
@@ -2740,10 +2804,11 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
result = rbd_img_request_fill(parent_request, OBJ_REQUEST_PAGES, pages);
if (result)
goto out_err;
+
parent_request->copyup_pages = pages;
parent_request->copyup_page_count = page_count;
-
parent_request->callback = rbd_img_obj_parent_read_full_callback;
+
result = rbd_img_request_submit(parent_request);
if (!result)
return 0;
@@ -2757,10 +2822,6 @@ out_err:
ceph_release_page_vector(pages, page_count);
if (parent_request)
rbd_img_request_put(parent_request);
- obj_request->result = result;
- obj_request->xferred = 0;
- obj_request_done_set(obj_request);
-
return result;
}
@@ -2793,17 +2854,13 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
/*
* If the overlap has become 0 (most likely because the
- * image has been flattened) we need to free the pages
- * and re-submit the original write request.
+ * image has been flattened) we need to re-submit the
+ * original request.
*/
rbd_dev = orig_request->img_request->rbd_dev;
if (!rbd_dev->parent_overlap) {
- struct ceph_osd_client *osdc;
-
- osdc = &rbd_dev->rbd_client->client->osdc;
- result = rbd_obj_request_submit(osdc, orig_request);
- if (!result)
- return;
+ rbd_obj_request_submit(orig_request);
+ return;
}
/*
@@ -2816,31 +2873,45 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
obj_request_existence_set(orig_request, true);
} else if (result == -ENOENT) {
obj_request_existence_set(orig_request, false);
- } else if (result) {
- orig_request->result = result;
- goto out;
+ } else {
+ goto fail_orig_request;
}
/*
* Resubmit the original request now that we have recorded
* whether the target object exists.
*/
- orig_request->result = rbd_img_obj_request_submit(orig_request);
-out:
- if (orig_request->result)
- rbd_obj_request_complete(orig_request);
+ result = rbd_img_obj_request_submit(orig_request);
+ if (result)
+ goto fail_orig_request;
+
+ return;
+
+fail_orig_request:
+ rbd_obj_request_error(orig_request, result);
}
static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
{
+ struct rbd_device *rbd_dev = obj_request->img_request->rbd_dev;
struct rbd_obj_request *stat_request;
- struct rbd_device *rbd_dev;
- struct ceph_osd_client *osdc;
- struct page **pages = NULL;
+ struct page **pages;
u32 page_count;
size_t size;
int ret;
+ stat_request = rbd_obj_request_create(obj_request->object_name, 0, 0,
+ OBJ_REQUEST_PAGES);
+ if (!stat_request)
+ return -ENOMEM;
+
+ stat_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
+ stat_request);
+ if (!stat_request->osd_req) {
+ ret = -ENOMEM;
+ goto fail_stat_request;
+ }
+
/*
* The response data for a STAT call consists of:
* le64 length;
@@ -2852,52 +2923,33 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
size = sizeof (__le64) + sizeof (__le32) + sizeof (__le32);
page_count = (u32)calc_pages_for(0, size);
pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
- if (IS_ERR(pages))
- return PTR_ERR(pages);
+ if (IS_ERR(pages)) {
+ ret = PTR_ERR(pages);
+ goto fail_stat_request;
+ }
- ret = -ENOMEM;
- stat_request = rbd_obj_request_create(obj_request->object_name, 0, 0,
- OBJ_REQUEST_PAGES);
- if (!stat_request)
- goto out;
+ osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT, 0);
+ osd_req_op_raw_data_in_pages(stat_request->osd_req, 0, pages, size, 0,
+ false, false);
rbd_obj_request_get(obj_request);
stat_request->obj_request = obj_request;
stat_request->pages = pages;
stat_request->page_count = page_count;
-
- rbd_assert(obj_request->img_request);
- rbd_dev = obj_request->img_request->rbd_dev;
- stat_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
- stat_request);
- if (!stat_request->osd_req)
- goto out;
stat_request->callback = rbd_img_obj_exists_callback;
- osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT, 0);
- osd_req_op_raw_data_in_pages(stat_request->osd_req, 0, pages, size, 0,
- false, false);
- rbd_osd_req_format_read(stat_request);
-
- osdc = &rbd_dev->rbd_client->client->osdc;
- ret = rbd_obj_request_submit(osdc, stat_request);
-out:
- if (ret)
- rbd_obj_request_put(obj_request);
+ rbd_obj_request_submit(stat_request);
+ return 0;
+fail_stat_request:
+ rbd_obj_request_put(stat_request);
return ret;
}
static bool img_obj_request_simple(struct rbd_obj_request *obj_request)
{
- struct rbd_img_request *img_request;
- struct rbd_device *rbd_dev;
-
- rbd_assert(obj_request_img_data_test(obj_request));
-
- img_request = obj_request->img_request;
- rbd_assert(img_request);
- rbd_dev = img_request->rbd_dev;
+ struct rbd_img_request *img_request = obj_request->img_request;
+ struct rbd_device *rbd_dev = img_request->rbd_dev;
/* Reads */
if (!img_request_write_test(img_request) &&
@@ -2936,14 +2988,13 @@ static bool img_obj_request_simple(struct rbd_obj_request *obj_request)
static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request)
{
- if (img_obj_request_simple(obj_request)) {
- struct rbd_device *rbd_dev;
- struct ceph_osd_client *osdc;
-
- rbd_dev = obj_request->img_request->rbd_dev;
- osdc = &rbd_dev->rbd_client->client->osdc;
+ rbd_assert(obj_request_img_data_test(obj_request));
+ rbd_assert(obj_request_type_valid(obj_request->type));
+ rbd_assert(obj_request->img_request);
- return rbd_obj_request_submit(osdc, obj_request);
+ if (img_obj_request_simple(obj_request)) {
+ rbd_obj_request_submit(obj_request);
+ return 0;
}
/*
@@ -3006,12 +3057,8 @@ static void rbd_img_parent_read_callback(struct rbd_img_request *img_request)
rbd_assert(obj_request->img_request);
rbd_dev = obj_request->img_request->rbd_dev;
if (!rbd_dev->parent_overlap) {
- struct ceph_osd_client *osdc;
-
- osdc = &rbd_dev->rbd_client->client->osdc;
- img_result = rbd_obj_request_submit(osdc, obj_request);
- if (!img_result)
- return;
+ rbd_obj_request_submit(obj_request);
+ return;
}
obj_request->result = img_result;
@@ -3084,65 +3131,724 @@ out_err:
obj_request_done_set(obj_request);
}
-static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev);
-static void __rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev);
+static const struct rbd_client_id rbd_empty_cid;
-static void rbd_watch_cb(void *arg, u64 notify_id, u64 cookie,
- u64 notifier_id, void *data, size_t data_len)
+static bool rbd_cid_equal(const struct rbd_client_id *lhs,
+ const struct rbd_client_id *rhs)
+{
+ return lhs->gid == rhs->gid && lhs->handle == rhs->handle;
+}
+
+static struct rbd_client_id rbd_get_cid(struct rbd_device *rbd_dev)
+{
+ struct rbd_client_id cid;
+
+ mutex_lock(&rbd_dev->watch_mutex);
+ cid.gid = ceph_client_gid(rbd_dev->rbd_client->client);
+ cid.handle = rbd_dev->watch_cookie;
+ mutex_unlock(&rbd_dev->watch_mutex);
+ return cid;
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static void rbd_set_owner_cid(struct rbd_device *rbd_dev,
+ const struct rbd_client_id *cid)
+{
+ dout("%s rbd_dev %p %llu-%llu -> %llu-%llu\n", __func__, rbd_dev,
+ rbd_dev->owner_cid.gid, rbd_dev->owner_cid.handle,
+ cid->gid, cid->handle);
+ rbd_dev->owner_cid = *cid; /* struct */
+}
+
+static void format_lock_cookie(struct rbd_device *rbd_dev, char *buf)
+{
+ mutex_lock(&rbd_dev->watch_mutex);
+ sprintf(buf, "%s %llu", RBD_LOCK_COOKIE_PREFIX, rbd_dev->watch_cookie);
+ mutex_unlock(&rbd_dev->watch_mutex);
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static int rbd_lock(struct rbd_device *rbd_dev)
{
- struct rbd_device *rbd_dev = arg;
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ struct rbd_client_id cid = rbd_get_cid(rbd_dev);
+ char cookie[32];
+ int ret;
+
+ WARN_ON(__rbd_is_lock_owner(rbd_dev));
+
+ format_lock_cookie(rbd_dev, cookie);
+ ret = ceph_cls_lock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
+ RBD_LOCK_NAME, CEPH_CLS_LOCK_EXCLUSIVE, cookie,
+ RBD_LOCK_TAG, "", 0);
+ if (ret)
+ return ret;
+
+ rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED;
+ rbd_set_owner_cid(rbd_dev, &cid);
+ queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work);
+ return 0;
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static int rbd_unlock(struct rbd_device *rbd_dev)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ char cookie[32];
+ int ret;
+
+ WARN_ON(!__rbd_is_lock_owner(rbd_dev));
+
+ rbd_dev->lock_state = RBD_LOCK_STATE_UNLOCKED;
+
+ format_lock_cookie(rbd_dev, cookie);
+ ret = ceph_cls_unlock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
+ RBD_LOCK_NAME, cookie);
+ if (ret && ret != -ENOENT) {
+ rbd_warn(rbd_dev, "cls_unlock failed: %d", ret);
+ return ret;
+ }
+
+ rbd_set_owner_cid(rbd_dev, &rbd_empty_cid);
+ queue_work(rbd_dev->task_wq, &rbd_dev->released_lock_work);
+ return 0;
+}
+
+static int __rbd_notify_op_lock(struct rbd_device *rbd_dev,
+ enum rbd_notify_op notify_op,
+ struct page ***preply_pages,
+ size_t *preply_len)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ struct rbd_client_id cid = rbd_get_cid(rbd_dev);
+ int buf_size = 4 + 8 + 8 + CEPH_ENCODING_START_BLK_LEN;
+ char buf[buf_size];
+ void *p = buf;
+
+ dout("%s rbd_dev %p notify_op %d\n", __func__, rbd_dev, notify_op);
+
+ /* encode *LockPayload NotifyMessage (op + ClientId) */
+ ceph_start_encoding(&p, 2, 1, buf_size - CEPH_ENCODING_START_BLK_LEN);
+ ceph_encode_32(&p, notify_op);
+ ceph_encode_64(&p, cid.gid);
+ ceph_encode_64(&p, cid.handle);
+
+ return ceph_osdc_notify(osdc, &rbd_dev->header_oid,
+ &rbd_dev->header_oloc, buf, buf_size,
+ RBD_NOTIFY_TIMEOUT, preply_pages, preply_len);
+}
+
+static void rbd_notify_op_lock(struct rbd_device *rbd_dev,
+ enum rbd_notify_op notify_op)
+{
+ struct page **reply_pages;
+ size_t reply_len;
+
+ __rbd_notify_op_lock(rbd_dev, notify_op, &reply_pages, &reply_len);
+ ceph_release_page_vector(reply_pages, calc_pages_for(0, reply_len));
+}
+
+static void rbd_notify_acquired_lock(struct work_struct *work)
+{
+ struct rbd_device *rbd_dev = container_of(work, struct rbd_device,
+ acquired_lock_work);
+
+ rbd_notify_op_lock(rbd_dev, RBD_NOTIFY_OP_ACQUIRED_LOCK);
+}
+
+static void rbd_notify_released_lock(struct work_struct *work)
+{
+ struct rbd_device *rbd_dev = container_of(work, struct rbd_device,
+ released_lock_work);
+
+ rbd_notify_op_lock(rbd_dev, RBD_NOTIFY_OP_RELEASED_LOCK);
+}
+
+static int rbd_request_lock(struct rbd_device *rbd_dev)
+{
+ struct page **reply_pages;
+ size_t reply_len;
+ bool lock_owner_responded = false;
int ret;
- dout("%s rbd_dev %p cookie %llu notify_id %llu\n", __func__, rbd_dev,
- cookie, notify_id);
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+ ret = __rbd_notify_op_lock(rbd_dev, RBD_NOTIFY_OP_REQUEST_LOCK,
+ &reply_pages, &reply_len);
+ if (ret && ret != -ETIMEDOUT) {
+ rbd_warn(rbd_dev, "failed to request lock: %d", ret);
+ goto out;
+ }
+
+ if (reply_len > 0 && reply_len <= PAGE_SIZE) {
+ void *p = page_address(reply_pages[0]);
+ void *const end = p + reply_len;
+ u32 n;
+
+ ceph_decode_32_safe(&p, end, n, e_inval); /* num_acks */
+ while (n--) {
+ u8 struct_v;
+ u32 len;
+ ceph_decode_need(&p, end, 8 + 8, e_inval);
+ p += 8 + 8; /* skip gid and cookie */
+
+ ceph_decode_32_safe(&p, end, len, e_inval);
+ if (!len)
+ continue;
+
+ if (lock_owner_responded) {
+ rbd_warn(rbd_dev,
+ "duplicate lock owners detected");
+ ret = -EIO;
+ goto out;
+ }
+
+ lock_owner_responded = true;
+ ret = ceph_start_decoding(&p, end, 1, "ResponseMessage",
+ &struct_v, &len);
+ if (ret) {
+ rbd_warn(rbd_dev,
+ "failed to decode ResponseMessage: %d",
+ ret);
+ goto e_inval;
+ }
+
+ ret = ceph_decode_32(&p);
+ }
+ }
+
+ if (!lock_owner_responded) {
+ rbd_warn(rbd_dev, "no lock owners detected");
+ ret = -ETIMEDOUT;
+ }
+
+out:
+ ceph_release_page_vector(reply_pages, calc_pages_for(0, reply_len));
+ return ret;
+
+e_inval:
+ ret = -EINVAL;
+ goto out;
+}
+
+static void wake_requests(struct rbd_device *rbd_dev, bool wake_all)
+{
+ dout("%s rbd_dev %p wake_all %d\n", __func__, rbd_dev, wake_all);
+
+ cancel_delayed_work(&rbd_dev->lock_dwork);
+ if (wake_all)
+ wake_up_all(&rbd_dev->lock_waitq);
+ else
+ wake_up(&rbd_dev->lock_waitq);
+}
+
+static int get_lock_owner_info(struct rbd_device *rbd_dev,
+ struct ceph_locker **lockers, u32 *num_lockers)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ u8 lock_type;
+ char *lock_tag;
+ int ret;
+
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+ ret = ceph_cls_lock_info(osdc, &rbd_dev->header_oid,
+ &rbd_dev->header_oloc, RBD_LOCK_NAME,
+ &lock_type, &lock_tag, lockers, num_lockers);
+ if (ret)
+ return ret;
+
+ if (*num_lockers == 0) {
+ dout("%s rbd_dev %p no lockers detected\n", __func__, rbd_dev);
+ goto out;
+ }
+
+ if (strcmp(lock_tag, RBD_LOCK_TAG)) {
+ rbd_warn(rbd_dev, "locked by external mechanism, tag %s",
+ lock_tag);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (lock_type == CEPH_CLS_LOCK_SHARED) {
+ rbd_warn(rbd_dev, "shared lock type detected");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (strncmp((*lockers)[0].id.cookie, RBD_LOCK_COOKIE_PREFIX,
+ strlen(RBD_LOCK_COOKIE_PREFIX))) {
+ rbd_warn(rbd_dev, "locked by external mechanism, cookie %s",
+ (*lockers)[0].id.cookie);
+ ret = -EBUSY;
+ goto out;
+ }
+
+out:
+ kfree(lock_tag);
+ return ret;
+}
+
+static int find_watcher(struct rbd_device *rbd_dev,
+ const struct ceph_locker *locker)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ struct ceph_watch_item *watchers;
+ u32 num_watchers;
+ u64 cookie;
+ int i;
+ int ret;
+
+ ret = ceph_osdc_list_watchers(osdc, &rbd_dev->header_oid,
+ &rbd_dev->header_oloc, &watchers,
+ &num_watchers);
+ if (ret)
+ return ret;
+
+ sscanf(locker->id.cookie, RBD_LOCK_COOKIE_PREFIX " %llu", &cookie);
+ for (i = 0; i < num_watchers; i++) {
+ if (!memcmp(&watchers[i].addr, &locker->info.addr,
+ sizeof(locker->info.addr)) &&
+ watchers[i].cookie == cookie) {
+ struct rbd_client_id cid = {
+ .gid = le64_to_cpu(watchers[i].name.num),
+ .handle = cookie,
+ };
+
+ dout("%s rbd_dev %p found cid %llu-%llu\n", __func__,
+ rbd_dev, cid.gid, cid.handle);
+ rbd_set_owner_cid(rbd_dev, &cid);
+ ret = 1;
+ goto out;
+ }
+ }
+
+ dout("%s rbd_dev %p no watchers\n", __func__, rbd_dev);
+ ret = 0;
+out:
+ kfree(watchers);
+ return ret;
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static int rbd_try_lock(struct rbd_device *rbd_dev)
+{
+ struct ceph_client *client = rbd_dev->rbd_client->client;
+ struct ceph_locker *lockers;
+ u32 num_lockers;
+ int ret;
+
+ for (;;) {
+ ret = rbd_lock(rbd_dev);
+ if (ret != -EBUSY)
+ return ret;
+
+ /* determine if the current lock holder is still alive */
+ ret = get_lock_owner_info(rbd_dev, &lockers, &num_lockers);
+ if (ret)
+ return ret;
+
+ if (num_lockers == 0)
+ goto again;
+
+ ret = find_watcher(rbd_dev, lockers);
+ if (ret) {
+ if (ret > 0)
+ ret = 0; /* have to request lock */
+ goto out;
+ }
+
+ rbd_warn(rbd_dev, "%s%llu seems dead, breaking lock",
+ ENTITY_NAME(lockers[0].id.name));
+
+ ret = ceph_monc_blacklist_add(&client->monc,
+ &lockers[0].info.addr);
+ if (ret) {
+ rbd_warn(rbd_dev, "blacklist of %s%llu failed: %d",
+ ENTITY_NAME(lockers[0].id.name), ret);
+ goto out;
+ }
+
+ ret = ceph_cls_break_lock(&client->osdc, &rbd_dev->header_oid,
+ &rbd_dev->header_oloc, RBD_LOCK_NAME,
+ lockers[0].id.cookie,
+ &lockers[0].id.name);
+ if (ret && ret != -ENOENT)
+ goto out;
+
+again:
+ ceph_free_lockers(lockers, num_lockers);
+ }
+
+out:
+ ceph_free_lockers(lockers, num_lockers);
+ return ret;
+}
+
+/*
+ * ret is set only if lock_state is RBD_LOCK_STATE_UNLOCKED
+ */
+static enum rbd_lock_state rbd_try_acquire_lock(struct rbd_device *rbd_dev,
+ int *pret)
+{
+ enum rbd_lock_state lock_state;
+
+ down_read(&rbd_dev->lock_rwsem);
+ dout("%s rbd_dev %p read lock_state %d\n", __func__, rbd_dev,
+ rbd_dev->lock_state);
+ if (__rbd_is_lock_owner(rbd_dev)) {
+ lock_state = rbd_dev->lock_state;
+ up_read(&rbd_dev->lock_rwsem);
+ return lock_state;
+ }
+
+ up_read(&rbd_dev->lock_rwsem);
+ down_write(&rbd_dev->lock_rwsem);
+ dout("%s rbd_dev %p write lock_state %d\n", __func__, rbd_dev,
+ rbd_dev->lock_state);
+ if (!__rbd_is_lock_owner(rbd_dev)) {
+ *pret = rbd_try_lock(rbd_dev);
+ if (*pret)
+ rbd_warn(rbd_dev, "failed to acquire lock: %d", *pret);
+ }
+
+ lock_state = rbd_dev->lock_state;
+ up_write(&rbd_dev->lock_rwsem);
+ return lock_state;
+}
+
+static void rbd_acquire_lock(struct work_struct *work)
+{
+ struct rbd_device *rbd_dev = container_of(to_delayed_work(work),
+ struct rbd_device, lock_dwork);
+ enum rbd_lock_state lock_state;
+ int ret;
+
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+again:
+ lock_state = rbd_try_acquire_lock(rbd_dev, &ret);
+ if (lock_state != RBD_LOCK_STATE_UNLOCKED || ret == -EBLACKLISTED) {
+ if (lock_state == RBD_LOCK_STATE_LOCKED)
+ wake_requests(rbd_dev, true);
+ dout("%s rbd_dev %p lock_state %d ret %d - done\n", __func__,
+ rbd_dev, lock_state, ret);
+ return;
+ }
+
+ ret = rbd_request_lock(rbd_dev);
+ if (ret == -ETIMEDOUT) {
+ goto again; /* treat this as a dead client */
+ } else if (ret < 0) {
+ rbd_warn(rbd_dev, "error requesting lock: %d", ret);
+ mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork,
+ RBD_RETRY_DELAY);
+ } else {
+ /*
+ * lock owner acked, but resend if we don't see them
+ * release the lock
+ */
+ dout("%s rbd_dev %p requeueing lock_dwork\n", __func__,
+ rbd_dev);
+ mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork,
+ msecs_to_jiffies(2 * RBD_NOTIFY_TIMEOUT * MSEC_PER_SEC));
+ }
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static bool rbd_release_lock(struct rbd_device *rbd_dev)
+{
+ dout("%s rbd_dev %p read lock_state %d\n", __func__, rbd_dev,
+ rbd_dev->lock_state);
+ if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED)
+ return false;
+
+ rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING;
+ downgrade_write(&rbd_dev->lock_rwsem);
/*
- * Until adequate refresh error handling is in place, there is
- * not much we can do here, except warn.
+ * Ensure that all in-flight IO is flushed.
*
- * See http://tracker.ceph.com/issues/5040
+ * FIXME: ceph_osdc_sync() flushes the entire OSD client, which
+ * may be shared with other devices.
*/
- ret = rbd_dev_refresh(rbd_dev);
- if (ret)
- rbd_warn(rbd_dev, "refresh failed: %d", ret);
+ ceph_osdc_sync(&rbd_dev->rbd_client->client->osdc);
+ up_read(&rbd_dev->lock_rwsem);
+
+ down_write(&rbd_dev->lock_rwsem);
+ dout("%s rbd_dev %p write lock_state %d\n", __func__, rbd_dev,
+ rbd_dev->lock_state);
+ if (rbd_dev->lock_state != RBD_LOCK_STATE_RELEASING)
+ return false;
+
+ if (!rbd_unlock(rbd_dev))
+ /*
+ * Give others a chance to grab the lock - we would re-acquire
+ * almost immediately if we got new IO during ceph_osdc_sync()
+ * otherwise. We need to ack our own notifications, so this
+ * lock_dwork will be requeued from rbd_wait_state_locked()
+ * after wake_requests() in rbd_handle_released_lock().
+ */
+ cancel_delayed_work(&rbd_dev->lock_dwork);
+
+ return true;
+}
+
+static void rbd_release_lock_work(struct work_struct *work)
+{
+ struct rbd_device *rbd_dev = container_of(work, struct rbd_device,
+ unlock_work);
+
+ down_write(&rbd_dev->lock_rwsem);
+ rbd_release_lock(rbd_dev);
+ up_write(&rbd_dev->lock_rwsem);
+}
+
+static void rbd_handle_acquired_lock(struct rbd_device *rbd_dev, u8 struct_v,
+ void **p)
+{
+ struct rbd_client_id cid = { 0 };
+
+ if (struct_v >= 2) {
+ cid.gid = ceph_decode_64(p);
+ cid.handle = ceph_decode_64(p);
+ }
+
+ dout("%s rbd_dev %p cid %llu-%llu\n", __func__, rbd_dev, cid.gid,
+ cid.handle);
+ if (!rbd_cid_equal(&cid, &rbd_empty_cid)) {
+ down_write(&rbd_dev->lock_rwsem);
+ if (rbd_cid_equal(&cid, &rbd_dev->owner_cid)) {
+ /*
+ * we already know that the remote client is
+ * the owner
+ */
+ up_write(&rbd_dev->lock_rwsem);
+ return;
+ }
+
+ rbd_set_owner_cid(rbd_dev, &cid);
+ downgrade_write(&rbd_dev->lock_rwsem);
+ } else {
+ down_read(&rbd_dev->lock_rwsem);
+ }
+
+ if (!__rbd_is_lock_owner(rbd_dev))
+ wake_requests(rbd_dev, false);
+ up_read(&rbd_dev->lock_rwsem);
+}
+
+static void rbd_handle_released_lock(struct rbd_device *rbd_dev, u8 struct_v,
+ void **p)
+{
+ struct rbd_client_id cid = { 0 };
+
+ if (struct_v >= 2) {
+ cid.gid = ceph_decode_64(p);
+ cid.handle = ceph_decode_64(p);
+ }
+
+ dout("%s rbd_dev %p cid %llu-%llu\n", __func__, rbd_dev, cid.gid,
+ cid.handle);
+ if (!rbd_cid_equal(&cid, &rbd_empty_cid)) {
+ down_write(&rbd_dev->lock_rwsem);
+ if (!rbd_cid_equal(&cid, &rbd_dev->owner_cid)) {
+ dout("%s rbd_dev %p unexpected owner, cid %llu-%llu != owner_cid %llu-%llu\n",
+ __func__, rbd_dev, cid.gid, cid.handle,
+ rbd_dev->owner_cid.gid, rbd_dev->owner_cid.handle);
+ up_write(&rbd_dev->lock_rwsem);
+ return;
+ }
+
+ rbd_set_owner_cid(rbd_dev, &rbd_empty_cid);
+ downgrade_write(&rbd_dev->lock_rwsem);
+ } else {
+ down_read(&rbd_dev->lock_rwsem);
+ }
+
+ if (!__rbd_is_lock_owner(rbd_dev))
+ wake_requests(rbd_dev, false);
+ up_read(&rbd_dev->lock_rwsem);
+}
+
+static bool rbd_handle_request_lock(struct rbd_device *rbd_dev, u8 struct_v,
+ void **p)
+{
+ struct rbd_client_id my_cid = rbd_get_cid(rbd_dev);
+ struct rbd_client_id cid = { 0 };
+ bool need_to_send;
+
+ if (struct_v >= 2) {
+ cid.gid = ceph_decode_64(p);
+ cid.handle = ceph_decode_64(p);
+ }
+
+ dout("%s rbd_dev %p cid %llu-%llu\n", __func__, rbd_dev, cid.gid,
+ cid.handle);
+ if (rbd_cid_equal(&cid, &my_cid))
+ return false;
+
+ down_read(&rbd_dev->lock_rwsem);
+ need_to_send = __rbd_is_lock_owner(rbd_dev);
+ if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) {
+ if (!rbd_cid_equal(&rbd_dev->owner_cid, &rbd_empty_cid)) {
+ dout("%s rbd_dev %p queueing unlock_work\n", __func__,
+ rbd_dev);
+ queue_work(rbd_dev->task_wq, &rbd_dev->unlock_work);
+ }
+ }
+ up_read(&rbd_dev->lock_rwsem);
+ return need_to_send;
+}
+
+static void __rbd_acknowledge_notify(struct rbd_device *rbd_dev,
+ u64 notify_id, u64 cookie, s32 *result)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ int buf_size = 4 + CEPH_ENCODING_START_BLK_LEN;
+ char buf[buf_size];
+ int ret;
+
+ if (result) {
+ void *p = buf;
+
+ /* encode ResponseMessage */
+ ceph_start_encoding(&p, 1, 1,
+ buf_size - CEPH_ENCODING_START_BLK_LEN);
+ ceph_encode_32(&p, *result);
+ } else {
+ buf_size = 0;
+ }
ret = ceph_osdc_notify_ack(osdc, &rbd_dev->header_oid,
&rbd_dev->header_oloc, notify_id, cookie,
- NULL, 0);
+ buf, buf_size);
if (ret)
- rbd_warn(rbd_dev, "notify_ack ret %d", ret);
+ rbd_warn(rbd_dev, "acknowledge_notify failed: %d", ret);
}
-static void rbd_watch_errcb(void *arg, u64 cookie, int err)
+static void rbd_acknowledge_notify(struct rbd_device *rbd_dev, u64 notify_id,
+ u64 cookie)
+{
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+ __rbd_acknowledge_notify(rbd_dev, notify_id, cookie, NULL);
+}
+
+static void rbd_acknowledge_notify_result(struct rbd_device *rbd_dev,
+ u64 notify_id, u64 cookie, s32 result)
+{
+ dout("%s rbd_dev %p result %d\n", __func__, rbd_dev, result);
+ __rbd_acknowledge_notify(rbd_dev, notify_id, cookie, &result);
+}
+
+static void rbd_watch_cb(void *arg, u64 notify_id, u64 cookie,
+ u64 notifier_id, void *data, size_t data_len)
{
struct rbd_device *rbd_dev = arg;
+ void *p = data;
+ void *const end = p + data_len;
+ u8 struct_v;
+ u32 len;
+ u32 notify_op;
int ret;
- rbd_warn(rbd_dev, "encountered watch error: %d", err);
+ dout("%s rbd_dev %p cookie %llu notify_id %llu data_len %zu\n",
+ __func__, rbd_dev, cookie, notify_id, data_len);
+ if (data_len) {
+ ret = ceph_start_decoding(&p, end, 1, "NotifyMessage",
+ &struct_v, &len);
+ if (ret) {
+ rbd_warn(rbd_dev, "failed to decode NotifyMessage: %d",
+ ret);
+ return;
+ }
- __rbd_dev_header_unwatch_sync(rbd_dev);
+ notify_op = ceph_decode_32(&p);
+ } else {
+ /* legacy notification for header updates */
+ notify_op = RBD_NOTIFY_OP_HEADER_UPDATE;
+ len = 0;
+ }
- ret = rbd_dev_header_watch_sync(rbd_dev);
- if (ret) {
- rbd_warn(rbd_dev, "failed to reregister watch: %d", ret);
- return;
+ dout("%s rbd_dev %p notify_op %u\n", __func__, rbd_dev, notify_op);
+ switch (notify_op) {
+ case RBD_NOTIFY_OP_ACQUIRED_LOCK:
+ rbd_handle_acquired_lock(rbd_dev, struct_v, &p);
+ rbd_acknowledge_notify(rbd_dev, notify_id, cookie);
+ break;
+ case RBD_NOTIFY_OP_RELEASED_LOCK:
+ rbd_handle_released_lock(rbd_dev, struct_v, &p);
+ rbd_acknowledge_notify(rbd_dev, notify_id, cookie);
+ break;
+ case RBD_NOTIFY_OP_REQUEST_LOCK:
+ if (rbd_handle_request_lock(rbd_dev, struct_v, &p))
+ /*
+ * send ResponseMessage(0) back so the client
+ * can detect a missing owner
+ */
+ rbd_acknowledge_notify_result(rbd_dev, notify_id,
+ cookie, 0);
+ else
+ rbd_acknowledge_notify(rbd_dev, notify_id, cookie);
+ break;
+ case RBD_NOTIFY_OP_HEADER_UPDATE:
+ ret = rbd_dev_refresh(rbd_dev);
+ if (ret)
+ rbd_warn(rbd_dev, "refresh failed: %d", ret);
+
+ rbd_acknowledge_notify(rbd_dev, notify_id, cookie);
+ break;
+ default:
+ if (rbd_is_lock_owner(rbd_dev))
+ rbd_acknowledge_notify_result(rbd_dev, notify_id,
+ cookie, -EOPNOTSUPP);
+ else
+ rbd_acknowledge_notify(rbd_dev, notify_id, cookie);
+ break;
}
+}
- ret = rbd_dev_refresh(rbd_dev);
- if (ret)
- rbd_warn(rbd_dev, "reregisteration refresh failed: %d", ret);
+static void __rbd_unregister_watch(struct rbd_device *rbd_dev);
+
+static void rbd_watch_errcb(void *arg, u64 cookie, int err)
+{
+ struct rbd_device *rbd_dev = arg;
+
+ rbd_warn(rbd_dev, "encountered watch error: %d", err);
+
+ down_write(&rbd_dev->lock_rwsem);
+ rbd_set_owner_cid(rbd_dev, &rbd_empty_cid);
+ up_write(&rbd_dev->lock_rwsem);
+
+ mutex_lock(&rbd_dev->watch_mutex);
+ if (rbd_dev->watch_state == RBD_WATCH_STATE_REGISTERED) {
+ __rbd_unregister_watch(rbd_dev);
+ rbd_dev->watch_state = RBD_WATCH_STATE_ERROR;
+
+ queue_delayed_work(rbd_dev->task_wq, &rbd_dev->watch_dwork, 0);
+ }
+ mutex_unlock(&rbd_dev->watch_mutex);
}
/*
- * Initiate a watch request, synchronously.
+ * watch_mutex must be locked
*/
-static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev)
+static int __rbd_register_watch(struct rbd_device *rbd_dev)
{
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
struct ceph_osd_linger_request *handle;
rbd_assert(!rbd_dev->watch_handle);
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
handle = ceph_osdc_watch(osdc, &rbd_dev->header_oid,
&rbd_dev->header_oloc, rbd_watch_cb,
@@ -3154,13 +3860,16 @@ static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev)
return 0;
}
-static void __rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev)
+/*
+ * watch_mutex must be locked
+ */
+static void __rbd_unregister_watch(struct rbd_device *rbd_dev)
{
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
int ret;
- if (!rbd_dev->watch_handle)
- return;
+ rbd_assert(rbd_dev->watch_handle);
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
ret = ceph_osdc_unwatch(osdc, rbd_dev->watch_handle);
if (ret)
@@ -3169,17 +3878,100 @@ static void __rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev)
rbd_dev->watch_handle = NULL;
}
-/*
- * Tear down a watch request, synchronously.
- */
-static void rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev)
+static int rbd_register_watch(struct rbd_device *rbd_dev)
+{
+ int ret;
+
+ mutex_lock(&rbd_dev->watch_mutex);
+ rbd_assert(rbd_dev->watch_state == RBD_WATCH_STATE_UNREGISTERED);
+ ret = __rbd_register_watch(rbd_dev);
+ if (ret)
+ goto out;
+
+ rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED;
+ rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id;
+
+out:
+ mutex_unlock(&rbd_dev->watch_mutex);
+ return ret;
+}
+
+static void cancel_tasks_sync(struct rbd_device *rbd_dev)
{
- __rbd_dev_header_unwatch_sync(rbd_dev);
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+ cancel_delayed_work_sync(&rbd_dev->watch_dwork);
+ cancel_work_sync(&rbd_dev->acquired_lock_work);
+ cancel_work_sync(&rbd_dev->released_lock_work);
+ cancel_delayed_work_sync(&rbd_dev->lock_dwork);
+ cancel_work_sync(&rbd_dev->unlock_work);
+}
+
+static void rbd_unregister_watch(struct rbd_device *rbd_dev)
+{
+ WARN_ON(waitqueue_active(&rbd_dev->lock_waitq));
+ cancel_tasks_sync(rbd_dev);
+
+ mutex_lock(&rbd_dev->watch_mutex);
+ if (rbd_dev->watch_state == RBD_WATCH_STATE_REGISTERED)
+ __rbd_unregister_watch(rbd_dev);
+ rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED;
+ mutex_unlock(&rbd_dev->watch_mutex);
- dout("%s flushing notifies\n", __func__);
ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc);
}
+static void rbd_reregister_watch(struct work_struct *work)
+{
+ struct rbd_device *rbd_dev = container_of(to_delayed_work(work),
+ struct rbd_device, watch_dwork);
+ bool was_lock_owner = false;
+ int ret;
+
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+
+ down_write(&rbd_dev->lock_rwsem);
+ if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED)
+ was_lock_owner = rbd_release_lock(rbd_dev);
+
+ mutex_lock(&rbd_dev->watch_mutex);
+ if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR)
+ goto fail_unlock;
+
+ ret = __rbd_register_watch(rbd_dev);
+ if (ret) {
+ rbd_warn(rbd_dev, "failed to reregister watch: %d", ret);
+ if (ret != -EBLACKLISTED)
+ queue_delayed_work(rbd_dev->task_wq,
+ &rbd_dev->watch_dwork,
+ RBD_RETRY_DELAY);
+ goto fail_unlock;
+ }
+
+ rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED;
+ rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id;
+ mutex_unlock(&rbd_dev->watch_mutex);
+
+ ret = rbd_dev_refresh(rbd_dev);
+ if (ret)
+ rbd_warn(rbd_dev, "reregisteration refresh failed: %d", ret);
+
+ if (was_lock_owner) {
+ ret = rbd_try_lock(rbd_dev);
+ if (ret)
+ rbd_warn(rbd_dev, "reregisteration lock failed: %d",
+ ret);
+ }
+
+ up_write(&rbd_dev->lock_rwsem);
+ wake_requests(rbd_dev, true);
+ return;
+
+fail_unlock:
+ mutex_unlock(&rbd_dev->watch_mutex);
+ up_write(&rbd_dev->lock_rwsem);
+}
+
/*
* Synchronous osd object method call. Returns the number of bytes
* returned in the outbound buffer, or a negative error code.
@@ -3193,7 +3985,6 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
void *inbound,
size_t inbound_size)
{
- struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
struct rbd_obj_request *obj_request;
struct page **pages;
u32 page_count;
@@ -3242,11 +4033,8 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
osd_req_op_cls_response_data_pages(obj_request->osd_req, 0,
obj_request->pages, inbound_size,
0, false, false);
- rbd_osd_req_format_read(obj_request);
- ret = rbd_obj_request_submit(osdc, obj_request);
- if (ret)
- goto out;
+ rbd_obj_request_submit(obj_request);
ret = rbd_obj_request_wait(obj_request);
if (ret)
goto out;
@@ -3267,6 +4055,29 @@ out:
return ret;
}
+/*
+ * lock_rwsem must be held for read
+ */
+static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
+{
+ DEFINE_WAIT(wait);
+
+ do {
+ /*
+ * Note the use of mod_delayed_work() in rbd_acquire_lock()
+ * and cancel_delayed_work() in wake_requests().
+ */
+ dout("%s rbd_dev %p queueing lock_dwork\n", __func__, rbd_dev);
+ queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+ prepare_to_wait_exclusive(&rbd_dev->lock_waitq, &wait,
+ TASK_UNINTERRUPTIBLE);
+ up_read(&rbd_dev->lock_rwsem);
+ schedule();
+ down_read(&rbd_dev->lock_rwsem);
+ } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
+ finish_wait(&rbd_dev->lock_waitq, &wait);
+}
+
static void rbd_queue_workfn(struct work_struct *work)
{
struct request *rq = blk_mq_rq_from_pdu(work);
@@ -3277,6 +4088,7 @@ static void rbd_queue_workfn(struct work_struct *work)
u64 length = blk_rq_bytes(rq);
enum obj_operation_type op_type;
u64 mapping_size;
+ bool must_be_locked;
int result;
if (rq->cmd_type != REQ_TYPE_FS) {
@@ -3338,6 +4150,10 @@ static void rbd_queue_workfn(struct work_struct *work)
if (op_type != OBJ_OP_READ) {
snapc = rbd_dev->header.snapc;
ceph_get_snap_context(snapc);
+ must_be_locked = rbd_is_lock_supported(rbd_dev);
+ } else {
+ must_be_locked = rbd_dev->opts->lock_on_read &&
+ rbd_is_lock_supported(rbd_dev);
}
up_read(&rbd_dev->header_rwsem);
@@ -3348,11 +4164,17 @@ static void rbd_queue_workfn(struct work_struct *work)
goto err_rq;
}
+ if (must_be_locked) {
+ down_read(&rbd_dev->lock_rwsem);
+ if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED)
+ rbd_wait_state_locked(rbd_dev);
+ }
+
img_request = rbd_img_request_create(rbd_dev, offset, length, op_type,
snapc);
if (!img_request) {
result = -ENOMEM;
- goto err_rq;
+ goto err_unlock;
}
img_request->rq = rq;
snapc = NULL; /* img_request consumes a ref */
@@ -3370,10 +4192,15 @@ static void rbd_queue_workfn(struct work_struct *work)
if (result)
goto err_img_request;
+ if (must_be_locked)
+ up_read(&rbd_dev->lock_rwsem);
return;
err_img_request:
rbd_img_request_put(img_request);
+err_unlock:
+ if (must_be_locked)
+ up_read(&rbd_dev->lock_rwsem);
err_rq:
if (result)
rbd_warn(rbd_dev, "%s %llx at %llx result %d",
@@ -3415,7 +4242,6 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
u64 offset, u64 length, void *buf)
{
- struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
struct rbd_obj_request *obj_request;
struct page **pages = NULL;
u32 page_count;
@@ -3448,11 +4274,8 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
obj_request->length,
obj_request->offset & ~PAGE_MASK,
false, false);
- rbd_osd_req_format_read(obj_request);
- ret = rbd_obj_request_submit(osdc, obj_request);
- if (ret)
- goto out;
+ rbd_obj_request_submit(obj_request);
ret = rbd_obj_request_wait(obj_request);
if (ret)
goto out;
@@ -3621,7 +4444,6 @@ static int rbd_init_request(void *data, struct request *rq,
static struct blk_mq_ops rbd_mq_ops = {
.queue_rq = rbd_queue_rq,
- .map_queue = blk_mq_map_queue,
.init_request = rbd_init_request,
};
@@ -3752,13 +4574,40 @@ static ssize_t rbd_minor_show(struct device *dev,
return sprintf(buf, "%d\n", rbd_dev->minor);
}
+static ssize_t rbd_client_addr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+ struct ceph_entity_addr *client_addr =
+ ceph_client_addr(rbd_dev->rbd_client->client);
+
+ return sprintf(buf, "%pISpc/%u\n", &client_addr->in_addr,
+ le32_to_cpu(client_addr->nonce));
+}
+
static ssize_t rbd_client_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
return sprintf(buf, "client%lld\n",
- ceph_client_id(rbd_dev->rbd_client->client));
+ ceph_client_gid(rbd_dev->rbd_client->client));
+}
+
+static ssize_t rbd_cluster_fsid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+
+ return sprintf(buf, "%pU\n", &rbd_dev->rbd_client->client->fsid);
+}
+
+static ssize_t rbd_config_info_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+
+ return sprintf(buf, "%s\n", rbd_dev->config_info);
}
static ssize_t rbd_pool_show(struct device *dev,
@@ -3810,6 +4659,14 @@ static ssize_t rbd_snap_show(struct device *dev,
return sprintf(buf, "%s\n", rbd_dev->spec->snap_name);
}
+static ssize_t rbd_snap_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+
+ return sprintf(buf, "%llu\n", rbd_dev->spec->snap_id);
+}
+
/*
* For a v2 image, shows the chain of parent images, separated by empty
* lines. For v1 images or if there is no parent, shows "(no parent
@@ -3862,13 +4719,17 @@ static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL);
static DEVICE_ATTR(features, S_IRUGO, rbd_features_show, NULL);
static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL);
static DEVICE_ATTR(minor, S_IRUGO, rbd_minor_show, NULL);
+static DEVICE_ATTR(client_addr, S_IRUGO, rbd_client_addr_show, NULL);
static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL);
+static DEVICE_ATTR(cluster_fsid, S_IRUGO, rbd_cluster_fsid_show, NULL);
+static DEVICE_ATTR(config_info, S_IRUSR, rbd_config_info_show, NULL);
static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL);
static DEVICE_ATTR(pool_id, S_IRUGO, rbd_pool_id_show, NULL);
static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL);
static DEVICE_ATTR(image_id, S_IRUGO, rbd_image_id_show, NULL);
static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh);
static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL);
+static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL);
static DEVICE_ATTR(parent, S_IRUGO, rbd_parent_show, NULL);
static struct attribute *rbd_attrs[] = {
@@ -3876,12 +4737,16 @@ static struct attribute *rbd_attrs[] = {
&dev_attr_features.attr,
&dev_attr_major.attr,
&dev_attr_minor.attr,
+ &dev_attr_client_addr.attr,
&dev_attr_client_id.attr,
+ &dev_attr_cluster_fsid.attr,
+ &dev_attr_config_info.attr,
&dev_attr_pool.attr,
&dev_attr_pool_id.attr,
&dev_attr_name.attr,
&dev_attr_image_id.attr,
&dev_attr_current_snap.attr,
+ &dev_attr_snap_id.attr,
&dev_attr_parent.attr,
&dev_attr_refresh.attr,
NULL
@@ -3944,18 +4809,32 @@ static void rbd_spec_free(struct kref *kref)
kfree(spec);
}
-static void rbd_dev_release(struct device *dev)
+static void rbd_dev_free(struct rbd_device *rbd_dev)
{
- struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
- bool need_put = !!rbd_dev->opts;
+ WARN_ON(rbd_dev->watch_state != RBD_WATCH_STATE_UNREGISTERED);
+ WARN_ON(rbd_dev->lock_state != RBD_LOCK_STATE_UNLOCKED);
ceph_oid_destroy(&rbd_dev->header_oid);
ceph_oloc_destroy(&rbd_dev->header_oloc);
+ kfree(rbd_dev->config_info);
rbd_put_client(rbd_dev->rbd_client);
rbd_spec_put(rbd_dev->spec);
kfree(rbd_dev->opts);
kfree(rbd_dev);
+}
+
+static void rbd_dev_release(struct device *dev)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+ bool need_put = !!rbd_dev->opts;
+
+ if (need_put) {
+ destroy_workqueue(rbd_dev->task_wq);
+ ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
+ }
+
+ rbd_dev_free(rbd_dev);
/*
* This is racy, but way better than putting module outside of
@@ -3966,25 +4845,34 @@ static void rbd_dev_release(struct device *dev)
module_put(THIS_MODULE);
}
-static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
- struct rbd_spec *spec,
- struct rbd_options *opts)
+static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
+ struct rbd_spec *spec)
{
struct rbd_device *rbd_dev;
- rbd_dev = kzalloc(sizeof (*rbd_dev), GFP_KERNEL);
+ rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
if (!rbd_dev)
return NULL;
spin_lock_init(&rbd_dev->lock);
- rbd_dev->flags = 0;
- atomic_set(&rbd_dev->parent_ref, 0);
INIT_LIST_HEAD(&rbd_dev->node);
init_rwsem(&rbd_dev->header_rwsem);
ceph_oid_init(&rbd_dev->header_oid);
ceph_oloc_init(&rbd_dev->header_oloc);
+ mutex_init(&rbd_dev->watch_mutex);
+ rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED;
+ INIT_DELAYED_WORK(&rbd_dev->watch_dwork, rbd_reregister_watch);
+
+ init_rwsem(&rbd_dev->lock_rwsem);
+ rbd_dev->lock_state = RBD_LOCK_STATE_UNLOCKED;
+ INIT_WORK(&rbd_dev->acquired_lock_work, rbd_notify_acquired_lock);
+ INIT_WORK(&rbd_dev->released_lock_work, rbd_notify_released_lock);
+ INIT_DELAYED_WORK(&rbd_dev->lock_dwork, rbd_acquire_lock);
+ INIT_WORK(&rbd_dev->unlock_work, rbd_release_lock_work);
+ init_waitqueue_head(&rbd_dev->lock_waitq);
+
rbd_dev->dev.bus = &rbd_bus_type;
rbd_dev->dev.type = &rbd_device_type;
rbd_dev->dev.parent = &rbd_root_dev;
@@ -3992,9 +4880,6 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
rbd_dev->rbd_client = rbdc;
rbd_dev->spec = spec;
- rbd_dev->opts = opts;
-
- /* Initialize the layout used for all rbd requests */
rbd_dev->layout.stripe_unit = 1 << RBD_MAX_OBJ_ORDER;
rbd_dev->layout.stripe_count = 1;
@@ -4002,15 +4887,48 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
rbd_dev->layout.pool_id = spec->pool_id;
RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
- /*
- * If this is a mapping rbd_dev (as opposed to a parent one),
- * pin our module. We have a ref from do_rbd_add(), so use
- * __module_get().
- */
- if (rbd_dev->opts)
- __module_get(THIS_MODULE);
+ return rbd_dev;
+}
+/*
+ * Create a mapping rbd_dev.
+ */
+static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
+ struct rbd_spec *spec,
+ struct rbd_options *opts)
+{
+ struct rbd_device *rbd_dev;
+
+ rbd_dev = __rbd_dev_create(rbdc, spec);
+ if (!rbd_dev)
+ return NULL;
+
+ rbd_dev->opts = opts;
+
+ /* get an id and fill in device name */
+ rbd_dev->dev_id = ida_simple_get(&rbd_dev_id_ida, 0,
+ minor_to_rbd_dev_id(1 << MINORBITS),
+ GFP_KERNEL);
+ if (rbd_dev->dev_id < 0)
+ goto fail_rbd_dev;
+
+ sprintf(rbd_dev->name, RBD_DRV_NAME "%d", rbd_dev->dev_id);
+ rbd_dev->task_wq = alloc_ordered_workqueue("%s-tasks", WQ_MEM_RECLAIM,
+ rbd_dev->name);
+ if (!rbd_dev->task_wq)
+ goto fail_dev_id;
+
+ /* we have a ref from do_rbd_add() */
+ __module_get(THIS_MODULE);
+
+ dout("%s rbd_dev %p dev_id %d\n", __func__, rbd_dev, rbd_dev->dev_id);
return rbd_dev;
+
+fail_dev_id:
+ ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
+fail_rbd_dev:
+ rbd_dev_free(rbd_dev);
+ return NULL;
}
static void rbd_dev_destroy(struct rbd_device *rbd_dev)
@@ -4646,46 +5564,6 @@ static int rbd_dev_header_info(struct rbd_device *rbd_dev)
}
/*
- * Get a unique rbd identifier for the given new rbd_dev, and add
- * the rbd_dev to the global list.
- */
-static int rbd_dev_id_get(struct rbd_device *rbd_dev)
-{
- int new_dev_id;
-
- new_dev_id = ida_simple_get(&rbd_dev_id_ida,
- 0, minor_to_rbd_dev_id(1 << MINORBITS),
- GFP_KERNEL);
- if (new_dev_id < 0)
- return new_dev_id;
-
- rbd_dev->dev_id = new_dev_id;
-
- spin_lock(&rbd_dev_list_lock);
- list_add_tail(&rbd_dev->node, &rbd_dev_list);
- spin_unlock(&rbd_dev_list_lock);
-
- dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id);
-
- return 0;
-}
-
-/*
- * Remove an rbd_dev from the global list, and record that its
- * identifier is no longer in use.
- */
-static void rbd_dev_id_put(struct rbd_device *rbd_dev)
-{
- spin_lock(&rbd_dev_list_lock);
- list_del_init(&rbd_dev->node);
- spin_unlock(&rbd_dev_list_lock);
-
- ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
-
- dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id);
-}
-
-/*
* Skips over white space at *buf, and updates *buf to point to the
* first found non-space character (if any). Returns the length of
* the token (string of non-white space characters) found. Note
@@ -4860,6 +5738,7 @@ static int rbd_add_parse_args(const char *buf,
rbd_opts->read_only = RBD_READ_ONLY_DEFAULT;
rbd_opts->queue_depth = RBD_QUEUE_DEPTH_DEFAULT;
+ rbd_opts->lock_on_read = RBD_LOCK_ON_READ_DEFAULT;
copts = ceph_parse_options(options, mon_addrs,
mon_addrs + mon_addrs_size - 1,
@@ -5077,8 +5956,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
goto out_err;
}
- parent = rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec,
- NULL);
+ parent = __rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
if (!parent) {
ret = -ENOMEM;
goto out_err;
@@ -5113,22 +5991,12 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
{
int ret;
- /* Get an id and fill in device name. */
-
- ret = rbd_dev_id_get(rbd_dev);
- if (ret)
- goto err_out_unlock;
-
- BUILD_BUG_ON(DEV_NAME_LEN
- < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH);
- sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id);
-
/* Record our major and minor device numbers. */
if (!single_major) {
ret = register_blkdev(0, rbd_dev->name);
if (ret < 0)
- goto err_out_id;
+ goto err_out_unlock;
rbd_dev->major = ret;
rbd_dev->minor = 0;
@@ -5160,9 +6028,14 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
up_write(&rbd_dev->header_rwsem);
+ spin_lock(&rbd_dev_list_lock);
+ list_add_tail(&rbd_dev->node, &rbd_dev_list);
+ spin_unlock(&rbd_dev_list_lock);
+
add_disk(rbd_dev->disk);
- pr_info("%s: added with size 0x%llx\n", rbd_dev->disk->disk_name,
- (unsigned long long) rbd_dev->mapping.size);
+ pr_info("%s: capacity %llu features 0x%llx\n", rbd_dev->disk->disk_name,
+ (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT,
+ rbd_dev->header.features);
return ret;
@@ -5173,8 +6046,6 @@ err_out_disk:
err_out_blkdev:
if (!single_major)
unregister_blkdev(rbd_dev->major, rbd_dev->name);
-err_out_id:
- rbd_dev_id_put(rbd_dev);
err_out_unlock:
up_write(&rbd_dev->header_rwsem);
return ret;
@@ -5235,7 +6106,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
goto err_out_format;
if (!depth) {
- ret = rbd_dev_header_watch_sync(rbd_dev);
+ ret = rbd_register_watch(rbd_dev);
if (ret) {
if (ret == -ENOENT)
pr_info("image %s/%s does not exist\n",
@@ -5294,7 +6165,7 @@ err_out_probe:
rbd_dev_unprobe(rbd_dev);
err_out_watch:
if (!depth)
- rbd_dev_header_unwatch_sync(rbd_dev);
+ rbd_unregister_watch(rbd_dev);
err_out_format:
rbd_dev->image_format = 0;
kfree(rbd_dev->spec->image_id);
@@ -5346,10 +6217,18 @@ static ssize_t do_rbd_add(struct bus_type *bus,
spec = NULL; /* rbd_dev now owns this */
rbd_opts = NULL; /* rbd_dev now owns this */
+ rbd_dev->config_info = kstrdup(buf, GFP_KERNEL);
+ if (!rbd_dev->config_info) {
+ rc = -ENOMEM;
+ goto err_out_rbd_dev;
+ }
+
down_write(&rbd_dev->header_rwsem);
rc = rbd_dev_image_probe(rbd_dev, 0);
- if (rc < 0)
+ if (rc < 0) {
+ up_write(&rbd_dev->header_rwsem);
goto err_out_rbd_dev;
+ }
/* If we are mapping a snapshot it must be marked read-only */
@@ -5361,11 +6240,11 @@ static ssize_t do_rbd_add(struct bus_type *bus,
rc = rbd_dev_device_setup(rbd_dev);
if (rc) {
/*
- * rbd_dev_header_unwatch_sync() can't be moved into
+ * rbd_unregister_watch() can't be moved into
* rbd_dev_image_release() without refactoring, see
* commit 1f3ef78861ac.
*/
- rbd_dev_header_unwatch_sync(rbd_dev);
+ rbd_unregister_watch(rbd_dev);
rbd_dev_image_release(rbd_dev);
goto out;
}
@@ -5376,7 +6255,6 @@ out:
return rc;
err_out_rbd_dev:
- up_write(&rbd_dev->header_rwsem);
rbd_dev_destroy(rbd_dev);
err_out_client:
rbd_put_client(rbdc);
@@ -5406,12 +6284,16 @@ static ssize_t rbd_add_single_major(struct bus_type *bus,
static void rbd_dev_device_release(struct rbd_device *rbd_dev)
{
rbd_free_disk(rbd_dev);
+
+ spin_lock(&rbd_dev_list_lock);
+ list_del_init(&rbd_dev->node);
+ spin_unlock(&rbd_dev_list_lock);
+
clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
device_del(&rbd_dev->dev);
rbd_dev_mapping_clear(rbd_dev);
if (!single_major)
unregister_blkdev(rbd_dev->major, rbd_dev->name);
- rbd_dev_id_put(rbd_dev);
}
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
@@ -5447,18 +6329,26 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
struct rbd_device *rbd_dev = NULL;
struct list_head *tmp;
int dev_id;
- unsigned long ul;
+ char opt_buf[6];
bool already = false;
+ bool force = false;
int ret;
- ret = kstrtoul(buf, 10, &ul);
- if (ret)
- return ret;
-
- /* convert to int; abort if we lost anything in the conversion */
- dev_id = (int)ul;
- if (dev_id != ul)
+ dev_id = -1;
+ opt_buf[0] = '\0';
+ sscanf(buf, "%d %5s", &dev_id, opt_buf);
+ if (dev_id < 0) {
+ pr_err("dev_id out of range\n");
return -EINVAL;
+ }
+ if (opt_buf[0] != '\0') {
+ if (!strcmp(opt_buf, "force")) {
+ force = true;
+ } else {
+ pr_err("bad remove option at '%s'\n", opt_buf);
+ return -EINVAL;
+ }
+ }
ret = -ENOENT;
spin_lock(&rbd_dev_list_lock);
@@ -5471,7 +6361,7 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
}
if (!ret) {
spin_lock_irq(&rbd_dev->lock);
- if (rbd_dev->open_count)
+ if (rbd_dev->open_count && !force)
ret = -EBUSY;
else
already = test_and_set_bit(RBD_DEV_FLAG_REMOVING,
@@ -5482,7 +6372,20 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
if (ret < 0 || already)
return ret;
- rbd_dev_header_unwatch_sync(rbd_dev);
+ if (force) {
+ /*
+ * Prevent new IO from being queued and wait for existing
+ * IO to complete/fail.
+ */
+ blk_mq_freeze_queue(rbd_dev->disk->queue);
+ blk_set_queue_dying(rbd_dev->disk->queue);
+ }
+
+ down_write(&rbd_dev->lock_rwsem);
+ if (__rbd_is_lock_owner(rbd_dev))
+ rbd_unlock(rbd_dev);
+ up_write(&rbd_dev->lock_rwsem);
+ rbd_unregister_watch(rbd_dev);
/*
* Don't free anything from rbd_dev->disk until after all
diff --git a/drivers/block/rbd_types.h b/drivers/block/rbd_types.h
index 49d77cbcf8bd..94f367db27b0 100644
--- a/drivers/block/rbd_types.h
+++ b/drivers/block/rbd_types.h
@@ -28,6 +28,17 @@
#define RBD_DATA_PREFIX "rbd_data."
#define RBD_ID_PREFIX "rbd_id."
+#define RBD_LOCK_NAME "rbd_lock"
+#define RBD_LOCK_TAG "internal"
+#define RBD_LOCK_COOKIE_PREFIX "auto"
+
+enum rbd_notify_op {
+ RBD_NOTIFY_OP_ACQUIRED_LOCK = 0,
+ RBD_NOTIFY_OP_RELEASED_LOCK = 1,
+ RBD_NOTIFY_OP_REQUEST_LOCK = 2,
+ RBD_NOTIFY_OP_HEADER_UPDATE = 3,
+};
+
/*
* For format version 1, rbd image 'foo' consists of objects
* foo.rbd - image metadata
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 93b1aaa5ba3b..2dc5c96c186a 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -542,7 +542,6 @@ static int virtblk_init_request(void *data, struct request *rq,
static struct blk_mq_ops virtio_mq_ops = {
.queue_rq = virtio_queue_rq,
- .map_queue = blk_mq_map_queue,
.complete = virtblk_request_done,
.init_request = virtblk_init_request,
};
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 88ef6d4729b4..9908597c5209 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -909,7 +909,6 @@ out_busy:
static struct blk_mq_ops blkfront_mq_ops = {
.queue_rq = blkif_queue_rq,
- .map_queue = blk_mq_map_queue,
};
static void blkif_set_queue_limits(struct blkfront_info *info)
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 3b205e212337..7010dcac9328 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -108,6 +108,14 @@ config OMAP_OCP2SCP
OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via
OCP2SCP.
+config QCOM_EBI2
+ bool "Qualcomm External Bus Interface 2 (EBI2)"
+ depends on HAS_IOMEM
+ help
+ Say y here to enable support for the Qualcomm External Bus
+ Interface 2, which can be used to connect things like NAND Flash,
+ SRAM, ethernet adapters, FPGAs and LCD displays.
+
config SIMPLE_PM_BUS
bool "Simple Power-Managed Bus Driver"
depends on OF && PM
@@ -132,12 +140,8 @@ config SUNXI_RSB
with various RSB based devices, such as AXP223, AXP8XX PMICs,
and AC100/AC200 ICs.
-# TODO: This uses pm_clk_*() symbols that aren't exported in v4.7 and hence
-# the driver will fail to build as a module. However there are patches to
-# address that queued for v4.8, so this can be turned into a tristate symbol
-# after v4.8-rc1.
config TEGRA_ACONNECT
- bool "Tegra ACONNECT Bus Driver"
+ tristate "Tegra ACONNECT Bus Driver"
depends on ARCH_TEGRA_210_SOC
depends on OF && PM
select PM_CLK
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index ac84cc4348e3..c6cfa6b2606e 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
+obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c
new file mode 100644
index 000000000000..a6444244c411
--- /dev/null
+++ b/drivers/bus/qcom-ebi2.c
@@ -0,0 +1,408 @@
+/*
+ * Qualcomm External Bus Interface 2 (EBI2) driver
+ * an older version of the Qualcomm Parallel Interface Controller (QPIC)
+ *
+ * Copyright (C) 2016 Linaro Ltd.
+ *
+ * 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.
+ *
+ * See the device tree bindings for this block for more details on the
+ * hardware.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+
+/*
+ * CS0, CS1, CS4 and CS5 are two bits wide, CS2 and CS3 are one bit.
+ */
+#define EBI2_CS0_ENABLE_MASK BIT(0)|BIT(1)
+#define EBI2_CS1_ENABLE_MASK BIT(2)|BIT(3)
+#define EBI2_CS2_ENABLE_MASK BIT(4)
+#define EBI2_CS3_ENABLE_MASK BIT(5)
+#define EBI2_CS4_ENABLE_MASK BIT(6)|BIT(7)
+#define EBI2_CS5_ENABLE_MASK BIT(8)|BIT(9)
+#define EBI2_CSN_MASK GENMASK(9, 0)
+
+#define EBI2_XMEM_CFG 0x0000 /* Power management etc */
+
+/*
+ * SLOW CSn CFG
+ *
+ * Bits 31-28: RECOVERY recovery cycles (0 = 1, 1 = 2 etc) this is the time the
+ * memory continues to drive the data bus after OE is de-asserted.
+ * Inserted when reading one CS and switching to another CS or read
+ * followed by write on the same CS. Valid values 0 thru 15.
+ * Bits 27-24: WR_HOLD write hold cycles, these are extra cycles inserted after
+ * every write minimum 1. The data out is driven from the time WE is
+ * asserted until CS is asserted. With a hold of 1, the CS stays
+ * active for 1 extra cycle etc. Valid values 0 thru 15.
+ * Bits 23-16: WR_DELTA initial latency for write cycles inserted for the first
+ * write to a page or burst memory
+ * Bits 15-8: RD_DELTA initial latency for read cycles inserted for the first
+ * read to a page or burst memory
+ * Bits 7-4: WR_WAIT number of wait cycles for every write access, 0=1 cycle
+ * so 1 thru 16 cycles.
+ * Bits 3-0: RD_WAIT number of wait cycles for every read access, 0=1 cycle
+ * so 1 thru 16 cycles.
+ */
+#define EBI2_XMEM_CS0_SLOW_CFG 0x0008
+#define EBI2_XMEM_CS1_SLOW_CFG 0x000C
+#define EBI2_XMEM_CS2_SLOW_CFG 0x0010
+#define EBI2_XMEM_CS3_SLOW_CFG 0x0014
+#define EBI2_XMEM_CS4_SLOW_CFG 0x0018
+#define EBI2_XMEM_CS5_SLOW_CFG 0x001C
+
+#define EBI2_XMEM_RECOVERY_SHIFT 28
+#define EBI2_XMEM_WR_HOLD_SHIFT 24
+#define EBI2_XMEM_WR_DELTA_SHIFT 16
+#define EBI2_XMEM_RD_DELTA_SHIFT 8
+#define EBI2_XMEM_WR_WAIT_SHIFT 4
+#define EBI2_XMEM_RD_WAIT_SHIFT 0
+
+/*
+ * FAST CSn CFG
+ * Bits 31-28: ?
+ * Bits 27-24: RD_HOLD: the length in cycles of the first segment of a read
+ * transfer. For a single read trandfer this will be the time
+ * from CS assertion to OE assertion.
+ * Bits 18-24: ?
+ * Bits 17-16: ADV_OE_RECOVERY, the number of cycles elapsed before an OE
+ * assertion, with respect to the cycle where ADV is asserted.
+ * 2 means 2 cycles between ADV and OE. Values 0, 1, 2 or 3.
+ * Bits 5: ADDR_HOLD_ENA, The address is held for an extra cycle to meet
+ * hold time requirements with ADV assertion.
+ *
+ * The manual mentions "write precharge cycles" and "precharge cycles".
+ * We have not been able to figure out which bit fields these correspond to
+ * in the hardware, or what valid values exist. The current hypothesis is that
+ * this is something just used on the FAST chip selects. There is also a "byte
+ * device enable" flag somewhere for 8bit memories.
+ */
+#define EBI2_XMEM_CS0_FAST_CFG 0x0028
+#define EBI2_XMEM_CS1_FAST_CFG 0x002C
+#define EBI2_XMEM_CS2_FAST_CFG 0x0030
+#define EBI2_XMEM_CS3_FAST_CFG 0x0034
+#define EBI2_XMEM_CS4_FAST_CFG 0x0038
+#define EBI2_XMEM_CS5_FAST_CFG 0x003C
+
+#define EBI2_XMEM_RD_HOLD_SHIFT 24
+#define EBI2_XMEM_ADV_OE_RECOVERY_SHIFT 16
+#define EBI2_XMEM_ADDR_HOLD_ENA_SHIFT 5
+
+/**
+ * struct cs_data - struct with info on a chipselect setting
+ * @enable_mask: mask to enable the chipselect in the EBI2 config
+ * @slow_cfg0: offset to XMEMC slow CS config
+ * @fast_cfg1: offset to XMEMC fast CS config
+ */
+struct cs_data {
+ u32 enable_mask;
+ u16 slow_cfg;
+ u16 fast_cfg;
+};
+
+static const struct cs_data cs_info[] = {
+ {
+ /* CS0 */
+ .enable_mask = EBI2_CS0_ENABLE_MASK,
+ .slow_cfg = EBI2_XMEM_CS0_SLOW_CFG,
+ .fast_cfg = EBI2_XMEM_CS0_FAST_CFG,
+ },
+ {
+ /* CS1 */
+ .enable_mask = EBI2_CS1_ENABLE_MASK,
+ .slow_cfg = EBI2_XMEM_CS1_SLOW_CFG,
+ .fast_cfg = EBI2_XMEM_CS1_FAST_CFG,
+ },
+ {
+ /* CS2 */
+ .enable_mask = EBI2_CS2_ENABLE_MASK,
+ .slow_cfg = EBI2_XMEM_CS2_SLOW_CFG,
+ .fast_cfg = EBI2_XMEM_CS2_FAST_CFG,
+ },
+ {
+ /* CS3 */
+ .enable_mask = EBI2_CS3_ENABLE_MASK,
+ .slow_cfg = EBI2_XMEM_CS3_SLOW_CFG,
+ .fast_cfg = EBI2_XMEM_CS3_FAST_CFG,
+ },
+ {
+ /* CS4 */
+ .enable_mask = EBI2_CS4_ENABLE_MASK,
+ .slow_cfg = EBI2_XMEM_CS4_SLOW_CFG,
+ .fast_cfg = EBI2_XMEM_CS4_FAST_CFG,
+ },
+ {
+ /* CS5 */
+ .enable_mask = EBI2_CS5_ENABLE_MASK,
+ .slow_cfg = EBI2_XMEM_CS5_SLOW_CFG,
+ .fast_cfg = EBI2_XMEM_CS5_FAST_CFG,
+ },
+};
+
+/**
+ * struct ebi2_xmem_prop - describes an XMEM config property
+ * @prop: the device tree binding name
+ * @max: maximum value for the property
+ * @slowreg: true if this property is in the SLOW CS config register
+ * else it is assumed to be in the FAST config register
+ * @shift: the bit field start in the SLOW or FAST register for this
+ * property
+ */
+struct ebi2_xmem_prop {
+ const char *prop;
+ u32 max;
+ bool slowreg;
+ u16 shift;
+};
+
+static const struct ebi2_xmem_prop xmem_props[] = {
+ {
+ .prop = "qcom,xmem-recovery-cycles",
+ .max = 15,
+ .slowreg = true,
+ .shift = EBI2_XMEM_RECOVERY_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-write-hold-cycles",
+ .max = 15,
+ .slowreg = true,
+ .shift = EBI2_XMEM_WR_HOLD_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-write-delta-cycles",
+ .max = 255,
+ .slowreg = true,
+ .shift = EBI2_XMEM_WR_DELTA_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-read-delta-cycles",
+ .max = 255,
+ .slowreg = true,
+ .shift = EBI2_XMEM_RD_DELTA_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-write-wait-cycles",
+ .max = 15,
+ .slowreg = true,
+ .shift = EBI2_XMEM_WR_WAIT_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-read-wait-cycles",
+ .max = 15,
+ .slowreg = true,
+ .shift = EBI2_XMEM_RD_WAIT_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-address-hold-enable",
+ .max = 1, /* boolean prop */
+ .slowreg = false,
+ .shift = EBI2_XMEM_ADDR_HOLD_ENA_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-adv-to-oe-recovery-cycles",
+ .max = 3,
+ .slowreg = false,
+ .shift = EBI2_XMEM_ADV_OE_RECOVERY_SHIFT,
+ },
+ {
+ .prop = "qcom,xmem-read-hold-cycles",
+ .max = 15,
+ .slowreg = false,
+ .shift = EBI2_XMEM_RD_HOLD_SHIFT,
+ },
+};
+
+static void qcom_ebi2_setup_chipselect(struct device_node *np,
+ struct device *dev,
+ void __iomem *ebi2_base,
+ void __iomem *ebi2_xmem,
+ u32 csindex)
+{
+ const struct cs_data *csd;
+ u32 slowcfg, fastcfg;
+ u32 val;
+ int ret;
+ int i;
+
+ csd = &cs_info[csindex];
+ val = readl(ebi2_base);
+ val |= csd->enable_mask;
+ writel(val, ebi2_base);
+ dev_dbg(dev, "enabled CS%u\n", csindex);
+
+ /* Next set up the XMEMC */
+ slowcfg = 0;
+ fastcfg = 0;
+
+ for (i = 0; i < ARRAY_SIZE(xmem_props); i++) {
+ const struct ebi2_xmem_prop *xp = &xmem_props[i];
+
+ /* All are regular u32 values */
+ ret = of_property_read_u32(np, xp->prop, &val);
+ if (ret) {
+ dev_dbg(dev, "could not read %s for CS%d\n",
+ xp->prop, csindex);
+ continue;
+ }
+
+ /* First check boolean props */
+ if (xp->max == 1 && val) {
+ if (xp->slowreg)
+ slowcfg |= BIT(xp->shift);
+ else
+ fastcfg |= BIT(xp->shift);
+ dev_dbg(dev, "set %s flag\n", xp->prop);
+ continue;
+ }
+
+ /* We're dealing with an u32 */
+ if (val > xp->max) {
+ dev_err(dev,
+ "too high value for %s: %u, capped at %u\n",
+ xp->prop, val, xp->max);
+ val = xp->max;
+ }
+ if (xp->slowreg)
+ slowcfg |= (val << xp->shift);
+ else
+ fastcfg |= (val << xp->shift);
+ dev_dbg(dev, "set %s to %u\n", xp->prop, val);
+ }
+
+ dev_info(dev, "CS%u: SLOW CFG 0x%08x, FAST CFG 0x%08x\n",
+ csindex, slowcfg, fastcfg);
+
+ if (slowcfg)
+ writel(slowcfg, ebi2_xmem + csd->slow_cfg);
+ if (fastcfg)
+ writel(fastcfg, ebi2_xmem + csd->fast_cfg);
+}
+
+static int qcom_ebi2_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ void __iomem *ebi2_base;
+ void __iomem *ebi2_xmem;
+ struct clk *ebi2xclk;
+ struct clk *ebi2clk;
+ bool have_children = false;
+ u32 val;
+ int ret;
+
+ ebi2xclk = devm_clk_get(dev, "ebi2x");
+ if (IS_ERR(ebi2xclk))
+ return PTR_ERR(ebi2xclk);
+
+ ret = clk_prepare_enable(ebi2xclk);
+ if (ret) {
+ dev_err(dev, "could not enable EBI2X clk (%d)\n", ret);
+ return ret;
+ }
+
+ ebi2clk = devm_clk_get(dev, "ebi2");
+ if (IS_ERR(ebi2clk)) {
+ ret = PTR_ERR(ebi2clk);
+ goto err_disable_2x_clk;
+ }
+
+ ret = clk_prepare_enable(ebi2clk);
+ if (ret) {
+ dev_err(dev, "could not enable EBI2 clk\n");
+ goto err_disable_2x_clk;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ebi2_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ebi2_base)) {
+ ret = PTR_ERR(ebi2_base);
+ goto err_disable_clk;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ebi2_xmem = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ebi2_xmem)) {
+ ret = PTR_ERR(ebi2_xmem);
+ goto err_disable_clk;
+ }
+
+ /* Allegedly this turns the power save mode off */
+ writel(0UL, ebi2_xmem + EBI2_XMEM_CFG);
+
+ /* Disable all chipselects */
+ val = readl(ebi2_base);
+ val &= ~EBI2_CSN_MASK;
+ writel(val, ebi2_base);
+
+ /* Walk over the child nodes and see what chipselects we use */
+ for_each_available_child_of_node(np, child) {
+ u32 csindex;
+
+ /* Figure out the chipselect */
+ ret = of_property_read_u32(child, "reg", &csindex);
+ if (ret)
+ return ret;
+
+ if (csindex > 5) {
+ dev_err(dev,
+ "invalid chipselect %u, we only support 0-5\n",
+ csindex);
+ continue;
+ }
+
+ qcom_ebi2_setup_chipselect(child,
+ dev,
+ ebi2_base,
+ ebi2_xmem,
+ csindex);
+
+ /* We have at least one child */
+ have_children = true;
+ }
+
+ if (have_children)
+ return of_platform_default_populate(np, NULL, dev);
+ return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(ebi2clk);
+err_disable_2x_clk:
+ clk_disable_unprepare(ebi2xclk);
+
+ return ret;
+}
+
+static const struct of_device_id qcom_ebi2_of_match[] = {
+ { .compatible = "qcom,msm8660-ebi2", },
+ { .compatible = "qcom,apq8060-ebi2", },
+ { }
+};
+
+static struct platform_driver qcom_ebi2_driver = {
+ .probe = qcom_ebi2_probe,
+ .driver = {
+ .name = "qcom-ebi2",
+ .of_match_table = qcom_ebi2_of_match,
+ },
+};
+module_platform_driver(qcom_ebi2_driver);
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm EBI2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c
index 7e4104b74fa8..084ae286fa23 100644
--- a/drivers/bus/tegra-aconnect.c
+++ b/drivers/bus/tegra-aconnect.c
@@ -15,24 +15,6 @@
#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
-static int tegra_aconnect_add_clock(struct device *dev, char *name)
-{
- struct clk *clk;
- int ret;
-
- clk = clk_get(dev, name);
- if (IS_ERR(clk)) {
- dev_err(dev, "%s clock not found\n", name);
- return PTR_ERR(clk);
- }
-
- ret = pm_clk_add_clk(dev, clk);
- if (ret)
- clk_put(clk);
-
- return ret;
-}
-
static int tegra_aconnect_probe(struct platform_device *pdev)
{
int ret;
@@ -44,11 +26,11 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = tegra_aconnect_add_clock(&pdev->dev, "ape");
+ ret = of_pm_clk_add_clk(&pdev->dev, "ape");
if (ret)
goto clk_destroy;
- ret = tegra_aconnect_add_clock(&pdev->dev, "apb2ape");
+ ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape");
if (ret)
goto clk_destroy;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 8c0770bf8881..200dab5136a7 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -410,6 +410,19 @@ config HW_RANDOM_MESON
If unsure, say Y.
+config HW_RANDOM_CAVIUM
+ tristate "Cavium ThunderX Random Number Generator support"
+ depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT))
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Cavium SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cavium_rng.
+
+ If unsure, say Y.
+
endif # HW_RANDOM
config UML_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 04bb0b03356f..5f52b1e4e7be 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -35,3 +35,4 @@ obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o
obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o
+obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 48f6a83cdd61..4a99ac756f08 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -24,16 +24,18 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/hw_random.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/hw_random.h>
-#include <linux/delay.h>
-#include <asm/io.h>
+#define DRV_NAME "AMD768-HWRNG"
-#define PFX KBUILD_MODNAME ": "
-
+#define RNGDATA 0x00
+#define RNGDONE 0x04
+#define PMBASE_OFFSET 0xF0
+#define PMBASE_SIZE 8
/*
* Data for PCI driver interface
@@ -50,72 +52,84 @@ static const struct pci_device_id pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
-static struct pci_dev *amd_pdev;
-
+struct amd768_priv {
+ void __iomem *iobase;
+ struct pci_dev *pcidev;
+};
-static int amd_rng_data_present(struct hwrng *rng, int wait)
+static int amd_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
- u32 pmbase = (u32)rng->priv;
- int data, i;
-
- for (i = 0; i < 20; i++) {
- data = !!(inl(pmbase + 0xF4) & 1);
- if (data || !wait)
- break;
- udelay(10);
+ u32 *data = buf;
+ struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
+ size_t read = 0;
+ /* We will wait at maximum one time per read */
+ int timeout = max / 4 + 1;
+
+ /*
+ * RNG data is available when RNGDONE is set to 1
+ * New random numbers are generated approximately 128 microseconds
+ * after RNGDATA is read
+ */
+ while (read < max) {
+ if (ioread32(priv->iobase + RNGDONE) == 0) {
+ if (wait) {
+ /* Delay given by datasheet */
+ usleep_range(128, 196);
+ if (timeout-- == 0)
+ return read;
+ } else {
+ return 0;
+ }
+ } else {
+ *data = ioread32(priv->iobase + RNGDATA);
+ data++;
+ read += 4;
+ }
}
- return data;
-}
-static int amd_rng_data_read(struct hwrng *rng, u32 *data)
-{
- u32 pmbase = (u32)rng->priv;
-
- *data = inl(pmbase + 0xF0);
-
- return 4;
+ return read;
}
static int amd_rng_init(struct hwrng *rng)
{
+ struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
u8 rnen;
- pci_read_config_byte(amd_pdev, 0x40, &rnen);
- rnen |= (1 << 7); /* RNG on */
- pci_write_config_byte(amd_pdev, 0x40, rnen);
+ pci_read_config_byte(priv->pcidev, 0x40, &rnen);
+ rnen |= BIT(7); /* RNG on */
+ pci_write_config_byte(priv->pcidev, 0x40, rnen);
- pci_read_config_byte(amd_pdev, 0x41, &rnen);
- rnen |= (1 << 7); /* PMIO enable */
- pci_write_config_byte(amd_pdev, 0x41, rnen);
+ pci_read_config_byte(priv->pcidev, 0x41, &rnen);
+ rnen |= BIT(7); /* PMIO enable */
+ pci_write_config_byte(priv->pcidev, 0x41, rnen);
return 0;
}
static void amd_rng_cleanup(struct hwrng *rng)
{
+ struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
u8 rnen;
- pci_read_config_byte(amd_pdev, 0x40, &rnen);
- rnen &= ~(1 << 7); /* RNG off */
- pci_write_config_byte(amd_pdev, 0x40, rnen);
+ pci_read_config_byte(priv->pcidev, 0x40, &rnen);
+ rnen &= ~BIT(7); /* RNG off */
+ pci_write_config_byte(priv->pcidev, 0x40, rnen);
}
-
static struct hwrng amd_rng = {
.name = "amd",
.init = amd_rng_init,
.cleanup = amd_rng_cleanup,
- .data_present = amd_rng_data_present,
- .data_read = amd_rng_data_read,
+ .read = amd_rng_read,
};
-
static int __init mod_init(void)
{
int err = -ENODEV;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;
u32 pmbase;
+ struct amd768_priv *priv;
for_each_pci_dev(pdev) {
ent = pci_match_id(pci_tbl, pdev);
@@ -123,42 +137,44 @@ static int __init mod_init(void)
goto found;
}
/* Device not found. */
- goto out;
+ return -ENODEV;
found:
err = pci_read_config_dword(pdev, 0x58, &pmbase);
if (err)
- goto out;
- err = -EIO;
+ return err;
+
pmbase &= 0x0000FF00;
if (pmbase == 0)
- goto out;
- if (!request_region(pmbase + 0xF0, 8, "AMD HWRNG")) {
- dev_err(&pdev->dev, "AMD HWRNG region 0x%x already in use!\n",
+ return -EIO;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (!devm_request_region(&pdev->dev, pmbase + PMBASE_OFFSET,
+ PMBASE_SIZE, DRV_NAME)) {
+ dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
pmbase + 0xF0);
- err = -EBUSY;
- goto out;
+ return -EBUSY;
}
- amd_rng.priv = (unsigned long)pmbase;
- amd_pdev = pdev;
-
- pr_info("AMD768 RNG detected\n");
- err = hwrng_register(&amd_rng);
- if (err) {
- pr_err(PFX "RNG registering failed (%d)\n",
- err);
- release_region(pmbase + 0xF0, 8);
- goto out;
+
+ priv->iobase = devm_ioport_map(&pdev->dev, pmbase + PMBASE_OFFSET,
+ PMBASE_SIZE);
+ if (!priv->iobase) {
+ pr_err(DRV_NAME "Cannot map ioport\n");
+ return -ENOMEM;
}
-out:
- return err;
+
+ amd_rng.priv = (unsigned long)priv;
+ priv->pcidev = pdev;
+
+ pr_info(DRV_NAME " detected\n");
+ return devm_hwrng_register(&pdev->dev, &amd_rng);
}
static void __exit mod_exit(void)
{
- u32 pmbase = (unsigned long)amd_rng.priv;
- release_region(pmbase + 0xF0, 8);
- hwrng_unregister(&amd_rng);
}
module_init(mod_init);
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index af2149273fe0..574211a49549 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -92,9 +92,10 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
bcm2835_rng_ops.priv = (unsigned long)rng_base;
rng_id = of_match_node(bcm2835_rng_of_match, np);
- if (!rng_id)
+ if (!rng_id) {
+ iounmap(rng_base);
return -EINVAL;
-
+ }
/* Check for rng init function, execute it */
rng_setup = rng_id->data;
if (rng_setup)
diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c
new file mode 100644
index 000000000000..066ae0e78d63
--- /dev/null
+++ b/drivers/char/hw_random/cavium-rng-vf.c
@@ -0,0 +1,99 @@
+/*
+ * Hardware Random Number Generator support for Cavium, Inc.
+ * Thunder processor family.
+ *
+ * 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) 2016 Cavium, Inc.
+ */
+
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+struct cavium_rng {
+ struct hwrng ops;
+ void __iomem *result;
+};
+
+/* Read data from the RNG unit */
+static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait)
+{
+ struct cavium_rng *p = container_of(rng, struct cavium_rng, ops);
+ unsigned int size = max;
+
+ while (size >= 8) {
+ *((u64 *)dat) = readq(p->result);
+ size -= 8;
+ dat += 8;
+ }
+ while (size > 0) {
+ *((u8 *)dat) = readb(p->result);
+ size--;
+ dat++;
+ }
+ return max;
+}
+
+/* Map Cavium RNG to an HWRNG object */
+static int cavium_rng_probe_vf(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct cavium_rng *rng;
+ int ret;
+
+ rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
+ if (!rng)
+ return -ENOMEM;
+
+ /* Map the RNG result */
+ rng->result = pcim_iomap(pdev, 0, 0);
+ if (!rng->result) {
+ dev_err(&pdev->dev, "Error iomap failed retrieving result.\n");
+ return -ENOMEM;
+ }
+
+ rng->ops.name = "cavium rng";
+ rng->ops.read = cavium_rng_read;
+ rng->ops.quality = 1000;
+
+ pci_set_drvdata(pdev, rng);
+
+ ret = hwrng_register(&rng->ops);
+ if (ret) {
+ dev_err(&pdev->dev, "Error registering device as HWRNG.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Remove the VF */
+void cavium_rng_remove_vf(struct pci_dev *pdev)
+{
+ struct cavium_rng *rng;
+
+ rng = pci_get_drvdata(pdev);
+ hwrng_unregister(&rng->ops);
+}
+
+static const struct pci_device_id cavium_rng_vf_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0},
+ {0,},
+};
+MODULE_DEVICE_TABLE(pci, cavium_rng_vf_id_table);
+
+static struct pci_driver cavium_rng_vf_driver = {
+ .name = "cavium_rng_vf",
+ .id_table = cavium_rng_vf_id_table,
+ .probe = cavium_rng_probe_vf,
+ .remove = cavium_rng_remove_vf,
+};
+module_pci_driver(cavium_rng_vf_driver);
+
+MODULE_AUTHOR("Omer Khaliq <okhaliq@caviumnetworks.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/cavium-rng.c
new file mode 100644
index 000000000000..a944e0a47f42
--- /dev/null
+++ b/drivers/char/hw_random/cavium-rng.c
@@ -0,0 +1,94 @@
+/*
+ * Hardware Random Number Generator support for Cavium Inc.
+ * Thunder processor family.
+ *
+ * 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) 2016 Cavium, Inc.
+ */
+
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#define THUNDERX_RNM_ENT_EN 0x1
+#define THUNDERX_RNM_RNG_EN 0x2
+
+struct cavium_rng_pf {
+ void __iomem *control_status;
+};
+
+/* Enable the RNG hardware and activate the VF */
+static int cavium_rng_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct cavium_rng_pf *rng;
+ int iov_err;
+
+ rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
+ if (!rng)
+ return -ENOMEM;
+
+ /*Map the RNG control */
+ rng->control_status = pcim_iomap(pdev, 0, 0);
+ if (!rng->control_status) {
+ dev_err(&pdev->dev,
+ "Error iomap failed retrieving control_status.\n");
+ return -ENOMEM;
+ }
+
+ /* Enable the RNG hardware and entropy source */
+ writeq(THUNDERX_RNM_RNG_EN | THUNDERX_RNM_ENT_EN,
+ rng->control_status);
+
+ pci_set_drvdata(pdev, rng);
+
+ /* Enable the Cavium RNG as a VF */
+ iov_err = pci_enable_sriov(pdev, 1);
+ if (iov_err != 0) {
+ /* Disable the RNG hardware and entropy source */
+ writeq(0, rng->control_status);
+ dev_err(&pdev->dev,
+ "Error initializing RNG virtual function,(%i).\n",
+ iov_err);
+ return iov_err;
+ }
+
+ return 0;
+}
+
+/* Disable VF and RNG Hardware */
+void cavium_rng_remove(struct pci_dev *pdev)
+{
+ struct cavium_rng_pf *rng;
+
+ rng = pci_get_drvdata(pdev);
+
+ /* Remove the VF */
+ pci_disable_sriov(pdev);
+
+ /* Disable the RNG hardware and entropy source */
+ writeq(0, rng->control_status);
+}
+
+static const struct pci_device_id cavium_rng_pf_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa018), 0, 0, 0}, /* Thunder RNM */
+ {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, cavium_rng_pf_id_table);
+
+static struct pci_driver cavium_rng_pf_driver = {
+ .name = "cavium_rng_pf",
+ .id_table = cavium_rng_pf_id_table,
+ .probe = cavium_rng_probe,
+ .remove = cavium_rng_remove,
+};
+
+module_pci_driver(cavium_rng_pf_driver);
+MODULE_AUTHOR("Omer Khaliq <okhaliq@caviumnetworks.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 9203f2d130c0..482794526e8c 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -449,22 +449,6 @@ int hwrng_register(struct hwrng *rng)
goto out;
mutex_lock(&rng_mutex);
-
- /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */
- err = -ENOMEM;
- if (!rng_buffer) {
- rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL);
- if (!rng_buffer)
- goto out_unlock;
- }
- if (!rng_fillbuf) {
- rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL);
- if (!rng_fillbuf) {
- kfree(rng_buffer);
- goto out_unlock;
- }
- }
-
/* Must not register two RNGs with the same name. */
err = -EEXIST;
list_for_each_entry(tmp, &rng_list, list) {
@@ -573,7 +557,26 @@ EXPORT_SYMBOL_GPL(devm_hwrng_unregister);
static int __init hwrng_modinit(void)
{
- return register_miscdev();
+ int ret = -ENOMEM;
+
+ /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */
+ rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL);
+ if (!rng_buffer)
+ return -ENOMEM;
+
+ rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL);
+ if (!rng_fillbuf) {
+ kfree(rng_buffer);
+ return -ENOMEM;
+ }
+
+ ret = register_miscdev();
+ if (ret) {
+ kfree(rng_fillbuf);
+ kfree(rng_buffer);
+ }
+
+ return ret;
}
static void __exit hwrng_modexit(void)
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index 0d0579fe465e..e7a245942029 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -24,15 +24,12 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/hw_random.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-
-#define PFX KBUILD_MODNAME ": "
#define GEODE_RNG_DATA_REG 0x50
#define GEODE_RNG_STATUS_REG 0x54
@@ -85,7 +82,6 @@ static struct hwrng geode_rng = {
static int __init mod_init(void)
{
- int err = -ENODEV;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;
void __iomem *mem;
@@ -93,43 +89,27 @@ static int __init mod_init(void)
for_each_pci_dev(pdev) {
ent = pci_match_id(pci_tbl, pdev);
- if (ent)
- goto found;
- }
- /* Device not found. */
- goto out;
-
-found:
- rng_base = pci_resource_start(pdev, 0);
- if (rng_base == 0)
- goto out;
- err = -ENOMEM;
- mem = ioremap(rng_base, 0x58);
- if (!mem)
- goto out;
- geode_rng.priv = (unsigned long)mem;
-
- pr_info("AMD Geode RNG detected\n");
- err = hwrng_register(&geode_rng);
- if (err) {
- pr_err(PFX "RNG registering failed (%d)\n",
- err);
- goto err_unmap;
+ if (ent) {
+ rng_base = pci_resource_start(pdev, 0);
+ if (rng_base == 0)
+ return -ENODEV;
+
+ mem = devm_ioremap(&pdev->dev, rng_base, 0x58);
+ if (!mem)
+ return -ENOMEM;
+ geode_rng.priv = (unsigned long)mem;
+
+ pr_info("AMD Geode RNG detected\n");
+ return devm_hwrng_register(&pdev->dev, &geode_rng);
+ }
}
-out:
- return err;
-err_unmap:
- iounmap(mem);
- goto out;
+ /* Device not found. */
+ return -ENODEV;
}
static void __exit mod_exit(void)
{
- void __iomem *mem = (void __iomem *)geode_rng.priv;
-
- hwrng_unregister(&geode_rng);
- iounmap(mem);
}
module_init(mod_init);
diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c
index 0cfd81bcaeac..58bef39f7286 100644
--- a/drivers/char/hw_random/meson-rng.c
+++ b/drivers/char/hw_random/meson-rng.c
@@ -76,9 +76,6 @@ static int meson_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
struct meson_rng_data *data =
container_of(rng, struct meson_rng_data, rng);
- if (max < sizeof(u32))
- return 0;
-
*(u32 *)buf = readl_relaxed(data->base + RNG_DATA);
return sizeof(u32);
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 01d4be2c354b..f5c26a5f6875 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -385,7 +385,7 @@ static int omap_rng_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
- if (ret) {
+ if (ret < 0) {
dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);
pm_runtime_put_noidle(&pdev->dev);
goto err_ioremap;
@@ -443,7 +443,7 @@ static int __maybe_unused omap_rng_resume(struct device *dev)
int ret;
ret = pm_runtime_get_sync(dev);
- if (ret) {
+ if (ret < 0) {
dev_err(dev, "Failed to runtime_get device: %d\n", ret);
pm_runtime_put_noidle(dev);
return ret;
diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c
index 8da14f1a1f56..37a58d78aab3 100644
--- a/drivers/char/hw_random/omap3-rom-rng.c
+++ b/drivers/char/hw_random/omap3-rom-rng.c
@@ -71,12 +71,7 @@ static int omap3_rom_rng_get_random(void *buf, unsigned int count)
return 0;
}
-static int omap3_rom_rng_data_present(struct hwrng *rng, int wait)
-{
- return 1;
-}
-
-static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data)
+static int omap3_rom_rng_read(struct hwrng *rng, void *data, size_t max, bool w)
{
int r;
@@ -88,8 +83,7 @@ static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data)
static struct hwrng omap3_rom_rng_ops = {
.name = "omap3-rom",
- .data_present = omap3_rom_rng_data_present,
- .data_read = omap3_rom_rng_data_read,
+ .read = omap3_rom_rng_read,
};
static int omap3_rom_rng_probe(struct platform_device *pdev)
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index 699b7259f5d7..545df485bcc4 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -26,7 +26,7 @@
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <asm/io.h>
+#include <linux/io.h>
#define SDCRNG_CTL_REG 0x00
#define SDCRNG_CTL_FVLD_M 0x0000f000
@@ -95,42 +95,20 @@ static struct hwrng pasemi_rng = {
.data_read = pasemi_rng_data_read,
};
-static int rng_probe(struct platform_device *ofdev)
+static int rng_probe(struct platform_device *pdev)
{
void __iomem *rng_regs;
- struct device_node *rng_np = ofdev->dev.of_node;
- struct resource res;
- int err = 0;
+ struct resource *res;
- err = of_address_to_resource(rng_np, 0, &res);
- if (err)
- return -ENODEV;
-
- rng_regs = ioremap(res.start, 0x100);
-
- if (!rng_regs)
- return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rng_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rng_regs))
+ return PTR_ERR(rng_regs);
pasemi_rng.priv = (unsigned long)rng_regs;
pr_info("Registering PA Semi RNG\n");
-
- err = hwrng_register(&pasemi_rng);
-
- if (err)
- iounmap(rng_regs);
-
- return err;
-}
-
-static int rng_remove(struct platform_device *dev)
-{
- void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
-
- hwrng_unregister(&pasemi_rng);
- iounmap(rng_regs);
-
- return 0;
+ return devm_hwrng_register(&pdev->dev, &pasemi_rng);
}
static const struct of_device_id rng_match[] = {
@@ -146,7 +124,6 @@ static struct platform_driver rng_driver = {
.of_match_table = rng_match,
},
.probe = rng_probe,
- .remove = rng_remove,
};
module_platform_driver(rng_driver);
diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c
index 108897bea2d0..11dc9b7c09ce 100644
--- a/drivers/char/hw_random/pic32-rng.c
+++ b/drivers/char/hw_random/pic32-rng.c
@@ -143,7 +143,6 @@ static struct platform_driver pic32_rng_driver = {
.remove = pic32_rng_remove,
.driver = {
.name = "pic32-rng",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(pic32_rng_of_match),
},
};
diff --git a/drivers/char/hw_random/st-rng.c b/drivers/char/hw_random/st-rng.c
index 1d35363d23c5..938ec10e733d 100644
--- a/drivers/char/hw_random/st-rng.c
+++ b/drivers/char/hw_random/st-rng.c
@@ -54,9 +54,6 @@ static int st_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
u32 status;
int i;
- if (max < sizeof(u16))
- return -EINVAL;
-
/* Wait until FIFO is full - max 4uS*/
for (i = 0; i < ST_RNG_FILL_FIFO_TIMEOUT; i++) {
status = readl_relaxed(ddata->base + ST_RNG_STATUS_REG);
@@ -111,6 +108,7 @@ static int st_rng_probe(struct platform_device *pdev)
ret = hwrng_register(&ddata->ops);
if (ret) {
dev_err(&pdev->dev, "Failed to register HW RNG\n");
+ clk_disable_unprepare(clk);
return ret;
}
diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c
index a7b694913416..1093583b579c 100644
--- a/drivers/char/hw_random/tx4939-rng.c
+++ b/drivers/char/hw_random/tx4939-rng.c
@@ -144,22 +144,13 @@ static int __init tx4939_rng_probe(struct platform_device *dev)
}
platform_set_drvdata(dev, rngdev);
- return hwrng_register(&rngdev->rng);
-}
-
-static int __exit tx4939_rng_remove(struct platform_device *dev)
-{
- struct tx4939_rng *rngdev = platform_get_drvdata(dev);
-
- hwrng_unregister(&rngdev->rng);
- return 0;
+ return devm_hwrng_register(&dev->dev, &rngdev->rng);
}
static struct platform_driver tx4939_rng_driver = {
.driver = {
.name = "tx4939-rng",
},
- .remove = tx4939_rng_remove,
};
module_platform_driver_probe(tx4939_rng_driver, tx4939_rng_probe);
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index e496daefe9e0..719c5b4eed39 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -934,7 +934,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
if (ret > 0) {
struct inode *inode = file_inode(file);
- inode->i_atime = current_fs_time(inode->i_sb);
+ inode->i_atime = current_time(inode);
}
return ret;
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 5da47e26a012..8114744bf30c 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -889,7 +889,7 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
return 0;
/* Try lock this page */
- if (buf->ops->steal(pipe, buf) == 0) {
+ if (pipe_buf_steal(pipe, buf) == 0) {
/* Get reference and unlock page for moving */
get_page(buf->page);
unlock_page(buf->page);
diff --git a/drivers/clk/imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c
index 99cf802fa51f..eaa462ad09e8 100644
--- a/drivers/clk/imx/clk-imx1.c
+++ b/drivers/clk/imx/clk-imx1.c
@@ -45,10 +45,13 @@ static void __iomem *ccm __initdata;
#define CCM_PCDR (ccm + 0x0020)
#define SCM_GCCR (ccm + 0x0810)
-static void __init _mx1_clocks_init(unsigned long fref)
+static void __init mx1_clocks_init_dt(struct device_node *np)
{
+ ccm = of_iomap(np, 0);
+ BUG_ON(!ccm);
+
clk[IMX1_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
- clk[IMX1_CLK_CLK32] = imx_obtain_fixed_clock("clk32", fref);
+ clk[IMX1_CLK_CLK32] = imx_obtain_fixed_clock("clk32", 32768);
clk[IMX1_CLK_CLK16M_EXT] = imx_clk_fixed("clk16m_ext", 16000000);
clk[IMX1_CLK_CLK16M] = imx_clk_gate("clk16m", "clk16m_ext", CCM_CSCR, 17);
clk[IMX1_CLK_CLK32_PREMULT] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1);
@@ -74,45 +77,6 @@ static void __init _mx1_clocks_init(unsigned long fref)
clk[IMX1_CLK_USBD_GATE] = imx_clk_gate("usbd_gate", "clk48m", SCM_GCCR, 0);
imx_check_clocks(clk, ARRAY_SIZE(clk));
-}
-
-int __init mx1_clocks_init(unsigned long fref)
-{
- ccm = ioremap(MX1_CCM_BASE_ADDR, SZ_4K);
- BUG_ON(!ccm);
-
- _mx1_clocks_init(fref);
-
- clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx-gpt.0");
- clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx-gpt.0");
- clk_register_clkdev(clk[IMX1_CLK_DMA_GATE], "ahb", "imx1-dma");
- clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx1-dma");
- clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx1-uart.0");
- clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx1-uart.0");
- clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx1-uart.1");
- clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx1-uart.1");
- clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx1-uart.2");
- clk_register_clkdev(clk[IMX1_CLK_UART3_GATE], "ipg", "imx1-uart.2");
- clk_register_clkdev(clk[IMX1_CLK_HCLK], NULL, "imx1-i2c.0");
- clk_register_clkdev(clk[IMX1_CLK_PER2], "per", "imx1-cspi.0");
- clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-cspi.0");
- clk_register_clkdev(clk[IMX1_CLK_PER2], "per", "imx1-cspi.1");
- clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-cspi.1");
- clk_register_clkdev(clk[IMX1_CLK_PER2], "per", "imx1-fb.0");
- clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-fb.0");
- clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ahb", "imx1-fb.0");
-
- mxc_timer_init(MX1_TIM1_BASE_ADDR, MX1_TIM1_INT, GPT_TYPE_IMX1);
-
- return 0;
-}
-
-static void __init mx1_clocks_init_dt(struct device_node *np)
-{
- ccm = of_iomap(np, 0);
- BUG_ON(!ccm);
-
- _mx1_clocks_init(32768);
clk_data.clks = clk;
clk_data.clk_num = ARRAY_SIZE(clk);
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index ae461b16af75..0252939ba58f 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -183,14 +183,14 @@
/* CLKID_CLK81 */
#define CLKID_MPLL0 13
#define CLKID_MPLL1 14
-#define CLKID_MPLL2 15
+/* CLKID_MPLL2 */
#define CLKID_DDR 16
#define CLKID_DOS 17
#define CLKID_ISA 18
#define CLKID_PL301 19
#define CLKID_PERIPHS 20
#define CLKID_SPICC 21
-#define CLKID_I2C 22
+/* CLKID_I2C */
#define CLKID_SAR_ADC 23
#define CLKID_SMART_CARD 24
#define CLKID_RNG0 25
@@ -202,7 +202,7 @@
#define CLKID_ABUF 31
#define CLKID_HIU_IFACE 32
#define CLKID_ASSIST_MISC 33
-#define CLKID_SPI 34
+/* CLKID_SPI */
#define CLKID_I2S_SPDIF 35
#define CLKID_ETH 36
#define CLKID_DEMUX 37
@@ -218,12 +218,12 @@
#define CLKID_AIU 47
#define CLKID_UART1 48
#define CLKID_G2D 49
-#define CLKID_USB0 50
-#define CLKID_USB1 51
+/* CLKID_USB0 */
+/* CLKID_USB1 */
#define CLKID_RESET 52
#define CLKID_NAND 53
#define CLKID_DOS_PARSER 54
-#define CLKID_USB 55
+/* CLKID_USB */
#define CLKID_VDIN1 56
#define CLKID_AHB_ARB0 57
#define CLKID_EFUSE 58
@@ -232,8 +232,8 @@
#define CLKID_AHB_CTRL_BUS 61
#define CLKID_HDMI_INTR_SYNC 62
#define CLKID_HDMI_PCLK 63
-#define CLKID_USB1_DDR_BRIDGE 64
-#define CLKID_USB0_DDR_BRIDGE 65
+/* CLKID_USB1_DDR_BRIDGE */
+/* CLKID_USB0_DDR_BRIDGE */
#define CLKID_MMC_PCLK 66
#define CLKID_DVIN 67
#define CLKID_UART2 68
@@ -261,7 +261,7 @@
#define CLKID_AO_AHB_SRAM 90
#define CLKID_AO_AHB_BUS 91
#define CLKID_AO_IFACE 92
-#define CLKID_AO_I2C 93
+/* CLKID_AO_I2C */
/* CLKID_SD_EMMC_A */
/* CLKID_SD_EMMC_B */
/* CLKID_SD_EMMC_C */
diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c
index fd129566c1ce..a6e5bee23385 100644
--- a/drivers/clk/mvebu/orion.c
+++ b/drivers/clk/mvebu/orion.c
@@ -21,6 +21,76 @@ static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
};
/*
+ * Orion 5181
+ */
+
+#define SAR_MV88F5181_TCLK_FREQ 8
+#define SAR_MV88F5181_TCLK_FREQ_MASK 0x3
+
+static u32 __init mv88f5181_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5181_TCLK_FREQ) &
+ SAR_MV88F5181_TCLK_FREQ_MASK;
+ if (opt == 0)
+ return 133333333;
+ else if (opt == 1)
+ return 150000000;
+ else if (opt == 2)
+ return 166666667;
+ else
+ return 0;
+}
+
+#define SAR_MV88F5181_CPU_FREQ 4
+#define SAR_MV88F5181_CPU_FREQ_MASK 0xf
+
+static u32 __init mv88f5181_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5181_CPU_FREQ) &
+ SAR_MV88F5181_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 mv88f5181_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5181_CPU_FREQ) &
+ SAR_MV88F5181_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 mv88f5181_coreclks = {
+ .get_tclk_freq = mv88f5181_get_tclk_freq,
+ .get_cpu_freq = mv88f5181_get_cpu_freq,
+ .get_clk_ratio = mv88f5181_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5181_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f5181_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5181_clk, "marvell,mv88f5181-core-clock", mv88f5181_clk_init);
+
+/*
* Orion 5182
*/
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 8a753fd5b79d..245190839359 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -361,7 +361,7 @@ config CLKSRC_METAG_GENERIC
config CLKSRC_EXYNOS_MCT
bool "Exynos multi core timer driver" if COMPILE_TEST
- depends on ARM
+ depends on ARM || ARM64
help
Support for Multi Core Timer controller on Exynos SoCs.
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 41840d02c331..8f3488b80896 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -223,6 +223,7 @@ static u64 notrace exynos4_read_sched_clock(void)
return exynos4_read_count_32();
}
+#if defined(CONFIG_ARM)
static struct delay_timer exynos4_delay_timer;
static cycles_t exynos4_read_current_timer(void)
@@ -231,14 +232,17 @@ static cycles_t exynos4_read_current_timer(void)
"cycles_t needs to move to 32-bit for ARM64 usage");
return exynos4_read_count_32();
}
+#endif
static int __init exynos4_clocksource_init(void)
{
exynos4_mct_frc_start();
+#if defined(CONFIG_ARM)
exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
exynos4_delay_timer.freq = clk_rate;
register_current_timer_delay(&exynos4_delay_timer);
+#endif
if (clocksource_register_hz(&mct_frc, clk_rate))
panic("%s: can't register clocksource\n", mct_frc.name);
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 389ade4572be..ab264d393233 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -14,6 +14,7 @@
#include <linux/cpuidle.h>
#include <linux/cpumask.h>
#include <linux/tick.h>
+#include <linux/cpu.h>
#include "cpuidle.h"
@@ -178,8 +179,8 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
}
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static int __cpuidle poll_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
local_irq_enable();
if (!current_set_polling_and_test()) {
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 9b035b7d7f4f..4d2b81f2b223 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -318,6 +318,9 @@ config CRYPTO_DEV_OMAP_AES
select CRYPTO_AES
select CRYPTO_BLKCIPHER
select CRYPTO_ENGINE
+ select CRYPTO_CBC
+ select CRYPTO_ECB
+ select CRYPTO_CTR
help
OMAP processors have AES module accelerator. Select this if you
want to use the OMAP module for AES algorithms.
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index b3044219772c..156aad167cd6 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -111,6 +111,42 @@
#else
#define debug(format, arg...)
#endif
+
+#ifdef DEBUG
+#include <linux/highmem.h>
+
+static void dbg_dump_sg(const char *level, const char *prefix_str,
+ int prefix_type, int rowsize, int groupsize,
+ struct scatterlist *sg, size_t tlen, bool ascii,
+ bool may_sleep)
+{
+ struct scatterlist *it;
+ void *it_page;
+ size_t len;
+ void *buf;
+
+ for (it = sg; it != NULL && tlen > 0 ; it = sg_next(sg)) {
+ /*
+ * make sure the scatterlist's page
+ * has a valid virtual memory mapping
+ */
+ it_page = kmap_atomic(sg_page(it));
+ if (unlikely(!it_page)) {
+ printk(KERN_ERR "dbg_dump_sg: kmap failed\n");
+ return;
+ }
+
+ buf = it_page + it->offset;
+ len = min(tlen, it->length);
+ print_hex_dump(level, prefix_str, prefix_type, rowsize,
+ groupsize, buf, len, ascii);
+ tlen -= len;
+
+ kunmap_atomic(it_page);
+ }
+}
+#endif
+
static struct list_head alg_list;
struct caam_alg_entry {
@@ -227,8 +263,9 @@ static void append_key_aead(u32 *desc, struct caam_ctx *ctx,
if (is_rfc3686) {
nonce = (u32 *)((void *)ctx->key + ctx->split_key_pad_len +
enckeylen);
- append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB |
- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
append_move(desc,
MOVE_SRC_OUTFIFO |
MOVE_DEST_CLASS1CTX |
@@ -500,11 +537,10 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* Load Counter into CONTEXT1 reg */
if (is_rfc3686)
- append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
- LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
+ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT |
+ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
+ LDST_OFFSET_SHIFT));
/* Class 1 operation */
append_operation(desc, ctx->class1_alg_type |
@@ -578,11 +614,10 @@ skip_enc:
/* Load Counter into CONTEXT1 reg */
if (is_rfc3686)
- append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
- LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
+ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT |
+ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
+ LDST_OFFSET_SHIFT));
/* Choose operation */
if (ctr_mode)
@@ -683,11 +718,10 @@ copy_iv:
/* Load Counter into CONTEXT1 reg */
if (is_rfc3686)
- append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
- LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
+ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT |
+ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
+ LDST_OFFSET_SHIFT));
/* Class 1 operation */
append_operation(desc, ctx->class1_alg_type |
@@ -1478,7 +1512,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
int ret = 0;
u32 *key_jump_cmd;
u32 *desc;
- u32 *nonce;
+ u8 *nonce;
u32 geniv;
u32 ctx1_iv_off = 0;
const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) ==
@@ -1531,9 +1565,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Load nonce into CONTEXT1 reg */
if (is_rfc3686) {
- nonce = (u32 *)(key + keylen);
- append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB |
- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
+ nonce = (u8 *)key + keylen;
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
append_move(desc, MOVE_WAITCOMP |
MOVE_SRC_OUTFIFO |
MOVE_DEST_CLASS1CTX |
@@ -1549,11 +1584,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Load counter into CONTEXT1 reg */
if (is_rfc3686)
- append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
- LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
+ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT |
+ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
+ LDST_OFFSET_SHIFT));
/* Load operation */
append_operation(desc, ctx->class1_alg_type |
@@ -1590,9 +1624,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Load nonce into CONTEXT1 reg */
if (is_rfc3686) {
- nonce = (u32 *)(key + keylen);
- append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB |
- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
+ nonce = (u8 *)key + keylen;
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
append_move(desc, MOVE_WAITCOMP |
MOVE_SRC_OUTFIFO |
MOVE_DEST_CLASS1CTX |
@@ -1608,11 +1643,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Load counter into CONTEXT1 reg */
if (is_rfc3686)
- append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
- LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
+ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT |
+ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
+ LDST_OFFSET_SHIFT));
/* Choose operation */
if (ctr_mode)
@@ -1653,9 +1687,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Load Nonce into CONTEXT1 reg */
if (is_rfc3686) {
- nonce = (u32 *)(key + keylen);
- append_load_imm_u32(desc, *nonce, LDST_CLASS_IND_CCB |
- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
+ nonce = (u8 *)key + keylen;
+ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
+ LDST_CLASS_IND_CCB |
+ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
append_move(desc, MOVE_WAITCOMP |
MOVE_SRC_OUTFIFO |
MOVE_DEST_CLASS1CTX |
@@ -1685,11 +1720,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
/* Load Counter into CONTEXT1 reg */
if (is_rfc3686)
- append_load_imm_u32(desc, (u32)1, LDST_IMM |
- LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
+ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT |
+ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
+ LDST_OFFSET_SHIFT));
if (ctx1_iv_off)
append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP |
@@ -1995,9 +2029,9 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->info,
edesc->src_nents > 1 ? 100 : ivsize, 1);
- print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
- edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
+ dbg_dump_sg(KERN_ERR, "dst @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
+ edesc->dst_nents > 1 ? 100 : req->nbytes, 1, true);
#endif
ablkcipher_unmap(jrdev, edesc, req);
@@ -2027,9 +2061,9 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->info,
ivsize, 1);
- print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
- edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
+ dbg_dump_sg(KERN_ERR, "dst @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
+ edesc->dst_nents > 1 ? 100 : req->nbytes, 1, true);
#endif
ablkcipher_unmap(jrdev, edesc, req);
@@ -2184,12 +2218,15 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr,
int len, sec4_sg_index = 0;
#ifdef DEBUG
+ bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP)) != 0);
print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->info,
ivsize, 1);
- print_hex_dump(KERN_ERR, "src @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
- edesc->src_nents ? 100 : req->nbytes, 1);
+ printk(KERN_ERR "asked=%d, nbytes%d\n", (int)edesc->src_nents ? 100 : req->nbytes, req->nbytes);
+ dbg_dump_sg(KERN_ERR, "src @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->src,
+ edesc->src_nents ? 100 : req->nbytes, 1, may_sleep);
#endif
len = desc_len(sh_desc);
@@ -2241,12 +2278,14 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr,
int len, sec4_sg_index = 0;
#ifdef DEBUG
+ bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP)) != 0);
print_hex_dump(KERN_ERR, "presciv@" __stringify(__LINE__) ": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->info,
ivsize, 1);
- print_hex_dump(KERN_ERR, "src @" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
- edesc->src_nents ? 100 : req->nbytes, 1);
+ dbg_dump_sg(KERN_ERR, "src @" __stringify(__LINE__) ": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->src,
+ edesc->src_nents ? 100 : req->nbytes, 1, may_sleep);
#endif
len = desc_len(sh_desc);
@@ -2516,18 +2555,20 @@ static int aead_decrypt(struct aead_request *req)
u32 *desc;
int ret = 0;
+#ifdef DEBUG
+ bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP)) != 0);
+ dbg_dump_sg(KERN_ERR, "dec src@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->src,
+ req->assoclen + req->cryptlen, 1, may_sleep);
+#endif
+
/* allocate extended descriptor */
edesc = aead_edesc_alloc(req, AUTHENC_DESC_JOB_IO_LEN,
&all_contig, false);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "dec src@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src),
- req->assoclen + req->cryptlen, 1);
-#endif
-
/* Create and submit job descriptor*/
init_authenc_job(req, edesc, all_contig, false);
#ifdef DEBUG
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 36365b3efdfd..660dc206969f 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -99,17 +99,17 @@ static struct list_head hash_list;
/* ahash per-session context */
struct caam_hash_ctx {
- struct device *jrdev;
- u32 sh_desc_update[DESC_HASH_MAX_USED_LEN];
- u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN];
- u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN];
- u32 sh_desc_digest[DESC_HASH_MAX_USED_LEN];
- u32 sh_desc_finup[DESC_HASH_MAX_USED_LEN];
- dma_addr_t sh_desc_update_dma;
+ u32 sh_desc_update[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
+ u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
+ u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
+ u32 sh_desc_digest[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
+ u32 sh_desc_finup[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
+ dma_addr_t sh_desc_update_dma ____cacheline_aligned;
dma_addr_t sh_desc_update_first_dma;
dma_addr_t sh_desc_fin_dma;
dma_addr_t sh_desc_digest_dma;
dma_addr_t sh_desc_finup_dma;
+ struct device *jrdev;
u32 alg_type;
u32 alg_op;
u8 key[CAAM_MAX_HASH_KEY_SIZE];
@@ -187,15 +187,6 @@ static inline dma_addr_t buf_map_to_sec4_sg(struct device *jrdev,
return buf_dma;
}
-/* Map req->src and put it in link table */
-static inline void src_map_to_sec4_sg(struct device *jrdev,
- struct scatterlist *src, int src_nents,
- struct sec4_sg_entry *sec4_sg)
-{
- dma_map_sg(jrdev, src, src_nents, DMA_TO_DEVICE);
- sg_to_sec4_sg_last(src, src_nents, sec4_sg, 0);
-}
-
/*
* Only put buffer in link table if it contains data, which is possible,
* since a buffer has previously been used, and needs to be unmapped,
@@ -449,7 +440,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
u32 *desc;
struct split_key_result result;
dma_addr_t src_dma, dst_dma;
- int ret = 0;
+ int ret;
desc = kmalloc(CAAM_CMD_SZ * 8 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA);
if (!desc) {
@@ -526,7 +517,7 @@ static int ahash_setkey(struct crypto_ahash *ahash,
struct device *jrdev = ctx->jrdev;
int blocksize = crypto_tfm_alg_blocksize(&ahash->base);
int digestsize = crypto_ahash_digestsize(ahash);
- int ret = 0;
+ int ret;
u8 *hashed_key = NULL;
#ifdef DEBUG
@@ -534,14 +525,15 @@ static int ahash_setkey(struct crypto_ahash *ahash,
#endif
if (keylen > blocksize) {
- hashed_key = kmalloc(sizeof(u8) * digestsize, GFP_KERNEL |
- GFP_DMA);
+ hashed_key = kmalloc_array(digestsize,
+ sizeof(*hashed_key),
+ GFP_KERNEL | GFP_DMA);
if (!hashed_key)
return -ENOMEM;
ret = hash_digest_key(ctx, key, &keylen, hashed_key,
digestsize);
if (ret)
- goto badkey;
+ goto bad_free_key;
key = hashed_key;
}
@@ -559,14 +551,14 @@ static int ahash_setkey(struct crypto_ahash *ahash,
ret = gen_split_hash_key(ctx, key, keylen);
if (ret)
- goto badkey;
+ goto bad_free_key;
ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len,
DMA_TO_DEVICE);
if (dma_mapping_error(jrdev, ctx->key_dma)) {
dev_err(jrdev, "unable to map key i/o memory\n");
ret = -ENOMEM;
- goto map_err;
+ goto error_free_key;
}
#ifdef DEBUG
print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
@@ -579,11 +571,10 @@ static int ahash_setkey(struct crypto_ahash *ahash,
dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len,
DMA_TO_DEVICE);
}
-
-map_err:
+ error_free_key:
kfree(hashed_key);
return ret;
-badkey:
+ bad_free_key:
kfree(hashed_key);
crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
@@ -595,16 +586,16 @@ badkey:
* @sec4_sg_dma: physical mapped address of h/w link table
* @src_nents: number of segments in input scatterlist
* @sec4_sg_bytes: length of dma mapped sec4_sg space
- * @sec4_sg: pointer to h/w link table
* @hw_desc: the h/w job descriptor followed by any referenced link tables
+ * @sec4_sg: h/w link table
*/
struct ahash_edesc {
dma_addr_t dst_dma;
dma_addr_t sec4_sg_dma;
int src_nents;
int sec4_sg_bytes;
- struct sec4_sg_entry *sec4_sg;
- u32 hw_desc[0];
+ u32 hw_desc[DESC_JOB_IO_LEN / sizeof(u32)] ____cacheline_aligned;
+ struct sec4_sg_entry sec4_sg[0];
};
static inline void ahash_unmap(struct device *dev,
@@ -774,6 +765,65 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err,
req->base.complete(&req->base, err);
}
+/*
+ * Allocate an enhanced descriptor, which contains the hardware descriptor
+ * and space for hardware scatter table containing sg_num entries.
+ */
+static struct ahash_edesc *ahash_edesc_alloc(struct caam_hash_ctx *ctx,
+ int sg_num, u32 *sh_desc,
+ dma_addr_t sh_desc_dma,
+ gfp_t flags)
+{
+ struct ahash_edesc *edesc;
+ unsigned int sg_size = sg_num * sizeof(struct sec4_sg_entry);
+
+ edesc = kzalloc(sizeof(*edesc) + sg_size, GFP_DMA | flags);
+ if (!edesc) {
+ dev_err(ctx->jrdev, "could not allocate extended descriptor\n");
+ return NULL;
+ }
+
+ init_job_desc_shared(edesc->hw_desc, sh_desc_dma, desc_len(sh_desc),
+ HDR_SHARE_DEFER | HDR_REVERSE);
+
+ return edesc;
+}
+
+static int ahash_edesc_add_src(struct caam_hash_ctx *ctx,
+ struct ahash_edesc *edesc,
+ struct ahash_request *req, int nents,
+ unsigned int first_sg,
+ unsigned int first_bytes, size_t to_hash)
+{
+ dma_addr_t src_dma;
+ u32 options;
+
+ if (nents > 1 || first_sg) {
+ struct sec4_sg_entry *sg = edesc->sec4_sg;
+ unsigned int sgsize = sizeof(*sg) * (first_sg + nents);
+
+ sg_to_sec4_sg_last(req->src, nents, sg + first_sg, 0);
+
+ src_dma = dma_map_single(ctx->jrdev, sg, sgsize, DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->jrdev, src_dma)) {
+ dev_err(ctx->jrdev, "unable to map S/G table\n");
+ return -ENOMEM;
+ }
+
+ edesc->sec4_sg_bytes = sgsize;
+ edesc->sec4_sg_dma = src_dma;
+ options = LDST_SGF;
+ } else {
+ src_dma = sg_dma_address(req->src);
+ options = 0;
+ }
+
+ append_seq_in_ptr(edesc->hw_desc, src_dma, first_bytes + to_hash,
+ options);
+
+ return 0;
+}
+
/* submit update job descriptor */
static int ahash_update_ctx(struct ahash_request *req)
{
@@ -789,12 +839,10 @@ static int ahash_update_ctx(struct ahash_request *req)
int *next_buflen = state->current_buf ? &state->buflen_0 :
&state->buflen_1, last_buflen;
int in_len = *buflen + req->nbytes, to_hash;
- u32 *sh_desc = ctx->sh_desc_update, *desc;
- dma_addr_t ptr = ctx->sh_desc_update_dma;
- int src_nents, sec4_sg_bytes, sec4_sg_src_index;
+ u32 *desc;
+ int src_nents, mapped_nents, sec4_sg_bytes, sec4_sg_src_index;
struct ahash_edesc *edesc;
int ret = 0;
- int sh_len;
last_buflen = *next_buflen;
*next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
@@ -807,40 +855,51 @@ static int ahash_update_ctx(struct ahash_request *req)
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
}
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(jrdev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(jrdev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
sec4_sg_src_index = 1 + (*buflen ? 1 : 0);
- sec4_sg_bytes = (sec4_sg_src_index + src_nents) *
+ sec4_sg_bytes = (sec4_sg_src_index + mapped_nents) *
sizeof(struct sec4_sg_entry);
/*
* allocate space for base edesc and hw desc commands,
* link tables
*/
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN +
- sec4_sg_bytes, GFP_DMA | flags);
+ edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents,
+ ctx->sh_desc_update,
+ ctx->sh_desc_update_dma, flags);
if (!edesc) {
- dev_err(jrdev,
- "could not allocate extended descriptor\n");
+ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
return -ENOMEM;
}
edesc->src_nents = src_nents;
edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len,
edesc->sec4_sg, DMA_BIDIRECTIONAL);
if (ret)
- return ret;
+ goto unmap_ctx;
state->buf_dma = try_buf_map_to_sec4_sg(jrdev,
edesc->sec4_sg + 1,
buf, state->buf_dma,
*buflen, last_buflen);
- if (src_nents) {
- src_map_to_sec4_sg(jrdev, req->src, src_nents,
- edesc->sec4_sg + sec4_sg_src_index);
+ if (mapped_nents) {
+ sg_to_sec4_sg_last(req->src, mapped_nents,
+ edesc->sec4_sg + sec4_sg_src_index,
+ 0);
if (*next_buflen)
scatterwalk_map_and_copy(next_buf, req->src,
to_hash - *buflen,
@@ -852,17 +911,15 @@ static int ahash_update_ctx(struct ahash_request *req)
state->current_buf = !state->current_buf;
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER |
- HDR_REVERSE);
edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
sec4_sg_bytes,
DMA_TO_DEVICE);
if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unmap_ctx;
}
append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len +
@@ -877,13 +934,10 @@ static int ahash_update_ctx(struct ahash_request *req)
#endif
ret = caam_jr_enqueue(jrdev, desc, ahash_done_bi, req);
- if (!ret) {
- ret = -EINPROGRESS;
- } else {
- ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len,
- DMA_BIDIRECTIONAL);
- kfree(edesc);
- }
+ if (ret)
+ goto unmap_ctx;
+
+ ret = -EINPROGRESS;
} else if (*next_buflen) {
scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
req->nbytes, 0);
@@ -899,6 +953,10 @@ static int ahash_update_ctx(struct ahash_request *req)
#endif
return ret;
+ unmap_ctx:
+ ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL);
+ kfree(edesc);
+ return ret;
}
static int ahash_final_ctx(struct ahash_request *req)
@@ -913,38 +971,31 @@ static int ahash_final_ctx(struct ahash_request *req)
int buflen = state->current_buf ? state->buflen_1 : state->buflen_0;
int last_buflen = state->current_buf ? state->buflen_0 :
state->buflen_1;
- u32 *sh_desc = ctx->sh_desc_fin, *desc;
- dma_addr_t ptr = ctx->sh_desc_fin_dma;
+ u32 *desc;
int sec4_sg_bytes, sec4_sg_src_index;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
- int ret = 0;
- int sh_len;
+ int ret;
sec4_sg_src_index = 1 + (buflen ? 1 : 0);
sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry);
/* allocate space for base edesc and hw desc commands, link tables */
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes,
- GFP_DMA | flags);
- if (!edesc) {
- dev_err(jrdev, "could not allocate extended descriptor\n");
+ edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index,
+ ctx->sh_desc_fin, ctx->sh_desc_fin_dma,
+ flags);
+ if (!edesc)
return -ENOMEM;
- }
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE);
edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
edesc->src_nents = 0;
ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len,
edesc->sec4_sg, DMA_TO_DEVICE);
if (ret)
- return ret;
+ goto unmap_ctx;
state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1,
buf, state->buf_dma, buflen,
@@ -956,7 +1007,8 @@ static int ahash_final_ctx(struct ahash_request *req)
sec4_sg_bytes, DMA_TO_DEVICE);
if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unmap_ctx;
}
append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + buflen,
@@ -966,7 +1018,8 @@ static int ahash_final_ctx(struct ahash_request *req)
digestsize);
if (dma_mapping_error(jrdev, edesc->dst_dma)) {
dev_err(jrdev, "unable to map dst\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unmap_ctx;
}
#ifdef DEBUG
@@ -975,13 +1028,13 @@ static int ahash_final_ctx(struct ahash_request *req)
#endif
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
- if (!ret) {
- ret = -EINPROGRESS;
- } else {
- ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE);
- kfree(edesc);
- }
+ if (ret)
+ goto unmap_ctx;
+ return -EINPROGRESS;
+ unmap_ctx:
+ ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE);
+ kfree(edesc);
return ret;
}
@@ -997,68 +1050,66 @@ static int ahash_finup_ctx(struct ahash_request *req)
int buflen = state->current_buf ? state->buflen_1 : state->buflen_0;
int last_buflen = state->current_buf ? state->buflen_0 :
state->buflen_1;
- u32 *sh_desc = ctx->sh_desc_finup, *desc;
- dma_addr_t ptr = ctx->sh_desc_finup_dma;
- int sec4_sg_bytes, sec4_sg_src_index;
- int src_nents;
+ u32 *desc;
+ int sec4_sg_src_index;
+ int src_nents, mapped_nents;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
- int ret = 0;
- int sh_len;
+ int ret;
src_nents = sg_nents_for_len(req->src, req->nbytes);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
}
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(jrdev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(jrdev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
sec4_sg_src_index = 1 + (buflen ? 1 : 0);
- sec4_sg_bytes = (sec4_sg_src_index + src_nents) *
- sizeof(struct sec4_sg_entry);
/* allocate space for base edesc and hw desc commands, link tables */
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes,
- GFP_DMA | flags);
+ edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents,
+ ctx->sh_desc_finup, ctx->sh_desc_finup_dma,
+ flags);
if (!edesc) {
- dev_err(jrdev, "could not allocate extended descriptor\n");
+ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
return -ENOMEM;
}
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE);
edesc->src_nents = src_nents;
- edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
ret = ctx_map_to_sec4_sg(desc, jrdev, state, ctx->ctx_len,
edesc->sec4_sg, DMA_TO_DEVICE);
if (ret)
- return ret;
+ goto unmap_ctx;
state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1,
buf, state->buf_dma, buflen,
last_buflen);
- src_map_to_sec4_sg(jrdev, req->src, src_nents, edesc->sec4_sg +
- sec4_sg_src_index);
-
- edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
- sec4_sg_bytes, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
- dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
- }
-
- append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len +
- buflen + req->nbytes, LDST_SGF);
+ ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents,
+ sec4_sg_src_index, ctx->ctx_len + buflen,
+ req->nbytes);
+ if (ret)
+ goto unmap_ctx;
edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result,
digestsize);
if (dma_mapping_error(jrdev, edesc->dst_dma)) {
dev_err(jrdev, "unable to map dst\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unmap_ctx;
}
#ifdef DEBUG
@@ -1067,13 +1118,13 @@ static int ahash_finup_ctx(struct ahash_request *req)
#endif
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
- if (!ret) {
- ret = -EINPROGRESS;
- } else {
- ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE);
- kfree(edesc);
- }
+ if (ret)
+ goto unmap_ctx;
+ return -EINPROGRESS;
+ unmap_ctx:
+ ahash_unmap_ctx(jrdev, edesc, req, digestsize, DMA_FROM_DEVICE);
+ kfree(edesc);
return ret;
}
@@ -1084,60 +1135,56 @@ static int ahash_digest(struct ahash_request *req)
struct device *jrdev = ctx->jrdev;
gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC;
- u32 *sh_desc = ctx->sh_desc_digest, *desc;
- dma_addr_t ptr = ctx->sh_desc_digest_dma;
+ u32 *desc;
int digestsize = crypto_ahash_digestsize(ahash);
- int src_nents, sec4_sg_bytes;
- dma_addr_t src_dma;
+ int src_nents, mapped_nents;
struct ahash_edesc *edesc;
- int ret = 0;
- u32 options;
- int sh_len;
+ int ret;
- src_nents = sg_count(req->src, req->nbytes);
+ src_nents = sg_nents_for_len(req->src, req->nbytes);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
}
- dma_map_sg(jrdev, req->src, src_nents ? : 1, DMA_TO_DEVICE);
- sec4_sg_bytes = src_nents * sizeof(struct sec4_sg_entry);
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(jrdev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(jrdev, "unable to map source for DMA\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
/* allocate space for base edesc and hw desc commands, link tables */
- edesc = kzalloc(sizeof(*edesc) + sec4_sg_bytes + DESC_JOB_IO_LEN,
- GFP_DMA | flags);
+ edesc = ahash_edesc_alloc(ctx, mapped_nents > 1 ? mapped_nents : 0,
+ ctx->sh_desc_digest, ctx->sh_desc_digest_dma,
+ flags);
if (!edesc) {
- dev_err(jrdev, "could not allocate extended descriptor\n");
+ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
return -ENOMEM;
}
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
- edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->src_nents = src_nents;
- sh_len = desc_len(sh_desc);
- desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE);
+ edesc->src_nents = src_nents;
- if (src_nents) {
- sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0);
- edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
- sec4_sg_bytes, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
- dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
- }
- src_dma = edesc->sec4_sg_dma;
- options = LDST_SGF;
- } else {
- src_dma = sg_dma_address(req->src);
- options = 0;
+ ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 0, 0,
+ req->nbytes);
+ if (ret) {
+ ahash_unmap(jrdev, edesc, req, digestsize);
+ kfree(edesc);
+ return ret;
}
- append_seq_in_ptr(desc, src_dma, req->nbytes, options);
+
+ desc = edesc->hw_desc;
edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result,
digestsize);
if (dma_mapping_error(jrdev, edesc->dst_dma)) {
dev_err(jrdev, "unable to map dst\n");
+ ahash_unmap(jrdev, edesc, req, digestsize);
+ kfree(edesc);
return -ENOMEM;
}
@@ -1168,29 +1215,23 @@ static int ahash_final_no_ctx(struct ahash_request *req)
CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC;
u8 *buf = state->current_buf ? state->buf_1 : state->buf_0;
int buflen = state->current_buf ? state->buflen_1 : state->buflen_0;
- u32 *sh_desc = ctx->sh_desc_digest, *desc;
- dma_addr_t ptr = ctx->sh_desc_digest_dma;
+ u32 *desc;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
- int ret = 0;
- int sh_len;
+ int ret;
/* allocate space for base edesc and hw desc commands, link tables */
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN, GFP_DMA | flags);
- if (!edesc) {
- dev_err(jrdev, "could not allocate extended descriptor\n");
+ edesc = ahash_edesc_alloc(ctx, 0, ctx->sh_desc_digest,
+ ctx->sh_desc_digest_dma, flags);
+ if (!edesc)
return -ENOMEM;
- }
- edesc->sec4_sg_bytes = 0;
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE);
state->buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE);
if (dma_mapping_error(jrdev, state->buf_dma)) {
dev_err(jrdev, "unable to map src\n");
- return -ENOMEM;
+ goto unmap;
}
append_seq_in_ptr(desc, state->buf_dma, buflen, 0);
@@ -1199,7 +1240,7 @@ static int ahash_final_no_ctx(struct ahash_request *req)
digestsize);
if (dma_mapping_error(jrdev, edesc->dst_dma)) {
dev_err(jrdev, "unable to map dst\n");
- return -ENOMEM;
+ goto unmap;
}
edesc->src_nents = 0;
@@ -1217,6 +1258,11 @@ static int ahash_final_no_ctx(struct ahash_request *req)
}
return ret;
+ unmap:
+ ahash_unmap(jrdev, edesc, req, digestsize);
+ kfree(edesc);
+ return -ENOMEM;
+
}
/* submit ahash update if it the first job descriptor after update */
@@ -1234,48 +1280,58 @@ static int ahash_update_no_ctx(struct ahash_request *req)
int *next_buflen = state->current_buf ? &state->buflen_0 :
&state->buflen_1;
int in_len = *buflen + req->nbytes, to_hash;
- int sec4_sg_bytes, src_nents;
+ int sec4_sg_bytes, src_nents, mapped_nents;
struct ahash_edesc *edesc;
- u32 *desc, *sh_desc = ctx->sh_desc_update_first;
- dma_addr_t ptr = ctx->sh_desc_update_first_dma;
+ u32 *desc;
int ret = 0;
- int sh_len;
*next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
to_hash = in_len - *next_buflen;
if (to_hash) {
src_nents = sg_nents_for_len(req->src,
- req->nbytes - (*next_buflen));
+ req->nbytes - *next_buflen);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
}
- sec4_sg_bytes = (1 + src_nents) *
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(jrdev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(jrdev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ sec4_sg_bytes = (1 + mapped_nents) *
sizeof(struct sec4_sg_entry);
/*
* allocate space for base edesc and hw desc commands,
* link tables
*/
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN +
- sec4_sg_bytes, GFP_DMA | flags);
+ edesc = ahash_edesc_alloc(ctx, 1 + mapped_nents,
+ ctx->sh_desc_update_first,
+ ctx->sh_desc_update_first_dma,
+ flags);
if (!edesc) {
- dev_err(jrdev,
- "could not allocate extended descriptor\n");
+ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
return -ENOMEM;
}
edesc->src_nents = src_nents;
edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
edesc->dst_dma = 0;
state->buf_dma = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg,
buf, *buflen);
- src_map_to_sec4_sg(jrdev, req->src, src_nents,
- edesc->sec4_sg + 1);
+ sg_to_sec4_sg_last(req->src, mapped_nents,
+ edesc->sec4_sg + 1, 0);
+
if (*next_buflen) {
scatterwalk_map_and_copy(next_buf, req->src,
to_hash - *buflen,
@@ -1284,24 +1340,22 @@ static int ahash_update_no_ctx(struct ahash_request *req)
state->current_buf = !state->current_buf;
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER |
- HDR_REVERSE);
edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
sec4_sg_bytes,
DMA_TO_DEVICE);
if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unmap_ctx;
}
append_seq_in_ptr(desc, edesc->sec4_sg_dma, to_hash, LDST_SGF);
ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len);
if (ret)
- return ret;
+ goto unmap_ctx;
#ifdef DEBUG
print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
@@ -1310,16 +1364,13 @@ static int ahash_update_no_ctx(struct ahash_request *req)
#endif
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req);
- if (!ret) {
- ret = -EINPROGRESS;
- state->update = ahash_update_ctx;
- state->finup = ahash_finup_ctx;
- state->final = ahash_final_ctx;
- } else {
- ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len,
- DMA_TO_DEVICE);
- kfree(edesc);
- }
+ if (ret)
+ goto unmap_ctx;
+
+ ret = -EINPROGRESS;
+ state->update = ahash_update_ctx;
+ state->finup = ahash_finup_ctx;
+ state->final = ahash_final_ctx;
} else if (*next_buflen) {
scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
req->nbytes, 0);
@@ -1335,6 +1386,10 @@ static int ahash_update_no_ctx(struct ahash_request *req)
#endif
return ret;
+ unmap_ctx:
+ ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE);
+ kfree(edesc);
+ return ret;
}
/* submit ahash finup if it the first job descriptor after update */
@@ -1350,61 +1405,63 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
int buflen = state->current_buf ? state->buflen_1 : state->buflen_0;
int last_buflen = state->current_buf ? state->buflen_0 :
state->buflen_1;
- u32 *sh_desc = ctx->sh_desc_digest, *desc;
- dma_addr_t ptr = ctx->sh_desc_digest_dma;
- int sec4_sg_bytes, sec4_sg_src_index, src_nents;
+ u32 *desc;
+ int sec4_sg_bytes, sec4_sg_src_index, src_nents, mapped_nents;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
- int sh_len;
- int ret = 0;
+ int ret;
src_nents = sg_nents_for_len(req->src, req->nbytes);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
}
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(jrdev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(jrdev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
sec4_sg_src_index = 2;
- sec4_sg_bytes = (sec4_sg_src_index + src_nents) *
+ sec4_sg_bytes = (sec4_sg_src_index + mapped_nents) *
sizeof(struct sec4_sg_entry);
/* allocate space for base edesc and hw desc commands, link tables */
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes,
- GFP_DMA | flags);
+ edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents,
+ ctx->sh_desc_digest, ctx->sh_desc_digest_dma,
+ flags);
if (!edesc) {
- dev_err(jrdev, "could not allocate extended descriptor\n");
+ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
return -ENOMEM;
}
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE);
edesc->src_nents = src_nents;
edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, buf,
state->buf_dma, buflen,
last_buflen);
- src_map_to_sec4_sg(jrdev, req->src, src_nents, edesc->sec4_sg + 1);
-
- edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
- sec4_sg_bytes, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
+ ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 1, buflen,
+ req->nbytes);
+ if (ret) {
dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
+ goto unmap;
}
- append_seq_in_ptr(desc, edesc->sec4_sg_dma, buflen +
- req->nbytes, LDST_SGF);
-
edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result,
digestsize);
if (dma_mapping_error(jrdev, edesc->dst_dma)) {
dev_err(jrdev, "unable to map dst\n");
- return -ENOMEM;
+ goto unmap;
}
#ifdef DEBUG
@@ -1421,6 +1478,11 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
}
return ret;
+ unmap:
+ ahash_unmap(jrdev, edesc, req, digestsize);
+ kfree(edesc);
+ return -ENOMEM;
+
}
/* submit first update job descriptor after init */
@@ -1436,78 +1498,65 @@ static int ahash_update_first(struct ahash_request *req)
int *next_buflen = state->current_buf ?
&state->buflen_1 : &state->buflen_0;
int to_hash;
- u32 *sh_desc = ctx->sh_desc_update_first, *desc;
- dma_addr_t ptr = ctx->sh_desc_update_first_dma;
- int sec4_sg_bytes, src_nents;
- dma_addr_t src_dma;
- u32 options;
+ u32 *desc;
+ int src_nents, mapped_nents;
struct ahash_edesc *edesc;
int ret = 0;
- int sh_len;
*next_buflen = req->nbytes & (crypto_tfm_alg_blocksize(&ahash->base) -
1);
to_hash = req->nbytes - *next_buflen;
if (to_hash) {
- src_nents = sg_count(req->src, req->nbytes - (*next_buflen));
+ src_nents = sg_nents_for_len(req->src,
+ req->nbytes - *next_buflen);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
}
- dma_map_sg(jrdev, req->src, src_nents ? : 1, DMA_TO_DEVICE);
- sec4_sg_bytes = src_nents * sizeof(struct sec4_sg_entry);
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(jrdev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(jrdev, "unable to map source for DMA\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
/*
* allocate space for base edesc and hw desc commands,
* link tables
*/
- edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN +
- sec4_sg_bytes, GFP_DMA | flags);
+ edesc = ahash_edesc_alloc(ctx, mapped_nents > 1 ?
+ mapped_nents : 0,
+ ctx->sh_desc_update_first,
+ ctx->sh_desc_update_first_dma,
+ flags);
if (!edesc) {
- dev_err(jrdev,
- "could not allocate extended descriptor\n");
+ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
return -ENOMEM;
}
edesc->src_nents = src_nents;
- edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ahash_edesc) +
- DESC_JOB_IO_LEN;
edesc->dst_dma = 0;
- if (src_nents) {
- sg_to_sec4_sg_last(req->src, src_nents,
- edesc->sec4_sg, 0);
- edesc->sec4_sg_dma = dma_map_single(jrdev,
- edesc->sec4_sg,
- sec4_sg_bytes,
- DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
- dev_err(jrdev, "unable to map S/G table\n");
- return -ENOMEM;
- }
- src_dma = edesc->sec4_sg_dma;
- options = LDST_SGF;
- } else {
- src_dma = sg_dma_address(req->src);
- options = 0;
- }
+ ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 0, 0,
+ to_hash);
+ if (ret)
+ goto unmap_ctx;
if (*next_buflen)
scatterwalk_map_and_copy(next_buf, req->src, to_hash,
*next_buflen, 0);
- sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
- init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER |
- HDR_REVERSE);
-
- append_seq_in_ptr(desc, src_dma, to_hash, options);
ret = map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len);
if (ret)
- return ret;
+ goto unmap_ctx;
#ifdef DEBUG
print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
@@ -1515,18 +1564,14 @@ static int ahash_update_first(struct ahash_request *req)
desc_bytes(desc), 1);
#endif
- ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst,
- req);
- if (!ret) {
- ret = -EINPROGRESS;
- state->update = ahash_update_ctx;
- state->finup = ahash_finup_ctx;
- state->final = ahash_final_ctx;
- } else {
- ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len,
- DMA_TO_DEVICE);
- kfree(edesc);
- }
+ ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req);
+ if (ret)
+ goto unmap_ctx;
+
+ ret = -EINPROGRESS;
+ state->update = ahash_update_ctx;
+ state->finup = ahash_finup_ctx;
+ state->final = ahash_final_ctx;
} else if (*next_buflen) {
state->update = ahash_update_no_ctx;
state->finup = ahash_finup_no_ctx;
@@ -1541,6 +1586,10 @@ static int ahash_update_first(struct ahash_request *req)
#endif
return ret;
+ unmap_ctx:
+ ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE);
+ kfree(edesc);
+ return ret;
}
static int ahash_finup_first(struct ahash_request *req)
@@ -1799,7 +1848,6 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
HASH_MSG_LEN + SHA256_DIGEST_SIZE,
HASH_MSG_LEN + 64,
HASH_MSG_LEN + SHA512_DIGEST_SIZE };
- int ret = 0;
/*
* Get a Job ring from Job Ring driver to ensure in-order
@@ -1819,10 +1867,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct caam_hash_state));
-
- ret = ahash_set_sh_desc(ahash);
-
- return ret;
+ return ahash_set_sh_desc(ahash);
}
static void caam_hash_cra_exit(struct crypto_tfm *tfm)
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 0ec112ee5204..72ff19658985 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -14,6 +14,7 @@
#include "jr.h"
#include "desc_constr.h"
#include "error.h"
+#include "ctrl.h"
bool caam_little_end;
EXPORT_SYMBOL(caam_little_end);
@@ -826,6 +827,8 @@ static int caam_probe(struct platform_device *pdev)
caam_remove:
caam_remove(pdev);
+ return ret;
+
iounmap_ctrl:
iounmap(ctrl);
disable_caam_emi_slow:
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
index 26427c11ad87..513b6646bb36 100644
--- a/drivers/crypto/caam/desc.h
+++ b/drivers/crypto/caam/desc.h
@@ -23,13 +23,7 @@
#define SEC4_SG_OFFSET_MASK 0x00001fff
struct sec4_sg_entry {
-#if !defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) && \
- defined(CONFIG_CRYPTO_DEV_FSL_CAAM_IMX)
- u32 rsvd1;
- dma_addr_t ptr;
-#else
u64 ptr;
-#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_IMX */
u32 len;
u32 bpid_offset;
};
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index d3869b95e7b1..a8cd8a78ec1f 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -325,6 +325,23 @@ static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \
APPEND_CMD_RAW_IMM(load, LOAD, u32);
/*
+ * ee - endianness
+ * size - size of immediate type in bytes
+ */
+#define APPEND_CMD_RAW_IMM2(cmd, op, ee, size) \
+static inline void append_##cmd##_imm_##ee##size(u32 *desc, \
+ u##size immediate, \
+ u32 options) \
+{ \
+ __##ee##size data = cpu_to_##ee##size(immediate); \
+ PRINT_POS; \
+ append_cmd(desc, CMD_##op | IMMEDIATE | options | sizeof(data)); \
+ append_data(desc, &data, sizeof(data)); \
+}
+
+APPEND_CMD_RAW_IMM2(load, LOAD, be, 32);
+
+/*
* Append math command. Only the last part of destination and source need to
* be specified
*/
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index e2bcacc1a921..5d4c05074a5c 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -41,7 +41,6 @@ struct caam_drv_private_jr {
struct device *dev;
int ridx;
struct caam_job_ring __iomem *rregs; /* JobR's register space */
- struct tasklet_struct irqtask;
int irq; /* One per queue */
/* Number of scatterlist crypt transforms active on the JobR */
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index a81f551ac222..757c27f9953d 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -73,8 +73,6 @@ static int caam_jr_shutdown(struct device *dev)
ret = caam_reset_hw_jr(dev);
- tasklet_kill(&jrp->irqtask);
-
/* Release interrupt */
free_irq(jrp->irq, dev);
@@ -130,7 +128,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
/*
* Check the output ring for ready responses, kick
- * tasklet if jobs done.
+ * the threaded irq if jobs done.
*/
irqstate = rd_reg32(&jrp->rregs->jrintstatus);
if (!irqstate)
@@ -152,18 +150,13 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
/* Have valid interrupt at this point, just ACK and trigger */
wr_reg32(&jrp->rregs->jrintstatus, irqstate);
- preempt_disable();
- tasklet_schedule(&jrp->irqtask);
- preempt_enable();
-
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
-/* Deferred service handler, run as interrupt-fired tasklet */
-static void caam_jr_dequeue(unsigned long devarg)
+static irqreturn_t caam_jr_threadirq(int irq, void *st_dev)
{
int hw_idx, sw_idx, i, head, tail;
- struct device *dev = (struct device *)devarg;
+ struct device *dev = st_dev;
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
u32 *userdesc, userstatus;
@@ -237,6 +230,8 @@ static void caam_jr_dequeue(unsigned long devarg)
/* reenable / unmask IRQs */
clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+
+ return IRQ_HANDLED;
}
/**
@@ -394,11 +389,10 @@ static int caam_jr_init(struct device *dev)
jrp = dev_get_drvdata(dev);
- tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
-
/* Connect job ring interrupt handler. */
- error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED,
- dev_name(dev), dev);
+ error = request_threaded_irq(jrp->irq, caam_jr_interrupt,
+ caam_jr_threadirq, IRQF_SHARED,
+ dev_name(dev), dev);
if (error) {
dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
jrp->ridx, jrp->irq);
@@ -460,7 +454,6 @@ out_free_inpring:
out_free_irq:
free_irq(jrp->irq, dev);
out_kill_deq:
- tasklet_kill(&jrp->irqtask);
return error;
}
@@ -513,6 +506,7 @@ static int caam_jr_probe(struct platform_device *pdev)
error = caam_jr_init(jrdev); /* now turn on hardware */
if (error) {
irq_dispose_mapping(jrpriv->irq);
+ iounmap(ctrl);
return error;
}
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index b3c5016f6458..84d2f838a063 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -196,6 +196,14 @@ static inline u64 rd_reg64(void __iomem *reg)
#define caam_dma_to_cpu(value) caam32_to_cpu(value)
#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX
+#define cpu_to_caam_dma64(value) \
+ (((u64)cpu_to_caam32(lower_32_bits(value)) << 32) | \
+ (u64)cpu_to_caam32(upper_32_bits(value)))
+#else
+#define cpu_to_caam_dma64(value) cpu_to_caam64(value)
+#endif
+
/*
* jr_outentry
* Represents each entry in a JobR output ring
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index 19dc64fede0d..41cd5a356d05 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -15,7 +15,7 @@ struct sec4_sg_entry;
static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr,
dma_addr_t dma, u32 len, u16 offset)
{
- sec4_sg_ptr->ptr = cpu_to_caam_dma(dma);
+ sec4_sg_ptr->ptr = cpu_to_caam_dma64(dma);
sec4_sg_ptr->len = cpu_to_caam32(len);
sec4_sg_ptr->bpid_offset = cpu_to_caam32(offset & SEC4_SG_OFFSET_MASK);
#ifdef DEBUG
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index ee4d2741b3ab..346ceb8f17bd 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o
ccp-objs := ccp-dev.o \
ccp-ops.o \
ccp-dev-v3.o \
+ ccp-dev-v5.o \
ccp-platform.o \
ccp-dmaengine.o
ccp-$(CONFIG_PCI) += ccp-pci.o
diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
index 8f36af62fe95..84a652be4274 100644
--- a/drivers/crypto/ccp/ccp-crypto-sha.c
+++ b/drivers/crypto/ccp/ccp-crypto-sha.c
@@ -4,6 +4,7 @@
* Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.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
@@ -134,7 +135,22 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes,
rctx->cmd.engine = CCP_ENGINE_SHA;
rctx->cmd.u.sha.type = rctx->type;
rctx->cmd.u.sha.ctx = &rctx->ctx_sg;
- rctx->cmd.u.sha.ctx_len = sizeof(rctx->ctx);
+
+ switch (rctx->type) {
+ case CCP_SHA_TYPE_1:
+ rctx->cmd.u.sha.ctx_len = SHA1_DIGEST_SIZE;
+ break;
+ case CCP_SHA_TYPE_224:
+ rctx->cmd.u.sha.ctx_len = SHA224_DIGEST_SIZE;
+ break;
+ case CCP_SHA_TYPE_256:
+ rctx->cmd.u.sha.ctx_len = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ /* Should never get here */
+ break;
+ }
+
rctx->cmd.u.sha.src = sg;
rctx->cmd.u.sha.src_len = rctx->hash_cnt;
rctx->cmd.u.sha.opad = ctx->u.sha.key_len ?
diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c
index d7a710347967..8d2dbacc6161 100644
--- a/drivers/crypto/ccp/ccp-dev-v3.c
+++ b/drivers/crypto/ccp/ccp-dev-v3.c
@@ -4,6 +4,7 @@
* Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.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
@@ -19,6 +20,61 @@
#include "ccp-dev.h"
+static u32 ccp_alloc_ksb(struct ccp_cmd_queue *cmd_q, unsigned int count)
+{
+ int start;
+ struct ccp_device *ccp = cmd_q->ccp;
+
+ for (;;) {
+ mutex_lock(&ccp->sb_mutex);
+
+ start = (u32)bitmap_find_next_zero_area(ccp->sb,
+ ccp->sb_count,
+ ccp->sb_start,
+ count, 0);
+ if (start <= ccp->sb_count) {
+ bitmap_set(ccp->sb, start, count);
+
+ mutex_unlock(&ccp->sb_mutex);
+ break;
+ }
+
+ ccp->sb_avail = 0;
+
+ mutex_unlock(&ccp->sb_mutex);
+
+ /* Wait for KSB entries to become available */
+ if (wait_event_interruptible(ccp->sb_queue, ccp->sb_avail))
+ return 0;
+ }
+
+ return KSB_START + start;
+}
+
+static void ccp_free_ksb(struct ccp_cmd_queue *cmd_q, unsigned int start,
+ unsigned int count)
+{
+ struct ccp_device *ccp = cmd_q->ccp;
+
+ if (!start)
+ return;
+
+ mutex_lock(&ccp->sb_mutex);
+
+ bitmap_clear(ccp->sb, start - KSB_START, count);
+
+ ccp->sb_avail = 1;
+
+ mutex_unlock(&ccp->sb_mutex);
+
+ wake_up_interruptible_all(&ccp->sb_queue);
+}
+
+static unsigned int ccp_get_free_slots(struct ccp_cmd_queue *cmd_q)
+{
+ return CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
+}
+
static int ccp_do_cmd(struct ccp_op *op, u32 *cr, unsigned int cr_count)
{
struct ccp_cmd_queue *cmd_q = op->cmd_q;
@@ -68,6 +124,9 @@ static int ccp_do_cmd(struct ccp_op *op, u32 *cr, unsigned int cr_count)
/* On error delete all related jobs from the queue */
cmd = (cmd_q->id << DEL_Q_ID_SHIFT)
| op->jobid;
+ if (cmd_q->cmd_error)
+ ccp_log_error(cmd_q->ccp,
+ cmd_q->cmd_error);
iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
@@ -99,10 +158,10 @@ static int ccp_perform_aes(struct ccp_op *op)
| (op->u.aes.type << REQ1_AES_TYPE_SHIFT)
| (op->u.aes.mode << REQ1_AES_MODE_SHIFT)
| (op->u.aes.action << REQ1_AES_ACTION_SHIFT)
- | (op->ksb_key << REQ1_KEY_KSB_SHIFT);
+ | (op->sb_key << REQ1_KEY_KSB_SHIFT);
cr[1] = op->src.u.dma.length - 1;
cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
| ccp_addr_hi(&op->src.u.dma);
cr[4] = ccp_addr_lo(&op->dst.u.dma);
@@ -129,10 +188,10 @@ static int ccp_perform_xts_aes(struct ccp_op *op)
cr[0] = (CCP_ENGINE_XTS_AES_128 << REQ1_ENGINE_SHIFT)
| (op->u.xts.action << REQ1_AES_ACTION_SHIFT)
| (op->u.xts.unit_size << REQ1_XTS_AES_SIZE_SHIFT)
- | (op->ksb_key << REQ1_KEY_KSB_SHIFT);
+ | (op->sb_key << REQ1_KEY_KSB_SHIFT);
cr[1] = op->src.u.dma.length - 1;
cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
| ccp_addr_hi(&op->src.u.dma);
cr[4] = ccp_addr_lo(&op->dst.u.dma);
@@ -158,7 +217,7 @@ static int ccp_perform_sha(struct ccp_op *op)
| REQ1_INIT;
cr[1] = op->src.u.dma.length - 1;
cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
| ccp_addr_hi(&op->src.u.dma);
@@ -181,11 +240,11 @@ static int ccp_perform_rsa(struct ccp_op *op)
/* Fill out the register contents for REQ1 through REQ6 */
cr[0] = (CCP_ENGINE_RSA << REQ1_ENGINE_SHIFT)
| (op->u.rsa.mod_size << REQ1_RSA_MOD_SIZE_SHIFT)
- | (op->ksb_key << REQ1_KEY_KSB_SHIFT)
+ | (op->sb_key << REQ1_KEY_KSB_SHIFT)
| REQ1_EOM;
cr[1] = op->u.rsa.input_len - 1;
cr[2] = ccp_addr_lo(&op->src.u.dma);
- cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT)
+ cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
| ccp_addr_hi(&op->src.u.dma);
cr[4] = ccp_addr_lo(&op->dst.u.dma);
@@ -215,10 +274,10 @@ static int ccp_perform_passthru(struct ccp_op *op)
| ccp_addr_hi(&op->src.u.dma);
if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
- cr[3] |= (op->ksb_key << REQ4_KSB_SHIFT);
+ cr[3] |= (op->sb_key << REQ4_KSB_SHIFT);
} else {
- cr[2] = op->src.u.ksb * CCP_KSB_BYTES;
- cr[3] = (CCP_MEMTYPE_KSB << REQ4_MEMTYPE_SHIFT);
+ cr[2] = op->src.u.sb * CCP_SB_BYTES;
+ cr[3] = (CCP_MEMTYPE_SB << REQ4_MEMTYPE_SHIFT);
}
if (op->dst.type == CCP_MEMTYPE_SYSTEM) {
@@ -226,8 +285,8 @@ static int ccp_perform_passthru(struct ccp_op *op)
cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
| ccp_addr_hi(&op->dst.u.dma);
} else {
- cr[4] = op->dst.u.ksb * CCP_KSB_BYTES;
- cr[5] = (CCP_MEMTYPE_KSB << REQ6_MEMTYPE_SHIFT);
+ cr[4] = op->dst.u.sb * CCP_SB_BYTES;
+ cr[5] = (CCP_MEMTYPE_SB << REQ6_MEMTYPE_SHIFT);
}
if (op->eom)
@@ -256,35 +315,6 @@ static int ccp_perform_ecc(struct ccp_op *op)
return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
}
-static int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
-{
- struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng);
- u32 trng_value;
- int len = min_t(int, sizeof(trng_value), max);
-
- /*
- * Locking is provided by the caller so we can update device
- * hwrng-related fields safely
- */
- trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG);
- if (!trng_value) {
- /* Zero is returned if not data is available or if a
- * bad-entropy error is present. Assume an error if
- * we exceed TRNG_RETRIES reads of zero.
- */
- if (ccp->hwrng_retries++ > TRNG_RETRIES)
- return -EIO;
-
- return 0;
- }
-
- /* Reset the counter and save the rng value */
- ccp->hwrng_retries = 0;
- memcpy(data, &trng_value, len);
-
- return len;
-}
-
static int ccp_init(struct ccp_device *ccp)
{
struct device *dev = ccp->dev;
@@ -321,9 +351,9 @@ static int ccp_init(struct ccp_device *ccp)
cmd_q->dma_pool = dma_pool;
/* Reserve 2 KSB regions for the queue */
- cmd_q->ksb_key = KSB_START + ccp->ksb_start++;
- cmd_q->ksb_ctx = KSB_START + ccp->ksb_start++;
- ccp->ksb_count -= 2;
+ cmd_q->sb_key = KSB_START + ccp->sb_start++;
+ cmd_q->sb_ctx = KSB_START + ccp->sb_start++;
+ ccp->sb_count -= 2;
/* Preset some register values and masks that are queue
* number dependent
@@ -335,7 +365,7 @@ static int ccp_init(struct ccp_device *ccp)
cmd_q->int_ok = 1 << (i * 2);
cmd_q->int_err = 1 << ((i * 2) + 1);
- cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
+ cmd_q->free_slots = ccp_get_free_slots(cmd_q);
init_waitqueue_head(&cmd_q->int_queue);
@@ -375,9 +405,10 @@ static int ccp_init(struct ccp_device *ccp)
}
/* Initialize the queues used to wait for KSB space and suspend */
- init_waitqueue_head(&ccp->ksb_queue);
+ init_waitqueue_head(&ccp->sb_queue);
init_waitqueue_head(&ccp->suspend_queue);
+ dev_dbg(dev, "Starting threads...\n");
/* Create a kthread for each queue */
for (i = 0; i < ccp->cmd_q_count; i++) {
struct task_struct *kthread;
@@ -397,29 +428,26 @@ static int ccp_init(struct ccp_device *ccp)
wake_up_process(kthread);
}
- /* Register the RNG */
- ccp->hwrng.name = ccp->rngname;
- ccp->hwrng.read = ccp_trng_read;
- ret = hwrng_register(&ccp->hwrng);
- if (ret) {
- dev_err(dev, "error registering hwrng (%d)\n", ret);
+ dev_dbg(dev, "Enabling interrupts...\n");
+ /* Enable interrupts */
+ iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
+
+ dev_dbg(dev, "Registering device...\n");
+ ccp_add_device(ccp);
+
+ ret = ccp_register_rng(ccp);
+ if (ret)
goto e_kthread;
- }
/* Register the DMA engine support */
ret = ccp_dmaengine_register(ccp);
if (ret)
goto e_hwrng;
- ccp_add_device(ccp);
-
- /* Enable interrupts */
- iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
-
return 0;
e_hwrng:
- hwrng_unregister(&ccp->hwrng);
+ ccp_unregister_rng(ccp);
e_kthread:
for (i = 0; i < ccp->cmd_q_count; i++)
@@ -441,19 +469,14 @@ static void ccp_destroy(struct ccp_device *ccp)
struct ccp_cmd *cmd;
unsigned int qim, i;
- /* Remove this device from the list of available units first */
- ccp_del_device(ccp);
-
/* Unregister the DMA engine */
ccp_dmaengine_unregister(ccp);
/* Unregister the RNG */
- hwrng_unregister(&ccp->hwrng);
+ ccp_unregister_rng(ccp);
- /* Stop the queue kthreads */
- for (i = 0; i < ccp->cmd_q_count; i++)
- if (ccp->cmd_q[i].kthread)
- kthread_stop(ccp->cmd_q[i].kthread);
+ /* Remove this device from the list of available units */
+ ccp_del_device(ccp);
/* Build queue interrupt mask (two interrupt masks per queue) */
qim = 0;
@@ -472,6 +495,11 @@ static void ccp_destroy(struct ccp_device *ccp)
}
iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
+ /* Stop the queue kthreads */
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ if (ccp->cmd_q[i].kthread)
+ kthread_stop(ccp->cmd_q[i].kthread);
+
ccp->free_irq(ccp);
for (i = 0; i < ccp->cmd_q_count; i++)
@@ -527,18 +555,24 @@ static irqreturn_t ccp_irq_handler(int irq, void *data)
}
static const struct ccp_actions ccp3_actions = {
- .perform_aes = ccp_perform_aes,
- .perform_xts_aes = ccp_perform_xts_aes,
- .perform_sha = ccp_perform_sha,
- .perform_rsa = ccp_perform_rsa,
- .perform_passthru = ccp_perform_passthru,
- .perform_ecc = ccp_perform_ecc,
+ .aes = ccp_perform_aes,
+ .xts_aes = ccp_perform_xts_aes,
+ .sha = ccp_perform_sha,
+ .rsa = ccp_perform_rsa,
+ .passthru = ccp_perform_passthru,
+ .ecc = ccp_perform_ecc,
+ .sballoc = ccp_alloc_ksb,
+ .sbfree = ccp_free_ksb,
.init = ccp_init,
.destroy = ccp_destroy,
+ .get_free_slots = ccp_get_free_slots,
.irqhandler = ccp_irq_handler,
};
-struct ccp_vdata ccpv3 = {
+const struct ccp_vdata ccpv3 = {
.version = CCP_VERSION(3, 0),
+ .setup = NULL,
.perform = &ccp3_actions,
+ .bar = 2,
+ .offset = 0x20000,
};
diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c
new file mode 100644
index 000000000000..faf3cb3ddce2
--- /dev/null
+++ b/drivers/crypto/ccp/ccp-dev-v5.c
@@ -0,0 +1,1017 @@
+/*
+ * AMD Cryptographic Coprocessor (CCP) driver
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Gary R Hook <gary.hook@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/ccp.h>
+
+#include "ccp-dev.h"
+
+static u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsigned int count)
+{
+ struct ccp_device *ccp;
+ int start;
+
+ /* First look at the map for the queue */
+ if (cmd_q->lsb >= 0) {
+ start = (u32)bitmap_find_next_zero_area(cmd_q->lsbmap,
+ LSB_SIZE,
+ 0, count, 0);
+ if (start < LSB_SIZE) {
+ bitmap_set(cmd_q->lsbmap, start, count);
+ return start + cmd_q->lsb * LSB_SIZE;
+ }
+ }
+
+ /* No joy; try to get an entry from the shared blocks */
+ ccp = cmd_q->ccp;
+ for (;;) {
+ mutex_lock(&ccp->sb_mutex);
+
+ start = (u32)bitmap_find_next_zero_area(ccp->lsbmap,
+ MAX_LSB_CNT * LSB_SIZE,
+ 0,
+ count, 0);
+ if (start <= MAX_LSB_CNT * LSB_SIZE) {
+ bitmap_set(ccp->lsbmap, start, count);
+
+ mutex_unlock(&ccp->sb_mutex);
+ return start * LSB_ITEM_SIZE;
+ }
+
+ ccp->sb_avail = 0;
+
+ mutex_unlock(&ccp->sb_mutex);
+
+ /* Wait for KSB entries to become available */
+ if (wait_event_interruptible(ccp->sb_queue, ccp->sb_avail))
+ return 0;
+ }
+}
+
+static void ccp_lsb_free(struct ccp_cmd_queue *cmd_q, unsigned int start,
+ unsigned int count)
+{
+ int lsbno = start / LSB_SIZE;
+
+ if (!start)
+ return;
+
+ if (cmd_q->lsb == lsbno) {
+ /* An entry from the private LSB */
+ bitmap_clear(cmd_q->lsbmap, start % LSB_SIZE, count);
+ } else {
+ /* From the shared LSBs */
+ struct ccp_device *ccp = cmd_q->ccp;
+
+ mutex_lock(&ccp->sb_mutex);
+ bitmap_clear(ccp->lsbmap, start, count);
+ ccp->sb_avail = 1;
+ mutex_unlock(&ccp->sb_mutex);
+ wake_up_interruptible_all(&ccp->sb_queue);
+ }
+}
+
+/* CCP version 5: Union to define the function field (cmd_reg1/dword0) */
+union ccp_function {
+ struct {
+ u16 size:7;
+ u16 encrypt:1;
+ u16 mode:5;
+ u16 type:2;
+ } aes;
+ struct {
+ u16 size:7;
+ u16 encrypt:1;
+ u16 rsvd:5;
+ u16 type:2;
+ } aes_xts;
+ struct {
+ u16 rsvd1:10;
+ u16 type:4;
+ u16 rsvd2:1;
+ } sha;
+ struct {
+ u16 mode:3;
+ u16 size:12;
+ } rsa;
+ struct {
+ u16 byteswap:2;
+ u16 bitwise:3;
+ u16 reflect:2;
+ u16 rsvd:8;
+ } pt;
+ struct {
+ u16 rsvd:13;
+ } zlib;
+ struct {
+ u16 size:10;
+ u16 type:2;
+ u16 mode:3;
+ } ecc;
+ u16 raw;
+};
+
+#define CCP_AES_SIZE(p) ((p)->aes.size)
+#define CCP_AES_ENCRYPT(p) ((p)->aes.encrypt)
+#define CCP_AES_MODE(p) ((p)->aes.mode)
+#define CCP_AES_TYPE(p) ((p)->aes.type)
+#define CCP_XTS_SIZE(p) ((p)->aes_xts.size)
+#define CCP_XTS_ENCRYPT(p) ((p)->aes_xts.encrypt)
+#define CCP_SHA_TYPE(p) ((p)->sha.type)
+#define CCP_RSA_SIZE(p) ((p)->rsa.size)
+#define CCP_PT_BYTESWAP(p) ((p)->pt.byteswap)
+#define CCP_PT_BITWISE(p) ((p)->pt.bitwise)
+#define CCP_ECC_MODE(p) ((p)->ecc.mode)
+#define CCP_ECC_AFFINE(p) ((p)->ecc.one)
+
+/* Word 0 */
+#define CCP5_CMD_DW0(p) ((p)->dw0)
+#define CCP5_CMD_SOC(p) (CCP5_CMD_DW0(p).soc)
+#define CCP5_CMD_IOC(p) (CCP5_CMD_DW0(p).ioc)
+#define CCP5_CMD_INIT(p) (CCP5_CMD_DW0(p).init)
+#define CCP5_CMD_EOM(p) (CCP5_CMD_DW0(p).eom)
+#define CCP5_CMD_FUNCTION(p) (CCP5_CMD_DW0(p).function)
+#define CCP5_CMD_ENGINE(p) (CCP5_CMD_DW0(p).engine)
+#define CCP5_CMD_PROT(p) (CCP5_CMD_DW0(p).prot)
+
+/* Word 1 */
+#define CCP5_CMD_DW1(p) ((p)->length)
+#define CCP5_CMD_LEN(p) (CCP5_CMD_DW1(p))
+
+/* Word 2 */
+#define CCP5_CMD_DW2(p) ((p)->src_lo)
+#define CCP5_CMD_SRC_LO(p) (CCP5_CMD_DW2(p))
+
+/* Word 3 */
+#define CCP5_CMD_DW3(p) ((p)->dw3)
+#define CCP5_CMD_SRC_MEM(p) ((p)->dw3.src_mem)
+#define CCP5_CMD_SRC_HI(p) ((p)->dw3.src_hi)
+#define CCP5_CMD_LSB_ID(p) ((p)->dw3.lsb_cxt_id)
+#define CCP5_CMD_FIX_SRC(p) ((p)->dw3.fixed)
+
+/* Words 4/5 */
+#define CCP5_CMD_DW4(p) ((p)->dw4)
+#define CCP5_CMD_DST_LO(p) (CCP5_CMD_DW4(p).dst_lo)
+#define CCP5_CMD_DW5(p) ((p)->dw5.fields.dst_hi)
+#define CCP5_CMD_DST_HI(p) (CCP5_CMD_DW5(p))
+#define CCP5_CMD_DST_MEM(p) ((p)->dw5.fields.dst_mem)
+#define CCP5_CMD_FIX_DST(p) ((p)->dw5.fields.fixed)
+#define CCP5_CMD_SHA_LO(p) ((p)->dw4.sha_len_lo)
+#define CCP5_CMD_SHA_HI(p) ((p)->dw5.sha_len_hi)
+
+/* Word 6/7 */
+#define CCP5_CMD_DW6(p) ((p)->key_lo)
+#define CCP5_CMD_KEY_LO(p) (CCP5_CMD_DW6(p))
+#define CCP5_CMD_DW7(p) ((p)->dw7)
+#define CCP5_CMD_KEY_HI(p) ((p)->dw7.key_hi)
+#define CCP5_CMD_KEY_MEM(p) ((p)->dw7.key_mem)
+
+static inline u32 low_address(unsigned long addr)
+{
+ return (u64)addr & 0x0ffffffff;
+}
+
+static inline u32 high_address(unsigned long addr)
+{
+ return ((u64)addr >> 32) & 0x00000ffff;
+}
+
+static unsigned int ccp5_get_free_slots(struct ccp_cmd_queue *cmd_q)
+{
+ unsigned int head_idx, n;
+ u32 head_lo, queue_start;
+
+ queue_start = low_address(cmd_q->qdma_tail);
+ head_lo = ioread32(cmd_q->reg_head_lo);
+ head_idx = (head_lo - queue_start) / sizeof(struct ccp5_desc);
+
+ n = head_idx + COMMANDS_PER_QUEUE - cmd_q->qidx - 1;
+
+ return n % COMMANDS_PER_QUEUE; /* Always one unused spot */
+}
+
+static int ccp5_do_cmd(struct ccp5_desc *desc,
+ struct ccp_cmd_queue *cmd_q)
+{
+ u32 *mP;
+ __le32 *dP;
+ u32 tail;
+ int i;
+ int ret = 0;
+
+ if (CCP5_CMD_SOC(desc)) {
+ CCP5_CMD_IOC(desc) = 1;
+ CCP5_CMD_SOC(desc) = 0;
+ }
+ mutex_lock(&cmd_q->q_mutex);
+
+ mP = (u32 *) &cmd_q->qbase[cmd_q->qidx];
+ dP = (__le32 *) desc;
+ for (i = 0; i < 8; i++)
+ mP[i] = cpu_to_le32(dP[i]); /* handle endianness */
+
+ cmd_q->qidx = (cmd_q->qidx + 1) % COMMANDS_PER_QUEUE;
+
+ /* The data used by this command must be flushed to memory */
+ wmb();
+
+ /* Write the new tail address back to the queue register */
+ tail = low_address(cmd_q->qdma_tail + cmd_q->qidx * Q_DESC_SIZE);
+ iowrite32(tail, cmd_q->reg_tail_lo);
+
+ /* Turn the queue back on using our cached control register */
+ iowrite32(cmd_q->qcontrol | CMD5_Q_RUN, cmd_q->reg_control);
+ mutex_unlock(&cmd_q->q_mutex);
+
+ if (CCP5_CMD_IOC(desc)) {
+ /* Wait for the job to complete */
+ ret = wait_event_interruptible(cmd_q->int_queue,
+ cmd_q->int_rcvd);
+ if (ret || cmd_q->cmd_error) {
+ if (cmd_q->cmd_error)
+ ccp_log_error(cmd_q->ccp,
+ cmd_q->cmd_error);
+ /* A version 5 device doesn't use Job IDs... */
+ if (!ret)
+ ret = -EIO;
+ }
+ cmd_q->int_rcvd = 0;
+ }
+
+ return 0;
+}
+
+static int ccp5_perform_aes(struct ccp_op *op)
+{
+ struct ccp5_desc desc;
+ union ccp_function function;
+ u32 key_addr = op->sb_key * LSB_ITEM_SIZE;
+
+ /* Zero out all the fields of the command desc */
+ memset(&desc, 0, Q_DESC_SIZE);
+
+ CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_AES;
+
+ CCP5_CMD_SOC(&desc) = op->soc;
+ CCP5_CMD_IOC(&desc) = 1;
+ CCP5_CMD_INIT(&desc) = op->init;
+ CCP5_CMD_EOM(&desc) = op->eom;
+ CCP5_CMD_PROT(&desc) = 0;
+
+ function.raw = 0;
+ CCP_AES_ENCRYPT(&function) = op->u.aes.action;
+ CCP_AES_MODE(&function) = op->u.aes.mode;
+ CCP_AES_TYPE(&function) = op->u.aes.type;
+ if (op->u.aes.mode == CCP_AES_MODE_CFB)
+ CCP_AES_SIZE(&function) = 0x7f;
+
+ CCP5_CMD_FUNCTION(&desc) = function.raw;
+
+ CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
+
+ CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
+ CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
+ CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
+ CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ CCP5_CMD_KEY_LO(&desc) = lower_32_bits(key_addr);
+ CCP5_CMD_KEY_HI(&desc) = 0;
+ CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SB;
+ CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
+
+ return ccp5_do_cmd(&desc, op->cmd_q);
+}
+
+static int ccp5_perform_xts_aes(struct ccp_op *op)
+{
+ struct ccp5_desc desc;
+ union ccp_function function;
+ u32 key_addr = op->sb_key * LSB_ITEM_SIZE;
+
+ /* Zero out all the fields of the command desc */
+ memset(&desc, 0, Q_DESC_SIZE);
+
+ CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_XTS_AES_128;
+
+ CCP5_CMD_SOC(&desc) = op->soc;
+ CCP5_CMD_IOC(&desc) = 1;
+ CCP5_CMD_INIT(&desc) = op->init;
+ CCP5_CMD_EOM(&desc) = op->eom;
+ CCP5_CMD_PROT(&desc) = 0;
+
+ function.raw = 0;
+ CCP_XTS_ENCRYPT(&function) = op->u.xts.action;
+ CCP_XTS_SIZE(&function) = op->u.xts.unit_size;
+ CCP5_CMD_FUNCTION(&desc) = function.raw;
+
+ CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
+
+ CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
+ CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
+ CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
+ CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ CCP5_CMD_KEY_LO(&desc) = lower_32_bits(key_addr);
+ CCP5_CMD_KEY_HI(&desc) = 0;
+ CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SB;
+ CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
+
+ return ccp5_do_cmd(&desc, op->cmd_q);
+}
+
+static int ccp5_perform_sha(struct ccp_op *op)
+{
+ struct ccp5_desc desc;
+ union ccp_function function;
+
+ /* Zero out all the fields of the command desc */
+ memset(&desc, 0, Q_DESC_SIZE);
+
+ CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_SHA;
+
+ CCP5_CMD_SOC(&desc) = op->soc;
+ CCP5_CMD_IOC(&desc) = 1;
+ CCP5_CMD_INIT(&desc) = 1;
+ CCP5_CMD_EOM(&desc) = op->eom;
+ CCP5_CMD_PROT(&desc) = 0;
+
+ function.raw = 0;
+ CCP_SHA_TYPE(&function) = op->u.sha.type;
+ CCP5_CMD_FUNCTION(&desc) = function.raw;
+
+ CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
+
+ CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
+ CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ CCP5_CMD_LSB_ID(&desc) = op->sb_ctx;
+
+ if (op->eom) {
+ CCP5_CMD_SHA_LO(&desc) = lower_32_bits(op->u.sha.msg_bits);
+ CCP5_CMD_SHA_HI(&desc) = upper_32_bits(op->u.sha.msg_bits);
+ } else {
+ CCP5_CMD_SHA_LO(&desc) = 0;
+ CCP5_CMD_SHA_HI(&desc) = 0;
+ }
+
+ return ccp5_do_cmd(&desc, op->cmd_q);
+}
+
+static int ccp5_perform_rsa(struct ccp_op *op)
+{
+ struct ccp5_desc desc;
+ union ccp_function function;
+
+ /* Zero out all the fields of the command desc */
+ memset(&desc, 0, Q_DESC_SIZE);
+
+ CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_RSA;
+
+ CCP5_CMD_SOC(&desc) = op->soc;
+ CCP5_CMD_IOC(&desc) = 1;
+ CCP5_CMD_INIT(&desc) = 0;
+ CCP5_CMD_EOM(&desc) = 1;
+ CCP5_CMD_PROT(&desc) = 0;
+
+ function.raw = 0;
+ CCP_RSA_SIZE(&function) = op->u.rsa.mod_size;
+ CCP5_CMD_FUNCTION(&desc) = function.raw;
+
+ CCP5_CMD_LEN(&desc) = op->u.rsa.input_len;
+
+ /* Source is from external memory */
+ CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
+ CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ /* Destination is in external memory */
+ CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
+ CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
+ CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ /* Key (Exponent) is in external memory */
+ CCP5_CMD_KEY_LO(&desc) = ccp_addr_lo(&op->exp.u.dma);
+ CCP5_CMD_KEY_HI(&desc) = ccp_addr_hi(&op->exp.u.dma);
+ CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ return ccp5_do_cmd(&desc, op->cmd_q);
+}
+
+static int ccp5_perform_passthru(struct ccp_op *op)
+{
+ struct ccp5_desc desc;
+ union ccp_function function;
+ struct ccp_dma_info *saddr = &op->src.u.dma;
+ struct ccp_dma_info *daddr = &op->dst.u.dma;
+
+ memset(&desc, 0, Q_DESC_SIZE);
+
+ CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_PASSTHRU;
+
+ CCP5_CMD_SOC(&desc) = 0;
+ CCP5_CMD_IOC(&desc) = 1;
+ CCP5_CMD_INIT(&desc) = 0;
+ CCP5_CMD_EOM(&desc) = op->eom;
+ CCP5_CMD_PROT(&desc) = 0;
+
+ function.raw = 0;
+ CCP_PT_BYTESWAP(&function) = op->u.passthru.byte_swap;
+ CCP_PT_BITWISE(&function) = op->u.passthru.bit_mod;
+ CCP5_CMD_FUNCTION(&desc) = function.raw;
+
+ /* Length of source data is always 256 bytes */
+ if (op->src.type == CCP_MEMTYPE_SYSTEM)
+ CCP5_CMD_LEN(&desc) = saddr->length;
+ else
+ CCP5_CMD_LEN(&desc) = daddr->length;
+
+ if (op->src.type == CCP_MEMTYPE_SYSTEM) {
+ CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
+ CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
+ CCP5_CMD_LSB_ID(&desc) = op->sb_key;
+ } else {
+ u32 key_addr = op->src.u.sb * CCP_SB_BYTES;
+
+ CCP5_CMD_SRC_LO(&desc) = lower_32_bits(key_addr);
+ CCP5_CMD_SRC_HI(&desc) = 0;
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SB;
+ }
+
+ if (op->dst.type == CCP_MEMTYPE_SYSTEM) {
+ CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
+ CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
+ CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+ } else {
+ u32 key_addr = op->dst.u.sb * CCP_SB_BYTES;
+
+ CCP5_CMD_DST_LO(&desc) = lower_32_bits(key_addr);
+ CCP5_CMD_DST_HI(&desc) = 0;
+ CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SB;
+ }
+
+ return ccp5_do_cmd(&desc, op->cmd_q);
+}
+
+static int ccp5_perform_ecc(struct ccp_op *op)
+{
+ struct ccp5_desc desc;
+ union ccp_function function;
+
+ /* Zero out all the fields of the command desc */
+ memset(&desc, 0, Q_DESC_SIZE);
+
+ CCP5_CMD_ENGINE(&desc) = CCP_ENGINE_ECC;
+
+ CCP5_CMD_SOC(&desc) = 0;
+ CCP5_CMD_IOC(&desc) = 1;
+ CCP5_CMD_INIT(&desc) = 0;
+ CCP5_CMD_EOM(&desc) = 1;
+ CCP5_CMD_PROT(&desc) = 0;
+
+ function.raw = 0;
+ function.ecc.mode = op->u.ecc.function;
+ CCP5_CMD_FUNCTION(&desc) = function.raw;
+
+ CCP5_CMD_LEN(&desc) = op->src.u.dma.length;
+
+ CCP5_CMD_SRC_LO(&desc) = ccp_addr_lo(&op->src.u.dma);
+ CCP5_CMD_SRC_HI(&desc) = ccp_addr_hi(&op->src.u.dma);
+ CCP5_CMD_SRC_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ CCP5_CMD_DST_LO(&desc) = ccp_addr_lo(&op->dst.u.dma);
+ CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma);
+ CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM;
+
+ return ccp5_do_cmd(&desc, op->cmd_q);
+}
+
+static int ccp_find_lsb_regions(struct ccp_cmd_queue *cmd_q, u64 status)
+{
+ int q_mask = 1 << cmd_q->id;
+ int queues = 0;
+ int j;
+
+ /* Build a bit mask to know which LSBs this queue has access to.
+ * Don't bother with segment 0 as it has special privileges.
+ */
+ for (j = 1; j < MAX_LSB_CNT; j++) {
+ if (status & q_mask)
+ bitmap_set(cmd_q->lsbmask, j, 1);
+ status >>= LSB_REGION_WIDTH;
+ }
+ queues = bitmap_weight(cmd_q->lsbmask, MAX_LSB_CNT);
+ dev_info(cmd_q->ccp->dev, "Queue %d can access %d LSB regions\n",
+ cmd_q->id, queues);
+
+ return queues ? 0 : -EINVAL;
+}
+
+
+static int ccp_find_and_assign_lsb_to_q(struct ccp_device *ccp,
+ int lsb_cnt, int n_lsbs,
+ unsigned long *lsb_pub)
+{
+ DECLARE_BITMAP(qlsb, MAX_LSB_CNT);
+ int bitno;
+ int qlsb_wgt;
+ int i;
+
+ /* For each queue:
+ * If the count of potential LSBs available to a queue matches the
+ * ordinal given to us in lsb_cnt:
+ * Copy the mask of possible LSBs for this queue into "qlsb";
+ * For each bit in qlsb, see if the corresponding bit in the
+ * aggregation mask is set; if so, we have a match.
+ * If we have a match, clear the bit in the aggregation to
+ * mark it as no longer available.
+ * If there is no match, clear the bit in qlsb and keep looking.
+ */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
+
+ qlsb_wgt = bitmap_weight(cmd_q->lsbmask, MAX_LSB_CNT);
+
+ if (qlsb_wgt == lsb_cnt) {
+ bitmap_copy(qlsb, cmd_q->lsbmask, MAX_LSB_CNT);
+
+ bitno = find_first_bit(qlsb, MAX_LSB_CNT);
+ while (bitno < MAX_LSB_CNT) {
+ if (test_bit(bitno, lsb_pub)) {
+ /* We found an available LSB
+ * that this queue can access
+ */
+ cmd_q->lsb = bitno;
+ bitmap_clear(lsb_pub, bitno, 1);
+ dev_info(ccp->dev,
+ "Queue %d gets LSB %d\n",
+ i, bitno);
+ break;
+ }
+ bitmap_clear(qlsb, bitno, 1);
+ bitno = find_first_bit(qlsb, MAX_LSB_CNT);
+ }
+ if (bitno >= MAX_LSB_CNT)
+ return -EINVAL;
+ n_lsbs--;
+ }
+ }
+ return n_lsbs;
+}
+
+/* For each queue, from the most- to least-constrained:
+ * find an LSB that can be assigned to the queue. If there are N queues that
+ * can only use M LSBs, where N > M, fail; otherwise, every queue will get a
+ * dedicated LSB. Remaining LSB regions become a shared resource.
+ * If we have fewer LSBs than queues, all LSB regions become shared resources.
+ */
+static int ccp_assign_lsbs(struct ccp_device *ccp)
+{
+ DECLARE_BITMAP(lsb_pub, MAX_LSB_CNT);
+ DECLARE_BITMAP(qlsb, MAX_LSB_CNT);
+ int n_lsbs = 0;
+ int bitno;
+ int i, lsb_cnt;
+ int rc = 0;
+
+ bitmap_zero(lsb_pub, MAX_LSB_CNT);
+
+ /* Create an aggregate bitmap to get a total count of available LSBs */
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ bitmap_or(lsb_pub,
+ lsb_pub, ccp->cmd_q[i].lsbmask,
+ MAX_LSB_CNT);
+
+ n_lsbs = bitmap_weight(lsb_pub, MAX_LSB_CNT);
+
+ if (n_lsbs >= ccp->cmd_q_count) {
+ /* We have enough LSBS to give every queue a private LSB.
+ * Brute force search to start with the queues that are more
+ * constrained in LSB choice. When an LSB is privately
+ * assigned, it is removed from the public mask.
+ * This is an ugly N squared algorithm with some optimization.
+ */
+ for (lsb_cnt = 1;
+ n_lsbs && (lsb_cnt <= MAX_LSB_CNT);
+ lsb_cnt++) {
+ rc = ccp_find_and_assign_lsb_to_q(ccp, lsb_cnt, n_lsbs,
+ lsb_pub);
+ if (rc < 0)
+ return -EINVAL;
+ n_lsbs = rc;
+ }
+ }
+
+ rc = 0;
+ /* What's left of the LSBs, according to the public mask, now become
+ * shared. Any zero bits in the lsb_pub mask represent an LSB region
+ * that can't be used as a shared resource, so mark the LSB slots for
+ * them as "in use".
+ */
+ bitmap_copy(qlsb, lsb_pub, MAX_LSB_CNT);
+
+ bitno = find_first_zero_bit(qlsb, MAX_LSB_CNT);
+ while (bitno < MAX_LSB_CNT) {
+ bitmap_set(ccp->lsbmap, bitno * LSB_SIZE, LSB_SIZE);
+ bitmap_set(qlsb, bitno, 1);
+ bitno = find_first_zero_bit(qlsb, MAX_LSB_CNT);
+ }
+
+ return rc;
+}
+
+static int ccp5_init(struct ccp_device *ccp)
+{
+ struct device *dev = ccp->dev;
+ struct ccp_cmd_queue *cmd_q;
+ struct dma_pool *dma_pool;
+ char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
+ unsigned int qmr, qim, i;
+ u64 status;
+ u32 status_lo, status_hi;
+ int ret;
+
+ /* Find available queues */
+ qim = 0;
+ qmr = ioread32(ccp->io_regs + Q_MASK_REG);
+ for (i = 0; i < MAX_HW_QUEUES; i++) {
+
+ if (!(qmr & (1 << i)))
+ continue;
+
+ /* Allocate a dma pool for this queue */
+ snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
+ ccp->name, i);
+ dma_pool = dma_pool_create(dma_pool_name, dev,
+ CCP_DMAPOOL_MAX_SIZE,
+ CCP_DMAPOOL_ALIGN, 0);
+ if (!dma_pool) {
+ dev_err(dev, "unable to allocate dma pool\n");
+ ret = -ENOMEM;
+ }
+
+ cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
+ ccp->cmd_q_count++;
+
+ cmd_q->ccp = ccp;
+ cmd_q->id = i;
+ cmd_q->dma_pool = dma_pool;
+ mutex_init(&cmd_q->q_mutex);
+
+ /* Page alignment satisfies our needs for N <= 128 */
+ BUILD_BUG_ON(COMMANDS_PER_QUEUE > 128);
+ cmd_q->qsize = Q_SIZE(Q_DESC_SIZE);
+ cmd_q->qbase = dma_zalloc_coherent(dev, cmd_q->qsize,
+ &cmd_q->qbase_dma,
+ GFP_KERNEL);
+ if (!cmd_q->qbase) {
+ dev_err(dev, "unable to allocate command queue\n");
+ ret = -ENOMEM;
+ goto e_pool;
+ }
+
+ cmd_q->qidx = 0;
+ /* Preset some register values and masks that are queue
+ * number dependent
+ */
+ cmd_q->reg_control = ccp->io_regs +
+ CMD5_Q_STATUS_INCR * (i + 1);
+ cmd_q->reg_tail_lo = cmd_q->reg_control + CMD5_Q_TAIL_LO_BASE;
+ cmd_q->reg_head_lo = cmd_q->reg_control + CMD5_Q_HEAD_LO_BASE;
+ cmd_q->reg_int_enable = cmd_q->reg_control +
+ CMD5_Q_INT_ENABLE_BASE;
+ cmd_q->reg_interrupt_status = cmd_q->reg_control +
+ CMD5_Q_INTERRUPT_STATUS_BASE;
+ cmd_q->reg_status = cmd_q->reg_control + CMD5_Q_STATUS_BASE;
+ cmd_q->reg_int_status = cmd_q->reg_control +
+ CMD5_Q_INT_STATUS_BASE;
+ cmd_q->reg_dma_status = cmd_q->reg_control +
+ CMD5_Q_DMA_STATUS_BASE;
+ cmd_q->reg_dma_read_status = cmd_q->reg_control +
+ CMD5_Q_DMA_READ_STATUS_BASE;
+ cmd_q->reg_dma_write_status = cmd_q->reg_control +
+ CMD5_Q_DMA_WRITE_STATUS_BASE;
+
+ init_waitqueue_head(&cmd_q->int_queue);
+
+ dev_dbg(dev, "queue #%u available\n", i);
+ }
+ if (ccp->cmd_q_count == 0) {
+ dev_notice(dev, "no command queues available\n");
+ ret = -EIO;
+ goto e_pool;
+ }
+ dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
+
+ /* Turn off the queues and disable interrupts until ready */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+
+ cmd_q->qcontrol = 0; /* Start with nothing */
+ iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
+
+ /* Disable the interrupts */
+ iowrite32(0x00, cmd_q->reg_int_enable);
+ ioread32(cmd_q->reg_int_status);
+ ioread32(cmd_q->reg_status);
+
+ /* Clear the interrupts */
+ iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status);
+ }
+
+ dev_dbg(dev, "Requesting an IRQ...\n");
+ /* Request an irq */
+ ret = ccp->get_irq(ccp);
+ if (ret) {
+ dev_err(dev, "unable to allocate an IRQ\n");
+ goto e_pool;
+ }
+
+ /* Initialize the queue used to suspend */
+ init_waitqueue_head(&ccp->suspend_queue);
+
+ dev_dbg(dev, "Loading LSB map...\n");
+ /* Copy the private LSB mask to the public registers */
+ status_lo = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_LO_OFFSET);
+ status_hi = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_HI_OFFSET);
+ iowrite32(status_lo, ccp->io_regs + LSB_PUBLIC_MASK_LO_OFFSET);
+ iowrite32(status_hi, ccp->io_regs + LSB_PUBLIC_MASK_HI_OFFSET);
+ status = ((u64)status_hi<<30) | (u64)status_lo;
+
+ dev_dbg(dev, "Configuring virtual queues...\n");
+ /* Configure size of each virtual queue accessible to host */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ u32 dma_addr_lo;
+ u32 dma_addr_hi;
+
+ cmd_q = &ccp->cmd_q[i];
+
+ cmd_q->qcontrol &= ~(CMD5_Q_SIZE << CMD5_Q_SHIFT);
+ cmd_q->qcontrol |= QUEUE_SIZE_VAL << CMD5_Q_SHIFT;
+
+ cmd_q->qdma_tail = cmd_q->qbase_dma;
+ dma_addr_lo = low_address(cmd_q->qdma_tail);
+ iowrite32((u32)dma_addr_lo, cmd_q->reg_tail_lo);
+ iowrite32((u32)dma_addr_lo, cmd_q->reg_head_lo);
+
+ dma_addr_hi = high_address(cmd_q->qdma_tail);
+ cmd_q->qcontrol |= (dma_addr_hi << 16);
+ iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
+
+ /* Find the LSB regions accessible to the queue */
+ ccp_find_lsb_regions(cmd_q, status);
+ cmd_q->lsb = -1; /* Unassigned value */
+ }
+
+ dev_dbg(dev, "Assigning LSBs...\n");
+ ret = ccp_assign_lsbs(ccp);
+ if (ret) {
+ dev_err(dev, "Unable to assign LSBs (%d)\n", ret);
+ goto e_irq;
+ }
+
+ /* Optimization: pre-allocate LSB slots for each queue */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ ccp->cmd_q[i].sb_key = ccp_lsb_alloc(&ccp->cmd_q[i], 2);
+ ccp->cmd_q[i].sb_ctx = ccp_lsb_alloc(&ccp->cmd_q[i], 2);
+ }
+
+ dev_dbg(dev, "Starting threads...\n");
+ /* Create a kthread for each queue */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ struct task_struct *kthread;
+
+ cmd_q = &ccp->cmd_q[i];
+
+ kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
+ "%s-q%u", ccp->name, cmd_q->id);
+ if (IS_ERR(kthread)) {
+ dev_err(dev, "error creating queue thread (%ld)\n",
+ PTR_ERR(kthread));
+ ret = PTR_ERR(kthread);
+ goto e_kthread;
+ }
+
+ cmd_q->kthread = kthread;
+ wake_up_process(kthread);
+ }
+
+ dev_dbg(dev, "Enabling interrupts...\n");
+ /* Enable interrupts */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+ iowrite32(ALL_INTERRUPTS, cmd_q->reg_int_enable);
+ }
+
+ dev_dbg(dev, "Registering device...\n");
+ /* Put this on the unit list to make it available */
+ ccp_add_device(ccp);
+
+ ret = ccp_register_rng(ccp);
+ if (ret)
+ goto e_kthread;
+
+ /* Register the DMA engine support */
+ ret = ccp_dmaengine_register(ccp);
+ if (ret)
+ goto e_hwrng;
+
+ return 0;
+
+e_hwrng:
+ ccp_unregister_rng(ccp);
+
+e_kthread:
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ if (ccp->cmd_q[i].kthread)
+ kthread_stop(ccp->cmd_q[i].kthread);
+
+e_irq:
+ ccp->free_irq(ccp);
+
+e_pool:
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ dma_pool_destroy(ccp->cmd_q[i].dma_pool);
+
+ return ret;
+}
+
+static void ccp5_destroy(struct ccp_device *ccp)
+{
+ struct device *dev = ccp->dev;
+ struct ccp_cmd_queue *cmd_q;
+ struct ccp_cmd *cmd;
+ unsigned int i;
+
+ /* Unregister the DMA engine */
+ ccp_dmaengine_unregister(ccp);
+
+ /* Unregister the RNG */
+ ccp_unregister_rng(ccp);
+
+ /* Remove this device from the list of available units first */
+ ccp_del_device(ccp);
+
+ /* Disable and clear interrupts */
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+
+ /* Turn off the run bit */
+ iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control);
+
+ /* Disable the interrupts */
+ iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status);
+
+ /* Clear the interrupt status */
+ iowrite32(0x00, cmd_q->reg_int_enable);
+ ioread32(cmd_q->reg_int_status);
+ ioread32(cmd_q->reg_status);
+ }
+
+ /* Stop the queue kthreads */
+ for (i = 0; i < ccp->cmd_q_count; i++)
+ if (ccp->cmd_q[i].kthread)
+ kthread_stop(ccp->cmd_q[i].kthread);
+
+ ccp->free_irq(ccp);
+
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ cmd_q = &ccp->cmd_q[i];
+ dma_free_coherent(dev, cmd_q->qsize, cmd_q->qbase,
+ cmd_q->qbase_dma);
+ }
+
+ /* Flush the cmd and backlog queue */
+ while (!list_empty(&ccp->cmd)) {
+ /* Invoke the callback directly with an error code */
+ cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
+ list_del(&cmd->entry);
+ cmd->callback(cmd->data, -ENODEV);
+ }
+ while (!list_empty(&ccp->backlog)) {
+ /* Invoke the callback directly with an error code */
+ cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
+ list_del(&cmd->entry);
+ cmd->callback(cmd->data, -ENODEV);
+ }
+}
+
+static irqreturn_t ccp5_irq_handler(int irq, void *data)
+{
+ struct device *dev = data;
+ struct ccp_device *ccp = dev_get_drvdata(dev);
+ u32 status;
+ unsigned int i;
+
+ for (i = 0; i < ccp->cmd_q_count; i++) {
+ struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
+
+ status = ioread32(cmd_q->reg_interrupt_status);
+
+ if (status) {
+ cmd_q->int_status = status;
+ cmd_q->q_status = ioread32(cmd_q->reg_status);
+ cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
+
+ /* On error, only save the first error value */
+ if ((status & INT_ERROR) && !cmd_q->cmd_error)
+ cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
+
+ cmd_q->int_rcvd = 1;
+
+ /* Acknowledge the interrupt and wake the kthread */
+ iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status);
+ wake_up_interruptible(&cmd_q->int_queue);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void ccp5_config(struct ccp_device *ccp)
+{
+ /* Public side */
+ iowrite32(0x00001249, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET);
+}
+
+static void ccp5other_config(struct ccp_device *ccp)
+{
+ int i;
+ u32 rnd;
+
+ /* We own all of the queues on the NTB CCP */
+
+ iowrite32(0x00012D57, ccp->io_regs + CMD5_TRNG_CTL_OFFSET);
+ iowrite32(0x00000003, ccp->io_regs + CMD5_CONFIG_0_OFFSET);
+ for (i = 0; i < 12; i++) {
+ rnd = ioread32(ccp->io_regs + TRNG_OUT_REG);
+ iowrite32(rnd, ccp->io_regs + CMD5_AES_MASK_OFFSET);
+ }
+
+ iowrite32(0x0000001F, ccp->io_regs + CMD5_QUEUE_MASK_OFFSET);
+ iowrite32(0x00005B6D, ccp->io_regs + CMD5_QUEUE_PRIO_OFFSET);
+ iowrite32(0x00000000, ccp->io_regs + CMD5_CMD_TIMEOUT_OFFSET);
+
+ iowrite32(0x3FFFFFFF, ccp->io_regs + LSB_PRIVATE_MASK_LO_OFFSET);
+ iowrite32(0x000003FF, ccp->io_regs + LSB_PRIVATE_MASK_HI_OFFSET);
+
+ iowrite32(0x00108823, ccp->io_regs + CMD5_CLK_GATE_CTL_OFFSET);
+
+ ccp5_config(ccp);
+}
+
+/* Version 5 adds some function, but is essentially the same as v5 */
+static const struct ccp_actions ccp5_actions = {
+ .aes = ccp5_perform_aes,
+ .xts_aes = ccp5_perform_xts_aes,
+ .sha = ccp5_perform_sha,
+ .rsa = ccp5_perform_rsa,
+ .passthru = ccp5_perform_passthru,
+ .ecc = ccp5_perform_ecc,
+ .sballoc = ccp_lsb_alloc,
+ .sbfree = ccp_lsb_free,
+ .init = ccp5_init,
+ .destroy = ccp5_destroy,
+ .get_free_slots = ccp5_get_free_slots,
+ .irqhandler = ccp5_irq_handler,
+};
+
+const struct ccp_vdata ccpv5a = {
+ .version = CCP_VERSION(5, 0),
+ .setup = ccp5_config,
+ .perform = &ccp5_actions,
+ .bar = 2,
+ .offset = 0x0,
+};
+
+const struct ccp_vdata ccpv5b = {
+ .version = CCP_VERSION(5, 0),
+ .setup = ccp5other_config,
+ .perform = &ccp5_actions,
+ .bar = 2,
+ .offset = 0x0,
+};
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index 87b9f2bfa623..cafa633aae10 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -4,6 +4,7 @@
* Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.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
@@ -39,6 +40,59 @@ struct ccp_tasklet_data {
struct ccp_cmd *cmd;
};
+/* Human-readable error strings */
+char *ccp_error_codes[] = {
+ "",
+ "ERR 01: ILLEGAL_ENGINE",
+ "ERR 02: ILLEGAL_KEY_ID",
+ "ERR 03: ILLEGAL_FUNCTION_TYPE",
+ "ERR 04: ILLEGAL_FUNCTION_MODE",
+ "ERR 05: ILLEGAL_FUNCTION_ENCRYPT",
+ "ERR 06: ILLEGAL_FUNCTION_SIZE",
+ "ERR 07: Zlib_MISSING_INIT_EOM",
+ "ERR 08: ILLEGAL_FUNCTION_RSVD",
+ "ERR 09: ILLEGAL_BUFFER_LENGTH",
+ "ERR 10: VLSB_FAULT",
+ "ERR 11: ILLEGAL_MEM_ADDR",
+ "ERR 12: ILLEGAL_MEM_SEL",
+ "ERR 13: ILLEGAL_CONTEXT_ID",
+ "ERR 14: ILLEGAL_KEY_ADDR",
+ "ERR 15: 0xF Reserved",
+ "ERR 16: Zlib_ILLEGAL_MULTI_QUEUE",
+ "ERR 17: Zlib_ILLEGAL_JOBID_CHANGE",
+ "ERR 18: CMD_TIMEOUT",
+ "ERR 19: IDMA0_AXI_SLVERR",
+ "ERR 20: IDMA0_AXI_DECERR",
+ "ERR 21: 0x15 Reserved",
+ "ERR 22: IDMA1_AXI_SLAVE_FAULT",
+ "ERR 23: IDMA1_AIXI_DECERR",
+ "ERR 24: 0x18 Reserved",
+ "ERR 25: ZLIBVHB_AXI_SLVERR",
+ "ERR 26: ZLIBVHB_AXI_DECERR",
+ "ERR 27: 0x1B Reserved",
+ "ERR 27: ZLIB_UNEXPECTED_EOM",
+ "ERR 27: ZLIB_EXTRA_DATA",
+ "ERR 30: ZLIB_BTYPE",
+ "ERR 31: ZLIB_UNDEFINED_SYMBOL",
+ "ERR 32: ZLIB_UNDEFINED_DISTANCE_S",
+ "ERR 33: ZLIB_CODE_LENGTH_SYMBOL",
+ "ERR 34: ZLIB _VHB_ILLEGAL_FETCH",
+ "ERR 35: ZLIB_UNCOMPRESSED_LEN",
+ "ERR 36: ZLIB_LIMIT_REACHED",
+ "ERR 37: ZLIB_CHECKSUM_MISMATCH0",
+ "ERR 38: ODMA0_AXI_SLVERR",
+ "ERR 39: ODMA0_AXI_DECERR",
+ "ERR 40: 0x28 Reserved",
+ "ERR 41: ODMA1_AXI_SLVERR",
+ "ERR 42: ODMA1_AXI_DECERR",
+ "ERR 43: LSB_PARITY_ERR",
+};
+
+void ccp_log_error(struct ccp_device *d, int e)
+{
+ dev_err(d->dev, "CCP error: %s (0x%x)\n", ccp_error_codes[e], e);
+}
+
/* List of CCPs, CCP count, read-write access lock, and access functions
*
* Lock structure: get ccp_unit_lock for reading whenever we need to
@@ -58,7 +112,7 @@ static struct ccp_device *ccp_rr;
/* Ever-increasing value to produce unique unit numbers */
static atomic_t ccp_unit_ordinal;
-unsigned int ccp_increment_unit_ordinal(void)
+static unsigned int ccp_increment_unit_ordinal(void)
{
return atomic_inc_return(&ccp_unit_ordinal);
}
@@ -118,6 +172,29 @@ void ccp_del_device(struct ccp_device *ccp)
write_unlock_irqrestore(&ccp_unit_lock, flags);
}
+
+
+int ccp_register_rng(struct ccp_device *ccp)
+{
+ int ret = 0;
+
+ dev_dbg(ccp->dev, "Registering RNG...\n");
+ /* Register an RNG */
+ ccp->hwrng.name = ccp->rngname;
+ ccp->hwrng.read = ccp_trng_read;
+ ret = hwrng_register(&ccp->hwrng);
+ if (ret)
+ dev_err(ccp->dev, "error registering hwrng (%d)\n", ret);
+
+ return ret;
+}
+
+void ccp_unregister_rng(struct ccp_device *ccp)
+{
+ if (ccp->hwrng.name)
+ hwrng_unregister(&ccp->hwrng);
+}
+
static struct ccp_device *ccp_get_device(void)
{
unsigned long flags;
@@ -397,9 +474,9 @@ struct ccp_device *ccp_alloc_struct(struct device *dev)
spin_lock_init(&ccp->cmd_lock);
mutex_init(&ccp->req_mutex);
- mutex_init(&ccp->ksb_mutex);
- ccp->ksb_count = KSB_COUNT;
- ccp->ksb_start = 0;
+ mutex_init(&ccp->sb_mutex);
+ ccp->sb_count = KSB_COUNT;
+ ccp->sb_start = 0;
ccp->ord = ccp_increment_unit_ordinal();
snprintf(ccp->name, MAX_CCP_NAME_LEN, "ccp-%u", ccp->ord);
@@ -408,6 +485,34 @@ struct ccp_device *ccp_alloc_struct(struct device *dev)
return ccp;
}
+int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng);
+ u32 trng_value;
+ int len = min_t(int, sizeof(trng_value), max);
+
+ /* Locking is provided by the caller so we can update device
+ * hwrng-related fields safely
+ */
+ trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG);
+ if (!trng_value) {
+ /* Zero is returned if not data is available or if a
+ * bad-entropy error is present. Assume an error if
+ * we exceed TRNG_RETRIES reads of zero.
+ */
+ if (ccp->hwrng_retries++ > TRNG_RETRIES)
+ return -EIO;
+
+ return 0;
+ }
+
+ /* Reset the counter and save the rng value */
+ ccp->hwrng_retries = 0;
+ memcpy(data, &trng_value, len);
+
+ return len;
+}
+
#ifdef CONFIG_PM
bool ccp_queues_suspended(struct ccp_device *ccp)
{
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index bd41ffceff82..da5f4a678083 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -4,6 +4,7 @@
* Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.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
@@ -60,7 +61,69 @@
#define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f)
#define CMD_Q_DEPTH(__qs) (((__qs) >> 12) & 0x0000000f)
-/****** REQ0 Related Values ******/
+/* ------------------------ CCP Version 5 Specifics ------------------------ */
+#define CMD5_QUEUE_MASK_OFFSET 0x00
+#define CMD5_QUEUE_PRIO_OFFSET 0x04
+#define CMD5_REQID_CONFIG_OFFSET 0x08
+#define CMD5_CMD_TIMEOUT_OFFSET 0x10
+#define LSB_PUBLIC_MASK_LO_OFFSET 0x18
+#define LSB_PUBLIC_MASK_HI_OFFSET 0x1C
+#define LSB_PRIVATE_MASK_LO_OFFSET 0x20
+#define LSB_PRIVATE_MASK_HI_OFFSET 0x24
+
+#define CMD5_Q_CONTROL_BASE 0x0000
+#define CMD5_Q_TAIL_LO_BASE 0x0004
+#define CMD5_Q_HEAD_LO_BASE 0x0008
+#define CMD5_Q_INT_ENABLE_BASE 0x000C
+#define CMD5_Q_INTERRUPT_STATUS_BASE 0x0010
+
+#define CMD5_Q_STATUS_BASE 0x0100
+#define CMD5_Q_INT_STATUS_BASE 0x0104
+#define CMD5_Q_DMA_STATUS_BASE 0x0108
+#define CMD5_Q_DMA_READ_STATUS_BASE 0x010C
+#define CMD5_Q_DMA_WRITE_STATUS_BASE 0x0110
+#define CMD5_Q_ABORT_BASE 0x0114
+#define CMD5_Q_AX_CACHE_BASE 0x0118
+
+#define CMD5_CONFIG_0_OFFSET 0x6000
+#define CMD5_TRNG_CTL_OFFSET 0x6008
+#define CMD5_AES_MASK_OFFSET 0x6010
+#define CMD5_CLK_GATE_CTL_OFFSET 0x603C
+
+/* Address offset between two virtual queue registers */
+#define CMD5_Q_STATUS_INCR 0x1000
+
+/* Bit masks */
+#define CMD5_Q_RUN 0x1
+#define CMD5_Q_HALT 0x2
+#define CMD5_Q_MEM_LOCATION 0x4
+#define CMD5_Q_SIZE 0x1F
+#define CMD5_Q_SHIFT 3
+#define COMMANDS_PER_QUEUE 16
+#define QUEUE_SIZE_VAL ((ffs(COMMANDS_PER_QUEUE) - 2) & \
+ CMD5_Q_SIZE)
+#define Q_PTR_MASK (2 << (QUEUE_SIZE_VAL + 5) - 1)
+#define Q_DESC_SIZE sizeof(struct ccp5_desc)
+#define Q_SIZE(n) (COMMANDS_PER_QUEUE*(n))
+
+#define INT_COMPLETION 0x1
+#define INT_ERROR 0x2
+#define INT_QUEUE_STOPPED 0x4
+#define ALL_INTERRUPTS (INT_COMPLETION| \
+ INT_ERROR| \
+ INT_QUEUE_STOPPED)
+
+#define LSB_REGION_WIDTH 5
+#define MAX_LSB_CNT 8
+
+#define LSB_SIZE 16
+#define LSB_ITEM_SIZE 32
+#define PLSB_MAP_SIZE (LSB_SIZE)
+#define SLSB_MAP_SIZE (MAX_LSB_CNT * LSB_SIZE)
+
+#define LSB_ENTRY_NUMBER(LSB_ADDR) (LSB_ADDR / LSB_ITEM_SIZE)
+
+/* ------------------------ CCP Version 3 Specifics ------------------------ */
#define REQ0_WAIT_FOR_WRITE 0x00000004
#define REQ0_INT_ON_COMPLETE 0x00000002
#define REQ0_STOP_ON_COMPLETE 0x00000001
@@ -110,29 +173,30 @@
#define KSB_START 77
#define KSB_END 127
#define KSB_COUNT (KSB_END - KSB_START + 1)
-#define CCP_KSB_BITS 256
-#define CCP_KSB_BYTES 32
+#define CCP_SB_BITS 256
#define CCP_JOBID_MASK 0x0000003f
+/* ------------------------ General CCP Defines ------------------------ */
+
#define CCP_DMAPOOL_MAX_SIZE 64
#define CCP_DMAPOOL_ALIGN BIT(5)
#define CCP_REVERSE_BUF_SIZE 64
-#define CCP_AES_KEY_KSB_COUNT 1
-#define CCP_AES_CTX_KSB_COUNT 1
+#define CCP_AES_KEY_SB_COUNT 1
+#define CCP_AES_CTX_SB_COUNT 1
-#define CCP_XTS_AES_KEY_KSB_COUNT 1
-#define CCP_XTS_AES_CTX_KSB_COUNT 1
+#define CCP_XTS_AES_KEY_SB_COUNT 1
+#define CCP_XTS_AES_CTX_SB_COUNT 1
-#define CCP_SHA_KSB_COUNT 1
+#define CCP_SHA_SB_COUNT 1
#define CCP_RSA_MAX_WIDTH 4096
#define CCP_PASSTHRU_BLOCKSIZE 256
#define CCP_PASSTHRU_MASKSIZE 32
-#define CCP_PASSTHRU_KSB_COUNT 1
+#define CCP_PASSTHRU_SB_COUNT 1
#define CCP_ECC_MODULUS_BYTES 48 /* 384-bits */
#define CCP_ECC_MAX_OPERANDS 6
@@ -144,31 +208,12 @@
#define CCP_ECC_RESULT_OFFSET 60
#define CCP_ECC_RESULT_SUCCESS 0x0001
-struct ccp_op;
-
-/* Structure for computation functions that are device-specific */
-struct ccp_actions {
- int (*perform_aes)(struct ccp_op *);
- int (*perform_xts_aes)(struct ccp_op *);
- int (*perform_sha)(struct ccp_op *);
- int (*perform_rsa)(struct ccp_op *);
- int (*perform_passthru)(struct ccp_op *);
- int (*perform_ecc)(struct ccp_op *);
- int (*init)(struct ccp_device *);
- void (*destroy)(struct ccp_device *);
- irqreturn_t (*irqhandler)(int, void *);
-};
-
-/* Structure to hold CCP version-specific values */
-struct ccp_vdata {
- unsigned int version;
- const struct ccp_actions *perform;
-};
-
-extern struct ccp_vdata ccpv3;
+#define CCP_SB_BYTES 32
+struct ccp_op;
struct ccp_device;
struct ccp_cmd;
+struct ccp_fns;
struct ccp_dma_cmd {
struct list_head entry;
@@ -212,9 +257,29 @@ struct ccp_cmd_queue {
/* Queue dma pool */
struct dma_pool *dma_pool;
- /* Queue reserved KSB regions */
- u32 ksb_key;
- u32 ksb_ctx;
+ /* Queue base address (not neccessarily aligned)*/
+ struct ccp5_desc *qbase;
+
+ /* Aligned queue start address (per requirement) */
+ struct mutex q_mutex ____cacheline_aligned;
+ unsigned int qidx;
+
+ /* Version 5 has different requirements for queue memory */
+ unsigned int qsize;
+ dma_addr_t qbase_dma;
+ dma_addr_t qdma_tail;
+
+ /* Per-queue reserved storage block(s) */
+ u32 sb_key;
+ u32 sb_ctx;
+
+ /* Bitmap of LSBs that can be accessed by this queue */
+ DECLARE_BITMAP(lsbmask, MAX_LSB_CNT);
+ /* Private LSB that is assigned to this queue, or -1 if none.
+ * Bitmap for my private LSB, unused otherwise
+ */
+ unsigned int lsb;
+ DECLARE_BITMAP(lsbmap, PLSB_MAP_SIZE);
/* Queue processing thread */
struct task_struct *kthread;
@@ -229,8 +294,17 @@ struct ccp_cmd_queue {
u32 int_err;
/* Register addresses for queue */
+ void __iomem *reg_control;
+ void __iomem *reg_tail_lo;
+ void __iomem *reg_head_lo;
+ void __iomem *reg_int_enable;
+ void __iomem *reg_interrupt_status;
void __iomem *reg_status;
void __iomem *reg_int_status;
+ void __iomem *reg_dma_status;
+ void __iomem *reg_dma_read_status;
+ void __iomem *reg_dma_write_status;
+ u32 qcontrol; /* Cached control register */
/* Status values from job */
u32 int_status;
@@ -253,16 +327,14 @@ struct ccp_device {
struct device *dev;
- /*
- * Bus specific device information
+ /* Bus specific device information
*/
void *dev_specific;
int (*get_irq)(struct ccp_device *ccp);
void (*free_irq)(struct ccp_device *ccp);
unsigned int irq;
- /*
- * I/O area used for device communication. The register mapping
+ /* I/O area used for device communication. The register mapping
* starts at an offset into the mapped bar.
* The CMD_REQx registers and the Delete_Cmd_Queue_Job register
* need to be protected while a command queue thread is accessing
@@ -272,8 +344,7 @@ struct ccp_device {
void __iomem *io_map;
void __iomem *io_regs;
- /*
- * Master lists that all cmds are queued on. Because there can be
+ /* Master lists that all cmds are queued on. Because there can be
* more than one CCP command queue that can process a cmd a separate
* backlog list is neeeded so that the backlog completion call
* completes before the cmd is available for execution.
@@ -283,47 +354,54 @@ struct ccp_device {
struct list_head cmd;
struct list_head backlog;
- /*
- * The command queues. These represent the queues available on the
+ /* The command queues. These represent the queues available on the
* CCP that are available for processing cmds
*/
struct ccp_cmd_queue cmd_q[MAX_HW_QUEUES];
unsigned int cmd_q_count;
- /*
- * Support for the CCP True RNG
+ /* Support for the CCP True RNG
*/
struct hwrng hwrng;
unsigned int hwrng_retries;
- /*
- * Support for the CCP DMA capabilities
+ /* Support for the CCP DMA capabilities
*/
struct dma_device dma_dev;
struct ccp_dma_chan *ccp_dma_chan;
struct kmem_cache *dma_cmd_cache;
struct kmem_cache *dma_desc_cache;
- /*
- * A counter used to generate job-ids for cmds submitted to the CCP
+ /* A counter used to generate job-ids for cmds submitted to the CCP
*/
atomic_t current_id ____cacheline_aligned;
- /*
- * The CCP uses key storage blocks (KSB) to maintain context for certain
- * operations. To prevent multiple cmds from using the same KSB range
- * a command queue reserves a KSB range for the duration of the cmd.
- * Each queue, will however, reserve 2 KSB blocks for operations that
- * only require single KSB entries (eg. AES context/iv and key) in order
- * to avoid allocation contention. This will reserve at most 10 KSB
- * entries, leaving 40 KSB entries available for dynamic allocation.
+ /* The v3 CCP uses key storage blocks (SB) to maintain context for
+ * certain operations. To prevent multiple cmds from using the same
+ * SB range a command queue reserves an SB range for the duration of
+ * the cmd. Each queue, will however, reserve 2 SB blocks for
+ * operations that only require single SB entries (eg. AES context/iv
+ * and key) in order to avoid allocation contention. This will reserve
+ * at most 10 SB entries, leaving 40 SB entries available for dynamic
+ * allocation.
+ *
+ * The v5 CCP Local Storage Block (LSB) is broken up into 8
+ * memrory ranges, each of which can be enabled for access by one
+ * or more queues. Device initialization takes this into account,
+ * and attempts to assign one region for exclusive use by each
+ * available queue; the rest are then aggregated as "public" use.
+ * If there are fewer regions than queues, all regions are shared
+ * amongst all queues.
*/
- struct mutex ksb_mutex ____cacheline_aligned;
- DECLARE_BITMAP(ksb, KSB_COUNT);
- wait_queue_head_t ksb_queue;
- unsigned int ksb_avail;
- unsigned int ksb_count;
- u32 ksb_start;
+ struct mutex sb_mutex ____cacheline_aligned;
+ DECLARE_BITMAP(sb, KSB_COUNT);
+ wait_queue_head_t sb_queue;
+ unsigned int sb_avail;
+ unsigned int sb_count;
+ u32 sb_start;
+
+ /* Bitmap of shared LSBs, if any */
+ DECLARE_BITMAP(lsbmap, SLSB_MAP_SIZE);
/* Suspend support */
unsigned int suspending;
@@ -335,10 +413,11 @@ struct ccp_device {
enum ccp_memtype {
CCP_MEMTYPE_SYSTEM = 0,
- CCP_MEMTYPE_KSB,
+ CCP_MEMTYPE_SB,
CCP_MEMTYPE_LOCAL,
CCP_MEMTYPE__LAST,
};
+#define CCP_MEMTYPE_LSB CCP_MEMTYPE_KSB
struct ccp_dma_info {
dma_addr_t address;
@@ -379,7 +458,7 @@ struct ccp_mem {
enum ccp_memtype type;
union {
struct ccp_dma_info dma;
- u32 ksb;
+ u32 sb;
} u;
};
@@ -419,13 +498,14 @@ struct ccp_op {
u32 jobid;
u32 ioc;
u32 soc;
- u32 ksb_key;
- u32 ksb_ctx;
+ u32 sb_key;
+ u32 sb_ctx;
u32 init;
u32 eom;
struct ccp_mem src;
struct ccp_mem dst;
+ struct ccp_mem exp;
union {
struct ccp_aes_op aes;
@@ -435,6 +515,7 @@ struct ccp_op {
struct ccp_passthru_op passthru;
struct ccp_ecc_op ecc;
} u;
+ struct ccp_mem key;
};
static inline u32 ccp_addr_lo(struct ccp_dma_info *info)
@@ -447,6 +528,70 @@ static inline u32 ccp_addr_hi(struct ccp_dma_info *info)
return upper_32_bits(info->address + info->offset) & 0x0000ffff;
}
+/**
+ * descriptor for version 5 CPP commands
+ * 8 32-bit words:
+ * word 0: function; engine; control bits
+ * word 1: length of source data
+ * word 2: low 32 bits of source pointer
+ * word 3: upper 16 bits of source pointer; source memory type
+ * word 4: low 32 bits of destination pointer
+ * word 5: upper 16 bits of destination pointer; destination memory type
+ * word 6: low 32 bits of key pointer
+ * word 7: upper 16 bits of key pointer; key memory type
+ */
+struct dword0 {
+ __le32 soc:1;
+ __le32 ioc:1;
+ __le32 rsvd1:1;
+ __le32 init:1;
+ __le32 eom:1; /* AES/SHA only */
+ __le32 function:15;
+ __le32 engine:4;
+ __le32 prot:1;
+ __le32 rsvd2:7;
+};
+
+struct dword3 {
+ __le32 src_hi:16;
+ __le32 src_mem:2;
+ __le32 lsb_cxt_id:8;
+ __le32 rsvd1:5;
+ __le32 fixed:1;
+};
+
+union dword4 {
+ __le32 dst_lo; /* NON-SHA */
+ __le32 sha_len_lo; /* SHA */
+};
+
+union dword5 {
+ struct {
+ __le32 dst_hi:16;
+ __le32 dst_mem:2;
+ __le32 rsvd1:13;
+ __le32 fixed:1;
+ } fields;
+ __le32 sha_len_hi;
+};
+
+struct dword7 {
+ __le32 key_hi:16;
+ __le32 key_mem:2;
+ __le32 rsvd1:14;
+};
+
+struct ccp5_desc {
+ struct dword0 dw0;
+ __le32 length;
+ __le32 src_lo;
+ struct dword3 dw3;
+ union dword4 dw4;
+ union dword5 dw5;
+ __le32 key_lo;
+ struct dword7 dw7;
+};
+
int ccp_pci_init(void);
void ccp_pci_exit(void);
@@ -456,13 +601,48 @@ void ccp_platform_exit(void);
void ccp_add_device(struct ccp_device *ccp);
void ccp_del_device(struct ccp_device *ccp);
+extern void ccp_log_error(struct ccp_device *, int);
+
struct ccp_device *ccp_alloc_struct(struct device *dev);
bool ccp_queues_suspended(struct ccp_device *ccp);
int ccp_cmd_queue_thread(void *data);
+int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait);
int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd);
+int ccp_register_rng(struct ccp_device *ccp);
+void ccp_unregister_rng(struct ccp_device *ccp);
int ccp_dmaengine_register(struct ccp_device *ccp);
void ccp_dmaengine_unregister(struct ccp_device *ccp);
+/* Structure for computation functions that are device-specific */
+struct ccp_actions {
+ int (*aes)(struct ccp_op *);
+ int (*xts_aes)(struct ccp_op *);
+ int (*sha)(struct ccp_op *);
+ int (*rsa)(struct ccp_op *);
+ int (*passthru)(struct ccp_op *);
+ int (*ecc)(struct ccp_op *);
+ u32 (*sballoc)(struct ccp_cmd_queue *, unsigned int);
+ void (*sbfree)(struct ccp_cmd_queue *, unsigned int,
+ unsigned int);
+ unsigned int (*get_free_slots)(struct ccp_cmd_queue *);
+ int (*init)(struct ccp_device *);
+ void (*destroy)(struct ccp_device *);
+ irqreturn_t (*irqhandler)(int, void *);
+};
+
+/* Structure to hold CCP version-specific values */
+struct ccp_vdata {
+ const unsigned int version;
+ void (*setup)(struct ccp_device *);
+ const struct ccp_actions *perform;
+ const unsigned int bar;
+ const unsigned int offset;
+};
+
+extern const struct ccp_vdata ccpv3;
+extern const struct ccp_vdata ccpv5a;
+extern const struct ccp_vdata ccpv5b;
+
#endif
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index 94f77b0f9ae7..6553912804f7 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -299,12 +299,10 @@ static struct ccp_dma_desc *ccp_alloc_dma_desc(struct ccp_dma_chan *chan,
{
struct ccp_dma_desc *desc;
- desc = kmem_cache_alloc(chan->ccp->dma_desc_cache, GFP_NOWAIT);
+ desc = kmem_cache_zalloc(chan->ccp->dma_desc_cache, GFP_NOWAIT);
if (!desc)
return NULL;
- memset(desc, 0, sizeof(*desc));
-
dma_async_tx_descriptor_init(&desc->tx_desc, &chan->dma_chan);
desc->tx_desc.flags = flags;
desc->tx_desc.tx_submit = ccp_tx_submit;
@@ -650,8 +648,11 @@ int ccp_dmaengine_register(struct ccp_device *ccp)
dma_desc_cache_name = devm_kasprintf(ccp->dev, GFP_KERNEL,
"%s-dmaengine-desc-cache",
ccp->name);
- if (!dma_cmd_cache_name)
- return -ENOMEM;
+ if (!dma_desc_cache_name) {
+ ret = -ENOMEM;
+ goto err_cache;
+ }
+
ccp->dma_desc_cache = kmem_cache_create(dma_desc_cache_name,
sizeof(struct ccp_dma_desc),
sizeof(void *),
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index ffa2891035ac..50fae4442801 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -4,6 +4,7 @@
* Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.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
@@ -20,72 +21,28 @@
#include "ccp-dev.h"
/* SHA initial context values */
-static const __be32 ccp_sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
+static const __be32 ccp_sha1_init[SHA1_DIGEST_SIZE / sizeof(__be32)] = {
cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3),
- cpu_to_be32(SHA1_H4), 0, 0, 0,
+ cpu_to_be32(SHA1_H4),
};
-static const __be32 ccp_sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
+static const __be32 ccp_sha224_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1),
cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3),
cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5),
cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7),
};
-static const __be32 ccp_sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = {
+static const __be32 ccp_sha256_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1),
cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3),
cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5),
cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
};
-static u32 ccp_alloc_ksb(struct ccp_device *ccp, unsigned int count)
-{
- int start;
-
- for (;;) {
- mutex_lock(&ccp->ksb_mutex);
-
- start = (u32)bitmap_find_next_zero_area(ccp->ksb,
- ccp->ksb_count,
- ccp->ksb_start,
- count, 0);
- if (start <= ccp->ksb_count) {
- bitmap_set(ccp->ksb, start, count);
-
- mutex_unlock(&ccp->ksb_mutex);
- break;
- }
-
- ccp->ksb_avail = 0;
-
- mutex_unlock(&ccp->ksb_mutex);
-
- /* Wait for KSB entries to become available */
- if (wait_event_interruptible(ccp->ksb_queue, ccp->ksb_avail))
- return 0;
- }
-
- return KSB_START + start;
-}
-
-static void ccp_free_ksb(struct ccp_device *ccp, unsigned int start,
- unsigned int count)
-{
- if (!start)
- return;
-
- mutex_lock(&ccp->ksb_mutex);
-
- bitmap_clear(ccp->ksb, start - KSB_START, count);
-
- ccp->ksb_avail = 1;
-
- mutex_unlock(&ccp->ksb_mutex);
-
- wake_up_interruptible_all(&ccp->ksb_queue);
-}
+#define CCP_NEW_JOBID(ccp) ((ccp->vdata->version == CCP_VERSION(3, 0)) ? \
+ ccp_gen_jobid(ccp) : 0)
static u32 ccp_gen_jobid(struct ccp_device *ccp)
{
@@ -231,7 +188,7 @@ static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
unsigned int len, unsigned int se_len,
bool sign_extend)
{
- unsigned int nbytes, sg_offset, dm_offset, ksb_len, i;
+ unsigned int nbytes, sg_offset, dm_offset, sb_len, i;
u8 buffer[CCP_REVERSE_BUF_SIZE];
if (WARN_ON(se_len > sizeof(buffer)))
@@ -241,21 +198,21 @@ static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
dm_offset = 0;
nbytes = len;
while (nbytes) {
- ksb_len = min_t(unsigned int, nbytes, se_len);
- sg_offset -= ksb_len;
+ sb_len = min_t(unsigned int, nbytes, se_len);
+ sg_offset -= sb_len;
- scatterwalk_map_and_copy(buffer, sg, sg_offset, ksb_len, 0);
- for (i = 0; i < ksb_len; i++)
- wa->address[dm_offset + i] = buffer[ksb_len - i - 1];
+ scatterwalk_map_and_copy(buffer, sg, sg_offset, sb_len, 0);
+ for (i = 0; i < sb_len; i++)
+ wa->address[dm_offset + i] = buffer[sb_len - i - 1];
- dm_offset += ksb_len;
- nbytes -= ksb_len;
+ dm_offset += sb_len;
+ nbytes -= sb_len;
- if ((ksb_len != se_len) && sign_extend) {
+ if ((sb_len != se_len) && sign_extend) {
/* Must sign-extend to nearest sign-extend length */
if (wa->address[dm_offset - 1] & 0x80)
memset(wa->address + dm_offset, 0xff,
- se_len - ksb_len);
+ se_len - sb_len);
}
}
@@ -266,22 +223,22 @@ static void ccp_reverse_get_dm_area(struct ccp_dm_workarea *wa,
struct scatterlist *sg,
unsigned int len)
{
- unsigned int nbytes, sg_offset, dm_offset, ksb_len, i;
+ unsigned int nbytes, sg_offset, dm_offset, sb_len, i;
u8 buffer[CCP_REVERSE_BUF_SIZE];
sg_offset = 0;
dm_offset = len;
nbytes = len;
while (nbytes) {
- ksb_len = min_t(unsigned int, nbytes, sizeof(buffer));
- dm_offset -= ksb_len;
+ sb_len = min_t(unsigned int, nbytes, sizeof(buffer));
+ dm_offset -= sb_len;
- for (i = 0; i < ksb_len; i++)
- buffer[ksb_len - i - 1] = wa->address[dm_offset + i];
- scatterwalk_map_and_copy(buffer, sg, sg_offset, ksb_len, 1);
+ for (i = 0; i < sb_len; i++)
+ buffer[sb_len - i - 1] = wa->address[dm_offset + i];
+ scatterwalk_map_and_copy(buffer, sg, sg_offset, sb_len, 1);
- sg_offset += ksb_len;
- nbytes -= ksb_len;
+ sg_offset += sb_len;
+ nbytes -= sb_len;
}
}
@@ -449,9 +406,9 @@ static void ccp_process_data(struct ccp_data *src, struct ccp_data *dst,
}
}
-static int ccp_copy_to_from_ksb(struct ccp_cmd_queue *cmd_q,
- struct ccp_dm_workarea *wa, u32 jobid, u32 ksb,
- u32 byte_swap, bool from)
+static int ccp_copy_to_from_sb(struct ccp_cmd_queue *cmd_q,
+ struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
+ u32 byte_swap, bool from)
{
struct ccp_op op;
@@ -463,8 +420,8 @@ static int ccp_copy_to_from_ksb(struct ccp_cmd_queue *cmd_q,
if (from) {
op.soc = 1;
- op.src.type = CCP_MEMTYPE_KSB;
- op.src.u.ksb = ksb;
+ op.src.type = CCP_MEMTYPE_SB;
+ op.src.u.sb = sb;
op.dst.type = CCP_MEMTYPE_SYSTEM;
op.dst.u.dma.address = wa->dma.address;
op.dst.u.dma.length = wa->length;
@@ -472,27 +429,27 @@ static int ccp_copy_to_from_ksb(struct ccp_cmd_queue *cmd_q,
op.src.type = CCP_MEMTYPE_SYSTEM;
op.src.u.dma.address = wa->dma.address;
op.src.u.dma.length = wa->length;
- op.dst.type = CCP_MEMTYPE_KSB;
- op.dst.u.ksb = ksb;
+ op.dst.type = CCP_MEMTYPE_SB;
+ op.dst.u.sb = sb;
}
op.u.passthru.byte_swap = byte_swap;
- return cmd_q->ccp->vdata->perform->perform_passthru(&op);
+ return cmd_q->ccp->vdata->perform->passthru(&op);
}
-static int ccp_copy_to_ksb(struct ccp_cmd_queue *cmd_q,
- struct ccp_dm_workarea *wa, u32 jobid, u32 ksb,
- u32 byte_swap)
+static int ccp_copy_to_sb(struct ccp_cmd_queue *cmd_q,
+ struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
+ u32 byte_swap)
{
- return ccp_copy_to_from_ksb(cmd_q, wa, jobid, ksb, byte_swap, false);
+ return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, false);
}
-static int ccp_copy_from_ksb(struct ccp_cmd_queue *cmd_q,
- struct ccp_dm_workarea *wa, u32 jobid, u32 ksb,
- u32 byte_swap)
+static int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q,
+ struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
+ u32 byte_swap)
{
- return ccp_copy_to_from_ksb(cmd_q, wa, jobid, ksb, byte_swap, true);
+ return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true);
}
static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
@@ -527,54 +484,54 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
return -EINVAL;
}
- BUILD_BUG_ON(CCP_AES_KEY_KSB_COUNT != 1);
- BUILD_BUG_ON(CCP_AES_CTX_KSB_COUNT != 1);
+ BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
+ BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
ret = -EIO;
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
- op.ksb_key = cmd_q->ksb_key;
- op.ksb_ctx = cmd_q->ksb_ctx;
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+ op.sb_key = cmd_q->sb_key;
+ op.sb_ctx = cmd_q->sb_ctx;
op.init = 1;
op.u.aes.type = aes->type;
op.u.aes.mode = aes->mode;
op.u.aes.action = aes->action;
- /* All supported key sizes fit in a single (32-byte) KSB entry
+ /* All supported key sizes fit in a single (32-byte) SB entry
* and must be in little endian format. Use the 256-bit byte
* swap passthru option to convert from big endian to little
* endian.
*/
ret = ccp_init_dm_workarea(&key, cmd_q,
- CCP_AES_KEY_KSB_COUNT * CCP_KSB_BYTES,
+ CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
DMA_TO_DEVICE);
if (ret)
return ret;
- dm_offset = CCP_KSB_BYTES - aes->key_len;
+ dm_offset = CCP_SB_BYTES - aes->key_len;
ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
- ret = ccp_copy_to_ksb(cmd_q, &key, op.jobid, op.ksb_key,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_key;
}
- /* The AES context fits in a single (32-byte) KSB entry and
+ /* The AES context fits in a single (32-byte) SB entry and
* must be in little endian format. Use the 256-bit byte swap
* passthru option to convert from big endian to little endian.
*/
ret = ccp_init_dm_workarea(&ctx, cmd_q,
- CCP_AES_CTX_KSB_COUNT * CCP_KSB_BYTES,
+ CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
DMA_BIDIRECTIONAL);
if (ret)
goto e_key;
- dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE;
+ dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
- ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_ctx;
@@ -592,9 +549,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
op.eom = 1;
/* Push the K1/K2 key to the CCP now */
- ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid,
- op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid,
+ op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_src;
@@ -602,15 +559,15 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
aes->cmac_key_len);
- ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_src;
}
}
- ret = cmd_q->ccp->vdata->perform->perform_aes(&op);
+ ret = cmd_q->ccp->vdata->perform->aes(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_src;
@@ -622,15 +579,15 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
/* Retrieve the AES context - convert from LE to BE using
* 32-byte (256-bit) byteswapping
*/
- ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_src;
}
/* ...but we only need AES_BLOCK_SIZE bytes */
- dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE;
+ dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
e_src:
@@ -680,56 +637,56 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
return -EINVAL;
}
- BUILD_BUG_ON(CCP_AES_KEY_KSB_COUNT != 1);
- BUILD_BUG_ON(CCP_AES_CTX_KSB_COUNT != 1);
+ BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
+ BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
ret = -EIO;
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
- op.ksb_key = cmd_q->ksb_key;
- op.ksb_ctx = cmd_q->ksb_ctx;
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+ op.sb_key = cmd_q->sb_key;
+ op.sb_ctx = cmd_q->sb_ctx;
op.init = (aes->mode == CCP_AES_MODE_ECB) ? 0 : 1;
op.u.aes.type = aes->type;
op.u.aes.mode = aes->mode;
op.u.aes.action = aes->action;
- /* All supported key sizes fit in a single (32-byte) KSB entry
+ /* All supported key sizes fit in a single (32-byte) SB entry
* and must be in little endian format. Use the 256-bit byte
* swap passthru option to convert from big endian to little
* endian.
*/
ret = ccp_init_dm_workarea(&key, cmd_q,
- CCP_AES_KEY_KSB_COUNT * CCP_KSB_BYTES,
+ CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
DMA_TO_DEVICE);
if (ret)
return ret;
- dm_offset = CCP_KSB_BYTES - aes->key_len;
+ dm_offset = CCP_SB_BYTES - aes->key_len;
ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
- ret = ccp_copy_to_ksb(cmd_q, &key, op.jobid, op.ksb_key,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_key;
}
- /* The AES context fits in a single (32-byte) KSB entry and
+ /* The AES context fits in a single (32-byte) SB entry and
* must be in little endian format. Use the 256-bit byte swap
* passthru option to convert from big endian to little endian.
*/
ret = ccp_init_dm_workarea(&ctx, cmd_q,
- CCP_AES_CTX_KSB_COUNT * CCP_KSB_BYTES,
+ CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
DMA_BIDIRECTIONAL);
if (ret)
goto e_key;
if (aes->mode != CCP_AES_MODE_ECB) {
- /* Load the AES context - conver to LE */
- dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE;
+ /* Load the AES context - convert to LE */
+ dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
- ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_ctx;
@@ -772,7 +729,7 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.soc = 1;
}
- ret = cmd_q->ccp->vdata->perform->perform_aes(&op);
+ ret = cmd_q->ccp->vdata->perform->aes(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -785,15 +742,15 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
/* Retrieve the AES context - convert from LE to BE using
* 32-byte (256-bit) byteswapping
*/
- ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
}
/* ...but we only need AES_BLOCK_SIZE bytes */
- dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE;
+ dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
}
@@ -857,53 +814,53 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
if (!xts->key || !xts->iv || !xts->src || !xts->dst)
return -EINVAL;
- BUILD_BUG_ON(CCP_XTS_AES_KEY_KSB_COUNT != 1);
- BUILD_BUG_ON(CCP_XTS_AES_CTX_KSB_COUNT != 1);
+ BUILD_BUG_ON(CCP_XTS_AES_KEY_SB_COUNT != 1);
+ BUILD_BUG_ON(CCP_XTS_AES_CTX_SB_COUNT != 1);
ret = -EIO;
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
- op.ksb_key = cmd_q->ksb_key;
- op.ksb_ctx = cmd_q->ksb_ctx;
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+ op.sb_key = cmd_q->sb_key;
+ op.sb_ctx = cmd_q->sb_ctx;
op.init = 1;
op.u.xts.action = xts->action;
op.u.xts.unit_size = xts->unit_size;
- /* All supported key sizes fit in a single (32-byte) KSB entry
+ /* All supported key sizes fit in a single (32-byte) SB entry
* and must be in little endian format. Use the 256-bit byte
* swap passthru option to convert from big endian to little
* endian.
*/
ret = ccp_init_dm_workarea(&key, cmd_q,
- CCP_XTS_AES_KEY_KSB_COUNT * CCP_KSB_BYTES,
+ CCP_XTS_AES_KEY_SB_COUNT * CCP_SB_BYTES,
DMA_TO_DEVICE);
if (ret)
return ret;
- dm_offset = CCP_KSB_BYTES - AES_KEYSIZE_128;
+ dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
ccp_set_dm_area(&key, 0, xts->key, dm_offset, xts->key_len);
- ret = ccp_copy_to_ksb(cmd_q, &key, op.jobid, op.ksb_key,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_key;
}
- /* The AES context fits in a single (32-byte) KSB entry and
+ /* The AES context fits in a single (32-byte) SB entry and
* for XTS is already in little endian format so no byte swapping
* is needed.
*/
ret = ccp_init_dm_workarea(&ctx, cmd_q,
- CCP_XTS_AES_CTX_KSB_COUNT * CCP_KSB_BYTES,
+ CCP_XTS_AES_CTX_SB_COUNT * CCP_SB_BYTES,
DMA_BIDIRECTIONAL);
if (ret)
goto e_key;
ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
- ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_NOOP);
+ ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_ctx;
@@ -937,7 +894,7 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
if (!src.sg_wa.bytes_left)
op.eom = 1;
- ret = cmd_q->ccp->vdata->perform->perform_xts_aes(&op);
+ ret = cmd_q->ccp->vdata->perform->xts_aes(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -949,15 +906,15 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
/* Retrieve the AES context - convert from LE to BE using
* 32-byte (256-bit) byteswapping
*/
- ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
}
/* ...but we only need AES_BLOCK_SIZE bytes */
- dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE;
+ dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_get_dm_area(&ctx, dm_offset, xts->iv, 0, xts->iv_len);
e_dst:
@@ -982,163 +939,227 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
struct ccp_dm_workarea ctx;
struct ccp_data src;
struct ccp_op op;
+ unsigned int ioffset, ooffset;
+ unsigned int digest_size;
+ int sb_count;
+ const void *init;
+ u64 block_size;
+ int ctx_size;
int ret;
- if (sha->ctx_len != CCP_SHA_CTXSIZE)
+ switch (sha->type) {
+ case CCP_SHA_TYPE_1:
+ if (sha->ctx_len < SHA1_DIGEST_SIZE)
+ return -EINVAL;
+ block_size = SHA1_BLOCK_SIZE;
+ break;
+ case CCP_SHA_TYPE_224:
+ if (sha->ctx_len < SHA224_DIGEST_SIZE)
+ return -EINVAL;
+ block_size = SHA224_BLOCK_SIZE;
+ break;
+ case CCP_SHA_TYPE_256:
+ if (sha->ctx_len < SHA256_DIGEST_SIZE)
+ return -EINVAL;
+ block_size = SHA256_BLOCK_SIZE;
+ break;
+ default:
return -EINVAL;
+ }
if (!sha->ctx)
return -EINVAL;
- if (!sha->final && (sha->src_len & (CCP_SHA_BLOCKSIZE - 1)))
+ if (!sha->final && (sha->src_len & (block_size - 1)))
return -EINVAL;
- if (!sha->src_len) {
- const u8 *sha_zero;
+ /* The version 3 device can't handle zero-length input */
+ if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
- /* Not final, just return */
- if (!sha->final)
- return 0;
+ if (!sha->src_len) {
+ unsigned int digest_len;
+ const u8 *sha_zero;
- /* CCP can't do a zero length sha operation so the caller
- * must buffer the data.
- */
- if (sha->msg_bits)
- return -EINVAL;
+ /* Not final, just return */
+ if (!sha->final)
+ return 0;
- /* The CCP cannot perform zero-length sha operations so the
- * caller is required to buffer data for the final operation.
- * However, a sha operation for a message with a total length
- * of zero is valid so known values are required to supply
- * the result.
- */
- switch (sha->type) {
- case CCP_SHA_TYPE_1:
- sha_zero = sha1_zero_message_hash;
- break;
- case CCP_SHA_TYPE_224:
- sha_zero = sha224_zero_message_hash;
- break;
- case CCP_SHA_TYPE_256:
- sha_zero = sha256_zero_message_hash;
- break;
- default:
- return -EINVAL;
- }
+ /* CCP can't do a zero length sha operation so the
+ * caller must buffer the data.
+ */
+ if (sha->msg_bits)
+ return -EINVAL;
+
+ /* The CCP cannot perform zero-length sha operations
+ * so the caller is required to buffer data for the
+ * final operation. However, a sha operation for a
+ * message with a total length of zero is valid so
+ * known values are required to supply the result.
+ */
+ switch (sha->type) {
+ case CCP_SHA_TYPE_1:
+ sha_zero = sha1_zero_message_hash;
+ digest_len = SHA1_DIGEST_SIZE;
+ break;
+ case CCP_SHA_TYPE_224:
+ sha_zero = sha224_zero_message_hash;
+ digest_len = SHA224_DIGEST_SIZE;
+ break;
+ case CCP_SHA_TYPE_256:
+ sha_zero = sha256_zero_message_hash;
+ digest_len = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ return -EINVAL;
+ }
- scatterwalk_map_and_copy((void *)sha_zero, sha->ctx, 0,
- sha->ctx_len, 1);
+ scatterwalk_map_and_copy((void *)sha_zero, sha->ctx, 0,
+ digest_len, 1);
- return 0;
+ return 0;
+ }
}
- if (!sha->src)
- return -EINVAL;
+ /* Set variables used throughout */
+ switch (sha->type) {
+ case CCP_SHA_TYPE_1:
+ digest_size = SHA1_DIGEST_SIZE;
+ init = (void *) ccp_sha1_init;
+ ctx_size = SHA1_DIGEST_SIZE;
+ sb_count = 1;
+ if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
+ ooffset = ioffset = CCP_SB_BYTES - SHA1_DIGEST_SIZE;
+ else
+ ooffset = ioffset = 0;
+ break;
+ case CCP_SHA_TYPE_224:
+ digest_size = SHA224_DIGEST_SIZE;
+ init = (void *) ccp_sha224_init;
+ ctx_size = SHA256_DIGEST_SIZE;
+ sb_count = 1;
+ ioffset = 0;
+ if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
+ ooffset = CCP_SB_BYTES - SHA224_DIGEST_SIZE;
+ else
+ ooffset = 0;
+ break;
+ case CCP_SHA_TYPE_256:
+ digest_size = SHA256_DIGEST_SIZE;
+ init = (void *) ccp_sha256_init;
+ ctx_size = SHA256_DIGEST_SIZE;
+ sb_count = 1;
+ ooffset = ioffset = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto e_data;
+ }
- BUILD_BUG_ON(CCP_SHA_KSB_COUNT != 1);
+ /* For zero-length plaintext the src pointer is ignored;
+ * otherwise both parts must be valid
+ */
+ if (sha->src_len && !sha->src)
+ return -EINVAL;
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
- op.ksb_ctx = cmd_q->ksb_ctx;
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+ op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
op.u.sha.type = sha->type;
op.u.sha.msg_bits = sha->msg_bits;
- /* The SHA context fits in a single (32-byte) KSB entry and
- * must be in little endian format. Use the 256-bit byte swap
- * passthru option to convert from big endian to little endian.
- */
- ret = ccp_init_dm_workarea(&ctx, cmd_q,
- CCP_SHA_KSB_COUNT * CCP_KSB_BYTES,
+ ret = ccp_init_dm_workarea(&ctx, cmd_q, sb_count * CCP_SB_BYTES,
DMA_BIDIRECTIONAL);
if (ret)
return ret;
-
if (sha->first) {
- const __be32 *init;
-
switch (sha->type) {
case CCP_SHA_TYPE_1:
- init = ccp_sha1_init;
- break;
case CCP_SHA_TYPE_224:
- init = ccp_sha224_init;
- break;
case CCP_SHA_TYPE_256:
- init = ccp_sha256_init;
+ memcpy(ctx.address + ioffset, init, ctx_size);
break;
default:
ret = -EINVAL;
goto e_ctx;
}
- memcpy(ctx.address, init, CCP_SHA_CTXSIZE);
} else {
- ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len);
+ /* Restore the context */
+ ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
+ sb_count * CCP_SB_BYTES);
}
- ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_ctx;
}
- /* Send data to the CCP SHA engine */
- ret = ccp_init_data(&src, cmd_q, sha->src, sha->src_len,
- CCP_SHA_BLOCKSIZE, DMA_TO_DEVICE);
- if (ret)
- goto e_ctx;
+ if (sha->src) {
+ /* Send data to the CCP SHA engine; block_size is set above */
+ ret = ccp_init_data(&src, cmd_q, sha->src, sha->src_len,
+ block_size, DMA_TO_DEVICE);
+ if (ret)
+ goto e_ctx;
- while (src.sg_wa.bytes_left) {
- ccp_prepare_data(&src, NULL, &op, CCP_SHA_BLOCKSIZE, false);
- if (sha->final && !src.sg_wa.bytes_left)
- op.eom = 1;
+ while (src.sg_wa.bytes_left) {
+ ccp_prepare_data(&src, NULL, &op, block_size, false);
+ if (sha->final && !src.sg_wa.bytes_left)
+ op.eom = 1;
+
+ ret = cmd_q->ccp->vdata->perform->sha(&op);
+ if (ret) {
+ cmd->engine_error = cmd_q->cmd_error;
+ goto e_data;
+ }
- ret = cmd_q->ccp->vdata->perform->perform_sha(&op);
+ ccp_process_data(&src, NULL, &op);
+ }
+ } else {
+ op.eom = 1;
+ ret = cmd_q->ccp->vdata->perform->sha(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_data;
}
-
- ccp_process_data(&src, NULL, &op);
}
/* Retrieve the SHA context - convert from LE to BE using
* 32-byte (256-bit) byteswapping to BE
*/
- ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx,
- CCP_PASSTHRU_BYTESWAP_256BIT);
+ ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_data;
}
- ccp_get_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len);
-
- if (sha->final && sha->opad) {
- /* HMAC operation, recursively perform final SHA */
- struct ccp_cmd hmac_cmd;
- struct scatterlist sg;
- u64 block_size, digest_size;
- u8 *hmac_buf;
-
+ if (sha->final) {
+ /* Finishing up, so get the digest */
switch (sha->type) {
case CCP_SHA_TYPE_1:
- block_size = SHA1_BLOCK_SIZE;
- digest_size = SHA1_DIGEST_SIZE;
- break;
case CCP_SHA_TYPE_224:
- block_size = SHA224_BLOCK_SIZE;
- digest_size = SHA224_DIGEST_SIZE;
- break;
case CCP_SHA_TYPE_256:
- block_size = SHA256_BLOCK_SIZE;
- digest_size = SHA256_DIGEST_SIZE;
+ ccp_get_dm_area(&ctx, ooffset,
+ sha->ctx, 0,
+ digest_size);
break;
default:
ret = -EINVAL;
- goto e_data;
+ goto e_ctx;
}
+ } else {
+ /* Stash the context */
+ ccp_get_dm_area(&ctx, 0, sha->ctx, 0,
+ sb_count * CCP_SB_BYTES);
+ }
+
+ if (sha->final && sha->opad) {
+ /* HMAC operation, recursively perform final SHA */
+ struct ccp_cmd hmac_cmd;
+ struct scatterlist sg;
+ u8 *hmac_buf;
if (sha->opad_len != block_size) {
ret = -EINVAL;
@@ -1153,7 +1174,18 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
sg_init_one(&sg, hmac_buf, block_size + digest_size);
scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0);
- memcpy(hmac_buf + block_size, ctx.address, digest_size);
+ switch (sha->type) {
+ case CCP_SHA_TYPE_1:
+ case CCP_SHA_TYPE_224:
+ case CCP_SHA_TYPE_256:
+ memcpy(hmac_buf + block_size,
+ ctx.address + ooffset,
+ digest_size);
+ break;
+ default:
+ ret = -EINVAL;
+ goto e_ctx;
+ }
memset(&hmac_cmd, 0, sizeof(hmac_cmd));
hmac_cmd.engine = CCP_ENGINE_SHA;
@@ -1176,7 +1208,8 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
}
e_data:
- ccp_free_data(&src, cmd_q);
+ if (sha->src)
+ ccp_free_data(&src, cmd_q);
e_ctx:
ccp_dm_free(&ctx);
@@ -1190,7 +1223,7 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
struct ccp_dm_workarea exp, src;
struct ccp_data dst;
struct ccp_op op;
- unsigned int ksb_count, i_len, o_len;
+ unsigned int sb_count, i_len, o_len;
int ret;
if (rsa->key_size > CCP_RSA_MAX_WIDTH)
@@ -1208,16 +1241,17 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
o_len = ((rsa->key_size + 255) / 256) * 32;
i_len = o_len * 2;
- ksb_count = o_len / CCP_KSB_BYTES;
+ sb_count = o_len / CCP_SB_BYTES;
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
op.jobid = ccp_gen_jobid(cmd_q->ccp);
- op.ksb_key = ccp_alloc_ksb(cmd_q->ccp, ksb_count);
- if (!op.ksb_key)
+ op.sb_key = cmd_q->ccp->vdata->perform->sballoc(cmd_q, sb_count);
+
+ if (!op.sb_key)
return -EIO;
- /* The RSA exponent may span multiple (32-byte) KSB entries and must
+ /* The RSA exponent may span multiple (32-byte) SB entries and must
* be in little endian format. Reverse copy each 32-byte chunk
* of the exponent (En chunk to E0 chunk, E(n-1) chunk to E1 chunk)
* and each byte within that chunk and do not perform any byte swap
@@ -1225,14 +1259,14 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
*/
ret = ccp_init_dm_workarea(&exp, cmd_q, o_len, DMA_TO_DEVICE);
if (ret)
- goto e_ksb;
+ goto e_sb;
ret = ccp_reverse_set_dm_area(&exp, rsa->exp, rsa->exp_len,
- CCP_KSB_BYTES, false);
+ CCP_SB_BYTES, false);
if (ret)
goto e_exp;
- ret = ccp_copy_to_ksb(cmd_q, &exp, op.jobid, op.ksb_key,
- CCP_PASSTHRU_BYTESWAP_NOOP);
+ ret = ccp_copy_to_sb(cmd_q, &exp, op.jobid, op.sb_key,
+ CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_exp;
@@ -1247,12 +1281,12 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
goto e_exp;
ret = ccp_reverse_set_dm_area(&src, rsa->mod, rsa->mod_len,
- CCP_KSB_BYTES, false);
+ CCP_SB_BYTES, false);
if (ret)
goto e_src;
src.address += o_len; /* Adjust the address for the copy operation */
ret = ccp_reverse_set_dm_area(&src, rsa->src, rsa->src_len,
- CCP_KSB_BYTES, false);
+ CCP_SB_BYTES, false);
if (ret)
goto e_src;
src.address -= o_len; /* Reset the address to original value */
@@ -1274,7 +1308,7 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.u.rsa.mod_size = rsa->key_size;
op.u.rsa.input_len = i_len;
- ret = cmd_q->ccp->vdata->perform->perform_rsa(&op);
+ ret = cmd_q->ccp->vdata->perform->rsa(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1291,8 +1325,8 @@ e_src:
e_exp:
ccp_dm_free(&exp);
-e_ksb:
- ccp_free_ksb(cmd_q->ccp, op.ksb_key, ksb_count);
+e_sb:
+ cmd_q->ccp->vdata->perform->sbfree(cmd_q, op.sb_key, sb_count);
return ret;
}
@@ -1306,7 +1340,7 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
struct ccp_op op;
bool in_place = false;
unsigned int i;
- int ret;
+ int ret = 0;
if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
return -EINVAL;
@@ -1321,26 +1355,26 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
return -EINVAL;
}
- BUILD_BUG_ON(CCP_PASSTHRU_KSB_COUNT != 1);
+ BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
/* Load the mask */
- op.ksb_key = cmd_q->ksb_key;
+ op.sb_key = cmd_q->sb_key;
ret = ccp_init_dm_workarea(&mask, cmd_q,
- CCP_PASSTHRU_KSB_COUNT *
- CCP_KSB_BYTES,
+ CCP_PASSTHRU_SB_COUNT *
+ CCP_SB_BYTES,
DMA_TO_DEVICE);
if (ret)
return ret;
ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
- ret = ccp_copy_to_ksb(cmd_q, &mask, op.jobid, op.ksb_key,
- CCP_PASSTHRU_BYTESWAP_NOOP);
+ ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
+ CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_mask;
@@ -1399,7 +1433,7 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
op.dst.u.dma.offset = dst.sg_wa.sg_used;
op.dst.u.dma.length = op.src.u.dma.length;
- ret = cmd_q->ccp->vdata->perform->perform_passthru(&op);
+ ret = cmd_q->ccp->vdata->perform->passthru(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1448,7 +1482,7 @@ static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
return -EINVAL;
}
- BUILD_BUG_ON(CCP_PASSTHRU_KSB_COUNT != 1);
+ BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
@@ -1456,13 +1490,13 @@ static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
/* Load the mask */
- op.ksb_key = cmd_q->ksb_key;
+ op.sb_key = cmd_q->sb_key;
mask.length = pt->mask_len;
mask.dma.address = pt->mask;
mask.dma.length = pt->mask_len;
- ret = ccp_copy_to_ksb(cmd_q, &mask, op.jobid, op.ksb_key,
+ ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
@@ -1484,7 +1518,7 @@ static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
op.dst.u.dma.offset = 0;
op.dst.u.dma.length = pt->src_len;
- ret = cmd_q->ccp->vdata->perform->perform_passthru(&op);
+ ret = cmd_q->ccp->vdata->perform->passthru(&op);
if (ret)
cmd->engine_error = cmd_q->cmd_error;
@@ -1514,7 +1548,7 @@ static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
/* Concatenate the modulus and the operands. Both the modulus and
* the operands must be in little endian format. Since the input
@@ -1575,7 +1609,7 @@ static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.u.ecc.function = cmd->u.ecc.function;
- ret = cmd_q->ccp->vdata->perform->perform_ecc(&op);
+ ret = cmd_q->ccp->vdata->perform->ecc(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1639,7 +1673,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = ccp_gen_jobid(cmd_q->ccp);
+ op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
/* Concatenate the modulus and the operands. Both the modulus and
* the operands must be in little endian format. Since the input
@@ -1677,7 +1711,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
goto e_src;
src.address += CCP_ECC_OPERAND_SIZE;
- /* Set the first point Z coordianate to 1 */
+ /* Set the first point Z coordinate to 1 */
*src.address = 0x01;
src.address += CCP_ECC_OPERAND_SIZE;
@@ -1696,7 +1730,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
goto e_src;
src.address += CCP_ECC_OPERAND_SIZE;
- /* Set the second point Z coordianate to 1 */
+ /* Set the second point Z coordinate to 1 */
*src.address = 0x01;
src.address += CCP_ECC_OPERAND_SIZE;
} else {
@@ -1739,7 +1773,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
op.u.ecc.function = cmd->u.ecc.function;
- ret = cmd_q->ccp->vdata->perform->perform_ecc(&op);
+ ret = cmd_q->ccp->vdata->perform->ecc(&op);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_dst;
@@ -1810,7 +1844,7 @@ int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
cmd->engine_error = 0;
cmd_q->cmd_error = 0;
cmd_q->int_rcvd = 0;
- cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
+ cmd_q->free_slots = cmd_q->ccp->vdata->perform->get_free_slots(cmd_q);
switch (cmd->engine) {
case CCP_ENGINE_AES:
diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c
index 0bf262e36b6b..28a9996c1085 100644
--- a/drivers/crypto/ccp/ccp-pci.c
+++ b/drivers/crypto/ccp/ccp-pci.c
@@ -4,6 +4,7 @@
* Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.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
@@ -25,9 +26,6 @@
#include "ccp-dev.h"
-#define IO_BAR 2
-#define IO_OFFSET 0x20000
-
#define MSIX_VECTORS 2
struct ccp_msix {
@@ -143,10 +141,11 @@ static void ccp_free_irqs(struct ccp_device *ccp)
free_irq(ccp_pci->msix[ccp_pci->msix_count].vector,
dev);
pci_disable_msix(pdev);
- } else {
+ } else if (ccp->irq) {
free_irq(ccp->irq, dev);
pci_disable_msi(pdev);
}
+ ccp->irq = 0;
}
static int ccp_find_mmio_area(struct ccp_device *ccp)
@@ -156,10 +155,11 @@ static int ccp_find_mmio_area(struct ccp_device *ccp)
resource_size_t io_len;
unsigned long io_flags;
- io_flags = pci_resource_flags(pdev, IO_BAR);
- io_len = pci_resource_len(pdev, IO_BAR);
- if ((io_flags & IORESOURCE_MEM) && (io_len >= (IO_OFFSET + 0x800)))
- return IO_BAR;
+ io_flags = pci_resource_flags(pdev, ccp->vdata->bar);
+ io_len = pci_resource_len(pdev, ccp->vdata->bar);
+ if ((io_flags & IORESOURCE_MEM) &&
+ (io_len >= (ccp->vdata->offset + 0x800)))
+ return ccp->vdata->bar;
return -EIO;
}
@@ -216,7 +216,7 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(dev, "pci_iomap failed\n");
goto e_device;
}
- ccp->io_regs = ccp->io_map + IO_OFFSET;
+ ccp->io_regs = ccp->io_map + ccp->vdata->offset;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
@@ -230,6 +230,9 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_set_drvdata(dev, ccp);
+ if (ccp->vdata->setup)
+ ccp->vdata->setup(ccp);
+
ret = ccp->vdata->perform->init(ccp);
if (ret)
goto e_iomap;
@@ -322,6 +325,8 @@ static int ccp_pci_resume(struct pci_dev *pdev)
static const struct pci_device_id ccp_pci_table[] = {
{ PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&ccpv3 },
+ { PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&ccpv5a },
+ { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&ccpv5b },
/* Last entry must be zero */
{ 0, }
};
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index eee2c7e6c299..e09d4055b19e 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -636,20 +636,12 @@ struct hifn_request_context {
static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg)
{
- u32 ret;
-
- ret = readl(dev->bar[0] + reg);
-
- return ret;
+ return readl(dev->bar[0] + reg);
}
static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg)
{
- u32 ret;
-
- ret = readl(dev->bar[1] + reg);
-
- return ret;
+ return readl(dev->bar[1] + reg);
}
static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c
index 68e8aa90fe01..a2e77b87485b 100644
--- a/drivers/crypto/img-hash.c
+++ b/drivers/crypto/img-hash.c
@@ -71,6 +71,7 @@
#define DRIVER_FLAGS_MD5 BIT(21)
#define IMG_HASH_QUEUE_LENGTH 20
+#define IMG_HASH_DMA_BURST 4
#define IMG_HASH_DMA_THRESHOLD 64
#ifdef __LITTLE_ENDIAN
@@ -102,8 +103,10 @@ struct img_hash_request_ctx {
unsigned long op;
size_t bufcnt;
- u8 buffer[0] __aligned(sizeof(u32));
struct ahash_request fallback_req;
+
+ /* Zero length buffer must remain last member of struct */
+ u8 buffer[0] __aligned(sizeof(u32));
};
struct img_hash_ctx {
@@ -340,7 +343,7 @@ static int img_hash_dma_init(struct img_hash_dev *hdev)
dma_conf.direction = DMA_MEM_TO_DEV;
dma_conf.dst_addr = hdev->bus_addr;
dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dma_conf.dst_maxburst = 16;
+ dma_conf.dst_maxburst = IMG_HASH_DMA_BURST;
dma_conf.device_fc = false;
err = dmaengine_slave_config(hdev->dma_lch, &dma_conf);
@@ -361,7 +364,7 @@ static void img_hash_dma_task(unsigned long d)
size_t nbytes, bleft, wsend, len, tbc;
struct scatterlist tsg;
- if (!ctx->sg)
+ if (!hdev->req || !ctx->sg)
return;
addr = sg_virt(ctx->sg);
@@ -587,6 +590,32 @@ static int img_hash_finup(struct ahash_request *req)
return crypto_ahash_finup(&rctx->fallback_req);
}
+static int img_hash_import(struct ahash_request *req, const void *in)
+{
+ struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+ rctx->fallback_req.base.flags = req->base.flags
+ & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ return crypto_ahash_import(&rctx->fallback_req, in);
+}
+
+static int img_hash_export(struct ahash_request *req, void *out)
+{
+ struct img_hash_request_ctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+ rctx->fallback_req.base.flags = req->base.flags
+ & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ return crypto_ahash_export(&rctx->fallback_req, out);
+}
+
static int img_hash_digest(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -643,10 +672,9 @@ static int img_hash_digest(struct ahash_request *req)
return err;
}
-static int img_hash_cra_init(struct crypto_tfm *tfm)
+static int img_hash_cra_init(struct crypto_tfm *tfm, const char *alg_name)
{
struct img_hash_ctx *ctx = crypto_tfm_ctx(tfm);
- const char *alg_name = crypto_tfm_alg_name(tfm);
int err = -ENOMEM;
ctx->fallback = crypto_alloc_ahash(alg_name, 0,
@@ -658,6 +686,7 @@ static int img_hash_cra_init(struct crypto_tfm *tfm)
}
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct img_hash_request_ctx) +
+ crypto_ahash_reqsize(ctx->fallback) +
IMG_HASH_DMA_THRESHOLD);
return 0;
@@ -666,6 +695,26 @@ err:
return err;
}
+static int img_hash_cra_md5_init(struct crypto_tfm *tfm)
+{
+ return img_hash_cra_init(tfm, "md5-generic");
+}
+
+static int img_hash_cra_sha1_init(struct crypto_tfm *tfm)
+{
+ return img_hash_cra_init(tfm, "sha1-generic");
+}
+
+static int img_hash_cra_sha224_init(struct crypto_tfm *tfm)
+{
+ return img_hash_cra_init(tfm, "sha224-generic");
+}
+
+static int img_hash_cra_sha256_init(struct crypto_tfm *tfm)
+{
+ return img_hash_cra_init(tfm, "sha256-generic");
+}
+
static void img_hash_cra_exit(struct crypto_tfm *tfm)
{
struct img_hash_ctx *tctx = crypto_tfm_ctx(tfm);
@@ -711,9 +760,12 @@ static struct ahash_alg img_algs[] = {
.update = img_hash_update,
.final = img_hash_final,
.finup = img_hash_finup,
+ .export = img_hash_export,
+ .import = img_hash_import,
.digest = img_hash_digest,
.halg = {
.digestsize = MD5_DIGEST_SIZE,
+ .statesize = sizeof(struct md5_state),
.base = {
.cra_name = "md5",
.cra_driver_name = "img-md5",
@@ -723,7 +775,7 @@ static struct ahash_alg img_algs[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct img_hash_ctx),
- .cra_init = img_hash_cra_init,
+ .cra_init = img_hash_cra_md5_init,
.cra_exit = img_hash_cra_exit,
.cra_module = THIS_MODULE,
}
@@ -734,9 +786,12 @@ static struct ahash_alg img_algs[] = {
.update = img_hash_update,
.final = img_hash_final,
.finup = img_hash_finup,
+ .export = img_hash_export,
+ .import = img_hash_import,
.digest = img_hash_digest,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct sha1_state),
.base = {
.cra_name = "sha1",
.cra_driver_name = "img-sha1",
@@ -746,7 +801,7 @@ static struct ahash_alg img_algs[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct img_hash_ctx),
- .cra_init = img_hash_cra_init,
+ .cra_init = img_hash_cra_sha1_init,
.cra_exit = img_hash_cra_exit,
.cra_module = THIS_MODULE,
}
@@ -757,9 +812,12 @@ static struct ahash_alg img_algs[] = {
.update = img_hash_update,
.final = img_hash_final,
.finup = img_hash_finup,
+ .export = img_hash_export,
+ .import = img_hash_import,
.digest = img_hash_digest,
.halg = {
.digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
.base = {
.cra_name = "sha224",
.cra_driver_name = "img-sha224",
@@ -769,7 +827,7 @@ static struct ahash_alg img_algs[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct img_hash_ctx),
- .cra_init = img_hash_cra_init,
+ .cra_init = img_hash_cra_sha224_init,
.cra_exit = img_hash_cra_exit,
.cra_module = THIS_MODULE,
}
@@ -780,9 +838,12 @@ static struct ahash_alg img_algs[] = {
.update = img_hash_update,
.final = img_hash_final,
.finup = img_hash_finup,
+ .export = img_hash_export,
+ .import = img_hash_import,
.digest = img_hash_digest,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
.base = {
.cra_name = "sha256",
.cra_driver_name = "img-sha256",
@@ -792,7 +853,7 @@ static struct ahash_alg img_algs[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct img_hash_ctx),
- .cra_init = img_hash_cra_init,
+ .cra_init = img_hash_cra_sha256_init,
.cra_exit = img_hash_cra_exit,
.cra_module = THIS_MODULE,
}
@@ -971,7 +1032,7 @@ static int img_hash_probe(struct platform_device *pdev)
err = img_register_algs(hdev);
if (err)
goto err_algs;
- dev_dbg(dev, "Img MD5/SHA1/SHA224/SHA256 Hardware accelerator initialized\n");
+ dev_info(dev, "Img MD5/SHA1/SHA224/SHA256 Hardware accelerator initialized\n");
return 0;
@@ -1013,11 +1074,38 @@ static int img_hash_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int img_hash_suspend(struct device *dev)
+{
+ struct img_hash_dev *hdev = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(hdev->hash_clk);
+ clk_disable_unprepare(hdev->sys_clk);
+
+ return 0;
+}
+
+static int img_hash_resume(struct device *dev)
+{
+ struct img_hash_dev *hdev = dev_get_drvdata(dev);
+
+ clk_prepare_enable(hdev->hash_clk);
+ clk_prepare_enable(hdev->sys_clk);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops img_hash_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(img_hash_suspend, img_hash_resume)
+};
+
static struct platform_driver img_hash_driver = {
.probe = img_hash_probe,
.remove = img_hash_remove,
.driver = {
.name = "img-hash-accelerator",
+ .pm = &img_hash_pm_ops,
.of_match_table = of_match_ptr(img_hash_match),
}
};
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 2296934455fc..7868765a70c5 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -447,9 +447,8 @@ static int init_ixp_crypto(struct device *dev)
if (!npe_running(npe_c)) {
ret = npe_load_firmware(npe_c, npe_name(npe_c), dev);
- if (ret) {
- return ret;
- }
+ if (ret)
+ goto npe_release;
if (npe_recv_message(npe_c, msg, "STATUS_MSG"))
goto npe_error;
} else {
@@ -473,7 +472,8 @@ static int init_ixp_crypto(struct device *dev)
default:
printk(KERN_ERR "Firmware of %s lacks crypto support\n",
npe_name(npe_c));
- return -ENODEV;
+ ret = -ENODEV;
+ goto npe_release;
}
/* buffer_pool will also be used to sometimes store the hmac,
* so assure it is large enough
@@ -512,6 +512,7 @@ npe_error:
err:
dma_pool_destroy(ctx_pool);
dma_pool_destroy(buffer_pool);
+npe_release:
npe_release(npe_c);
return ret;
}
diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c
index d64af8625d7e..37dadb2a4feb 100644
--- a/drivers/crypto/marvell/cesa.c
+++ b/drivers/crypto/marvell/cesa.c
@@ -166,6 +166,7 @@ static irqreturn_t mv_cesa_int(int irq, void *priv)
if (!req)
break;
+ ctx = crypto_tfm_ctx(req->tfm);
mv_cesa_complete_req(ctx, req, 0);
}
}
diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c
index 82e0f4e6eb1c..9f284682c091 100644
--- a/drivers/crypto/marvell/hash.c
+++ b/drivers/crypto/marvell/hash.c
@@ -374,7 +374,7 @@ static const struct mv_cesa_req_ops mv_cesa_ahash_req_ops = {
.complete = mv_cesa_ahash_complete,
};
-static int mv_cesa_ahash_init(struct ahash_request *req,
+static void mv_cesa_ahash_init(struct ahash_request *req,
struct mv_cesa_op_ctx *tmpl, bool algo_le)
{
struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
@@ -390,8 +390,6 @@ static int mv_cesa_ahash_init(struct ahash_request *req,
creq->op_tmpl = *tmpl;
creq->len = 0;
creq->algo_le = algo_le;
-
- return 0;
}
static inline int mv_cesa_ahash_cra_init(struct crypto_tfm *tfm)
@@ -405,15 +403,16 @@ static inline int mv_cesa_ahash_cra_init(struct crypto_tfm *tfm)
return 0;
}
-static int mv_cesa_ahash_cache_req(struct ahash_request *req, bool *cached)
+static bool mv_cesa_ahash_cache_req(struct ahash_request *req)
{
struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ bool cached = false;
- if (creq->cache_ptr + req->nbytes < 64 && !creq->last_req) {
- *cached = true;
+ if (creq->cache_ptr + req->nbytes < CESA_MAX_HASH_BLOCK_SIZE && !creq->last_req) {
+ cached = true;
if (!req->nbytes)
- return 0;
+ return cached;
sg_pcopy_to_buffer(req->src, creq->src_nents,
creq->cache + creq->cache_ptr,
@@ -422,7 +421,7 @@ static int mv_cesa_ahash_cache_req(struct ahash_request *req, bool *cached)
creq->cache_ptr += req->nbytes;
}
- return 0;
+ return cached;
}
static struct mv_cesa_op_ctx *
@@ -455,7 +454,6 @@ mv_cesa_dma_add_frag(struct mv_cesa_tdma_chain *chain,
static int
mv_cesa_ahash_dma_add_cache(struct mv_cesa_tdma_chain *chain,
- struct mv_cesa_ahash_dma_iter *dma_iter,
struct mv_cesa_ahash_req *creq,
gfp_t flags)
{
@@ -586,7 +584,7 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
* Add the cache (left-over data from a previous block) first.
* This will never overflow the SRAM size.
*/
- ret = mv_cesa_ahash_dma_add_cache(&basereq->chain, &iter, creq, flags);
+ ret = mv_cesa_ahash_dma_add_cache(&basereq->chain, creq, flags);
if (ret)
goto err_free_tdma;
@@ -668,7 +666,6 @@ err:
static int mv_cesa_ahash_req_init(struct ahash_request *req, bool *cached)
{
struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
- int ret;
creq->src_nents = sg_nents_for_len(req->src, req->nbytes);
if (creq->src_nents < 0) {
@@ -676,17 +673,15 @@ static int mv_cesa_ahash_req_init(struct ahash_request *req, bool *cached)
return creq->src_nents;
}
- ret = mv_cesa_ahash_cache_req(req, cached);
- if (ret)
- return ret;
+ *cached = mv_cesa_ahash_cache_req(req);
if (*cached)
return 0;
if (cesa_dev->caps->has_tdma)
- ret = mv_cesa_ahash_dma_req_init(req);
-
- return ret;
+ return mv_cesa_ahash_dma_req_init(req);
+ else
+ return 0;
}
static int mv_cesa_ahash_queue_req(struct ahash_request *req)
@@ -805,13 +800,14 @@ static int mv_cesa_md5_init(struct ahash_request *req)
struct mv_cesa_op_ctx tmpl = { };
mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_MD5);
+
+ mv_cesa_ahash_init(req, &tmpl, true);
+
creq->state[0] = MD5_H0;
creq->state[1] = MD5_H1;
creq->state[2] = MD5_H2;
creq->state[3] = MD5_H3;
- mv_cesa_ahash_init(req, &tmpl, true);
-
return 0;
}
@@ -873,14 +869,15 @@ static int mv_cesa_sha1_init(struct ahash_request *req)
struct mv_cesa_op_ctx tmpl = { };
mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_SHA1);
+
+ mv_cesa_ahash_init(req, &tmpl, false);
+
creq->state[0] = SHA1_H0;
creq->state[1] = SHA1_H1;
creq->state[2] = SHA1_H2;
creq->state[3] = SHA1_H3;
creq->state[4] = SHA1_H4;
- mv_cesa_ahash_init(req, &tmpl, false);
-
return 0;
}
@@ -942,6 +939,9 @@ static int mv_cesa_sha256_init(struct ahash_request *req)
struct mv_cesa_op_ctx tmpl = { };
mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_SHA256);
+
+ mv_cesa_ahash_init(req, &tmpl, false);
+
creq->state[0] = SHA256_H0;
creq->state[1] = SHA256_H1;
creq->state[2] = SHA256_H2;
@@ -951,8 +951,6 @@ static int mv_cesa_sha256_init(struct ahash_request *req)
creq->state[6] = SHA256_H6;
creq->state[7] = SHA256_H7;
- mv_cesa_ahash_init(req, &tmpl, false);
-
return 0;
}
diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c
index 86a065bcc187..9fd7a5fbaa1b 100644
--- a/drivers/crypto/marvell/tdma.c
+++ b/drivers/crypto/marvell/tdma.c
@@ -261,6 +261,7 @@ struct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain,
tdma->op = op;
tdma->byte_cnt = cpu_to_le32(size | BIT(31));
tdma->src = cpu_to_le32(dma_handle);
+ tdma->dst = CESA_SA_CFG_SRAM_OFFSET;
tdma->flags = CESA_TDMA_DST_IN_SRAM | CESA_TDMA_OP;
return op;
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index e6b658faef63..104e9ce9400a 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -1091,11 +1091,8 @@ static int mv_probe(struct platform_device *pdev)
cp->max_req_size = cp->sram_size - SRAM_CFG_SPACE;
- if (pdev->dev.of_node)
- irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
- else
- irq = platform_get_irq(pdev, 0);
- if (irq < 0 || irq == NO_IRQ) {
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
ret = irq;
goto err;
}
diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c
index ff383ef83871..ee4be1b0d30b 100644
--- a/drivers/crypto/mxc-scc.c
+++ b/drivers/crypto/mxc-scc.c
@@ -668,7 +668,9 @@ static int mxc_scc_probe(struct platform_device *pdev)
return PTR_ERR(scc->clk);
}
- clk_prepare_enable(scc->clk);
+ ret = clk_prepare_enable(scc->clk);
+ if (ret)
+ return ret;
/* clear error status register */
writel(0x0, scc->base + SCC_SCM_ERROR_STATUS);
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 4ab53a604312..fe32dd95ae4f 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -35,7 +35,8 @@
#include <linux/interrupt.h>
#include <crypto/scatterwalk.h>
#include <crypto/aes.h>
-#include <crypto/algapi.h>
+#include <crypto/engine.h>
+#include <crypto/internal/skcipher.h>
#define DST_MAXBURST 4
#define DMA_MIN (DST_MAXBURST * sizeof(u32))
@@ -85,6 +86,8 @@
#define AES_REG_IRQ_DATA_OUT BIT(2)
#define DEFAULT_TIMEOUT (5*HZ)
+#define DEFAULT_AUTOSUSPEND_DELAY 1000
+
#define FLAGS_MODE_MASK 0x000f
#define FLAGS_ENCRYPT BIT(0)
#define FLAGS_CBC BIT(1)
@@ -103,6 +106,7 @@ struct omap_aes_ctx {
int keylen;
u32 key[AES_KEYSIZE_256 / sizeof(u32)];
unsigned long flags;
+ struct crypto_skcipher *fallback;
};
struct omap_aes_reqctx {
@@ -238,11 +242,19 @@ static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset,
static int omap_aes_hw_init(struct omap_aes_dev *dd)
{
+ int err;
+
if (!(dd->flags & FLAGS_INIT)) {
dd->flags |= FLAGS_INIT;
dd->err = 0;
}
+ err = pm_runtime_get_sync(dd->dev);
+ if (err < 0) {
+ dev_err(dd->dev, "failed to get sync: %d\n", err);
+ return err;
+ }
+
return 0;
}
@@ -319,20 +331,12 @@ static void omap_aes_dma_stop(struct omap_aes_dev *dd)
static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
{
- struct omap_aes_dev *dd = NULL, *tmp;
+ struct omap_aes_dev *dd;
spin_lock_bh(&list_lock);
- if (!ctx->dd) {
- list_for_each_entry(tmp, &dev_list, list) {
- /* FIXME: take fist available aes core */
- dd = tmp;
- break;
- }
- ctx->dd = dd;
- } else {
- /* already found before */
- dd = ctx->dd;
- }
+ dd = list_first_entry(&dev_list, struct omap_aes_dev, list);
+ list_move_tail(&dd->list, &dev_list);
+ ctx->dd = dd;
spin_unlock_bh(&list_lock);
return dd;
@@ -519,7 +523,10 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
pr_debug("err: %d\n", err);
- crypto_finalize_request(dd->engine, req, err);
+ crypto_finalize_cipher_request(dd->engine, req, err);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
}
static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
@@ -592,7 +599,7 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
struct ablkcipher_request *req)
{
if (req)
- return crypto_transfer_request_to_engine(dd->engine, req);
+ return crypto_transfer_cipher_request_to_engine(dd->engine, req);
return 0;
}
@@ -602,7 +609,7 @@ static int omap_aes_prepare_req(struct crypto_engine *engine,
{
struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
- struct omap_aes_dev *dd = omap_aes_find_dev(ctx);
+ struct omap_aes_dev *dd = ctx->dd;
struct omap_aes_reqctx *rctx;
if (!dd)
@@ -648,7 +655,7 @@ static int omap_aes_crypt_req(struct crypto_engine *engine,
{
struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
- struct omap_aes_dev *dd = omap_aes_find_dev(ctx);
+ struct omap_aes_dev *dd = ctx->dd;
if (!dd)
return -ENODEV;
@@ -696,11 +703,29 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
crypto_ablkcipher_reqtfm(req));
struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
struct omap_aes_dev *dd;
+ int ret;
pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
!!(mode & FLAGS_ENCRYPT),
!!(mode & FLAGS_CBC));
+ if (req->nbytes < 200) {
+ SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+
+ skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_callback(subreq, req->base.flags, NULL,
+ NULL);
+ skcipher_request_set_crypt(subreq, req->src, req->dst,
+ req->nbytes, req->info);
+
+ if (mode & FLAGS_ENCRYPT)
+ ret = crypto_skcipher_encrypt(subreq);
+ else
+ ret = crypto_skcipher_decrypt(subreq);
+
+ skcipher_request_zero(subreq);
+ return ret;
+ }
dd = omap_aes_find_dev(ctx);
if (!dd)
return -ENODEV;
@@ -716,6 +741,7 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
unsigned int keylen)
{
struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ int ret;
if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
keylen != AES_KEYSIZE_256)
@@ -726,6 +752,14 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
memcpy(ctx->key, key, keylen);
ctx->keylen = keylen;
+ crypto_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags &
+ CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ if (!ret)
+ return 0;
+
return 0;
}
@@ -761,22 +795,16 @@ static int omap_aes_ctr_decrypt(struct ablkcipher_request *req)
static int omap_aes_cra_init(struct crypto_tfm *tfm)
{
- struct omap_aes_dev *dd = NULL;
- int err;
+ const char *name = crypto_tfm_alg_name(tfm);
+ const u32 flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK;
+ struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_skcipher *blk;
- /* Find AES device, currently picks the first device */
- spin_lock_bh(&list_lock);
- list_for_each_entry(dd, &dev_list, list) {
- break;
- }
- spin_unlock_bh(&list_lock);
+ blk = crypto_alloc_skcipher(name, 0, flags);
+ if (IS_ERR(blk))
+ return PTR_ERR(blk);
- err = pm_runtime_get_sync(dd->dev);
- if (err < 0) {
- dev_err(dd->dev, "%s: failed to get_sync(%d)\n",
- __func__, err);
- return err;
- }
+ ctx->fallback = blk;
tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
@@ -785,16 +813,12 @@ static int omap_aes_cra_init(struct crypto_tfm *tfm)
static void omap_aes_cra_exit(struct crypto_tfm *tfm)
{
- struct omap_aes_dev *dd = NULL;
+ struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
- /* Find AES device, currently picks the first device */
- spin_lock_bh(&list_lock);
- list_for_each_entry(dd, &dev_list, list) {
- break;
- }
- spin_unlock_bh(&list_lock);
+ if (ctx->fallback)
+ crypto_free_skcipher(ctx->fallback);
- pm_runtime_put_sync(dd->dev);
+ ctx->fallback = NULL;
}
/* ********************** ALGS ************************************ */
@@ -806,7 +830,7 @@ static struct crypto_alg algs_ecb_cbc[] = {
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_aes_ctx),
.cra_alignmask = 0,
@@ -828,7 +852,7 @@ static struct crypto_alg algs_ecb_cbc[] = {
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_aes_ctx),
.cra_alignmask = 0,
@@ -854,7 +878,7 @@ static struct crypto_alg algs_ctr[] = {
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_aes_ctx),
.cra_alignmask = 0,
@@ -1140,6 +1164,9 @@ static int omap_aes_probe(struct platform_device *pdev)
}
dd->phys_base = res.start;
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
+
pm_runtime_enable(dev);
err = pm_runtime_get_sync(dev);
if (err < 0) {
@@ -1186,6 +1213,19 @@ static int omap_aes_probe(struct platform_device *pdev)
list_add_tail(&dd->list, &dev_list);
spin_unlock(&list_lock);
+ /* Initialize crypto engine */
+ dd->engine = crypto_engine_alloc_init(dev, 1);
+ if (!dd->engine) {
+ err = -ENOMEM;
+ goto err_engine;
+ }
+
+ dd->engine->prepare_cipher_request = omap_aes_prepare_req;
+ dd->engine->cipher_one_request = omap_aes_crypt_req;
+ err = crypto_engine_start(dd->engine);
+ if (err)
+ goto err_engine;
+
for (i = 0; i < dd->pdata->algs_info_size; i++) {
if (!dd->pdata->algs_info[i].registered) {
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
@@ -1203,26 +1243,17 @@ static int omap_aes_probe(struct platform_device *pdev)
}
}
- /* Initialize crypto engine */
- dd->engine = crypto_engine_alloc_init(dev, 1);
- if (!dd->engine)
- goto err_algs;
-
- dd->engine->prepare_request = omap_aes_prepare_req;
- dd->engine->crypt_one_request = omap_aes_crypt_req;
- err = crypto_engine_start(dd->engine);
- if (err)
- goto err_engine;
-
return 0;
-err_engine:
- crypto_engine_exit(dd->engine);
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
crypto_unregister_alg(
&dd->pdata->algs_info[i].algs_list[j]);
+err_engine:
+ if (dd->engine)
+ crypto_engine_exit(dd->engine);
+
omap_aes_dma_cleanup(dd);
err_irq:
tasklet_kill(&dd->done_task);
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index 5691434ffb2d..a6f65532fd16 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -39,6 +39,7 @@
#include <crypto/scatterwalk.h>
#include <crypto/des.h>
#include <crypto/algapi.h>
+#include <crypto/engine.h>
#define DST_MAXBURST 2
@@ -506,7 +507,7 @@ static void omap_des_finish_req(struct omap_des_dev *dd, int err)
pr_debug("err: %d\n", err);
pm_runtime_put(dd->dev);
- crypto_finalize_request(dd->engine, req, err);
+ crypto_finalize_cipher_request(dd->engine, req, err);
}
static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
@@ -574,7 +575,7 @@ static int omap_des_handle_queue(struct omap_des_dev *dd,
struct ablkcipher_request *req)
{
if (req)
- return crypto_transfer_request_to_engine(dd->engine, req);
+ return crypto_transfer_cipher_request_to_engine(dd->engine, req);
return 0;
}
@@ -1078,6 +1079,19 @@ static int omap_des_probe(struct platform_device *pdev)
list_add_tail(&dd->list, &dev_list);
spin_unlock(&list_lock);
+ /* Initialize des crypto engine */
+ dd->engine = crypto_engine_alloc_init(dev, 1);
+ if (!dd->engine) {
+ err = -ENOMEM;
+ goto err_engine;
+ }
+
+ dd->engine->prepare_cipher_request = omap_des_prepare_req;
+ dd->engine->cipher_one_request = omap_des_crypt_req;
+ err = crypto_engine_start(dd->engine);
+ if (err)
+ goto err_engine;
+
for (i = 0; i < dd->pdata->algs_info_size; i++) {
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
algp = &dd->pdata->algs_info[i].algs_list[j];
@@ -1093,27 +1107,18 @@ static int omap_des_probe(struct platform_device *pdev)
}
}
- /* Initialize des crypto engine */
- dd->engine = crypto_engine_alloc_init(dev, 1);
- if (!dd->engine)
- goto err_algs;
-
- dd->engine->prepare_request = omap_des_prepare_req;
- dd->engine->crypt_one_request = omap_des_crypt_req;
- err = crypto_engine_start(dd->engine);
- if (err)
- goto err_engine;
-
return 0;
-err_engine:
- crypto_engine_exit(dd->engine);
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
crypto_unregister_alg(
&dd->pdata->algs_info[i].algs_list[j]);
+err_engine:
+ if (dd->engine)
+ crypto_engine_exit(dd->engine);
+
omap_des_dma_cleanup(dd);
err_irq:
tasklet_kill(&dd->done_task);
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 7fe4eef12fe2..d0b16e5e4ee5 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -112,9 +112,10 @@
#define FLAGS_DMA_READY 6
#define FLAGS_AUTO_XOR 7
#define FLAGS_BE32_SHA1 8
+#define FLAGS_SGS_COPIED 9
+#define FLAGS_SGS_ALLOCED 10
/* context flags */
#define FLAGS_FINUP 16
-#define FLAGS_SG 17
#define FLAGS_MODE_SHIFT 18
#define FLAGS_MODE_MASK (SHA_REG_MODE_ALGO_MASK << FLAGS_MODE_SHIFT)
@@ -134,7 +135,8 @@
#define OMAP_ALIGN_MASK (sizeof(u32)-1)
#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32))))
-#define BUFLEN PAGE_SIZE
+#define BUFLEN SHA512_BLOCK_SIZE
+#define OMAP_SHA_DMA_THRESHOLD 256
struct omap_sham_dev;
@@ -147,12 +149,12 @@ struct omap_sham_reqctx {
size_t digcnt;
size_t bufcnt;
size_t buflen;
- dma_addr_t dma_addr;
/* walk state */
struct scatterlist *sg;
- struct scatterlist sgl;
- unsigned int offset; /* offset in current sg */
+ struct scatterlist sgl[2];
+ int offset; /* offset in current sg */
+ int sg_len;
unsigned int total; /* total request */
u8 buffer[0] OMAP_ALIGNED;
@@ -223,6 +225,7 @@ struct omap_sham_dev {
struct dma_chan *dma_lch;
struct tasklet_struct done_task;
u8 polling_mode;
+ u8 xmit_buf[BUFLEN];
unsigned long flags;
struct crypto_queue queue;
@@ -510,12 +513,14 @@ static int omap_sham_poll_irq_omap4(struct omap_sham_dev *dd)
SHA_REG_IRQSTATUS_INPUT_RDY);
}
-static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
- size_t length, int final)
+static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, size_t length,
+ int final)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
int count, len32, bs32, offset = 0;
- const u32 *buffer = (const u32 *)buf;
+ const u32 *buffer;
+ int mlen;
+ struct sg_mapping_iter mi;
dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
@@ -525,6 +530,7 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
/* should be non-zero before next lines to disable clocks later */
ctx->digcnt += length;
+ ctx->total -= length;
if (final)
set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
@@ -534,16 +540,35 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
len32 = DIV_ROUND_UP(length, sizeof(u32));
bs32 = get_block_size(ctx) / sizeof(u32);
+ sg_miter_start(&mi, ctx->sg, ctx->sg_len,
+ SG_MITER_FROM_SG | SG_MITER_ATOMIC);
+
+ mlen = 0;
+
while (len32) {
if (dd->pdata->poll_irq(dd))
return -ETIMEDOUT;
- for (count = 0; count < min(len32, bs32); count++, offset++)
+ for (count = 0; count < min(len32, bs32); count++, offset++) {
+ if (!mlen) {
+ sg_miter_next(&mi);
+ mlen = mi.length;
+ if (!mlen) {
+ pr_err("sg miter failure.\n");
+ return -EINVAL;
+ }
+ offset = 0;
+ buffer = mi.addr;
+ }
omap_sham_write(dd, SHA_REG_DIN(dd, count),
buffer[offset]);
+ mlen -= 4;
+ }
len32 -= min(len32, bs32);
}
+ sg_miter_stop(&mi);
+
return -EINPROGRESS;
}
@@ -555,22 +580,27 @@ static void omap_sham_dma_callback(void *param)
tasklet_schedule(&dd->done_task);
}
-static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
- size_t length, int final, int is_sg)
+static int omap_sham_xmit_dma(struct omap_sham_dev *dd, size_t length,
+ int final)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
struct dma_async_tx_descriptor *tx;
struct dma_slave_config cfg;
- int len32, ret, dma_min = get_block_size(ctx);
+ int ret;
dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
+ if (!dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE)) {
+ dev_err(dd->dev, "dma_map_sg error\n");
+ return -EINVAL;
+ }
+
memset(&cfg, 0, sizeof(cfg));
cfg.dst_addr = dd->phys_base + SHA_REG_DIN(dd, 0);
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_maxburst = dma_min / DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_maxburst = get_block_size(ctx) / DMA_SLAVE_BUSWIDTH_4_BYTES;
ret = dmaengine_slave_config(dd->dma_lch, &cfg);
if (ret) {
@@ -578,30 +608,12 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
return ret;
}
- len32 = DIV_ROUND_UP(length, dma_min) * dma_min;
-
- if (is_sg) {
- /*
- * The SG entry passed in may not have the 'length' member
- * set correctly so use a local SG entry (sgl) with the
- * proper value for 'length' instead. If this is not done,
- * the dmaengine may try to DMA the incorrect amount of data.
- */
- sg_init_table(&ctx->sgl, 1);
- sg_assign_page(&ctx->sgl, sg_page(ctx->sg));
- ctx->sgl.offset = ctx->sg->offset;
- sg_dma_len(&ctx->sgl) = len32;
- sg_dma_address(&ctx->sgl) = sg_dma_address(ctx->sg);
-
- tx = dmaengine_prep_slave_sg(dd->dma_lch, &ctx->sgl, 1,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- } else {
- tx = dmaengine_prep_slave_single(dd->dma_lch, dma_addr, len32,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- }
+ tx = dmaengine_prep_slave_sg(dd->dma_lch, ctx->sg, ctx->sg_len,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!tx) {
- dev_err(dd->dev, "prep_slave_sg/single() failed\n");
+ dev_err(dd->dev, "prep_slave_sg failed\n");
return -EINVAL;
}
@@ -611,6 +623,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
dd->pdata->write_ctrl(dd, length, final, 1);
ctx->digcnt += length;
+ ctx->total -= length;
if (final)
set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
@@ -625,189 +638,257 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
return -EINPROGRESS;
}
-static size_t omap_sham_append_buffer(struct omap_sham_reqctx *ctx,
- const u8 *data, size_t length)
+static int omap_sham_copy_sg_lists(struct omap_sham_reqctx *ctx,
+ struct scatterlist *sg, int bs, int new_len)
{
- size_t count = min(length, ctx->buflen - ctx->bufcnt);
+ int n = sg_nents(sg);
+ struct scatterlist *tmp;
+ int offset = ctx->offset;
- count = min(count, ctx->total);
- if (count <= 0)
- return 0;
- memcpy(ctx->buffer + ctx->bufcnt, data, count);
- ctx->bufcnt += count;
+ if (ctx->bufcnt)
+ n++;
- return count;
-}
+ ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL);
+ if (!ctx->sg)
+ return -ENOMEM;
-static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx)
-{
- size_t count;
- const u8 *vaddr;
+ sg_init_table(ctx->sg, n);
- while (ctx->sg) {
- vaddr = kmap_atomic(sg_page(ctx->sg));
- vaddr += ctx->sg->offset;
+ tmp = ctx->sg;
- count = omap_sham_append_buffer(ctx,
- vaddr + ctx->offset,
- ctx->sg->length - ctx->offset);
+ ctx->sg_len = 0;
- kunmap_atomic((void *)vaddr);
+ if (ctx->bufcnt) {
+ sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt);
+ tmp = sg_next(tmp);
+ ctx->sg_len++;
+ }
- if (!count)
- break;
- ctx->offset += count;
- ctx->total -= count;
- if (ctx->offset == ctx->sg->length) {
- ctx->sg = sg_next(ctx->sg);
- if (ctx->sg)
- ctx->offset = 0;
- else
- ctx->total = 0;
+ while (sg && new_len) {
+ int len = sg->length - offset;
+
+ if (offset) {
+ offset -= sg->length;
+ if (offset < 0)
+ offset = 0;
+ }
+
+ if (new_len < len)
+ len = new_len;
+
+ if (len > 0) {
+ new_len -= len;
+ sg_set_page(tmp, sg_page(sg), len, sg->offset);
+ if (new_len <= 0)
+ sg_mark_end(tmp);
+ tmp = sg_next(tmp);
+ ctx->sg_len++;
}
+
+ sg = sg_next(sg);
}
+ set_bit(FLAGS_SGS_ALLOCED, &ctx->dd->flags);
+
+ ctx->bufcnt = 0;
+
return 0;
}
-static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd,
- struct omap_sham_reqctx *ctx,
- size_t length, int final)
+static int omap_sham_copy_sgs(struct omap_sham_reqctx *ctx,
+ struct scatterlist *sg, int bs, int new_len)
{
- int ret;
+ int pages;
+ void *buf;
+ int len;
- ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
- dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen);
- return -EINVAL;
+ len = new_len + ctx->bufcnt;
+
+ pages = get_order(ctx->total);
+
+ buf = (void *)__get_free_pages(GFP_ATOMIC, pages);
+ if (!buf) {
+ pr_err("Couldn't allocate pages for unaligned cases.\n");
+ return -ENOMEM;
}
- ctx->flags &= ~BIT(FLAGS_SG);
+ if (ctx->bufcnt)
+ memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt);
- ret = omap_sham_xmit_dma(dd, ctx->dma_addr, length, final, 0);
- if (ret != -EINPROGRESS)
- dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
- DMA_TO_DEVICE);
+ scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->offset,
+ ctx->total - ctx->bufcnt, 0);
+ sg_init_table(ctx->sgl, 1);
+ sg_set_buf(ctx->sgl, buf, len);
+ ctx->sg = ctx->sgl;
+ set_bit(FLAGS_SGS_COPIED, &ctx->dd->flags);
+ ctx->sg_len = 1;
+ ctx->bufcnt = 0;
+ ctx->offset = 0;
- return ret;
+ return 0;
}
-static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
+static int omap_sham_align_sgs(struct scatterlist *sg,
+ int nbytes, int bs, bool final,
+ struct omap_sham_reqctx *rctx)
{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- unsigned int final;
- size_t count;
+ int n = 0;
+ bool aligned = true;
+ bool list_ok = true;
+ struct scatterlist *sg_tmp = sg;
+ int new_len;
+ int offset = rctx->offset;
- omap_sham_append_sg(ctx);
+ if (!sg || !sg->length || !nbytes)
+ return 0;
+
+ new_len = nbytes;
- final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
+ if (offset)
+ list_ok = false;
- dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
- ctx->bufcnt, ctx->digcnt, final);
+ if (final)
+ new_len = DIV_ROUND_UP(new_len, bs) * bs;
+ else
+ new_len = new_len / bs * bs;
- if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
- count = ctx->bufcnt;
- ctx->bufcnt = 0;
- return omap_sham_xmit_dma_map(dd, ctx, count, final);
+ while (nbytes > 0 && sg_tmp) {
+ n++;
+
+ if (offset < sg_tmp->length) {
+ if (!IS_ALIGNED(offset + sg_tmp->offset, 4)) {
+ aligned = false;
+ break;
+ }
+
+ if (!IS_ALIGNED(sg_tmp->length - offset, bs)) {
+ aligned = false;
+ break;
+ }
+ }
+
+ if (offset) {
+ offset -= sg_tmp->length;
+ if (offset < 0) {
+ nbytes += offset;
+ offset = 0;
+ }
+ } else {
+ nbytes -= sg_tmp->length;
+ }
+
+ sg_tmp = sg_next(sg_tmp);
+
+ if (nbytes < 0) {
+ list_ok = false;
+ break;
+ }
}
+ if (!aligned)
+ return omap_sham_copy_sgs(rctx, sg, bs, new_len);
+ else if (!list_ok)
+ return omap_sham_copy_sg_lists(rctx, sg, bs, new_len);
+
+ rctx->sg_len = n;
+ rctx->sg = sg;
+
return 0;
}
-/* Start address alignment */
-#define SG_AA(sg) (IS_ALIGNED(sg->offset, sizeof(u32)))
-/* SHA1 block size alignment */
-#define SG_SA(sg, bs) (IS_ALIGNED(sg->length, bs))
-
-static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
+static int omap_sham_prepare_request(struct ahash_request *req, bool update)
{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- unsigned int length, final, tail;
- struct scatterlist *sg;
- int ret, bs;
+ struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
+ int bs;
+ int ret;
+ int nbytes;
+ bool final = rctx->flags & BIT(FLAGS_FINUP);
+ int xmit_len, hash_later;
- if (!ctx->total)
+ if (!req)
return 0;
- if (ctx->bufcnt || ctx->offset)
- return omap_sham_update_dma_slow(dd);
-
- /*
- * Don't use the sg interface when the transfer size is less
- * than the number of elements in a DMA frame. Otherwise,
- * the dmaengine infrastructure will calculate that it needs
- * to transfer 0 frames which ultimately fails.
- */
- if (ctx->total < get_block_size(ctx))
- return omap_sham_update_dma_slow(dd);
-
- dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
- ctx->digcnt, ctx->bufcnt, ctx->total);
+ bs = get_block_size(rctx);
- sg = ctx->sg;
- bs = get_block_size(ctx);
+ if (update)
+ nbytes = req->nbytes;
+ else
+ nbytes = 0;
- if (!SG_AA(sg))
- return omap_sham_update_dma_slow(dd);
+ rctx->total = nbytes + rctx->bufcnt;
- if (!sg_is_last(sg) && !SG_SA(sg, bs))
- /* size is not BLOCK_SIZE aligned */
- return omap_sham_update_dma_slow(dd);
+ if (!rctx->total)
+ return 0;
- length = min(ctx->total, sg->length);
+ if (nbytes && (!IS_ALIGNED(rctx->bufcnt, bs))) {
+ int len = bs - rctx->bufcnt % bs;
- if (sg_is_last(sg)) {
- if (!(ctx->flags & BIT(FLAGS_FINUP))) {
- /* not last sg must be BLOCK_SIZE aligned */
- tail = length & (bs - 1);
- /* without finup() we need one block to close hash */
- if (!tail)
- tail = bs;
- length -= tail;
- }
+ if (len > nbytes)
+ len = nbytes;
+ scatterwalk_map_and_copy(rctx->buffer + rctx->bufcnt, req->src,
+ 0, len, 0);
+ rctx->bufcnt += len;
+ nbytes -= len;
+ rctx->offset = len;
}
- if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
- dev_err(dd->dev, "dma_map_sg error\n");
- return -EINVAL;
- }
+ if (rctx->bufcnt)
+ memcpy(rctx->dd->xmit_buf, rctx->buffer, rctx->bufcnt);
- ctx->flags |= BIT(FLAGS_SG);
+ ret = omap_sham_align_sgs(req->src, nbytes, bs, final, rctx);
+ if (ret)
+ return ret;
- ctx->total -= length;
- ctx->offset = length; /* offset where to start slow */
+ xmit_len = rctx->total;
- final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
+ if (!IS_ALIGNED(xmit_len, bs)) {
+ if (final)
+ xmit_len = DIV_ROUND_UP(xmit_len, bs) * bs;
+ else
+ xmit_len = xmit_len / bs * bs;
+ }
- ret = omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final, 1);
- if (ret != -EINPROGRESS)
- dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
+ hash_later = rctx->total - xmit_len;
+ if (hash_later < 0)
+ hash_later = 0;
- return ret;
-}
+ if (rctx->bufcnt && nbytes) {
+ /* have data from previous operation and current */
+ sg_init_table(rctx->sgl, 2);
+ sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, rctx->bufcnt);
-static int omap_sham_update_cpu(struct omap_sham_dev *dd)
-{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- int bufcnt, final;
+ sg_chain(rctx->sgl, 2, req->src);
- if (!ctx->total)
- return 0;
+ rctx->sg = rctx->sgl;
- omap_sham_append_sg(ctx);
+ rctx->sg_len++;
+ } else if (rctx->bufcnt) {
+ /* have buffered data only */
+ sg_init_table(rctx->sgl, 1);
+ sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, xmit_len);
- final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
+ rctx->sg = rctx->sgl;
- dev_dbg(dd->dev, "cpu: bufcnt: %u, digcnt: %d, final: %d\n",
- ctx->bufcnt, ctx->digcnt, final);
+ rctx->sg_len = 1;
+ }
- if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
- bufcnt = ctx->bufcnt;
- ctx->bufcnt = 0;
- return omap_sham_xmit_cpu(dd, ctx->buffer, bufcnt, final);
+ if (hash_later) {
+ if (req->nbytes) {
+ scatterwalk_map_and_copy(rctx->buffer, req->src,
+ req->nbytes - hash_later,
+ hash_later, 0);
+ } else {
+ memcpy(rctx->buffer, rctx->buffer + xmit_len,
+ hash_later);
+ }
+ rctx->bufcnt = hash_later;
+ } else {
+ rctx->bufcnt = 0;
}
+ if (!final)
+ rctx->total = xmit_len;
+
return 0;
}
@@ -815,18 +896,9 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
+ dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE);
- if (ctx->flags & BIT(FLAGS_SG)) {
- dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
- if (ctx->sg->length == ctx->offset) {
- ctx->sg = sg_next(ctx->sg);
- if (ctx->sg)
- ctx->offset = 0;
- }
- } else {
- dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
- DMA_TO_DEVICE);
- }
+ clear_bit(FLAGS_DMA_ACTIVE, &dd->flags);
return 0;
}
@@ -887,6 +959,8 @@ static int omap_sham_init(struct ahash_request *req)
ctx->bufcnt = 0;
ctx->digcnt = 0;
+ ctx->total = 0;
+ ctx->offset = 0;
ctx->buflen = BUFLEN;
if (tctx->flags & BIT(FLAGS_HMAC)) {
@@ -909,14 +983,19 @@ static int omap_sham_update_req(struct omap_sham_dev *dd)
struct ahash_request *req = dd->req;
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int err;
+ bool final = ctx->flags & BIT(FLAGS_FINUP);
dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
ctx->total, ctx->digcnt, (ctx->flags & BIT(FLAGS_FINUP)) != 0);
+ if (ctx->total < get_block_size(ctx) ||
+ ctx->total < OMAP_SHA_DMA_THRESHOLD)
+ ctx->flags |= BIT(FLAGS_CPU);
+
if (ctx->flags & BIT(FLAGS_CPU))
- err = omap_sham_update_cpu(dd);
+ err = omap_sham_xmit_cpu(dd, ctx->total, final);
else
- err = omap_sham_update_dma_start(dd);
+ err = omap_sham_xmit_dma(dd, ctx->total, final);
/* wait for dma completion before can take more data */
dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt);
@@ -930,7 +1009,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int err = 0, use_dma = 1;
- if ((ctx->bufcnt <= get_block_size(ctx)) || dd->polling_mode)
+ if ((ctx->total <= get_block_size(ctx)) || dd->polling_mode)
/*
* faster to handle last block with cpu or
* use cpu when dma is not present.
@@ -938,9 +1017,9 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
use_dma = 0;
if (use_dma)
- err = omap_sham_xmit_dma_map(dd, ctx, ctx->bufcnt, 1);
+ err = omap_sham_xmit_dma(dd, ctx->total, 1);
else
- err = omap_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1);
+ err = omap_sham_xmit_cpu(dd, ctx->total, 1);
ctx->bufcnt = 0;
@@ -988,6 +1067,17 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_dev *dd = ctx->dd;
+ if (test_bit(FLAGS_SGS_COPIED, &dd->flags))
+ free_pages((unsigned long)sg_virt(ctx->sg),
+ get_order(ctx->sg->length));
+
+ if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags))
+ kfree(ctx->sg);
+
+ ctx->sg = NULL;
+
+ dd->flags &= ~(BIT(FLAGS_SGS_ALLOCED) | BIT(FLAGS_SGS_COPIED));
+
if (!err) {
dd->pdata->copy_hash(req, 1);
if (test_bit(FLAGS_FINAL, &dd->flags))
@@ -1005,9 +1095,6 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
if (req->base.complete)
req->base.complete(&req->base, err);
-
- /* handle new request */
- tasklet_schedule(&dd->done_task);
}
static int omap_sham_handle_queue(struct omap_sham_dev *dd,
@@ -1018,6 +1105,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
unsigned long flags;
int err = 0, ret = 0;
+retry:
spin_lock_irqsave(&dd->lock, flags);
if (req)
ret = ahash_enqueue_request(&dd->queue, req);
@@ -1041,6 +1129,10 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
dd->req = req;
ctx = ahash_request_ctx(req);
+ err = omap_sham_prepare_request(req, ctx->op == OP_UPDATE);
+ if (err)
+ goto err1;
+
dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
ctx->op, req->nbytes);
@@ -1061,11 +1153,19 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
err = omap_sham_final_req(dd);
}
err1:
- if (err != -EINPROGRESS)
+ dev_dbg(dd->dev, "exit, err: %d\n", err);
+
+ if (err != -EINPROGRESS) {
/* done_task will not finish it, so do it here */
omap_sham_finish_req(req, err);
+ req = NULL;
- dev_dbg(dd->dev, "exit, err: %d\n", err);
+ /*
+ * Execute next request immediately if there is anything
+ * in queue.
+ */
+ goto retry;
+ }
return ret;
}
@@ -1085,34 +1185,15 @@ static int omap_sham_update(struct ahash_request *req)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_dev *dd = ctx->dd;
- int bs = get_block_size(ctx);
if (!req->nbytes)
return 0;
- ctx->total = req->nbytes;
- ctx->sg = req->src;
- ctx->offset = 0;
-
- if (ctx->flags & BIT(FLAGS_FINUP)) {
- if ((ctx->digcnt + ctx->bufcnt + ctx->total) < 240) {
- /*
- * OMAP HW accel works only with buffers >= 9
- * will switch to bypass in final()
- * final has the same request and data
- */
- omap_sham_append_sg(ctx);
- return 0;
- } else if ((ctx->bufcnt + ctx->total <= bs) ||
- dd->polling_mode) {
- /*
- * faster to use CPU for short transfers or
- * use cpu when dma is not present.
- */
- ctx->flags |= BIT(FLAGS_CPU);
- }
- } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
- omap_sham_append_sg(ctx);
+ if (ctx->total + req->nbytes < ctx->buflen) {
+ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src,
+ 0, req->nbytes, 0);
+ ctx->bufcnt += req->nbytes;
+ ctx->total += req->nbytes;
return 0;
}
@@ -1137,9 +1218,20 @@ static int omap_sham_final_shash(struct ahash_request *req)
{
struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ int offset = 0;
+
+ /*
+ * If we are running HMAC on limited hardware support, skip
+ * the ipad in the beginning of the buffer if we are going for
+ * software fallback algorithm.
+ */
+ if (test_bit(FLAGS_HMAC, &ctx->flags) &&
+ !test_bit(FLAGS_AUTO_XOR, &ctx->dd->flags))
+ offset = get_block_size(ctx);
return omap_sham_shash_digest(tctx->fallback, req->base.flags,
- ctx->buffer, ctx->bufcnt, req->result);
+ ctx->buffer + offset,
+ ctx->bufcnt - offset, req->result);
}
static int omap_sham_final(struct ahash_request *req)
@@ -1154,10 +1246,11 @@ static int omap_sham_final(struct ahash_request *req)
/*
* OMAP HW accel works only with buffers >= 9.
* HMAC is always >= 9 because ipad == block size.
- * If buffersize is less than 240, we use fallback SW encoding,
- * as using DMA + HW in this case doesn't provide any benefit.
+ * If buffersize is less than DMA_THRESHOLD, we use fallback
+ * SW encoding, as using DMA + HW in this case doesn't provide
+ * any benefit.
*/
- if ((ctx->digcnt + ctx->bufcnt) < 240)
+ if (!ctx->digcnt && ctx->bufcnt < OMAP_SHA_DMA_THRESHOLD)
return omap_sham_final_shash(req);
else if (ctx->bufcnt)
return omap_sham_enqueue(req, OP_FINAL);
@@ -1323,6 +1416,25 @@ static void omap_sham_cra_exit(struct crypto_tfm *tfm)
}
}
+static int omap_sham_export(struct ahash_request *req, void *out)
+{
+ struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
+
+ memcpy(out, rctx, sizeof(*rctx) + rctx->bufcnt);
+
+ return 0;
+}
+
+static int omap_sham_import(struct ahash_request *req, const void *in)
+{
+ struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
+ const struct omap_sham_reqctx *ctx_in = in;
+
+ memcpy(rctx, in, sizeof(*rctx) + ctx_in->bufcnt);
+
+ return 0;
+}
+
static struct ahash_alg algs_sha1_md5[] = {
{
.init = omap_sham_init,
@@ -1341,7 +1453,7 @@ static struct ahash_alg algs_sha1_md5[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1440,7 +1552,7 @@ static struct ahash_alg algs_sha224_sha256[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1462,7 +1574,7 @@ static struct ahash_alg algs_sha224_sha256[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1535,7 +1647,7 @@ static struct ahash_alg algs_sha384_sha512[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1557,7 +1669,7 @@ static struct ahash_alg algs_sha384_sha512[] = {
CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct omap_sham_ctx),
- .cra_alignmask = 0,
+ .cra_alignmask = OMAP_ALIGN_MASK,
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
@@ -1624,12 +1736,8 @@ static void omap_sham_done_task(unsigned long data)
}
if (test_bit(FLAGS_CPU, &dd->flags)) {
- if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
- /* hash or semi-hash ready */
- err = omap_sham_update_cpu(dd);
- if (err != -EINPROGRESS)
- goto finish;
- }
+ if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
+ goto finish;
} else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
omap_sham_update_dma_stop(dd);
@@ -1641,8 +1749,6 @@ static void omap_sham_done_task(unsigned long data)
if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
/* hash or semi-hash ready */
clear_bit(FLAGS_DMA_READY, &dd->flags);
- err = omap_sham_update_dma_start(dd);
- if (err != -EINPROGRESS)
goto finish;
}
}
@@ -1653,6 +1759,10 @@ finish:
dev_dbg(dd->dev, "update done: err: %d\n", err);
/* finish curent request */
omap_sham_finish_req(dd->req, err);
+
+ /* If we are not busy, process next req */
+ if (!test_bit(FLAGS_BUSY, &dd->flags))
+ omap_sham_handle_queue(dd, NULL);
}
static irqreturn_t omap_sham_irq_common(struct omap_sham_dev *dd)
@@ -1977,8 +2087,14 @@ static int omap_sham_probe(struct platform_device *pdev)
for (i = 0; i < dd->pdata->algs_info_size; i++) {
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
- err = crypto_register_ahash(
- &dd->pdata->algs_info[i].algs_list[j]);
+ struct ahash_alg *alg;
+
+ alg = &dd->pdata->algs_info[i].algs_list[j];
+ alg->export = omap_sham_export;
+ alg->import = omap_sham_import;
+ alg->halg.statesize = sizeof(struct omap_sham_reqctx) +
+ BUFLEN;
+ err = crypto_register_ahash(alg);
if (err)
goto err_algs;
diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h
index 2f2681d3458a..afc9a0a86747 100644
--- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h
+++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h
@@ -55,7 +55,7 @@
#define ADF_C3XXX_MAX_ACCELERATORS 3
#define ADF_C3XXX_MAX_ACCELENGINES 6
#define ADF_C3XXX_ACCELERATORS_REG_OFFSET 16
-#define ADF_C3XXX_ACCELERATORS_MASK 0x3
+#define ADF_C3XXX_ACCELERATORS_MASK 0x7
#define ADF_C3XXX_ACCELENGINES_MASK 0x3F
#define ADF_C3XXX_ETR_MAX_BANKS 16
#define ADF_C3XXX_SMIAPF0_MASK_OFFSET (0x3A000 + 0x28)
diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c
index ce7c4626c983..3744b22f0c46 100644
--- a/drivers/crypto/qat/qat_common/adf_admin.c
+++ b/drivers/crypto/qat/qat_common/adf_admin.c
@@ -146,6 +146,7 @@ struct adf_admin_comms {
dma_addr_t phy_addr;
dma_addr_t const_tbl_addr;
void *virt_addr;
+ void *virt_tbl_addr;
void __iomem *mailbox_addr;
struct mutex lock; /* protects adf_admin_comms struct */
};
@@ -251,17 +252,19 @@ int adf_init_admin_comms(struct adf_accel_dev *accel_dev)
return -ENOMEM;
}
- admin->const_tbl_addr = dma_map_single(&GET_DEV(accel_dev),
- (void *) const_tab, 1024,
- DMA_TO_DEVICE);
-
- if (unlikely(dma_mapping_error(&GET_DEV(accel_dev),
- admin->const_tbl_addr))) {
+ admin->virt_tbl_addr = dma_zalloc_coherent(&GET_DEV(accel_dev),
+ PAGE_SIZE,
+ &admin->const_tbl_addr,
+ GFP_KERNEL);
+ if (!admin->virt_tbl_addr) {
+ dev_err(&GET_DEV(accel_dev), "Failed to allocate const_tbl\n");
dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE,
admin->virt_addr, admin->phy_addr);
kfree(admin);
return -ENOMEM;
}
+
+ memcpy(admin->virt_tbl_addr, const_tab, sizeof(const_tab));
reg_val = (u64)admin->phy_addr;
ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGUR_OFFSET, reg_val >> 32);
ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGLR_OFFSET, reg_val);
@@ -282,9 +285,10 @@ void adf_exit_admin_comms(struct adf_accel_dev *accel_dev)
if (admin->virt_addr)
dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE,
admin->virt_addr, admin->phy_addr);
+ if (admin->virt_tbl_addr)
+ dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE,
+ admin->virt_tbl_addr, admin->const_tbl_addr);
- dma_unmap_single(&GET_DEV(accel_dev), admin->const_tbl_addr, 1024,
- DMA_TO_DEVICE);
mutex_destroy(&admin->lock);
kfree(admin);
accel_dev->admin = NULL;
diff --git a/drivers/crypto/qat/qat_common/qat_uclo.c b/drivers/crypto/qat/qat_common/qat_uclo.c
index 9b961b37a282..e2454d90d949 100644
--- a/drivers/crypto/qat/qat_common/qat_uclo.c
+++ b/drivers/crypto/qat/qat_common/qat_uclo.c
@@ -967,10 +967,6 @@ static int qat_uclo_parse_uof_obj(struct icp_qat_fw_loader_handle *handle)
struct icp_qat_uclo_objhandle *obj_handle = handle->obj_handle;
unsigned int ae;
- obj_handle->uword_buf = kcalloc(UWORD_CPYBUF_SIZE, sizeof(uint64_t),
- GFP_KERNEL);
- if (!obj_handle->uword_buf)
- return -ENOMEM;
obj_handle->encap_uof_obj.beg_uof = obj_handle->obj_hdr->file_buff;
obj_handle->encap_uof_obj.obj_hdr = (struct icp_qat_uof_objhdr *)
obj_handle->obj_hdr->file_buff;
@@ -982,6 +978,10 @@ static int qat_uclo_parse_uof_obj(struct icp_qat_fw_loader_handle *handle)
pr_err("QAT: UOF incompatible\n");
return -EINVAL;
}
+ obj_handle->uword_buf = kcalloc(UWORD_CPYBUF_SIZE, sizeof(uint64_t),
+ GFP_KERNEL);
+ if (!obj_handle->uword_buf)
+ return -ENOMEM;
obj_handle->ustore_phy_size = ICP_QAT_UCLO_MAX_USTORE;
if (!obj_handle->obj_hdr->file_buff ||
!qat_uclo_map_str_table(obj_handle->obj_hdr, ICP_QAT_UOF_STRT,
diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
index af508258d2ea..d0f80c6241f9 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.c
+++ b/drivers/crypto/rockchip/rk3288_crypto.c
@@ -304,11 +304,9 @@ static int rk_crypto_probe(struct platform_device *pdev)
usleep_range(10, 20);
reset_control_deassert(crypto_info->rst);
- err = devm_add_action(dev, rk_crypto_action, crypto_info);
- if (err) {
- reset_control_assert(crypto_info->rst);
+ err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info);
+ if (err)
goto err_crypto;
- }
spin_lock_init(&crypto_info->lock);
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
index 3830d7c4e138..90efd10d57a1 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -29,7 +29,8 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
u32 tx_cnt = 0;
u32 spaces;
u32 v;
- int i, err = 0;
+ int err = 0;
+ unsigned int i;
unsigned int ileft = areq->nbytes;
unsigned int oleft = areq->nbytes;
unsigned int todo;
@@ -139,7 +140,8 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
u32 tx_cnt = 0;
u32 v;
u32 spaces;
- int i, err = 0;
+ int err = 0;
+ unsigned int i;
unsigned int ileft = areq->nbytes;
unsigned int oleft = areq->nbytes;
unsigned int todo;
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
index 107cd2a41cae..3ac6c6c4ad18 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
@@ -172,45 +172,45 @@ static struct sun4i_ss_alg_template ss_algs[] = {
},
{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
.alg.crypto = {
- .cra_name = "cbc(des3_ede)",
- .cra_driver_name = "cbc-des3-sun4i-ss",
- .cra_priority = 300,
- .cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .cra_ctxsize = sizeof(struct sun4i_req_ctx),
- .cra_module = THIS_MODULE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_init = sun4i_ss_cipher_init,
- .cra_u.ablkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = sun4i_ss_des3_setkey,
- .encrypt = sun4i_ss_cbc_des3_encrypt,
- .decrypt = sun4i_ss_cbc_des3_decrypt,
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-des3-sun4i-ss",
+ .cra_priority = 300,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .cra_ctxsize = sizeof(struct sun4i_req_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = sun4i_ss_cipher_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = sun4i_ss_des3_setkey,
+ .encrypt = sun4i_ss_cbc_des3_encrypt,
+ .decrypt = sun4i_ss_cbc_des3_decrypt,
}
}
},
{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
.alg.crypto = {
- .cra_name = "ecb(des3_ede)",
- .cra_driver_name = "ecb-des3-sun4i-ss",
- .cra_priority = 300,
- .cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .cra_ctxsize = sizeof(struct sun4i_req_ctx),
- .cra_module = THIS_MODULE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_init = sun4i_ss_cipher_init,
- .cra_u.ablkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = sun4i_ss_des3_setkey,
- .encrypt = sun4i_ss_ecb_des3_encrypt,
- .decrypt = sun4i_ss_ecb_des3_decrypt,
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "ecb-des3-sun4i-ss",
+ .cra_priority = 300,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .cra_ctxsize = sizeof(struct sun4i_req_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = sun4i_ss_cipher_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = sun4i_ss_des3_setkey,
+ .encrypt = sun4i_ss_ecb_des3_encrypt,
+ .decrypt = sun4i_ss_ecb_des3_decrypt,
}
}
},
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index ff8031498809..0de2f62d51ff 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -20,6 +20,15 @@
int sun4i_hash_crainit(struct crypto_tfm *tfm)
{
+ struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
+ struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+ struct sun4i_ss_alg_template *algt;
+
+ memset(op, 0, sizeof(struct sun4i_tfm_ctx));
+
+ algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash);
+ op->ss = algt->ss;
+
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct sun4i_req_ctx));
return 0;
@@ -32,13 +41,10 @@ int sun4i_hash_init(struct ahash_request *areq)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
struct sun4i_ss_alg_template *algt;
- struct sun4i_ss_ctx *ss;
memset(op, 0, sizeof(struct sun4i_req_ctx));
algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash);
- ss = algt->ss;
- op->ss = algt->ss;
op->mode = algt->mode;
return 0;
@@ -129,6 +135,9 @@ int sun4i_hash_import_sha1(struct ahash_request *areq, const void *in)
return 0;
}
+#define SS_HASH_UPDATE 1
+#define SS_HASH_FINAL 2
+
/*
* sun4i_hash_update: update hash engine
*
@@ -156,7 +165,7 @@ int sun4i_hash_import_sha1(struct ahash_request *areq, const void *in)
* write remaining data in op->buf
* final state op->len=56
*/
-int sun4i_hash_update(struct ahash_request *areq)
+static int sun4i_hash(struct ahash_request *areq)
{
u32 v, ivmode = 0;
unsigned int i = 0;
@@ -167,8 +176,9 @@ int sun4i_hash_update(struct ahash_request *areq)
*/
struct sun4i_req_ctx *op = ahash_request_ctx(areq);
- struct sun4i_ss_ctx *ss = op->ss;
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct sun4i_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+ struct sun4i_ss_ctx *ss = tfmctx->ss;
unsigned int in_i = 0; /* advancement in the current SG */
unsigned int end;
/*
@@ -180,22 +190,30 @@ int sun4i_hash_update(struct ahash_request *areq)
u32 spaces, rx_cnt = SS_RX_DEFAULT;
size_t copied = 0;
struct sg_mapping_iter mi;
+ unsigned int j = 0;
+ int zeros;
+ unsigned int index, padlen;
+ __be64 bits;
+ u32 bf[32];
+ u32 wb = 0;
+ unsigned int nwait, nbw = 0;
+ struct scatterlist *in_sg = areq->src;
dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x",
__func__, crypto_tfm_alg_name(areq->base.tfm),
op->byte_count, areq->nbytes, op->mode,
op->len, op->hash[0]);
- if (areq->nbytes == 0)
+ if (unlikely(areq->nbytes == 0) && (op->flags & SS_HASH_FINAL) == 0)
return 0;
/* protect against overflow */
- if (areq->nbytes > UINT_MAX - op->len) {
+ if (unlikely(areq->nbytes > UINT_MAX - op->len)) {
dev_err(ss->dev, "Cannot process too large request\n");
return -EINVAL;
}
- if (op->len + areq->nbytes < 64) {
+ if (op->len + areq->nbytes < 64 && (op->flags & SS_HASH_FINAL) == 0) {
/* linearize data to op->buf */
copied = sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
op->buf + op->len, areq->nbytes, 0);
@@ -203,14 +221,6 @@ int sun4i_hash_update(struct ahash_request *areq)
return 0;
}
- end = ((areq->nbytes + op->len) / 64) * 64 - op->len;
-
- if (end > areq->nbytes || areq->nbytes - end > 63) {
- dev_err(ss->dev, "ERROR: Bound error %u %u\n",
- end, areq->nbytes);
- return -EINVAL;
- }
-
spin_lock_bh(&ss->slock);
/*
@@ -225,6 +235,34 @@ int sun4i_hash_update(struct ahash_request *areq)
/* Enable the device */
writel(op->mode | SS_ENABLED | ivmode, ss->base + SS_CTL);
+ if ((op->flags & SS_HASH_UPDATE) == 0)
+ goto hash_final;
+
+ /* start of handling data */
+ if ((op->flags & SS_HASH_FINAL) == 0) {
+ end = ((areq->nbytes + op->len) / 64) * 64 - op->len;
+
+ if (end > areq->nbytes || areq->nbytes - end > 63) {
+ dev_err(ss->dev, "ERROR: Bound error %u %u\n",
+ end, areq->nbytes);
+ err = -EINVAL;
+ goto release_ss;
+ }
+ } else {
+ /* Since we have the flag final, we can go up to modulo 4 */
+ end = ((areq->nbytes + op->len) / 4) * 4 - op->len;
+ }
+
+ /* TODO if SGlen % 4 and op->len == 0 then DMA */
+ i = 1;
+ while (in_sg && i == 1) {
+ if ((in_sg->length % 4) != 0)
+ i = 0;
+ in_sg = sg_next(in_sg);
+ }
+ if (i == 1 && op->len == 0)
+ dev_dbg(ss->dev, "We can DMA\n");
+
i = 0;
sg_miter_start(&mi, areq->src, sg_nents(areq->src),
SG_MITER_FROM_SG | SG_MITER_ATOMIC);
@@ -285,7 +323,11 @@ int sun4i_hash_update(struct ahash_request *areq)
}
}
} while (i < end);
- /* final linear */
+
+ /*
+ * Now we have written to the device all that we can,
+ * store the remaining bytes in op->buf
+ */
if ((areq->nbytes - i) < 64) {
while (i < areq->nbytes && in_i < mi.length && op->len < 64) {
/* how many bytes we can read from current SG */
@@ -304,13 +346,21 @@ int sun4i_hash_update(struct ahash_request *areq)
sg_miter_stop(&mi);
+ /*
+ * End of data process
+ * Now if we have the flag final go to finalize part
+ * If not, store the partial hash
+ */
+ if ((op->flags & SS_HASH_FINAL) > 0)
+ goto hash_final;
+
writel(op->mode | SS_ENABLED | SS_DATA_END, ss->base + SS_CTL);
i = 0;
do {
v = readl(ss->base + SS_CTL);
i++;
} while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0);
- if (i >= SS_TIMEOUT) {
+ if (unlikely(i >= SS_TIMEOUT)) {
dev_err_ratelimited(ss->dev,
"ERROR: hash end timeout %d>%d ctl=%x len=%u\n",
i, SS_TIMEOUT, v, areq->nbytes);
@@ -318,56 +368,24 @@ int sun4i_hash_update(struct ahash_request *areq)
goto release_ss;
}
- /* get the partial hash only if something was written */
for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++)
op->hash[i] = readl(ss->base + SS_MD0 + i * 4);
-release_ss:
- writel(0, ss->base + SS_CTL);
- spin_unlock_bh(&ss->slock);
- return err;
-}
+ goto release_ss;
/*
- * sun4i_hash_final: finalize hashing operation
+ * hash_final: finalize hashing operation
*
* If we have some remaining bytes, we write them.
* Then ask the SS for finalizing the hashing operation
*
* I do not check RX FIFO size in this function since the size is 32
* after each enabling and this function neither write more than 32 words.
+ * If we come from the update part, we cannot have more than
+ * 3 remaining bytes to write and SS is fast enough to not care about it.
*/
-int sun4i_hash_final(struct ahash_request *areq)
-{
- u32 v, ivmode = 0;
- unsigned int i;
- unsigned int j = 0;
- int zeros, err = 0;
- unsigned int index, padlen;
- __be64 bits;
- struct sun4i_req_ctx *op = ahash_request_ctx(areq);
- struct sun4i_ss_ctx *ss = op->ss;
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- u32 bf[32];
- u32 wb = 0;
- unsigned int nwait, nbw = 0;
-
- dev_dbg(ss->dev, "%s: byte=%llu len=%u mode=%x wl=%u h=%x",
- __func__, op->byte_count, areq->nbytes, op->mode,
- op->len, op->hash[0]);
- spin_lock_bh(&ss->slock);
-
- /*
- * if we have already written something,
- * restore the partial hash state
- */
- if (op->byte_count > 0) {
- ivmode = SS_IV_ARBITRARY;
- for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++)
- writel(op->hash[i], ss->base + SS_IV0 + i * 4);
- }
- writel(op->mode | SS_ENABLED | ivmode, ss->base + SS_CTL);
+hash_final:
/* write the remaining words of the wait buffer */
if (op->len > 0) {
@@ -428,7 +446,7 @@ int sun4i_hash_final(struct ahash_request *areq)
/*
* Wait for SS to finish the hash.
- * The timeout could happen only in case of bad overcloking
+ * The timeout could happen only in case of bad overclocking
* or driver bug.
*/
i = 0;
@@ -436,7 +454,7 @@ int sun4i_hash_final(struct ahash_request *areq)
v = readl(ss->base + SS_CTL);
i++;
} while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0);
- if (i >= SS_TIMEOUT) {
+ if (unlikely(i >= SS_TIMEOUT)) {
dev_err_ratelimited(ss->dev,
"ERROR: hash end timeout %d>%d ctl=%x len=%u\n",
i, SS_TIMEOUT, v, areq->nbytes);
@@ -463,30 +481,41 @@ release_ss:
return err;
}
+int sun4i_hash_final(struct ahash_request *areq)
+{
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
+
+ op->flags = SS_HASH_FINAL;
+ return sun4i_hash(areq);
+}
+
+int sun4i_hash_update(struct ahash_request *areq)
+{
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
+
+ op->flags = SS_HASH_UPDATE;
+ return sun4i_hash(areq);
+}
+
/* sun4i_hash_finup: finalize hashing operation after an update */
int sun4i_hash_finup(struct ahash_request *areq)
{
- int err;
-
- err = sun4i_hash_update(areq);
- if (err != 0)
- return err;
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
- return sun4i_hash_final(areq);
+ op->flags = SS_HASH_UPDATE | SS_HASH_FINAL;
+ return sun4i_hash(areq);
}
/* combo of init/update/final functions */
int sun4i_hash_digest(struct ahash_request *areq)
{
int err;
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
err = sun4i_hash_init(areq);
if (err != 0)
return err;
- err = sun4i_hash_update(areq);
- if (err != 0)
- return err;
-
- return sun4i_hash_final(areq);
+ op->flags = SS_HASH_UPDATE | SS_HASH_FINAL;
+ return sun4i_hash(areq);
}
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h
index 8e9c05f6e4d4..f04c0f8cf026 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss.h
+++ b/drivers/crypto/sunxi-ss/sun4i-ss.h
@@ -163,7 +163,7 @@ struct sun4i_req_ctx {
u32 hash[5]; /* for storing SS_IVx register */
char buf[64];
unsigned int len;
- struct sun4i_ss_ctx *ss;
+ int flags;
};
int sun4i_hash_crainit(struct crypto_tfm *tfm);
diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig
index a83ead109d5f..c3d524ea6998 100644
--- a/drivers/crypto/vmx/Kconfig
+++ b/drivers/crypto/vmx/Kconfig
@@ -1,6 +1,7 @@
config CRYPTO_DEV_VMX_ENCRYPT
tristate "Encryption acceleration support on P8 CPU"
depends on CRYPTO_DEV_VMX
+ select CRYPTO_GHASH
default m
help
Support for VMX cryptographic acceleration instructions on Power8 CPU.
diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c
index 6c999cb01b80..27a94a119009 100644
--- a/drivers/crypto/vmx/ghash.c
+++ b/drivers/crypto/vmx/ghash.c
@@ -26,16 +26,13 @@
#include <linux/hardirq.h>
#include <asm/switch_to.h>
#include <crypto/aes.h>
+#include <crypto/ghash.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/hash.h>
#include <crypto/b128ops.h>
#define IN_INTERRUPT in_interrupt()
-#define GHASH_BLOCK_SIZE (16)
-#define GHASH_DIGEST_SIZE (16)
-#define GHASH_KEY_LEN (16)
-
void gcm_init_p8(u128 htable[16], const u64 Xi[2]);
void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]);
void gcm_ghash_p8(u64 Xi[2], const u128 htable[16],
@@ -55,16 +52,11 @@ struct p8_ghash_desc_ctx {
static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
{
- const char *alg;
+ const char *alg = "ghash-generic";
struct crypto_shash *fallback;
struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm);
struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
- if (!(alg = crypto_tfm_alg_name(tfm))) {
- printk(KERN_ERR "Failed to get algorithm name.\n");
- return -ENOENT;
- }
-
fallback = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(fallback)) {
printk(KERN_ERR
@@ -78,10 +70,18 @@ static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
crypto_shash_set_flags(fallback,
crypto_shash_get_flags((struct crypto_shash
*) tfm));
- ctx->fallback = fallback;
- shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx)
- + crypto_shash_descsize(fallback);
+ /* Check if the descsize defined in the algorithm is still enough. */
+ if (shash_tfm->descsize < sizeof(struct p8_ghash_desc_ctx)
+ + crypto_shash_descsize(fallback)) {
+ printk(KERN_ERR
+ "Desc size of the fallback implementation (%s) does not match the expected value: %lu vs %u\n",
+ alg,
+ shash_tfm->descsize - sizeof(struct p8_ghash_desc_ctx),
+ crypto_shash_descsize(fallback));
+ return -EINVAL;
+ }
+ ctx->fallback = fallback;
return 0;
}
@@ -113,7 +113,7 @@ static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
{
struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm));
- if (keylen != GHASH_KEY_LEN)
+ if (keylen != GHASH_BLOCK_SIZE)
return -EINVAL;
preempt_disable();
@@ -211,7 +211,8 @@ struct shash_alg p8_ghash_alg = {
.update = p8_ghash_update,
.final = p8_ghash_final,
.setkey = p8_ghash_setkey,
- .descsize = sizeof(struct p8_ghash_desc_ctx),
+ .descsize = sizeof(struct p8_ghash_desc_ctx)
+ + sizeof(struct ghash_desc_ctx),
.base = {
.cra_name = "ghash",
.cra_driver_name = "p8_ghash",
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 739f797b40d9..af63a6bcf564 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -102,7 +102,7 @@ config AXI_DMAC
config COH901318
bool "ST-Ericsson COH901318 DMA support"
select DMA_ENGINE
- depends on ARCH_U300
+ depends on ARCH_U300 || COMPILE_TEST
help
Enable support for ST-Ericsson COH 901 318 DMA.
@@ -114,13 +114,13 @@ config DMA_BCM2835
config DMA_JZ4740
tristate "JZ4740 DMA support"
- depends on MACH_JZ4740
+ depends on MACH_JZ4740 || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
config DMA_JZ4780
tristate "JZ4780 DMA support"
- depends on MACH_JZ4780
+ depends on MACH_JZ4780 || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -130,14 +130,14 @@ config DMA_JZ4780
config DMA_OMAP
tristate "OMAP DMA support"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
- select TI_DMA_CROSSBAR if SOC_DRA7XX
+ select TI_DMA_CROSSBAR if (SOC_DRA7XX || COMPILE_TEST)
config DMA_SA11X0
tristate "SA-11x0 DMA support"
- depends on ARCH_SA1100
+ depends on ARCH_SA1100 || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -150,7 +150,6 @@ config DMA_SUN4I
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
default (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I)
select DMA_ENGINE
- select DMA_OF
select DMA_VIRTUAL_CHANNELS
help
Enable support for the DMA controller present in the sun4i,
@@ -167,7 +166,7 @@ config DMA_SUN6I
config EP93XX_DMA
bool "Cirrus Logic EP93xx DMA support"
- depends on ARCH_EP93XX
+ depends on ARCH_EP93XX || COMPILE_TEST
select DMA_ENGINE
help
Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
@@ -279,7 +278,7 @@ config INTEL_MIC_X100_DMA
config K3_DMA
tristate "Hisilicon K3 DMA support"
- depends on ARCH_HI3xxx
+ depends on ARCH_HI3xxx || ARCH_HISI || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -297,16 +296,16 @@ config LPC18XX_DMAMUX
config MMP_PDMA
bool "MMP PDMA support"
- depends on (ARCH_MMP || ARCH_PXA)
+ depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
select DMA_ENGINE
help
Support the MMP PDMA engine for PXA and MMP platform.
config MMP_TDMA
bool "MMP Two-Channel DMA support"
- depends on ARCH_MMP
+ depends on ARCH_MMP || COMPILE_TEST
select DMA_ENGINE
- select MMP_SRAM
+ select MMP_SRAM if ARCH_MMP
help
Support the MMP Two-Channel DMA engine.
This engine used for MMP Audio DMA and pxa910 SQU.
@@ -316,7 +315,6 @@ config MOXART_DMA
tristate "MOXART DMA support"
depends on ARCH_MOXART
select DMA_ENGINE
- select DMA_OF
select DMA_VIRTUAL_CHANNELS
help
Enable support for the MOXA ART SoC DMA controller.
@@ -439,9 +437,8 @@ config STE_DMA40
config STM32_DMA
bool "STMicroelectronics STM32 DMA support"
- depends on ARCH_STM32
+ depends on ARCH_STM32 || COMPILE_TEST
select DMA_ENGINE
- select DMA_OF
select DMA_VIRTUAL_CHANNELS
help
Enable support for the on-chip DMA controller on STMicroelectronics
@@ -451,7 +448,7 @@ config STM32_DMA
config S3C24XX_DMAC
bool "Samsung S3C24XX DMA support"
- depends on ARCH_S3C24XX
+ depends on ARCH_S3C24XX || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -483,10 +480,9 @@ config TEGRA20_APB_DMA
config TEGRA210_ADMA
bool "NVIDIA Tegra210 ADMA support"
- depends on ARCH_TEGRA_210_SOC
+ depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) && PM_CLK
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
- select PM_CLK
help
Support for the NVIDIA Tegra210 ADMA controller driver. The
DMA controller has multiple DMA channels and is used to service
@@ -497,7 +493,7 @@ config TEGRA210_ADMA
config TIMB_DMA
tristate "Timberdale FPGA DMA support"
- depends on MFD_TIMBERDALE
+ depends on MFD_TIMBERDALE || COMPILE_TEST
select DMA_ENGINE
help
Enable support for the Timberdale FPGA DMA engine.
@@ -515,10 +511,10 @@ config TI_DMA_CROSSBAR
config TI_EDMA
bool "TI EDMA support"
- depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE
+ depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
- select TI_DMA_CROSSBAR if ARCH_OMAP
+ select TI_DMA_CROSSBAR if (ARCH_OMAP || COMPILE_TEST)
default n
help
Enable support for the TI EDMA controller. This DMA
@@ -561,7 +557,7 @@ config XILINX_ZYNQMP_DMA
config ZX_DMA
tristate "ZTE ZX296702 DMA support"
- depends on ARCH_ZX
+ depends on ARCH_ZX || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 53d22eb73b56..a4c8f80db29d 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -473,15 +473,11 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
/* for cyclic transfers,
* no need to replay callback function while stopping */
if (!atc_chan_is_cyclic(atchan)) {
- dma_async_tx_callback callback = txd->callback;
- void *param = txd->callback_param;
-
/*
* The API requires that no submissions are done from a
* callback, so we don't need to drop the lock here
*/
- if (callback)
- callback(param);
+ dmaengine_desc_get_callback_invoke(txd, NULL);
}
dma_run_dependencies(txd);
@@ -598,15 +594,12 @@ static void atc_handle_cyclic(struct at_dma_chan *atchan)
{
struct at_desc *first = atc_first_active(atchan);
struct dma_async_tx_descriptor *txd = &first->txd;
- dma_async_tx_callback callback = txd->callback;
- void *param = txd->callback_param;
dev_vdbg(chan2dev(&atchan->chan_common),
"new cyclic period llp 0x%08x\n",
channel_readl(atchan, DSCR));
- if (callback)
- callback(param);
+ dmaengine_desc_get_callback_invoke(txd, NULL);
}
/*-- IRQ & Tasklet ---------------------------------------------------*/
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 832cbd647145..b7d7f2d443a1 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -1572,8 +1572,8 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node);
txd = &desc->tx_dma_desc;
- if (txd->callback && (txd->flags & DMA_PREP_INTERRUPT))
- txd->callback(txd->callback_param);
+ if (txd->flags & DMA_PREP_INTERRUPT)
+ dmaengine_desc_get_callback_invoke(txd, NULL);
}
static void at_xdmac_tasklet(unsigned long data)
@@ -1616,8 +1616,8 @@ static void at_xdmac_tasklet(unsigned long data)
if (!at_xdmac_chan_is_cyclic(atchan)) {
dma_cookie_complete(txd);
- if (txd->callback && (txd->flags & DMA_PREP_INTERRUPT))
- txd->callback(txd->callback_param);
+ if (txd->flags & DMA_PREP_INTERRUPT)
+ dmaengine_desc_get_callback_invoke(txd, NULL);
}
dma_run_dependencies(txd);
diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c
index 7ce843723003..7a67b8345092 100644
--- a/drivers/dma/bestcomm/bestcomm.c
+++ b/drivers/dma/bestcomm/bestcomm.c
@@ -82,7 +82,7 @@ bcom_task_alloc(int bd_count, int bd_size, int priv_size)
/* Get IRQ of that task */
tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
- if (tsk->irq == NO_IRQ)
+ if (!tsk->irq)
goto error;
/* Init the BDs, if needed */
@@ -104,7 +104,7 @@ bcom_task_alloc(int bd_count, int bd_size, int priv_size)
error:
if (tsk) {
- if (tsk->irq != NO_IRQ)
+ if (tsk->irq)
irq_dispose_mapping(tsk->irq);
bcom_sram_free(tsk->bd);
kfree(tsk->cookie);
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index e4acd63e42aa..74794c9859f6 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1319,10 +1319,10 @@ static void coh901318_list_print(struct coh901318_chan *cohc,
int i = 0;
while (l) {
- dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src 0x%x"
- ", dst 0x%x, link 0x%x virt_link_addr 0x%p\n",
- i, l, l->control, l->src_addr, l->dst_addr,
- l->link_addr, l->virt_link_addr);
+ dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src 0x%pad"
+ ", dst 0x%pad, link 0x%pad virt_link_addr 0x%p\n",
+ i, l, l->control, &l->src_addr, &l->dst_addr,
+ &l->link_addr, l->virt_link_addr);
i++;
l = l->virt_link_addr;
}
@@ -1335,7 +1335,7 @@ static void coh901318_list_print(struct coh901318_chan *cohc,
static struct coh901318_base *debugfs_dma_base;
static struct dentry *dma_dentry;
-static int coh901318_debugfs_read(struct file *file, char __user *buf,
+static ssize_t coh901318_debugfs_read(struct file *file, char __user *buf,
size_t count, loff_t *f_pos)
{
u64 started_channels = debugfs_dma_base->pm.started_channels;
@@ -1352,9 +1352,10 @@ static int coh901318_debugfs_read(struct file *file, char __user *buf,
tmp += sprintf(tmp, "DMA -- enabled dma channels\n");
- for (i = 0; i < U300_DMA_CHANNELS; i++)
- if (started_channels & (1 << i))
+ for (i = 0; i < U300_DMA_CHANNELS; i++) {
+ if (started_channels & (1ULL << i))
tmp += sprintf(tmp, "channel %d\n", i);
+ }
tmp += sprintf(tmp, "Pool alloc nbr %d\n", pool_count);
@@ -1553,15 +1554,8 @@ coh901318_desc_submit(struct coh901318_chan *cohc, struct coh901318_desc *desc)
static struct coh901318_desc *
coh901318_first_active_get(struct coh901318_chan *cohc)
{
- struct coh901318_desc *d;
-
- if (list_empty(&cohc->active))
- return NULL;
-
- d = list_first_entry(&cohc->active,
- struct coh901318_desc,
- node);
- return d;
+ return list_first_entry_or_null(&cohc->active, struct coh901318_desc,
+ node);
}
static void
@@ -1579,15 +1573,8 @@ coh901318_desc_queue(struct coh901318_chan *cohc, struct coh901318_desc *desc)
static struct coh901318_desc *
coh901318_first_queued(struct coh901318_chan *cohc)
{
- struct coh901318_desc *d;
-
- if (list_empty(&cohc->queue))
- return NULL;
-
- d = list_first_entry(&cohc->queue,
- struct coh901318_desc,
- node);
- return d;
+ return list_first_entry_or_null(&cohc->queue, struct coh901318_desc,
+ node);
}
static inline u32 coh901318_get_bytes_in_lli(struct coh901318_lli *in_lli)
@@ -1766,7 +1753,7 @@ static int coh901318_resume(struct dma_chan *chan)
bool coh901318_filter_id(struct dma_chan *chan, void *chan_id)
{
- unsigned int ch_nr = (unsigned int) chan_id;
+ unsigned long ch_nr = (unsigned long) chan_id;
if (ch_nr == to_coh901318_chan(chan)->id)
return true;
@@ -1888,8 +1875,7 @@ static void dma_tasklet(unsigned long data)
struct coh901318_chan *cohc = (struct coh901318_chan *) data;
struct coh901318_desc *cohd_fin;
unsigned long flags;
- dma_async_tx_callback callback;
- void *callback_param;
+ struct dmaengine_desc_callback cb;
dev_vdbg(COHC_2_DEV(cohc), "[%s] chan_id %d"
" nbr_active_done %ld\n", __func__,
@@ -1904,8 +1890,7 @@ static void dma_tasklet(unsigned long data)
goto err;
/* locate callback to client */
- callback = cohd_fin->desc.callback;
- callback_param = cohd_fin->desc.callback_param;
+ dmaengine_desc_get_callback(&cohd_fin->desc, &cb);
/* sign this job as completed on the channel */
dma_cookie_complete(&cohd_fin->desc);
@@ -1920,8 +1905,7 @@ static void dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&cohc->lock, flags);
/* Call the callback when we're done */
- if (callback)
- callback(callback_param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock_irqsave(&cohc->lock, flags);
@@ -2247,8 +2231,8 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
spin_lock_irqsave(&cohc->lock, flg);
dev_vdbg(COHC_2_DEV(cohc),
- "[%s] channel %d src 0x%x dest 0x%x size %d\n",
- __func__, cohc->id, src, dest, size);
+ "[%s] channel %d src 0x%pad dest 0x%pad size %zu\n",
+ __func__, cohc->id, &src, &dest, size);
if (flags & DMA_PREP_INTERRUPT)
/* Trigger interrupt after last lli */
@@ -2744,8 +2728,8 @@ static int __init coh901318_probe(struct platform_device *pdev)
goto err_register_of_dma;
platform_set_drvdata(pdev, base);
- dev_info(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%08x\n",
- (u32) base->virtbase);
+ dev_info(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%p\n",
+ base->virtbase);
return err;
diff --git a/drivers/dma/coh901318_lli.c b/drivers/dma/coh901318_lli.c
index 702112d547c8..d612b2e5abc4 100644
--- a/drivers/dma/coh901318_lli.c
+++ b/drivers/dma/coh901318_lli.c
@@ -75,7 +75,7 @@ coh901318_lli_alloc(struct coh901318_pool *pool, unsigned int len)
lli = head;
lli->phy_this = phy;
lli->link_addr = 0x00000000;
- lli->virt_link_addr = 0x00000000U;
+ lli->virt_link_addr = NULL;
for (i = 1; i < len; i++) {
lli_prev = lli;
@@ -88,7 +88,7 @@ coh901318_lli_alloc(struct coh901318_pool *pool, unsigned int len)
DEBUGFS_POOL_COUNTER_ADD(pool, 1);
lli->phy_this = phy;
lli->link_addr = 0x00000000;
- lli->virt_link_addr = 0x00000000U;
+ lli->virt_link_addr = NULL;
lli_prev->link_addr = phy;
lli_prev->virt_link_addr = lli;
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index 4b2317426c8e..bac5f023013b 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -108,6 +108,8 @@ struct cppi41_channel {
unsigned td_queued:1;
unsigned td_seen:1;
unsigned td_desc_seen:1;
+
+ struct list_head node; /* Node for pending list */
};
struct cppi41_desc {
@@ -146,6 +148,9 @@ struct cppi41_dd {
const struct chan_queues *queues_tx;
struct chan_queues td_queue;
+ struct list_head pending; /* Pending queued transfers */
+ spinlock_t lock; /* Lock for pending list */
+
/* context for suspend/resume */
unsigned int dma_tdfdq;
};
@@ -331,7 +336,11 @@ static irqreturn_t cppi41_irq(int irq, void *data)
c->residue = pd_trans_len(c->desc->pd6) - len;
dma_cookie_complete(&c->txd);
- c->txd.callback(c->txd.callback_param);
+ dmaengine_desc_get_callback_invoke(&c->txd, NULL);
+
+ /* Paired with cppi41_dma_issue_pending */
+ pm_runtime_mark_last_busy(cdd->ddev.dev);
+ pm_runtime_put_autosuspend(cdd->ddev.dev);
}
}
return IRQ_HANDLED;
@@ -349,6 +358,12 @@ static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx)
static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_dd *cdd = c->cdd;
+ int error;
+
+ error = pm_runtime_get_sync(cdd->ddev.dev);
+ if (error < 0)
+ return error;
dma_cookie_init(chan);
dma_async_tx_descriptor_init(&c->txd, chan);
@@ -357,11 +372,26 @@ static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
if (!c->is_tx)
cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
+ pm_runtime_mark_last_busy(cdd->ddev.dev);
+ pm_runtime_put_autosuspend(cdd->ddev.dev);
+
return 0;
}
static void cppi41_dma_free_chan_resources(struct dma_chan *chan)
{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_dd *cdd = c->cdd;
+ int error;
+
+ error = pm_runtime_get_sync(cdd->ddev.dev);
+ if (error < 0)
+ return;
+
+ WARN_ON(!list_empty(&cdd->pending));
+
+ pm_runtime_mark_last_busy(cdd->ddev.dev);
+ pm_runtime_put_autosuspend(cdd->ddev.dev);
}
static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
@@ -386,21 +416,6 @@ static void push_desc_queue(struct cppi41_channel *c)
u32 desc_phys;
u32 reg;
- desc_phys = lower_32_bits(c->desc_phys);
- desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
- WARN_ON(cdd->chan_busy[desc_num]);
- cdd->chan_busy[desc_num] = c;
-
- reg = (sizeof(struct cppi41_desc) - 24) / 4;
- reg |= desc_phys;
- cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
-}
-
-static void cppi41_dma_issue_pending(struct dma_chan *chan)
-{
- struct cppi41_channel *c = to_cpp41_chan(chan);
- u32 reg;
-
c->residue = 0;
reg = GCR_CHAN_ENABLE;
@@ -418,7 +433,46 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan)
* before starting the dma engine.
*/
__iowmb();
- push_desc_queue(c);
+
+ desc_phys = lower_32_bits(c->desc_phys);
+ desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ WARN_ON(cdd->chan_busy[desc_num]);
+ cdd->chan_busy[desc_num] = c;
+
+ reg = (sizeof(struct cppi41_desc) - 24) / 4;
+ reg |= desc_phys;
+ cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+}
+
+static void pending_desc(struct cppi41_channel *c)
+{
+ struct cppi41_dd *cdd = c->cdd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cdd->lock, flags);
+ list_add_tail(&c->node, &cdd->pending);
+ spin_unlock_irqrestore(&cdd->lock, flags);
+}
+
+static void cppi41_dma_issue_pending(struct dma_chan *chan)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_dd *cdd = c->cdd;
+ int error;
+
+ /* PM runtime paired with dmaengine_desc_get_callback_invoke */
+ error = pm_runtime_get(cdd->ddev.dev);
+ if ((error != -EINPROGRESS) && error < 0) {
+ dev_err(cdd->ddev.dev, "Failed to pm_runtime_get: %i\n",
+ error);
+
+ return;
+ }
+
+ if (likely(pm_runtime_active(cdd->ddev.dev)))
+ push_desc_queue(c);
+ else
+ pending_desc(c);
}
static u32 get_host_pd0(u32 length)
@@ -940,12 +994,18 @@ static int cppi41_dma_probe(struct platform_device *pdev)
cdd->ctrl_mem = of_iomap(dev->of_node, 1);
cdd->sched_mem = of_iomap(dev->of_node, 2);
cdd->qmgr_mem = of_iomap(dev->of_node, 3);
+ spin_lock_init(&cdd->lock);
+ INIT_LIST_HEAD(&cdd->pending);
+
+ platform_set_drvdata(pdev, cdd);
if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem ||
!cdd->qmgr_mem)
return -ENXIO;
pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_get_sync;
@@ -985,7 +1045,9 @@ static int cppi41_dma_probe(struct platform_device *pdev)
if (ret)
goto err_of;
- platform_set_drvdata(pdev, cdd);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
return 0;
err_of:
dma_async_device_unregister(&cdd->ddev);
@@ -996,7 +1058,8 @@ err_irq:
err_chans:
deinit_cppi41(dev, cdd);
err_init_cppi:
- pm_runtime_put(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+ pm_runtime_put_sync(dev);
err_get_sync:
pm_runtime_disable(dev);
iounmap(cdd->usbss_mem);
@@ -1021,13 +1084,13 @@ static int cppi41_dma_remove(struct platform_device *pdev)
iounmap(cdd->ctrl_mem);
iounmap(cdd->sched_mem);
iounmap(cdd->qmgr_mem);
- pm_runtime_put(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int cppi41_suspend(struct device *dev)
+static int __maybe_unused cppi41_suspend(struct device *dev)
{
struct cppi41_dd *cdd = dev_get_drvdata(dev);
@@ -1038,7 +1101,7 @@ static int cppi41_suspend(struct device *dev)
return 0;
}
-static int cppi41_resume(struct device *dev)
+static int __maybe_unused cppi41_resume(struct device *dev)
{
struct cppi41_dd *cdd = dev_get_drvdata(dev);
struct cppi41_channel *c;
@@ -1062,9 +1125,38 @@ static int cppi41_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(cppi41_pm_ops, cppi41_suspend, cppi41_resume);
+static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
+{
+ struct cppi41_dd *cdd = dev_get_drvdata(dev);
+
+ WARN_ON(!list_empty(&cdd->pending));
+
+ return 0;
+}
+
+static int __maybe_unused cppi41_runtime_resume(struct device *dev)
+{
+ struct cppi41_dd *cdd = dev_get_drvdata(dev);
+ struct cppi41_channel *c, *_c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cdd->lock, flags);
+ list_for_each_entry_safe(c, _c, &cdd->pending, node) {
+ push_desc_queue(c);
+ list_del(&c->node);
+ }
+ spin_unlock_irqrestore(&cdd->lock, flags);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cppi41_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(cppi41_suspend, cppi41_resume)
+ SET_RUNTIME_PM_OPS(cppi41_runtime_suspend,
+ cppi41_runtime_resume,
+ NULL)
+};
static struct platform_driver cpp41_dma_driver = {
.probe = cppi41_dma_probe,
diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c
index 9689b36c005a..d50273fed715 100644
--- a/drivers/dma/dma-jz4740.c
+++ b/drivers/dma/dma-jz4740.c
@@ -21,8 +21,6 @@
#include <linux/irq.h>
#include <linux/clk.h>
-#include <asm/mach-jz4740/dma.h>
-
#include "virt-dma.h"
#define JZ_DMA_NR_CHANS 6
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index dade7c47ff18..7373b7a555ec 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -324,8 +324,10 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg(
sg_dma_address(&sgl[i]),
sg_dma_len(&sgl[i]),
direction);
- if (err < 0)
+ if (err < 0) {
+ jz4780_dma_desc_free(&jzchan->desc->vdesc);
return NULL;
+ }
desc->desc[i].dcm |= JZ_DMA_DCM_TIE;
@@ -368,8 +370,10 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_cyclic(
for (i = 0; i < periods; i++) {
err = jz4780_dma_setup_hwdesc(jzchan, &desc->desc[i], buf_addr,
period_len, direction);
- if (err < 0)
+ if (err < 0) {
+ jz4780_dma_desc_free(&jzchan->desc->vdesc);
return NULL;
+ }
buf_addr += period_len;
@@ -396,7 +400,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_cyclic(
return vchan_tx_prep(&jzchan->vchan, &desc->vdesc, flags);
}
-struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
+static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
{
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 8c9f45fd55fc..6b535262ac5d 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -997,6 +997,13 @@ int dma_async_device_register(struct dma_device *device)
}
chan->client_count = 0;
}
+
+ if (!chancnt) {
+ dev_err(device->dev, "%s: device has no channels!\n", __func__);
+ rc = -ENODEV;
+ goto err_out;
+ }
+
device->chancnt = chancnt;
mutex_lock(&dma_list_mutex);
diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h
index 17f983a4e9ba..882ff9448c3b 100644
--- a/drivers/dma/dmaengine.h
+++ b/drivers/dma/dmaengine.h
@@ -86,4 +86,88 @@ static inline void dma_set_residue(struct dma_tx_state *state, u32 residue)
state->residue = residue;
}
+struct dmaengine_desc_callback {
+ dma_async_tx_callback callback;
+ dma_async_tx_callback_result callback_result;
+ void *callback_param;
+};
+
+/**
+ * dmaengine_desc_get_callback - get the passed in callback function
+ * @tx: tx descriptor
+ * @cb: temp struct to hold the callback info
+ *
+ * Fill the passed in cb struct with what's available in the passed in
+ * tx descriptor struct
+ * No locking is required.
+ */
+static inline void
+dmaengine_desc_get_callback(struct dma_async_tx_descriptor *tx,
+ struct dmaengine_desc_callback *cb)
+{
+ cb->callback = tx->callback;
+ cb->callback_result = tx->callback_result;
+ cb->callback_param = tx->callback_param;
+}
+
+/**
+ * dmaengine_desc_callback_invoke - call the callback function in cb struct
+ * @cb: temp struct that is holding the callback info
+ * @result: transaction result
+ *
+ * Call the callback function provided in the cb struct with the parameter
+ * in the cb struct.
+ * Locking is dependent on the driver.
+ */
+static inline void
+dmaengine_desc_callback_invoke(struct dmaengine_desc_callback *cb,
+ const struct dmaengine_result *result)
+{
+ struct dmaengine_result dummy_result = {
+ .result = DMA_TRANS_NOERROR,
+ .residue = 0
+ };
+
+ if (cb->callback_result) {
+ if (!result)
+ result = &dummy_result;
+ cb->callback_result(cb->callback_param, result);
+ } else if (cb->callback) {
+ cb->callback(cb->callback_param);
+ }
+}
+
+/**
+ * dmaengine_desc_get_callback_invoke - get the callback in tx descriptor and
+ * then immediately call the callback.
+ * @tx: dma async tx descriptor
+ * @result: transaction result
+ *
+ * Call dmaengine_desc_get_callback() and dmaengine_desc_callback_invoke()
+ * in a single function since no work is necessary in between for the driver.
+ * Locking is dependent on the driver.
+ */
+static inline void
+dmaengine_desc_get_callback_invoke(struct dma_async_tx_descriptor *tx,
+ const struct dmaengine_result *result)
+{
+ struct dmaengine_desc_callback cb;
+
+ dmaengine_desc_get_callback(tx, &cb);
+ dmaengine_desc_callback_invoke(&cb, result);
+}
+
+/**
+ * dmaengine_desc_callback_valid - verify the callback is valid in cb
+ * @cb: callback info struct
+ *
+ * Return a bool that verifies whether callback in cb is valid or not.
+ * No locking is required.
+ */
+static inline bool
+dmaengine_desc_callback_valid(struct dmaengine_desc_callback *cb)
+{
+ return (cb->callback) ? true : false;
+}
+
#endif
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 1245db5438e1..cf76fc6149e5 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -56,10 +56,10 @@ module_param(sg_buffers, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(sg_buffers,
"Number of scatter gather buffers (default: 1)");
-static unsigned int dmatest = 1;
+static unsigned int dmatest;
module_param(dmatest, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dmatest,
- "dmatest 0-memcpy 1-slave_sg (default: 1)");
+ "dmatest 0-memcpy 1-slave_sg (default: 0)");
static unsigned int xor_sources = 3;
module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
@@ -426,7 +426,9 @@ static int dmatest_func(void *data)
int src_cnt;
int dst_cnt;
int i;
- ktime_t ktime;
+ ktime_t ktime, start, diff;
+ ktime_t filltime = ktime_set(0, 0);
+ ktime_t comparetime = ktime_set(0, 0);
s64 runtime = 0;
unsigned long long total_len = 0;
@@ -503,7 +505,7 @@ static int dmatest_func(void *data)
total_tests++;
/* honor alignment restrictions */
- if (thread->type == DMA_MEMCPY)
+ if (thread->type == DMA_MEMCPY || thread->type == DMA_SG)
align = dev->copy_align;
else if (thread->type == DMA_XOR)
align = dev->xor_align;
@@ -531,6 +533,7 @@ static int dmatest_func(void *data)
src_off = 0;
dst_off = 0;
} else {
+ start = ktime_get();
src_off = dmatest_random() % (params->buf_size - len + 1);
dst_off = dmatest_random() % (params->buf_size - len + 1);
@@ -541,6 +544,9 @@ static int dmatest_func(void *data)
params->buf_size);
dmatest_init_dsts(thread->dsts, dst_off, len,
params->buf_size);
+
+ diff = ktime_sub(ktime_get(), start);
+ filltime = ktime_add(filltime, diff);
}
um = dmaengine_get_unmap_data(dev->dev, src_cnt+dst_cnt,
@@ -683,6 +689,7 @@ static int dmatest_func(void *data)
continue;
}
+ start = ktime_get();
pr_debug("%s: verifying source buffer...\n", current->comm);
error_count = dmatest_verify(thread->srcs, 0, src_off,
0, PATTERN_SRC, true);
@@ -703,6 +710,9 @@ static int dmatest_func(void *data)
params->buf_size, dst_off + len,
PATTERN_DST, false);
+ diff = ktime_sub(ktime_get(), start);
+ comparetime = ktime_add(comparetime, diff);
+
if (error_count) {
result("data error", total_tests, src_off, dst_off,
len, error_count);
@@ -712,7 +722,10 @@ static int dmatest_func(void *data)
dst_off, len, 0);
}
}
- runtime = ktime_us_delta(ktime_get(), ktime);
+ ktime = ktime_sub(ktime_get(), ktime);
+ ktime = ktime_sub(ktime, comparetime);
+ ktime = ktime_sub(ktime, filltime);
+ runtime = ktime_to_us(ktime);
ret = 0;
err_dstbuf:
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index da18b18561c4..c2c0a613cb7a 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -274,20 +274,19 @@ static void
dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
bool callback_required)
{
- dma_async_tx_callback callback = NULL;
- void *param = NULL;
struct dma_async_tx_descriptor *txd = &desc->txd;
struct dw_desc *child;
unsigned long flags;
+ struct dmaengine_desc_callback cb;
dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
spin_lock_irqsave(&dwc->lock, flags);
dma_cookie_complete(txd);
- if (callback_required) {
- callback = txd->callback;
- param = txd->callback_param;
- }
+ if (callback_required)
+ dmaengine_desc_get_callback(txd, &cb);
+ else
+ memset(&cb, 0, sizeof(cb));
/* async_tx_ack */
list_for_each_entry(child, &desc->tx_list, desc_node)
@@ -296,8 +295,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
dwc_desc_put(dwc, desc);
spin_unlock_irqrestore(&dwc->lock, flags);
- if (callback)
- callback(param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
}
static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 3d277fa76c1a..e18a58068bca 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -263,22 +263,29 @@ static const struct edmacc_param dummy_paramset = {
#define EDMA_BINDING_LEGACY 0
#define EDMA_BINDING_TPCC 1
+static const u32 edma_binding_type[] = {
+ [EDMA_BINDING_LEGACY] = EDMA_BINDING_LEGACY,
+ [EDMA_BINDING_TPCC] = EDMA_BINDING_TPCC,
+};
+
static const struct of_device_id edma_of_ids[] = {
{
.compatible = "ti,edma3",
- .data = (void *)EDMA_BINDING_LEGACY,
+ .data = &edma_binding_type[EDMA_BINDING_LEGACY],
},
{
.compatible = "ti,edma3-tpcc",
- .data = (void *)EDMA_BINDING_TPCC,
+ .data = &edma_binding_type[EDMA_BINDING_TPCC],
},
{}
};
+MODULE_DEVICE_TABLE(of, edma_of_ids);
static const struct of_device_id edma_tptc_of_ids[] = {
{ .compatible = "ti,edma3-tptc", },
{}
};
+MODULE_DEVICE_TABLE(of, edma_tptc_of_ids);
static inline unsigned int edma_read(struct edma_cc *ecc, int offset)
{
@@ -405,18 +412,12 @@ static inline void edma_param_or(struct edma_cc *ecc, int offset, int param_no,
edma_or(ecc, EDMA_PARM + offset + (param_no << 5), or);
}
-static inline void set_bits(int offset, int len, unsigned long *p)
+static inline void edma_set_bits(int offset, int len, unsigned long *p)
{
for (; len > 0; len--)
set_bit(offset + (len - 1), p);
}
-static inline void clear_bits(int offset, int len, unsigned long *p)
-{
- for (; len > 0; len--)
- clear_bit(offset + (len - 1), p);
-}
-
static void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no,
int priority)
{
@@ -464,13 +465,15 @@ static void edma_write_slot(struct edma_cc *ecc, unsigned slot,
memcpy_toio(ecc->base + PARM_OFFSET(slot), param, PARM_SIZE);
}
-static void edma_read_slot(struct edma_cc *ecc, unsigned slot,
+static int edma_read_slot(struct edma_cc *ecc, unsigned slot,
struct edmacc_param *param)
{
slot = EDMA_CHAN_SLOT(slot);
if (slot >= ecc->num_slots)
- return;
+ return -EINVAL;
memcpy_fromio(param, ecc->base + PARM_OFFSET(slot), PARM_SIZE);
+
+ return 0;
}
/**
@@ -1476,13 +1479,15 @@ static void edma_error_handler(struct edma_chan *echan)
struct edma_cc *ecc = echan->ecc;
struct device *dev = echan->vchan.chan.device->dev;
struct edmacc_param p;
+ int err;
if (!echan->edesc)
return;
spin_lock(&echan->vchan.lock);
- edma_read_slot(ecc, echan->slot[0], &p);
+ err = edma_read_slot(ecc, echan->slot[0], &p);
+
/*
* Issue later based on missed flag which will be sure
* to happen as:
@@ -1495,7 +1500,7 @@ static void edma_error_handler(struct edma_chan *echan)
* lead to some nasty recursion when we are in a NULL
* slot. So we avoid doing so and set the missed flag.
*/
- if (p.a_b_cnt == 0 && p.ccnt == 0) {
+ if (err || (p.a_b_cnt == 0 && p.ccnt == 0)) {
dev_dbg(dev, "Error on null slot, setting miss\n");
echan->missed = 1;
} else {
@@ -2019,8 +2024,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
{
struct edma_soc_info *info;
struct property *prop;
- size_t sz;
- int ret;
+ int sz, ret;
info = devm_kzalloc(dev, sizeof(struct edma_soc_info), GFP_KERNEL);
if (!info)
@@ -2182,7 +2186,7 @@ static int edma_probe(struct platform_device *pdev)
const struct of_device_id *match;
match = of_match_node(edma_of_ids, node);
- if (match && (u32)match->data == EDMA_BINDING_TPCC)
+ if (match && (*(u32 *)match->data) == EDMA_BINDING_TPCC)
legacy_mode = false;
info = edma_setup_info_from_dt(dev, legacy_mode);
@@ -2260,7 +2264,7 @@ static int edma_probe(struct platform_device *pdev)
for (i = 0; rsv_slots[i][0] != -1; i++) {
off = rsv_slots[i][0];
ln = rsv_slots[i][1];
- set_bits(off, ln, ecc->slot_inuse);
+ edma_set_bits(off, ln, ecc->slot_inuse);
}
}
}
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 21f08cc3352b..d37e8dda8079 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -262,10 +262,8 @@ static void ep93xx_dma_set_active(struct ep93xx_dma_chan *edmac,
static struct ep93xx_dma_desc *
ep93xx_dma_get_active(struct ep93xx_dma_chan *edmac)
{
- if (list_empty(&edmac->active))
- return NULL;
-
- return list_first_entry(&edmac->active, struct ep93xx_dma_desc, node);
+ return list_first_entry_or_null(&edmac->active,
+ struct ep93xx_dma_desc, node);
}
/**
@@ -739,10 +737,10 @@ static void ep93xx_dma_tasklet(unsigned long data)
{
struct ep93xx_dma_chan *edmac = (struct ep93xx_dma_chan *)data;
struct ep93xx_dma_desc *desc, *d;
- dma_async_tx_callback callback = NULL;
- void *callback_param = NULL;
+ struct dmaengine_desc_callback cb;
LIST_HEAD(list);
+ memset(&cb, 0, sizeof(cb));
spin_lock_irq(&edmac->lock);
/*
* If dma_terminate_all() was called before we get to run, the active
@@ -757,8 +755,7 @@ static void ep93xx_dma_tasklet(unsigned long data)
dma_cookie_complete(&desc->txd);
list_splice_init(&edmac->active, &list);
}
- callback = desc->txd.callback;
- callback_param = desc->txd.callback_param;
+ dmaengine_desc_get_callback(&desc->txd, &cb);
}
spin_unlock_irq(&edmac->lock);
@@ -771,8 +768,7 @@ static void ep93xx_dma_tasklet(unsigned long data)
ep93xx_dma_desc_put(edmac, desc);
}
- if (callback)
- callback(callback_param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
}
static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
@@ -1047,11 +1043,11 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
first = NULL;
for_each_sg(sgl, sg, sg_len, i) {
- size_t sg_len = sg_dma_len(sg);
+ size_t len = sg_dma_len(sg);
- if (sg_len > DMA_MAX_CHAN_BYTES) {
- dev_warn(chan2dev(edmac), "too big transfer size %d\n",
- sg_len);
+ if (len > DMA_MAX_CHAN_BYTES) {
+ dev_warn(chan2dev(edmac), "too big transfer size %zu\n",
+ len);
goto fail;
}
@@ -1068,7 +1064,7 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc->src_addr = edmac->runtime_addr;
desc->dst_addr = sg_dma_address(sg);
}
- desc->size = sg_len;
+ desc->size = len;
if (!first)
first = desc;
@@ -1125,7 +1121,7 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
}
if (period_len > DMA_MAX_CHAN_BYTES) {
- dev_warn(chan2dev(edmac), "too big period length %d\n",
+ dev_warn(chan2dev(edmac), "too big period length %zu\n",
period_len);
return NULL;
}
diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
index de2a2a2b1d75..db2f9e1653a2 100644
--- a/drivers/dma/fsl_raid.c
+++ b/drivers/dma/fsl_raid.c
@@ -134,17 +134,9 @@ static void fsl_re_issue_pending(struct dma_chan *chan)
static void fsl_re_desc_done(struct fsl_re_desc *desc)
{
- dma_async_tx_callback callback;
- void *callback_param;
-
dma_cookie_complete(&desc->async_tx);
-
- callback = desc->async_tx.callback;
- callback_param = desc->async_tx.callback_param;
- if (callback)
- callback(callback_param);
-
dma_descriptor_unmap(&desc->async_tx);
+ dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
}
static void fsl_re_cleanup_descs(struct fsl_re_chan *re_chan)
@@ -670,7 +662,7 @@ static int fsl_re_chan_probe(struct platform_device *ofdev,
/* read irq property from dts */
chan->irq = irq_of_parse_and_map(np, 0);
- if (chan->irq == NO_IRQ) {
+ if (!chan->irq) {
dev_err(dev, "No IRQ defined for JR %d\n", q);
ret = -ENODEV;
goto err_free;
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 911b7177eb50..51c75bf2b9b6 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -516,13 +516,9 @@ static dma_cookie_t fsldma_run_tx_complete_actions(struct fsldma_chan *chan,
if (txd->cookie > 0) {
ret = txd->cookie;
- /* Run the link descriptor callback function */
- if (txd->callback) {
- chan_dbg(chan, "LD %p callback\n", desc);
- txd->callback(txd->callback_param);
- }
-
dma_descriptor_unmap(txd);
+ /* Run the link descriptor callback function */
+ dmaengine_desc_get_callback_invoke(txd, NULL);
}
/* Run any dependencies */
@@ -1153,7 +1149,7 @@ static void fsldma_free_irqs(struct fsldma_device *fdev)
struct fsldma_chan *chan;
int i;
- if (fdev->irq != NO_IRQ) {
+ if (fdev->irq) {
dev_dbg(fdev->dev, "free per-controller IRQ\n");
free_irq(fdev->irq, fdev);
return;
@@ -1161,7 +1157,7 @@ static void fsldma_free_irqs(struct fsldma_device *fdev)
for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
chan = fdev->chan[i];
- if (chan && chan->irq != NO_IRQ) {
+ if (chan && chan->irq) {
chan_dbg(chan, "free per-channel IRQ\n");
free_irq(chan->irq, chan);
}
@@ -1175,7 +1171,7 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
int i;
/* if we have a per-controller IRQ, use that */
- if (fdev->irq != NO_IRQ) {
+ if (fdev->irq) {
dev_dbg(fdev->dev, "request per-controller IRQ\n");
ret = request_irq(fdev->irq, fsldma_ctrl_irq, IRQF_SHARED,
"fsldma-controller", fdev);
@@ -1188,7 +1184,7 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
if (!chan)
continue;
- if (chan->irq == NO_IRQ) {
+ if (!chan->irq) {
chan_err(chan, "interrupts property missing in device tree\n");
ret = -ENODEV;
goto out_unwind;
@@ -1211,7 +1207,7 @@ out_unwind:
if (!chan)
continue;
- if (chan->irq == NO_IRQ)
+ if (!chan->irq)
continue;
free_irq(chan->irq, chan);
@@ -1311,7 +1307,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
list_add_tail(&chan->common.device_node, &fdev->common.channels);
dev_info(fdev->dev, "#%d (%s), irq %d\n", chan->id, compatible,
- chan->irq != NO_IRQ ? chan->irq : fdev->irq);
+ chan->irq ? chan->irq : fdev->irq);
return 0;
@@ -1351,7 +1347,7 @@ static int fsldma_of_probe(struct platform_device *op)
if (!fdev->regs) {
dev_err(&op->dev, "unable to ioremap registers\n");
err = -ENOMEM;
- goto out_free_fdev;
+ goto out_free;
}
/* map the channel IRQ if it exists, but don't hookup the handler yet */
@@ -1416,6 +1412,8 @@ static int fsldma_of_probe(struct platform_device *op)
out_free_fdev:
irq_dispose_mapping(fdev->irq);
+ iounmap(fdev->regs);
+out_free:
kfree(fdev);
out_return:
return err;
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index a960608c0a4d..ab0fb804fb1e 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -663,9 +663,7 @@ static void imxdma_tasklet(unsigned long data)
out:
spin_unlock_irqrestore(&imxdma->lock, flags);
- if (desc->desc.callback)
- desc->desc.callback(desc->desc.callback_param);
-
+ dmaengine_desc_get_callback_invoke(&desc->desc, NULL);
}
static int imxdma_terminate_all(struct dma_chan *chan)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 3cb47386fbb9..b9629b2bfc05 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -184,7 +184,7 @@
struct sdma_mode_count {
u32 count : 16; /* size of the buffer pointed by this BD */
u32 status : 8; /* E,R,I,C,W,D status bits stored here */
- u32 command : 8; /* command mostlky used for channel 0 */
+ u32 command : 8; /* command mostly used for channel 0 */
};
/*
@@ -479,6 +479,24 @@ static struct sdma_driver_data sdma_imx6q = {
.script_addrs = &sdma_script_imx6q,
};
+static struct sdma_script_start_addrs sdma_script_imx7d = {
+ .ap_2_ap_addr = 644,
+ .uart_2_mcu_addr = 819,
+ .mcu_2_app_addr = 749,
+ .uartsh_2_mcu_addr = 1034,
+ .mcu_2_shp_addr = 962,
+ .app_2_mcu_addr = 685,
+ .shp_2_mcu_addr = 893,
+ .spdif_2_mcu_addr = 1102,
+ .mcu_2_spdif_addr = 1136,
+};
+
+static struct sdma_driver_data sdma_imx7d = {
+ .chnenbl0 = SDMA_CHNENBL0_IMX35,
+ .num_events = 48,
+ .script_addrs = &sdma_script_imx7d,
+};
+
static const struct platform_device_id sdma_devtypes[] = {
{
.name = "imx25-sdma",
@@ -499,6 +517,9 @@ static const struct platform_device_id sdma_devtypes[] = {
.name = "imx6q-sdma",
.driver_data = (unsigned long)&sdma_imx6q,
}, {
+ .name = "imx7d-sdma",
+ .driver_data = (unsigned long)&sdma_imx7d,
+ }, {
/* sentinel */
}
};
@@ -511,6 +532,7 @@ static const struct of_device_id sdma_dt_ids[] = {
{ .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
+ { .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdma_dt_ids);
@@ -686,8 +708,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* executed.
*/
- if (sdmac->desc.callback)
- sdmac->desc.callback(sdmac->desc.callback_param);
+ dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
sdmac->buf_tail++;
sdmac->buf_tail %= sdmac->num_bd;
@@ -722,8 +743,8 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
sdmac->status = DMA_COMPLETE;
dma_cookie_complete(&sdmac->desc);
- if (sdmac->desc.callback)
- sdmac->desc.callback(sdmac->desc.callback_param);
+
+ dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
}
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -1387,6 +1408,7 @@ static void sdma_issue_pending(struct dma_chan *chan)
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 41
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 42
static void sdma_add_scripts(struct sdma_engine *sdma,
const struct sdma_script_start_addrs *addr)
@@ -1436,6 +1458,9 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
case 3:
sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3;
break;
+ case 4:
+ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4;
+ break;
default:
dev_err(sdma->dev, "unknown firmware version\n");
goto err_firmware;
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index bd09961443b1..49386ce04bf5 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -38,8 +38,54 @@
#include "../dmaengine.h"
+static char *chanerr_str[] = {
+ "DMA Transfer Destination Address Error",
+ "Next Descriptor Address Error",
+ "Descriptor Error",
+ "Chan Address Value Error",
+ "CHANCMD Error",
+ "Chipset Uncorrectable Data Integrity Error",
+ "DMA Uncorrectable Data Integrity Error",
+ "Read Data Error",
+ "Write Data Error",
+ "Descriptor Control Error",
+ "Descriptor Transfer Size Error",
+ "Completion Address Error",
+ "Interrupt Configuration Error",
+ "Super extended descriptor Address Error",
+ "Unaffiliated Error",
+ "CRC or XOR P Error",
+ "XOR Q Error",
+ "Descriptor Count Error",
+ "DIF All F detect Error",
+ "Guard Tag verification Error",
+ "Application Tag verification Error",
+ "Reference Tag verification Error",
+ "Bundle Bit Error",
+ "Result DIF All F detect Error",
+ "Result Guard Tag verification Error",
+ "Result Application Tag verification Error",
+ "Result Reference Tag verification Error",
+ NULL
+};
+
static void ioat_eh(struct ioatdma_chan *ioat_chan);
+static void ioat_print_chanerrs(struct ioatdma_chan *ioat_chan, u32 chanerr)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if ((chanerr >> i) & 1) {
+ if (chanerr_str[i]) {
+ dev_err(to_dev(ioat_chan), "Err(%d): %s\n",
+ i, chanerr_str[i]);
+ } else
+ break;
+ }
+ }
+}
+
/**
* ioat_dma_do_interrupt - handler used for single vector interrupt mode
* @irq: interrupt id
@@ -568,12 +614,14 @@ static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
tx = &desc->txd;
if (tx->cookie) {
+ struct dmaengine_result res;
+
dma_cookie_complete(tx);
dma_descriptor_unmap(tx);
- if (tx->callback) {
- tx->callback(tx->callback_param);
- tx->callback = NULL;
- }
+ res.result = DMA_TRANS_NOERROR;
+ dmaengine_desc_get_callback_invoke(tx, NULL);
+ tx->callback = NULL;
+ tx->callback_result = NULL;
}
if (tx->phys == phys_complete)
@@ -622,7 +670,8 @@ static void ioat_cleanup(struct ioatdma_chan *ioat_chan)
if (is_ioat_halted(*ioat_chan->completion)) {
u32 chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- if (chanerr & IOAT_CHANERR_HANDLE_MASK) {
+ if (chanerr &
+ (IOAT_CHANERR_HANDLE_MASK | IOAT_CHANERR_RECOVER_MASK)) {
mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT);
ioat_eh(ioat_chan);
}
@@ -652,6 +701,61 @@ static void ioat_restart_channel(struct ioatdma_chan *ioat_chan)
__ioat_restart_chan(ioat_chan);
}
+
+static void ioat_abort_descs(struct ioatdma_chan *ioat_chan)
+{
+ struct ioatdma_device *ioat_dma = ioat_chan->ioat_dma;
+ struct ioat_ring_ent *desc;
+ u16 active;
+ int idx = ioat_chan->tail, i;
+
+ /*
+ * We assume that the failed descriptor has been processed.
+ * Now we are just returning all the remaining submitted
+ * descriptors to abort.
+ */
+ active = ioat_ring_active(ioat_chan);
+
+ /* we skip the failed descriptor that tail points to */
+ for (i = 1; i < active; i++) {
+ struct dma_async_tx_descriptor *tx;
+
+ smp_read_barrier_depends();
+ prefetch(ioat_get_ring_ent(ioat_chan, idx + i + 1));
+ desc = ioat_get_ring_ent(ioat_chan, idx + i);
+
+ tx = &desc->txd;
+ if (tx->cookie) {
+ struct dmaengine_result res;
+
+ dma_cookie_complete(tx);
+ dma_descriptor_unmap(tx);
+ res.result = DMA_TRANS_ABORTED;
+ dmaengine_desc_get_callback_invoke(tx, &res);
+ tx->callback = NULL;
+ tx->callback_result = NULL;
+ }
+
+ /* skip extended descriptors */
+ if (desc_has_ext(desc)) {
+ WARN_ON(i + 1 >= active);
+ i++;
+ }
+
+ /* cleanup super extended descriptors */
+ if (desc->sed) {
+ ioat_free_sed(ioat_dma, desc->sed);
+ desc->sed = NULL;
+ }
+ }
+
+ smp_mb(); /* finish all descriptor reads before incrementing tail */
+ ioat_chan->tail = idx + active;
+
+ desc = ioat_get_ring_ent(ioat_chan, ioat_chan->tail);
+ ioat_chan->last_completion = *ioat_chan->completion = desc->txd.phys;
+}
+
static void ioat_eh(struct ioatdma_chan *ioat_chan)
{
struct pci_dev *pdev = to_pdev(ioat_chan);
@@ -662,6 +766,8 @@ static void ioat_eh(struct ioatdma_chan *ioat_chan)
u32 err_handled = 0;
u32 chanerr_int;
u32 chanerr;
+ bool abort = false;
+ struct dmaengine_result res;
/* cleanup so tail points to descriptor that caused the error */
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
@@ -697,30 +803,55 @@ static void ioat_eh(struct ioatdma_chan *ioat_chan)
break;
}
+ if (chanerr & IOAT_CHANERR_RECOVER_MASK) {
+ if (chanerr & IOAT_CHANERR_READ_DATA_ERR) {
+ res.result = DMA_TRANS_READ_FAILED;
+ err_handled |= IOAT_CHANERR_READ_DATA_ERR;
+ } else if (chanerr & IOAT_CHANERR_WRITE_DATA_ERR) {
+ res.result = DMA_TRANS_WRITE_FAILED;
+ err_handled |= IOAT_CHANERR_WRITE_DATA_ERR;
+ }
+
+ abort = true;
+ } else
+ res.result = DMA_TRANS_NOERROR;
+
/* fault on unhandled error or spurious halt */
if (chanerr ^ err_handled || chanerr == 0) {
dev_err(to_dev(ioat_chan), "%s: fatal error (%x:%x)\n",
__func__, chanerr, err_handled);
+ dev_err(to_dev(ioat_chan), "Errors handled:\n");
+ ioat_print_chanerrs(ioat_chan, err_handled);
+ dev_err(to_dev(ioat_chan), "Errors not handled:\n");
+ ioat_print_chanerrs(ioat_chan, (chanerr & ~err_handled));
+
BUG();
- } else { /* cleanup the faulty descriptor */
- tx = &desc->txd;
- if (tx->cookie) {
- dma_cookie_complete(tx);
- dma_descriptor_unmap(tx);
- if (tx->callback) {
- tx->callback(tx->callback_param);
- tx->callback = NULL;
- }
- }
}
- writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- pci_write_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, chanerr_int);
+ /* cleanup the faulty descriptor since we are continuing */
+ tx = &desc->txd;
+ if (tx->cookie) {
+ dma_cookie_complete(tx);
+ dma_descriptor_unmap(tx);
+ dmaengine_desc_get_callback_invoke(tx, &res);
+ tx->callback = NULL;
+ tx->callback_result = NULL;
+ }
/* mark faulting descriptor as complete */
*ioat_chan->completion = desc->txd.phys;
spin_lock_bh(&ioat_chan->prep_lock);
+ /* we need abort all descriptors */
+ if (abort) {
+ ioat_abort_descs(ioat_chan);
+ /* clean up the channel, we could be in weird state */
+ ioat_reset_hw(ioat_chan);
+ }
+
+ writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
+ pci_write_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, chanerr_int);
+
ioat_restart_channel(ioat_chan);
spin_unlock_bh(&ioat_chan->prep_lock);
}
@@ -753,10 +884,28 @@ void ioat_timer_event(unsigned long data)
chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
dev_err(to_dev(ioat_chan), "%s: Channel halted (%x)\n",
__func__, chanerr);
- if (test_bit(IOAT_RUN, &ioat_chan->state))
- BUG_ON(is_ioat_bug(chanerr));
- else /* we never got off the ground */
- return;
+ dev_err(to_dev(ioat_chan), "Errors:\n");
+ ioat_print_chanerrs(ioat_chan, chanerr);
+
+ if (test_bit(IOAT_RUN, &ioat_chan->state)) {
+ spin_lock_bh(&ioat_chan->cleanup_lock);
+ spin_lock_bh(&ioat_chan->prep_lock);
+ set_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
+ spin_unlock_bh(&ioat_chan->prep_lock);
+
+ ioat_abort_descs(ioat_chan);
+ dev_warn(to_dev(ioat_chan), "Reset channel...\n");
+ ioat_reset_hw(ioat_chan);
+ dev_warn(to_dev(ioat_chan), "Restart channel...\n");
+ ioat_restart_channel(ioat_chan);
+
+ spin_lock_bh(&ioat_chan->prep_lock);
+ clear_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
+ spin_unlock_bh(&ioat_chan->prep_lock);
+ spin_unlock_bh(&ioat_chan->cleanup_lock);
+ }
+
+ return;
}
spin_lock_bh(&ioat_chan->cleanup_lock);
@@ -780,14 +929,26 @@ void ioat_timer_event(unsigned long data)
u32 chanerr;
chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- dev_warn(to_dev(ioat_chan), "Restarting channel...\n");
- dev_warn(to_dev(ioat_chan), "CHANSTS: %#Lx CHANERR: %#x\n",
- status, chanerr);
- dev_warn(to_dev(ioat_chan), "Active descriptors: %d\n",
- ioat_ring_active(ioat_chan));
+ dev_err(to_dev(ioat_chan), "CHANSTS: %#Lx CHANERR: %#x\n",
+ status, chanerr);
+ dev_err(to_dev(ioat_chan), "Errors:\n");
+ ioat_print_chanerrs(ioat_chan, chanerr);
+
+ dev_dbg(to_dev(ioat_chan), "Active descriptors: %d\n",
+ ioat_ring_active(ioat_chan));
spin_lock_bh(&ioat_chan->prep_lock);
+ set_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
+ spin_unlock_bh(&ioat_chan->prep_lock);
+
+ ioat_abort_descs(ioat_chan);
+ dev_warn(to_dev(ioat_chan), "Resetting channel...\n");
+ ioat_reset_hw(ioat_chan);
+ dev_warn(to_dev(ioat_chan), "Restarting channel...\n");
ioat_restart_channel(ioat_chan);
+
+ spin_lock_bh(&ioat_chan->prep_lock);
+ clear_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
spin_unlock_bh(&ioat_chan->prep_lock);
spin_unlock_bh(&ioat_chan->cleanup_lock);
return;
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 7145f7716a92..015f7110b96d 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -828,7 +828,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma)
dest_dma = dma_map_page(dev, dest, 0, PAGE_SIZE, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, dest_dma))
- goto dma_unmap;
+ goto free_resources;
for (i = 0; i < IOAT_NUM_SRC_TEST; i++)
dma_srcs[i] = DMA_ERROR_CODE;
diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h
index 70534981a49b..48fa4cf9f64a 100644
--- a/drivers/dma/ioat/registers.h
+++ b/drivers/dma/ioat/registers.h
@@ -240,6 +240,8 @@
#define IOAT_CHANERR_DESCRIPTOR_COUNT_ERR 0x40000
#define IOAT_CHANERR_HANDLE_MASK (IOAT_CHANERR_XOR_P_OR_CRC_ERR | IOAT_CHANERR_XOR_Q_ERR)
+#define IOAT_CHANERR_RECOVER_MASK (IOAT_CHANERR_READ_DATA_ERR | \
+ IOAT_CHANERR_WRITE_DATA_ERR)
#define IOAT_CHANERR_MASK_OFFSET 0x2C /* 32-bit Channel Error Register */
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index f039cfadf17b..a410657f7bcd 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -71,8 +71,7 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc,
/* call the callback (must not sleep or submit new
* operations to this channel)
*/
- if (tx->callback)
- tx->callback(tx->callback_param);
+ dmaengine_desc_get_callback_invoke(tx, NULL);
dma_descriptor_unmap(tx);
if (desc->group_head)
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index b54f62de9232..ed76044ce4b9 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -1160,11 +1160,10 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
struct scatterlist **sg, *sgnext, *sgnew = NULL;
/* Next transfer descriptor */
struct idmac_tx_desc *desc, *descnew;
- dma_async_tx_callback callback;
- void *callback_param;
bool done = false;
u32 ready0, ready1, curbuf, err;
unsigned long flags;
+ struct dmaengine_desc_callback cb;
/* IDMAC has cleared the respective BUFx_RDY bit, we manage the buffer */
@@ -1278,12 +1277,12 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
if (likely(sgnew) &&
ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) {
- callback = descnew->txd.callback;
- callback_param = descnew->txd.callback_param;
+ dmaengine_desc_get_callback(&descnew->txd, &cb);
+
list_del_init(&descnew->list);
spin_unlock(&ichan->lock);
- if (callback)
- callback(callback_param);
+
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock(&ichan->lock);
}
@@ -1292,13 +1291,12 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
if (done)
dma_cookie_complete(&desc->txd);
- callback = desc->txd.callback;
- callback_param = desc->txd.callback_param;
+ dmaengine_desc_get_callback(&desc->txd, &cb);
spin_unlock(&ichan->lock);
- if (done && (desc->txd.flags & DMA_PREP_INTERRUPT) && callback)
- callback(callback_param);
+ if (done && (desc->txd.flags & DMA_PREP_INTERRUPT))
+ dmaengine_desc_callback_invoke(&cb, NULL);
return IRQ_HANDLED;
}
diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c
index 2bf37e68ad0f..dd184b50e5b4 100644
--- a/drivers/dma/ipu/ipu_irq.c
+++ b/drivers/dma/ipu/ipu_irq.c
@@ -286,22 +286,21 @@ static void ipu_irq_handler(struct irq_desc *desc)
raw_spin_unlock(&bank_lock);
while ((line = ffs(status))) {
struct ipu_irq_map *map;
- unsigned int irq = NO_IRQ;
+ unsigned int irq;
line--;
status &= ~(1UL << line);
raw_spin_lock(&bank_lock);
map = src2map(32 * i + line);
- if (map)
- irq = map->irq;
- raw_spin_unlock(&bank_lock);
-
if (!map) {
+ raw_spin_unlock(&bank_lock);
pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
line, i);
continue;
}
+ irq = map->irq;
+ raw_spin_unlock(&bank_lock);
generic_handle_irq(irq);
}
}
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 39de8980128c..aabcb7934b05 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 - 2015 Linaro Ltd.
* Copyright (c) 2013 Hisilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
@@ -8,6 +8,8 @@
*/
#include <linux/sched.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/dmaengine.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -25,22 +27,28 @@
#define DRIVER_NAME "k3-dma"
#define DMA_MAX_SIZE 0x1ffc
+#define DMA_CYCLIC_MAX_PERIOD 0x1000
+#define LLI_BLOCK_SIZE (4 * PAGE_SIZE)
#define INT_STAT 0x00
#define INT_TC1 0x04
+#define INT_TC2 0x08
#define INT_ERR1 0x0c
#define INT_ERR2 0x10
#define INT_TC1_MASK 0x18
+#define INT_TC2_MASK 0x1c
#define INT_ERR1_MASK 0x20
#define INT_ERR2_MASK 0x24
#define INT_TC1_RAW 0x600
-#define INT_ERR1_RAW 0x608
-#define INT_ERR2_RAW 0x610
+#define INT_TC2_RAW 0x608
+#define INT_ERR1_RAW 0x610
+#define INT_ERR2_RAW 0x618
#define CH_PRI 0x688
#define CH_STAT 0x690
#define CX_CUR_CNT 0x704
#define CX_LLI 0x800
-#define CX_CNT 0x810
+#define CX_CNT1 0x80c
+#define CX_CNT0 0x810
#define CX_SRC 0x814
#define CX_DST 0x818
#define CX_CFG 0x81c
@@ -49,6 +57,7 @@
#define CX_LLI_CHAIN_EN 0x2
#define CX_CFG_EN 0x1
+#define CX_CFG_NODEIRQ BIT(1)
#define CX_CFG_MEM2PER (0x1 << 2)
#define CX_CFG_PER2MEM (0x2 << 2)
#define CX_CFG_SRCINCR (0x1 << 31)
@@ -68,7 +77,7 @@ struct k3_dma_desc_sw {
dma_addr_t desc_hw_lli;
size_t desc_num;
size_t size;
- struct k3_desc_hw desc_hw[0];
+ struct k3_desc_hw *desc_hw;
};
struct k3_dma_phy;
@@ -81,6 +90,7 @@ struct k3_dma_chan {
enum dma_transfer_direction dir;
dma_addr_t dev_addr;
enum dma_status status;
+ bool cyclic;
};
struct k3_dma_phy {
@@ -100,6 +110,7 @@ struct k3_dma_dev {
struct k3_dma_phy *phy;
struct k3_dma_chan *chans;
struct clk *clk;
+ struct dma_pool *pool;
u32 dma_channels;
u32 dma_requests;
unsigned int irq;
@@ -135,6 +146,7 @@ static void k3_dma_terminate_chan(struct k3_dma_phy *phy, struct k3_dma_dev *d)
val = 0x1 << phy->idx;
writel_relaxed(val, d->base + INT_TC1_RAW);
+ writel_relaxed(val, d->base + INT_TC2_RAW);
writel_relaxed(val, d->base + INT_ERR1_RAW);
writel_relaxed(val, d->base + INT_ERR2_RAW);
}
@@ -142,7 +154,7 @@ static void k3_dma_terminate_chan(struct k3_dma_phy *phy, struct k3_dma_dev *d)
static void k3_dma_set_desc(struct k3_dma_phy *phy, struct k3_desc_hw *hw)
{
writel_relaxed(hw->lli, phy->base + CX_LLI);
- writel_relaxed(hw->count, phy->base + CX_CNT);
+ writel_relaxed(hw->count, phy->base + CX_CNT0);
writel_relaxed(hw->saddr, phy->base + CX_SRC);
writel_relaxed(hw->daddr, phy->base + CX_DST);
writel_relaxed(AXI_CFG_DEFAULT, phy->base + AXI_CFG);
@@ -176,11 +188,13 @@ static void k3_dma_enable_dma(struct k3_dma_dev *d, bool on)
/* unmask irq */
writel_relaxed(0xffff, d->base + INT_TC1_MASK);
+ writel_relaxed(0xffff, d->base + INT_TC2_MASK);
writel_relaxed(0xffff, d->base + INT_ERR1_MASK);
writel_relaxed(0xffff, d->base + INT_ERR2_MASK);
} else {
/* mask irq */
writel_relaxed(0x0, d->base + INT_TC1_MASK);
+ writel_relaxed(0x0, d->base + INT_TC2_MASK);
writel_relaxed(0x0, d->base + INT_ERR1_MASK);
writel_relaxed(0x0, d->base + INT_ERR2_MASK);
}
@@ -193,22 +207,31 @@ static irqreturn_t k3_dma_int_handler(int irq, void *dev_id)
struct k3_dma_chan *c;
u32 stat = readl_relaxed(d->base + INT_STAT);
u32 tc1 = readl_relaxed(d->base + INT_TC1);
+ u32 tc2 = readl_relaxed(d->base + INT_TC2);
u32 err1 = readl_relaxed(d->base + INT_ERR1);
u32 err2 = readl_relaxed(d->base + INT_ERR2);
u32 i, irq_chan = 0;
while (stat) {
i = __ffs(stat);
- stat &= (stat - 1);
- if (likely(tc1 & BIT(i))) {
+ stat &= ~BIT(i);
+ if (likely(tc1 & BIT(i)) || (tc2 & BIT(i))) {
+ unsigned long flags;
+
p = &d->phy[i];
c = p->vchan;
- if (c) {
- unsigned long flags;
-
+ if (c && (tc1 & BIT(i))) {
spin_lock_irqsave(&c->vc.lock, flags);
vchan_cookie_complete(&p->ds_run->vd);
+ WARN_ON_ONCE(p->ds_done);
p->ds_done = p->ds_run;
+ p->ds_run = NULL;
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ }
+ if (c && (tc2 & BIT(i))) {
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (p->ds_run != NULL)
+ vchan_cyclic_callback(&p->ds_run->vd);
spin_unlock_irqrestore(&c->vc.lock, flags);
}
irq_chan |= BIT(i);
@@ -218,14 +241,17 @@ static irqreturn_t k3_dma_int_handler(int irq, void *dev_id)
}
writel_relaxed(irq_chan, d->base + INT_TC1_RAW);
+ writel_relaxed(irq_chan, d->base + INT_TC2_RAW);
writel_relaxed(err1, d->base + INT_ERR1_RAW);
writel_relaxed(err2, d->base + INT_ERR2_RAW);
- if (irq_chan) {
+ if (irq_chan)
tasklet_schedule(&d->task);
+
+ if (irq_chan || err1 || err2)
return IRQ_HANDLED;
- } else
- return IRQ_NONE;
+
+ return IRQ_NONE;
}
static int k3_dma_start_txd(struct k3_dma_chan *c)
@@ -247,14 +273,14 @@ static int k3_dma_start_txd(struct k3_dma_chan *c)
* so vc->desc_issued only contains desc pending
*/
list_del(&ds->vd.node);
+
+ WARN_ON_ONCE(c->phy->ds_run);
+ WARN_ON_ONCE(c->phy->ds_done);
c->phy->ds_run = ds;
- c->phy->ds_done = NULL;
/* start dma */
k3_dma_set_desc(c->phy, &ds->desc_hw[0]);
return 0;
}
- c->phy->ds_done = NULL;
- c->phy->ds_run = NULL;
return -EAGAIN;
}
@@ -351,7 +377,7 @@ static enum dma_status k3_dma_tx_status(struct dma_chan *chan,
* its total size.
*/
vd = vchan_find_desc(&c->vc, cookie);
- if (vd) {
+ if (vd && !c->cyclic) {
bytes = container_of(vd, struct k3_dma_desc_sw, vd)->size;
} else if ((!p) || (!p->ds_run)) {
bytes = 0;
@@ -361,7 +387,8 @@ static enum dma_status k3_dma_tx_status(struct dma_chan *chan,
bytes = k3_dma_get_curr_cnt(d, p);
clli = k3_dma_get_curr_lli(p);
- index = (clli - ds->desc_hw_lli) / sizeof(struct k3_desc_hw);
+ index = ((clli - ds->desc_hw_lli) /
+ sizeof(struct k3_desc_hw)) + 1;
for (; index < ds->desc_num; index++) {
bytes += ds->desc_hw[index].count;
/* end of lli */
@@ -402,9 +429,10 @@ static void k3_dma_issue_pending(struct dma_chan *chan)
static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst,
dma_addr_t src, size_t len, u32 num, u32 ccfg)
{
- if ((num + 1) < ds->desc_num)
+ if (num != ds->desc_num - 1)
ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
sizeof(struct k3_desc_hw);
+
ds->desc_hw[num].lli |= CX_LLI_CHAIN_EN;
ds->desc_hw[num].count = len;
ds->desc_hw[num].saddr = src;
@@ -412,6 +440,35 @@ static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst,
ds->desc_hw[num].config = ccfg;
}
+static struct k3_dma_desc_sw *k3_dma_alloc_desc_resource(int num,
+ struct dma_chan *chan)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_desc_sw *ds;
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ int lli_limit = LLI_BLOCK_SIZE / sizeof(struct k3_desc_hw);
+
+ if (num > lli_limit) {
+ dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n",
+ &c->vc, num, lli_limit);
+ return NULL;
+ }
+
+ ds = kzalloc(sizeof(*ds), GFP_NOWAIT);
+ if (!ds)
+ return NULL;
+
+ ds->desc_hw = dma_pool_alloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli);
+ if (!ds->desc_hw) {
+ dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc);
+ kfree(ds);
+ return NULL;
+ }
+ memset(ds->desc_hw, 0, sizeof(struct k3_desc_hw) * num);
+ ds->desc_num = num;
+ return ds;
+}
+
static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
size_t len, unsigned long flags)
@@ -425,13 +482,13 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
return NULL;
num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
- ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
+
+ ds = k3_dma_alloc_desc_resource(num, chan);
if (!ds)
return NULL;
- ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
+ c->cyclic = 0;
ds->size = len;
- ds->desc_num = num;
num = 0;
if (!c->ccfg) {
@@ -474,18 +531,17 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
if (sgl == NULL)
return NULL;
+ c->cyclic = 0;
+
for_each_sg(sgl, sg, sglen, i) {
avail = sg_dma_len(sg);
if (avail > DMA_MAX_SIZE)
num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
}
- ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
+ ds = k3_dma_alloc_desc_resource(num, chan);
if (!ds)
return NULL;
-
- ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
- ds->desc_num = num;
num = 0;
for_each_sg(sgl, sg, sglen, i) {
@@ -516,6 +572,73 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
return vchan_tx_prep(&c->vc, &ds->vd, flags);
}
+static struct dma_async_tx_descriptor *
+k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
+ size_t buf_len, size_t period_len,
+ enum dma_transfer_direction dir,
+ unsigned long flags)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_desc_sw *ds;
+ size_t len, avail, total = 0;
+ dma_addr_t addr, src = 0, dst = 0;
+ int num = 1, since = 0;
+ size_t modulo = DMA_CYCLIC_MAX_PERIOD;
+ u32 en_tc2 = 0;
+
+ dev_dbg(chan->device->dev, "%s: buf %pad, dst %pad, buf len %zu, period_len = %zu, dir %d\n",
+ __func__, &buf_addr, &to_k3_chan(chan)->dev_addr,
+ buf_len, period_len, (int)dir);
+
+ avail = buf_len;
+ if (avail > modulo)
+ num += DIV_ROUND_UP(avail, modulo) - 1;
+
+ ds = k3_dma_alloc_desc_resource(num, chan);
+ if (!ds)
+ return NULL;
+
+ c->cyclic = 1;
+ addr = buf_addr;
+ avail = buf_len;
+ total = avail;
+ num = 0;
+
+ if (period_len < modulo)
+ modulo = period_len;
+
+ do {
+ len = min_t(size_t, avail, modulo);
+
+ if (dir == DMA_MEM_TO_DEV) {
+ src = addr;
+ dst = c->dev_addr;
+ } else if (dir == DMA_DEV_TO_MEM) {
+ src = c->dev_addr;
+ dst = addr;
+ }
+ since += len;
+ if (since >= period_len) {
+ /* descriptor asks for TC2 interrupt on completion */
+ en_tc2 = CX_CFG_NODEIRQ;
+ since -= period_len;
+ } else
+ en_tc2 = 0;
+
+ k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg | en_tc2);
+
+ addr += len;
+ avail -= len;
+ } while (avail);
+
+ /* "Cyclic" == end of link points back to start of link */
+ ds->desc_hw[num - 1].lli |= ds->desc_hw_lli;
+
+ ds->size = total;
+
+ return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
static int k3_dma_config(struct dma_chan *chan,
struct dma_slave_config *cfg)
{
@@ -551,7 +674,7 @@ static int k3_dma_config(struct dma_chan *chan,
c->ccfg |= (val << 12) | (val << 16);
if ((maxburst == 0) || (maxburst > 16))
- val = 16;
+ val = 15;
else
val = maxburst - 1;
c->ccfg |= (val << 20) | (val << 24);
@@ -563,6 +686,16 @@ static int k3_dma_config(struct dma_chan *chan,
return 0;
}
+static void k3_dma_free_desc(struct virt_dma_desc *vd)
+{
+ struct k3_dma_desc_sw *ds =
+ container_of(vd, struct k3_dma_desc_sw, vd);
+ struct k3_dma_dev *d = to_k3_dma(vd->tx.chan->device);
+
+ dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli);
+ kfree(ds);
+}
+
static int k3_dma_terminate_all(struct dma_chan *chan)
{
struct k3_dma_chan *c = to_k3_chan(chan);
@@ -586,7 +719,15 @@ static int k3_dma_terminate_all(struct dma_chan *chan)
k3_dma_terminate_chan(p, d);
c->phy = NULL;
p->vchan = NULL;
- p->ds_run = p->ds_done = NULL;
+ if (p->ds_run) {
+ k3_dma_free_desc(&p->ds_run->vd);
+ p->ds_run = NULL;
+ }
+ if (p->ds_done) {
+ k3_dma_free_desc(&p->ds_done->vd);
+ p->ds_done = NULL;
+ }
+
}
spin_unlock_irqrestore(&c->vc.lock, flags);
vchan_dma_desc_free_list(&c->vc, &head);
@@ -639,14 +780,6 @@ static int k3_dma_transfer_resume(struct dma_chan *chan)
return 0;
}
-static void k3_dma_free_desc(struct virt_dma_desc *vd)
-{
- struct k3_dma_desc_sw *ds =
- container_of(vd, struct k3_dma_desc_sw, vd);
-
- kfree(ds);
-}
-
static const struct of_device_id k3_pdma_dt_ids[] = {
{ .compatible = "hisilicon,k3-dma-1.0", },
{}
@@ -706,6 +839,12 @@ static int k3_dma_probe(struct platform_device *op)
d->irq = irq;
+ /* A DMA memory pool for LLIs, align on 32-byte boundary */
+ d->pool = dmam_pool_create(DRIVER_NAME, &op->dev,
+ LLI_BLOCK_SIZE, 32, 0);
+ if (!d->pool)
+ return -ENOMEM;
+
/* init phy channel */
d->phy = devm_kzalloc(&op->dev,
d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL);
@@ -722,11 +861,13 @@ static int k3_dma_probe(struct platform_device *op)
INIT_LIST_HEAD(&d->slave.channels);
dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
+ dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
d->slave.dev = &op->dev;
d->slave.device_free_chan_resources = k3_dma_free_chan_resources;
d->slave.device_tx_status = k3_dma_tx_status;
d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
+ d->slave.device_prep_dma_cyclic = k3_dma_prep_dma_cyclic;
d->slave.device_issue_pending = k3_dma_issue_pending;
d->slave.device_config = k3_dma_config;
d->slave.device_pause = k3_dma_transfer_pause;
diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index 1502b24b7c7d..818255844a3c 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -104,10 +104,8 @@ static void mic_dma_cleanup(struct mic_dma_chan *ch)
tx = &ch->tx_array[last_tail];
if (tx->cookie) {
dma_cookie_complete(tx);
- if (tx->callback) {
- tx->callback(tx->callback_param);
- tx->callback = NULL;
- }
+ dmaengine_desc_get_callback_invoke(tx, NULL);
+ tx->callback = NULL;
}
last_tail = mic_dma_hw_ring_inc(last_tail);
}
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index f4b25fb0d040..eb3a1f42ab06 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -864,19 +864,15 @@ static void dma_do_tasklet(unsigned long data)
struct mmp_pdma_desc_sw *desc, *_desc;
LIST_HEAD(chain_cleanup);
unsigned long flags;
+ struct dmaengine_desc_callback cb;
if (chan->cyclic_first) {
- dma_async_tx_callback cb = NULL;
- void *cb_data = NULL;
-
spin_lock_irqsave(&chan->desc_lock, flags);
desc = chan->cyclic_first;
- cb = desc->async_tx.callback;
- cb_data = desc->async_tx.callback_param;
+ dmaengine_desc_get_callback(&desc->async_tx, &cb);
spin_unlock_irqrestore(&chan->desc_lock, flags);
- if (cb)
- cb(cb_data);
+ dmaengine_desc_callback_invoke(&cb, NULL);
return;
}
@@ -921,8 +917,8 @@ static void dma_do_tasklet(unsigned long data)
/* Remove from the list of transactions */
list_del(&desc->node);
/* Run the link descriptor callback function */
- if (txd->callback)
- txd->callback(txd->callback_param);
+ dmaengine_desc_get_callback(txd, &cb);
+ dmaengine_desc_callback_invoke(&cb, NULL);
dma_pool_free(chan->desc_pool, desc, txd->phys);
}
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index b3441f57a364..13c68b6434ce 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -349,9 +349,7 @@ static void dma_do_tasklet(unsigned long data)
{
struct mmp_tdma_chan *tdmac = (struct mmp_tdma_chan *)data;
- if (tdmac->desc.callback)
- tdmac->desc.callback(tdmac->desc.callback_param);
-
+ dmaengine_desc_get_callback_invoke(&tdmac->desc, NULL);
}
static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
@@ -433,7 +431,7 @@ static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
if (period_len > TDMA_MAX_XFER_BYTES) {
dev_err(tdmac->dev,
- "maximum period size exceeded: %d > %d\n",
+ "maximum period size exceeded: %zu > %d\n",
period_len, TDMA_MAX_XFER_BYTES);
goto err_out;
}
diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c
index a6e642792e5a..e1a5c2242f6f 100644
--- a/drivers/dma/moxart-dma.c
+++ b/drivers/dma/moxart-dma.c
@@ -579,7 +579,7 @@ static int moxart_probe(struct platform_device *pdev)
return -ENOMEM;
irq = irq_of_parse_and_map(node, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
dev_err(dev, "no IRQ resource\n");
return -EINVAL;
}
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index fa86592c7ae1..dde713461a95 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -411,8 +411,7 @@ static void mpc_dma_process_completed(struct mpc_dma *mdma)
list_for_each_entry(mdesc, &list, node) {
desc = &mdesc->desc;
- if (desc->callback)
- desc->callback(desc->callback_param);
+ dmaengine_desc_get_callback_invoke(desc, NULL);
last_cookie = desc->cookie;
dma_run_dependencies(desc);
@@ -926,7 +925,7 @@ static int mpc_dma_probe(struct platform_device *op)
}
mdma->irq = irq_of_parse_and_map(dn, 0);
- if (mdma->irq == NO_IRQ) {
+ if (!mdma->irq) {
dev_err(dev, "Error mapping IRQ!\n");
retval = -EINVAL;
goto err;
@@ -935,7 +934,7 @@ static int mpc_dma_probe(struct platform_device *op)
if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) {
mdma->is_mpc8308 = 1;
mdma->irq2 = irq_of_parse_and_map(dn, 1);
- if (mdma->irq2 == NO_IRQ) {
+ if (!mdma->irq2) {
dev_err(dev, "Error mapping IRQ!\n");
retval = -EINVAL;
goto err_dispose1;
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index f4c9f98ec35e..23f75285a4d9 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -206,14 +206,11 @@ mv_desc_run_tx_complete_actions(struct mv_xor_desc_slot *desc,
if (desc->async_tx.cookie > 0) {
cookie = desc->async_tx.cookie;
+ dma_descriptor_unmap(&desc->async_tx);
/* call the callback (must not sleep or submit new
* operations to this channel)
*/
- if (desc->async_tx.callback)
- desc->async_tx.callback(
- desc->async_tx.callback_param);
-
- dma_descriptor_unmap(&desc->async_tx);
+ dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
}
/* run dependent operations */
@@ -470,12 +467,90 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
return mv_chan->slots_allocated ? : -ENOMEM;
}
+/*
+ * Check if source or destination is an PCIe/IO address (non-SDRAM) and add
+ * a new MBus window if necessary. Use a cache for these check so that
+ * the MMIO mapped registers don't have to be accessed for this check
+ * to speed up this process.
+ */
+static int mv_xor_add_io_win(struct mv_xor_chan *mv_chan, u32 addr)
+{
+ struct mv_xor_device *xordev = mv_chan->xordev;
+ void __iomem *base = mv_chan->mmr_high_base;
+ u32 win_enable;
+ u32 size;
+ u8 target, attr;
+ int ret;
+ int i;
+
+ /* Nothing needs to get done for the Armada 3700 */
+ if (xordev->xor_type == XOR_ARMADA_37XX)
+ return 0;
+
+ /*
+ * Loop over the cached windows to check, if the requested area
+ * is already mapped. If this the case, nothing needs to be done
+ * and we can return.
+ */
+ for (i = 0; i < WINDOW_COUNT; i++) {
+ if (addr >= xordev->win_start[i] &&
+ addr <= xordev->win_end[i]) {
+ /* Window is already mapped */
+ return 0;
+ }
+ }
+
+ /*
+ * The window is not mapped, so we need to create the new mapping
+ */
+
+ /* If no IO window is found that addr has to be located in SDRAM */
+ ret = mvebu_mbus_get_io_win_info(addr, &size, &target, &attr);
+ if (ret < 0)
+ return 0;
+
+ /*
+ * Mask the base addr 'addr' according to 'size' read back from the
+ * MBus window. Otherwise we might end up with an address located
+ * somewhere in the middle of this area here.
+ */
+ size -= 1;
+ addr &= ~size;
+
+ /*
+ * Reading one of both enabled register is enough, as they are always
+ * programmed to the identical values
+ */
+ win_enable = readl(base + WINDOW_BAR_ENABLE(0));
+
+ /* Set 'i' to the first free window to write the new values to */
+ i = ffs(~win_enable) - 1;
+ if (i >= WINDOW_COUNT)
+ return -ENOMEM;
+
+ writel((addr & 0xffff0000) | (attr << 8) | target,
+ base + WINDOW_BASE(i));
+ writel(size & 0xffff0000, base + WINDOW_SIZE(i));
+
+ /* Fill the caching variables for later use */
+ xordev->win_start[i] = addr;
+ xordev->win_end[i] = addr + size;
+
+ win_enable |= (1 << i);
+ win_enable |= 3 << (16 + (2 * i));
+ writel(win_enable, base + WINDOW_BAR_ENABLE(0));
+ writel(win_enable, base + WINDOW_BAR_ENABLE(1));
+
+ return 0;
+}
+
static struct dma_async_tx_descriptor *
mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
unsigned int src_cnt, size_t len, unsigned long flags)
{
struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
struct mv_xor_desc_slot *sw_desc;
+ int ret;
if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
return NULL;
@@ -486,6 +561,11 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
"%s src_cnt: %d len: %zu dest %pad flags: %ld\n",
__func__, src_cnt, len, &dest, flags);
+ /* Check if a new window needs to get added for 'dest' */
+ ret = mv_xor_add_io_win(mv_chan, dest);
+ if (ret)
+ return NULL;
+
sw_desc = mv_chan_alloc_slot(mv_chan);
if (sw_desc) {
sw_desc->type = DMA_XOR;
@@ -493,8 +573,13 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
mv_desc_init(sw_desc, dest, len, flags);
if (mv_chan->op_in_desc == XOR_MODE_IN_DESC)
mv_desc_set_mode(sw_desc);
- while (src_cnt--)
+ while (src_cnt--) {
+ /* Check if a new window needs to get added for 'src' */
+ ret = mv_xor_add_io_win(mv_chan, src[src_cnt]);
+ if (ret)
+ return NULL;
mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]);
+ }
}
dev_dbg(mv_chan_to_devp(mv_chan),
@@ -959,6 +1044,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
mv_chan->op_in_desc = XOR_MODE_IN_DESC;
dma_dev = &mv_chan->dmadev;
+ mv_chan->xordev = xordev;
/*
* These source and destination dummy buffers are used to implement
@@ -1086,6 +1172,10 @@ mv_xor_conf_mbus_windows(struct mv_xor_device *xordev,
dram->mbus_dram_target_id, base + WINDOW_BASE(i));
writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i));
+ /* Fill the caching variables for later use */
+ xordev->win_start[i] = cs->base;
+ xordev->win_end[i] = cs->base + cs->size - 1;
+
win_enable |= (1 << i);
win_enable |= 3 << (16 + (2 * i));
}
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index bf56e082e7cd..88eeab222a23 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -80,12 +80,17 @@
#define WINDOW_BAR_ENABLE(chan) (0x40 + ((chan) << 2))
#define WINDOW_OVERRIDE_CTRL(chan) (0xA0 + ((chan) << 2))
+#define WINDOW_COUNT 8
+
struct mv_xor_device {
void __iomem *xor_base;
void __iomem *xor_high_base;
struct clk *clk;
struct mv_xor_chan *channels[MV_XOR_MAX_CHANNELS];
int xor_type;
+
+ u32 win_start[WINDOW_COUNT];
+ u32 win_end[WINDOW_COUNT];
};
/**
@@ -127,6 +132,8 @@ struct mv_xor_chan {
char dummy_dst[MV_XOR_MIN_BYTE_COUNT];
dma_addr_t dummy_src_addr, dummy_dst_addr;
u32 saved_config_reg, saved_int_mask_reg;
+
+ struct mv_xor_device *xordev;
};
/**
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 60de35251da5..e217268c7098 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -326,8 +326,7 @@ static void mxs_dma_tasklet(unsigned long data)
{
struct mxs_dma_chan *mxs_chan = (struct mxs_dma_chan *) data;
- if (mxs_chan->desc.callback)
- mxs_chan->desc.callback(mxs_chan->desc.callback_param);
+ dmaengine_desc_get_callback_invoke(&mxs_chan->desc, NULL);
}
static int mxs_dma_irq_to_chan(struct mxs_dma_engine *mxs_dma, int irq)
@@ -429,12 +428,10 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
goto err_alloc;
}
- if (mxs_chan->chan_irq != NO_IRQ) {
- ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
- 0, "mxs-dma", mxs_dma);
- if (ret)
- goto err_irq;
- }
+ ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
+ 0, "mxs-dma", mxs_dma);
+ if (ret)
+ goto err_irq;
ret = clk_prepare_enable(mxs_dma->clk);
if (ret)
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 08c45c185549..09de71519d37 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1102,8 +1102,7 @@ static void nbpf_chan_tasklet(unsigned long data)
{
struct nbpf_channel *chan = (struct nbpf_channel *)data;
struct nbpf_desc *desc, *tmp;
- dma_async_tx_callback callback;
- void *param;
+ struct dmaengine_desc_callback cb;
while (!list_empty(&chan->done)) {
bool found = false, must_put, recycling = false;
@@ -1151,14 +1150,12 @@ static void nbpf_chan_tasklet(unsigned long data)
must_put = false;
}
- callback = desc->async_tx.callback;
- param = desc->async_tx.callback_param;
+ dmaengine_desc_get_callback(&desc->async_tx, &cb);
/* ack and callback completed descriptor */
spin_unlock_irq(&chan->lock);
- if (callback)
- callback(param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
if (must_put)
nbpf_desc_put(desc);
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index d99ca2b511c4..7ca27d4b1c54 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -32,10 +33,12 @@ struct omap_dmadev {
const struct omap_dma_reg *reg_map;
struct omap_system_dma_plat_info *plat;
bool legacy;
+ bool ll123_supported;
+ struct dma_pool *desc_pool;
unsigned dma_requests;
spinlock_t irq_lock;
uint32_t irq_enable_mask;
- struct omap_chan *lch_map[OMAP_SDMA_CHANNELS];
+ struct omap_chan **lch_map;
};
struct omap_chan {
@@ -55,16 +58,40 @@ struct omap_chan {
unsigned sgidx;
};
+#define DESC_NXT_SV_REFRESH (0x1 << 24)
+#define DESC_NXT_SV_REUSE (0x2 << 24)
+#define DESC_NXT_DV_REFRESH (0x1 << 26)
+#define DESC_NXT_DV_REUSE (0x2 << 26)
+#define DESC_NTYPE_TYPE2 (0x2 << 29)
+
+/* Type 2 descriptor with Source or Destination address update */
+struct omap_type2_desc {
+ uint32_t next_desc;
+ uint32_t en;
+ uint32_t addr; /* src or dst */
+ uint16_t fn;
+ uint16_t cicr;
+ int16_t cdei;
+ int16_t csei;
+ int32_t cdfi;
+ int32_t csfi;
+} __packed;
+
struct omap_sg {
dma_addr_t addr;
uint32_t en; /* number of elements (24-bit) */
uint32_t fn; /* number of frames (16-bit) */
int32_t fi; /* for double indexing */
int16_t ei; /* for double indexing */
+
+ /* Linked list */
+ struct omap_type2_desc *t2_desc;
+ dma_addr_t t2_desc_paddr;
};
struct omap_desc {
struct virt_dma_desc vd;
+ bool using_ll;
enum dma_transfer_direction dir;
dma_addr_t dev_addr;
@@ -81,6 +108,9 @@ struct omap_desc {
};
enum {
+ CAPS_0_SUPPORT_LL123 = BIT(20), /* Linked List type1/2/3 */
+ CAPS_0_SUPPORT_LL4 = BIT(21), /* Linked List type4 */
+
CCR_FS = BIT(5),
CCR_READ_PRIORITY = BIT(6),
CCR_ENABLE = BIT(7),
@@ -151,6 +181,19 @@ enum {
CICR_SUPER_BLOCK_IE = BIT(14), /* OMAP2+ only */
CLNK_CTRL_ENABLE_LNK = BIT(15),
+
+ CDP_DST_VALID_INC = 0 << 0,
+ CDP_DST_VALID_RELOAD = 1 << 0,
+ CDP_DST_VALID_REUSE = 2 << 0,
+ CDP_SRC_VALID_INC = 0 << 2,
+ CDP_SRC_VALID_RELOAD = 1 << 2,
+ CDP_SRC_VALID_REUSE = 2 << 2,
+ CDP_NTYPE_TYPE1 = 1 << 4,
+ CDP_NTYPE_TYPE2 = 2 << 4,
+ CDP_NTYPE_TYPE3 = 3 << 4,
+ CDP_TMODE_NORMAL = 0 << 8,
+ CDP_TMODE_LLIST = 1 << 8,
+ CDP_FAST = BIT(10),
};
static const unsigned es_bytes[] = {
@@ -180,7 +223,64 @@ static inline struct omap_desc *to_omap_dma_desc(struct dma_async_tx_descriptor
static void omap_dma_desc_free(struct virt_dma_desc *vd)
{
- kfree(container_of(vd, struct omap_desc, vd));
+ struct omap_desc *d = to_omap_dma_desc(&vd->tx);
+
+ if (d->using_ll) {
+ struct omap_dmadev *od = to_omap_dma_dev(vd->tx.chan->device);
+ int i;
+
+ for (i = 0; i < d->sglen; i++) {
+ if (d->sg[i].t2_desc)
+ dma_pool_free(od->desc_pool, d->sg[i].t2_desc,
+ d->sg[i].t2_desc_paddr);
+ }
+ }
+
+ kfree(d);
+}
+
+static void omap_dma_fill_type2_desc(struct omap_desc *d, int idx,
+ enum dma_transfer_direction dir, bool last)
+{
+ struct omap_sg *sg = &d->sg[idx];
+ struct omap_type2_desc *t2_desc = sg->t2_desc;
+
+ if (idx)
+ d->sg[idx - 1].t2_desc->next_desc = sg->t2_desc_paddr;
+ if (last)
+ t2_desc->next_desc = 0xfffffffc;
+
+ t2_desc->en = sg->en;
+ t2_desc->addr = sg->addr;
+ t2_desc->fn = sg->fn & 0xffff;
+ t2_desc->cicr = d->cicr;
+ if (!last)
+ t2_desc->cicr &= ~CICR_BLOCK_IE;
+
+ switch (dir) {
+ case DMA_DEV_TO_MEM:
+ t2_desc->cdei = sg->ei;
+ t2_desc->csei = d->ei;
+ t2_desc->cdfi = sg->fi;
+ t2_desc->csfi = d->fi;
+
+ t2_desc->en |= DESC_NXT_DV_REFRESH;
+ t2_desc->en |= DESC_NXT_SV_REUSE;
+ break;
+ case DMA_MEM_TO_DEV:
+ t2_desc->cdei = d->ei;
+ t2_desc->csei = sg->ei;
+ t2_desc->cdfi = d->fi;
+ t2_desc->csfi = sg->fi;
+
+ t2_desc->en |= DESC_NXT_SV_REFRESH;
+ t2_desc->en |= DESC_NXT_DV_REUSE;
+ break;
+ default:
+ return;
+ }
+
+ t2_desc->en |= DESC_NTYPE_TYPE2;
}
static void omap_dma_write(uint32_t val, unsigned type, void __iomem *addr)
@@ -285,6 +385,7 @@ static void omap_dma_assign(struct omap_dmadev *od, struct omap_chan *c,
static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
{
struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
+ uint16_t cicr = d->cicr;
if (__dma_omap15xx(od->plat->dma_attr))
omap_dma_chan_write(c, CPC, 0);
@@ -293,8 +394,27 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
omap_dma_clear_csr(c);
+ if (d->using_ll) {
+ uint32_t cdp = CDP_TMODE_LLIST | CDP_NTYPE_TYPE2 | CDP_FAST;
+
+ if (d->dir == DMA_DEV_TO_MEM)
+ cdp |= (CDP_DST_VALID_RELOAD | CDP_SRC_VALID_REUSE);
+ else
+ cdp |= (CDP_DST_VALID_REUSE | CDP_SRC_VALID_RELOAD);
+ omap_dma_chan_write(c, CDP, cdp);
+
+ omap_dma_chan_write(c, CNDP, d->sg[0].t2_desc_paddr);
+ omap_dma_chan_write(c, CCDN, 0);
+ omap_dma_chan_write(c, CCFN, 0xffff);
+ omap_dma_chan_write(c, CCEN, 0xffffff);
+
+ cicr &= ~CICR_BLOCK_IE;
+ } else if (od->ll123_supported) {
+ omap_dma_chan_write(c, CDP, 0);
+ }
+
/* Enable interrupts */
- omap_dma_chan_write(c, CICR, d->cicr);
+ omap_dma_chan_write(c, CICR, cicr);
/* Enable channel */
omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE);
@@ -365,10 +485,9 @@ static void omap_dma_stop(struct omap_chan *c)
c->running = false;
}
-static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
- unsigned idx)
+static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d)
{
- struct omap_sg *sg = d->sg + idx;
+ struct omap_sg *sg = d->sg + c->sgidx;
unsigned cxsa, cxei, cxfi;
if (d->dir == DMA_DEV_TO_MEM || d->dir == DMA_MEM_TO_MEM) {
@@ -388,6 +507,7 @@ static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
omap_dma_chan_write(c, CFN, sg->fn);
omap_dma_start(c, d);
+ c->sgidx++;
}
static void omap_dma_start_desc(struct omap_chan *c)
@@ -433,7 +553,7 @@ static void omap_dma_start_desc(struct omap_chan *c)
omap_dma_chan_write(c, CSDP, d->csdp);
omap_dma_chan_write(c, CLNK_CTRL, d->clnk_ctrl);
- omap_dma_start_sg(c, d, 0);
+ omap_dma_start_sg(c, d);
}
static void omap_dma_callback(int ch, u16 status, void *data)
@@ -445,15 +565,13 @@ static void omap_dma_callback(int ch, u16 status, void *data)
spin_lock_irqsave(&c->vc.lock, flags);
d = c->desc;
if (d) {
- if (!c->cyclic) {
- if (++c->sgidx < d->sglen) {
- omap_dma_start_sg(c, d, c->sgidx);
- } else {
- omap_dma_start_desc(c);
- vchan_cookie_complete(&d->vd);
- }
- } else {
+ if (c->cyclic) {
vchan_cyclic_callback(&d->vd);
+ } else if (d->using_ll || c->sgidx == d->sglen) {
+ omap_dma_start_desc(c);
+ vchan_cookie_complete(&d->vd);
+ } else {
+ omap_dma_start_sg(c, d);
}
}
spin_unlock_irqrestore(&c->vc.lock, flags);
@@ -503,6 +621,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct omap_dmadev *od = to_omap_dma_dev(chan->device);
struct omap_chan *c = to_omap_dma_chan(chan);
+ struct device *dev = od->ddev.dev;
int ret;
if (od->legacy) {
@@ -513,8 +632,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
&c->dma_ch);
}
- dev_dbg(od->ddev.dev, "allocating channel %u for %u\n",
- c->dma_ch, c->dma_sig);
+ dev_dbg(dev, "allocating channel %u for %u\n", c->dma_ch, c->dma_sig);
if (ret >= 0) {
omap_dma_assign(od, c, c->dma_ch);
@@ -570,7 +688,8 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan)
vchan_free_chan_resources(&c->vc);
omap_free_dma(c->dma_ch);
- dev_dbg(od->ddev.dev, "freeing channel for %u\n", c->dma_sig);
+ dev_dbg(od->ddev.dev, "freeing channel %u used for %u\n", c->dma_ch,
+ c->dma_sig);
c->dma_sig = 0;
}
@@ -744,6 +863,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
struct omap_desc *d;
dma_addr_t dev_addr;
unsigned i, es, en, frame_bytes;
+ bool ll_failed = false;
u32 burst;
if (dir == DMA_DEV_TO_MEM) {
@@ -784,13 +904,16 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
d->es = es;
d->ccr = c->ccr | CCR_SYNC_FRAME;
- if (dir == DMA_DEV_TO_MEM)
+ if (dir == DMA_DEV_TO_MEM) {
d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_CONSTANT;
- else
+ d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED;
+ } else {
d->ccr |= CCR_DST_AMODE_CONSTANT | CCR_SRC_AMODE_POSTINC;
+ d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED;
+ }
d->cicr = CICR_DROP_IE | CICR_BLOCK_IE;
- d->csdp = es;
+ d->csdp |= es;
if (dma_omap1()) {
d->cicr |= CICR_TOUT_IE;
@@ -819,14 +942,47 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
*/
en = burst;
frame_bytes = es_bytes[es] * en;
+
+ if (sglen >= 2)
+ d->using_ll = od->ll123_supported;
+
for_each_sg(sgl, sgent, sglen, i) {
- d->sg[i].addr = sg_dma_address(sgent);
- d->sg[i].en = en;
- d->sg[i].fn = sg_dma_len(sgent) / frame_bytes;
+ struct omap_sg *osg = &d->sg[i];
+
+ osg->addr = sg_dma_address(sgent);
+ osg->en = en;
+ osg->fn = sg_dma_len(sgent) / frame_bytes;
+
+ if (d->using_ll) {
+ osg->t2_desc = dma_pool_alloc(od->desc_pool, GFP_ATOMIC,
+ &osg->t2_desc_paddr);
+ if (!osg->t2_desc) {
+ dev_err(chan->device->dev,
+ "t2_desc[%d] allocation failed\n", i);
+ ll_failed = true;
+ d->using_ll = false;
+ continue;
+ }
+
+ omap_dma_fill_type2_desc(d, i, dir, (i == sglen - 1));
+ }
}
d->sglen = sglen;
+ /* Release the dma_pool entries if one allocation failed */
+ if (ll_failed) {
+ for (i = 0; i < d->sglen; i++) {
+ struct omap_sg *osg = &d->sg[i];
+
+ if (osg->t2_desc) {
+ dma_pool_free(od->desc_pool, osg->t2_desc,
+ osg->t2_desc_paddr);
+ osg->t2_desc = NULL;
+ }
+ }
+ }
+
return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
}
@@ -1225,16 +1381,24 @@ static int omap_dma_probe(struct platform_device *pdev)
spin_lock_init(&od->lock);
spin_lock_init(&od->irq_lock);
- od->dma_requests = OMAP_SDMA_REQUESTS;
- if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
- "dma-requests",
- &od->dma_requests)) {
+ if (!pdev->dev.of_node) {
+ od->dma_requests = od->plat->dma_attr->lch_count;
+ if (unlikely(!od->dma_requests))
+ od->dma_requests = OMAP_SDMA_REQUESTS;
+ } else if (of_property_read_u32(pdev->dev.of_node, "dma-requests",
+ &od->dma_requests)) {
dev_info(&pdev->dev,
"Missing dma-requests property, using %u.\n",
OMAP_SDMA_REQUESTS);
+ od->dma_requests = OMAP_SDMA_REQUESTS;
}
- for (i = 0; i < OMAP_SDMA_CHANNELS; i++) {
+ od->lch_map = devm_kcalloc(&pdev->dev, od->dma_requests,
+ sizeof(*od->lch_map), GFP_KERNEL);
+ if (!od->lch_map)
+ return -ENOMEM;
+
+ for (i = 0; i < od->dma_requests; i++) {
rc = omap_dma_chan_init(od);
if (rc) {
omap_dma_free(od);
@@ -1257,10 +1421,25 @@ static int omap_dma_probe(struct platform_device *pdev)
return rc;
}
+ if (omap_dma_glbl_read(od, CAPS_0) & CAPS_0_SUPPORT_LL123)
+ od->ll123_supported = true;
+
od->ddev.filter.map = od->plat->slave_map;
od->ddev.filter.mapcnt = od->plat->slavecnt;
od->ddev.filter.fn = omap_dma_filter_fn;
+ if (od->ll123_supported) {
+ od->desc_pool = dma_pool_create(dev_name(&pdev->dev),
+ &pdev->dev,
+ sizeof(struct omap_type2_desc),
+ 4, 0);
+ if (!od->desc_pool) {
+ dev_err(&pdev->dev,
+ "unable to allocate descriptor pool\n");
+ od->ll123_supported = false;
+ }
+ }
+
rc = dma_async_device_register(&od->ddev);
if (rc) {
pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n",
@@ -1284,7 +1463,8 @@ static int omap_dma_probe(struct platform_device *pdev)
}
}
- dev_info(&pdev->dev, "OMAP DMA engine driver\n");
+ dev_info(&pdev->dev, "OMAP DMA engine driver%s\n",
+ od->ll123_supported ? " (LinkedList1/2/3 supported)" : "");
return rc;
}
@@ -1307,6 +1487,9 @@ static int omap_dma_remove(struct platform_device *pdev)
omap_dma_glbl_write(od, IRQENABLE_L0, 0);
}
+ if (od->ll123_supported)
+ dma_pool_destroy(od->desc_pool);
+
omap_dma_free(od);
return 0;
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index 113605f6fe20..df95727dc2fb 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -357,14 +357,13 @@ static void pdc_chain_complete(struct pch_dma_chan *pd_chan,
struct pch_dma_desc *desc)
{
struct dma_async_tx_descriptor *txd = &desc->txd;
- dma_async_tx_callback callback = txd->callback;
- void *param = txd->callback_param;
+ struct dmaengine_desc_callback cb;
+ dmaengine_desc_get_callback(txd, &cb);
list_splice_init(&desc->tx_list, &pd_chan->free_list);
list_move(&desc->desc_node, &pd_chan->free_list);
- if (callback)
- callback(param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
}
static void pdc_complete_all(struct pch_dma_chan *pd_chan)
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 4fc3ffbd5ca0..030fe05ed43b 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2039,14 +2039,12 @@ static void pl330_tasklet(unsigned long data)
}
while (!list_empty(&pch->completed_list)) {
- dma_async_tx_callback callback;
- void *callback_param;
+ struct dmaengine_desc_callback cb;
desc = list_first_entry(&pch->completed_list,
struct dma_pl330_desc, node);
- callback = desc->txd.callback;
- callback_param = desc->txd.callback_param;
+ dmaengine_desc_get_callback(&desc->txd, &cb);
if (pch->cyclic) {
desc->status = PREP;
@@ -2064,9 +2062,9 @@ static void pl330_tasklet(unsigned long data)
dma_descriptor_unmap(&desc->txd);
- if (callback) {
+ if (dmaengine_desc_callback_valid(&cb)) {
spin_unlock_irqrestore(&pch->lock, flags);
- callback(callback_param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock_irqsave(&pch->lock, flags);
}
}
@@ -2274,7 +2272,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
{
enum dma_status ret;
unsigned long flags;
- struct dma_pl330_desc *desc, *running = NULL;
+ struct dma_pl330_desc *desc, *running = NULL, *last_enq = NULL;
struct dma_pl330_chan *pch = to_pchan(chan);
unsigned int transferred, residual = 0;
@@ -2287,10 +2285,13 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
goto out;
spin_lock_irqsave(&pch->lock, flags);
+ spin_lock(&pch->thread->dmac->lock);
if (pch->thread->req_running != -1)
running = pch->thread->req[pch->thread->req_running].desc;
+ last_enq = pch->thread->req[pch->thread->lstenq].desc;
+
/* Check in pending list */
list_for_each_entry(desc, &pch->work_list, node) {
if (desc->status == DONE)
@@ -2298,6 +2299,15 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
else if (running && desc == running)
transferred =
pl330_get_current_xferred_count(pch, desc);
+ else if (desc->status == BUSY)
+ /*
+ * Busy but not running means either just enqueued,
+ * or finished and not yet marked done
+ */
+ if (desc == last_enq)
+ transferred = 0;
+ else
+ transferred = desc->bytes_requested;
else
transferred = 0;
residual += desc->bytes_requested - transferred;
@@ -2318,6 +2328,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
if (desc->last)
residual = 0;
}
+ spin_unlock(&pch->thread->dmac->lock);
spin_unlock_irqrestore(&pch->lock, flags);
out:
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index da3688b94bdc..b1535b1fe95c 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -1482,14 +1482,11 @@ static dma_cookie_t ppc440spe_adma_run_tx_complete_actions(
cookie = desc->async_tx.cookie;
desc->async_tx.cookie = 0;
+ dma_descriptor_unmap(&desc->async_tx);
/* call the callback (must not sleep or submit new
* operations to this channel)
*/
- if (desc->async_tx.callback)
- desc->async_tx.callback(
- desc->async_tx.callback_param);
-
- dma_descriptor_unmap(&desc->async_tx);
+ dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
}
/* run dependent operations */
@@ -3891,7 +3888,7 @@ static int ppc440spe_adma_setup_irqs(struct ppc440spe_adma_device *adev,
np = ofdev->dev.of_node;
if (adev->id != PPC440SPE_XOR_ID) {
adev->err_irq = irq_of_parse_and_map(np, 1);
- if (adev->err_irq == NO_IRQ) {
+ if (!adev->err_irq) {
dev_warn(adev->dev, "no err irq resource?\n");
*initcode = PPC_ADMA_INIT_IRQ2;
adev->err_irq = -ENXIO;
@@ -3902,7 +3899,7 @@ static int ppc440spe_adma_setup_irqs(struct ppc440spe_adma_device *adev,
}
adev->irq = irq_of_parse_and_map(np, 0);
- if (adev->irq == NO_IRQ) {
+ if (!adev->irq) {
dev_err(adev->dev, "no irq resource\n");
*initcode = PPC_ADMA_INIT_IRQ1;
ret = -ENXIO;
diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c
index b2374cd91e45..e244e10a94b5 100644
--- a/drivers/dma/qcom/hidma.c
+++ b/drivers/dma/qcom/hidma.c
@@ -111,6 +111,7 @@ static void hidma_process_completed(struct hidma_chan *mchan)
struct dma_async_tx_descriptor *desc;
dma_cookie_t last_cookie;
struct hidma_desc *mdesc;
+ struct hidma_desc *next;
unsigned long irqflags;
struct list_head list;
@@ -122,28 +123,36 @@ static void hidma_process_completed(struct hidma_chan *mchan)
spin_unlock_irqrestore(&mchan->lock, irqflags);
/* Execute callbacks and run dependencies */
- list_for_each_entry(mdesc, &list, node) {
+ list_for_each_entry_safe(mdesc, next, &list, node) {
enum dma_status llstat;
+ struct dmaengine_desc_callback cb;
+ struct dmaengine_result result;
desc = &mdesc->desc;
+ last_cookie = desc->cookie;
spin_lock_irqsave(&mchan->lock, irqflags);
dma_cookie_complete(desc);
spin_unlock_irqrestore(&mchan->lock, irqflags);
llstat = hidma_ll_status(mdma->lldev, mdesc->tre_ch);
- if (desc->callback && (llstat == DMA_COMPLETE))
- desc->callback(desc->callback_param);
+ dmaengine_desc_get_callback(desc, &cb);
- last_cookie = desc->cookie;
dma_run_dependencies(desc);
- }
- /* Free descriptors */
- spin_lock_irqsave(&mchan->lock, irqflags);
- list_splice_tail_init(&list, &mchan->free);
- spin_unlock_irqrestore(&mchan->lock, irqflags);
+ spin_lock_irqsave(&mchan->lock, irqflags);
+ list_move(&mdesc->node, &mchan->free);
+
+ if (llstat == DMA_COMPLETE) {
+ mchan->last_success = last_cookie;
+ result.result = DMA_TRANS_NOERROR;
+ } else
+ result.result = DMA_TRANS_ABORTED;
+
+ spin_unlock_irqrestore(&mchan->lock, irqflags);
+ dmaengine_desc_callback_invoke(&cb, &result);
+ }
}
/*
@@ -238,6 +247,19 @@ static void hidma_issue_pending(struct dma_chan *dmach)
hidma_ll_start(dmadev->lldev);
}
+static inline bool hidma_txn_is_success(dma_cookie_t cookie,
+ dma_cookie_t last_success, dma_cookie_t last_used)
+{
+ if (last_success <= last_used) {
+ if ((cookie <= last_success) || (cookie > last_used))
+ return true;
+ } else {
+ if ((cookie <= last_success) && (cookie > last_used))
+ return true;
+ }
+ return false;
+}
+
static enum dma_status hidma_tx_status(struct dma_chan *dmach,
dma_cookie_t cookie,
struct dma_tx_state *txstate)
@@ -246,8 +268,13 @@ static enum dma_status hidma_tx_status(struct dma_chan *dmach,
enum dma_status ret;
ret = dma_cookie_status(dmach, cookie, txstate);
- if (ret == DMA_COMPLETE)
- return ret;
+ if (ret == DMA_COMPLETE) {
+ bool is_success;
+
+ is_success = hidma_txn_is_success(cookie, mchan->last_success,
+ dmach->cookie);
+ return is_success ? ret : DMA_ERROR;
+ }
if (mchan->paused && (ret == DMA_IN_PROGRESS)) {
unsigned long flags;
@@ -398,6 +425,7 @@ static int hidma_terminate_channel(struct dma_chan *chan)
hidma_process_completed(mchan);
spin_lock_irqsave(&mchan->lock, irqflags);
+ mchan->last_success = 0;
list_splice_init(&mchan->active, &list);
list_splice_init(&mchan->prepared, &list);
list_splice_init(&mchan->completed, &list);
@@ -413,14 +441,9 @@ static int hidma_terminate_channel(struct dma_chan *chan)
/* return all user requests */
list_for_each_entry_safe(mdesc, tmp, &list, node) {
struct dma_async_tx_descriptor *txd = &mdesc->desc;
- dma_async_tx_callback callback = mdesc->desc.callback;
- void *param = mdesc->desc.callback_param;
dma_descriptor_unmap(txd);
-
- if (callback)
- callback(param);
-
+ dmaengine_desc_get_callback_invoke(txd, NULL);
dma_run_dependencies(txd);
/* move myself to free_list */
diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h
index db413a5efc4e..e52e20716303 100644
--- a/drivers/dma/qcom/hidma.h
+++ b/drivers/dma/qcom/hidma.h
@@ -72,7 +72,6 @@ struct hidma_lldev {
u32 tre_write_offset; /* TRE write location */
struct tasklet_struct task; /* task delivering notifications */
- struct tasklet_struct rst_task; /* task to reset HW */
DECLARE_KFIFO_PTR(handoff_fifo,
struct hidma_tre *); /* pending TREs FIFO */
};
@@ -89,6 +88,7 @@ struct hidma_chan {
bool allocated;
char dbg_name[16];
u32 dma_sig;
+ dma_cookie_t last_success;
/*
* active descriptor on this channel
diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c
index ad20dfb64c71..3224f24c577b 100644
--- a/drivers/dma/qcom/hidma_ll.c
+++ b/drivers/dma/qcom/hidma_ll.c
@@ -381,27 +381,6 @@ static int hidma_ll_reset(struct hidma_lldev *lldev)
}
/*
- * Abort all transactions and perform a reset.
- */
-static void hidma_ll_abort(unsigned long arg)
-{
- struct hidma_lldev *lldev = (struct hidma_lldev *)arg;
- u8 err_code = HIDMA_EVRE_STATUS_ERROR;
- u8 err_info = 0xFF;
- int rc;
-
- hidma_cleanup_pending_tre(lldev, err_info, err_code);
-
- /* reset the channel for recovery */
- rc = hidma_ll_setup(lldev);
- if (rc) {
- dev_err(lldev->dev, "channel reinitialize failed after error\n");
- return;
- }
- writel(ENABLE_IRQS, lldev->evca + HIDMA_EVCA_IRQ_EN_REG);
-}
-
-/*
* The interrupt handler for HIDMA will try to consume as many pending
* EVRE from the event queue as possible. Each EVRE has an associated
* TRE that holds the user interface parameters. EVRE reports the
@@ -454,13 +433,18 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg)
while (cause) {
if (cause & HIDMA_ERR_INT_MASK) {
- dev_err(lldev->dev, "error 0x%x, resetting...\n",
+ dev_err(lldev->dev, "error 0x%x, disabling...\n",
cause);
/* Clear out pending interrupts */
writel(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG);
- tasklet_schedule(&lldev->rst_task);
+ /* No further submissions. */
+ hidma_ll_disable(lldev);
+
+ /* Driver completes the txn and intimates the client.*/
+ hidma_cleanup_pending_tre(lldev, 0xFF,
+ HIDMA_EVRE_STATUS_ERROR);
goto out;
}
@@ -808,7 +792,6 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres,
return NULL;
spin_lock_init(&lldev->lock);
- tasklet_init(&lldev->rst_task, hidma_ll_abort, (unsigned long)lldev);
tasklet_init(&lldev->task, hidma_ll_tre_complete, (unsigned long)lldev);
lldev->initialized = 1;
writel(ENABLE_IRQS, lldev->evca + HIDMA_EVCA_IRQ_EN_REG);
@@ -831,7 +814,6 @@ int hidma_ll_uninit(struct hidma_lldev *lldev)
required_bytes = sizeof(struct hidma_tre) * lldev->nr_tres;
tasklet_kill(&lldev->task);
- tasklet_kill(&lldev->rst_task);
memset(lldev->trepool, 0, required_bytes);
lldev->trepool = NULL;
lldev->pending_tre_count = 0;
diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c
index ce67075589f5..3c579abbabb7 100644
--- a/drivers/dma/s3c24xx-dma.c
+++ b/drivers/dma/s3c24xx-dma.c
@@ -823,11 +823,11 @@ static struct dma_async_tx_descriptor *s3c24xx_dma_prep_memcpy(
struct s3c24xx_sg *dsg;
int src_mod, dest_mod;
- dev_dbg(&s3cdma->pdev->dev, "prepare memcpy of %d bytes from %s\n",
+ dev_dbg(&s3cdma->pdev->dev, "prepare memcpy of %zu bytes from %s\n",
len, s3cchan->name);
if ((len & S3C24XX_DCON_TC_MASK) != len) {
- dev_err(&s3cdma->pdev->dev, "memcpy size %d to large\n", len);
+ dev_err(&s3cdma->pdev->dev, "memcpy size %zu to large\n", len);
return NULL;
}
@@ -1301,6 +1301,9 @@ static int s3c24xx_dma_probe(struct platform_device *pdev)
s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic;
s3cdma->slave.device_config = s3c24xx_dma_set_runtime_config;
s3cdma->slave.device_terminate_all = s3c24xx_dma_terminate_all;
+ s3cdma->slave.filter.map = pdata->slave_map;
+ s3cdma->slave.filter.mapcnt = pdata->slavecnt;
+ s3cdma->slave.filter.fn = s3c24xx_dma_filter;
/* Register as many memcpy channels as there are physical channels */
ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->memcpy,
@@ -1418,7 +1421,7 @@ bool s3c24xx_dma_filter(struct dma_chan *chan, void *param)
s3cchan = to_s3c24xx_dma_chan(chan);
- return s3cchan->id == (int)param;
+ return s3cchan->id == (uintptr_t)param;
}
EXPORT_SYMBOL(s3c24xx_dma_filter);
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index 43db255050d2..1adeb3265085 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -463,7 +463,7 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
dma_addr_t addr = sa11x0_dma_pos(p);
unsigned i;
- dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
+ dev_vdbg(d->slave.dev, "tx_status: addr:%pad\n", &addr);
for (i = 0; i < txd->sglen; i++) {
dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
@@ -491,7 +491,7 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
}
spin_unlock_irqrestore(&c->vc.lock, flags);
- dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", state->residue);
+ dev_vdbg(d->slave.dev, "tx_status: bytes 0x%x\n", state->residue);
return ret;
}
@@ -551,8 +551,8 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
if (len > DMA_MAX_SIZE)
j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
if (addr & DMA_ALIGN) {
- dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
- &c->vc, addr);
+ dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %pad\n",
+ &c->vc, &addr);
return NULL;
}
}
@@ -599,7 +599,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
txd->size = size;
txd->sglen = j;
- dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
+ dev_dbg(chan->device->dev, "vchan %p: txd %p: size %zu nr %u\n",
&c->vc, &txd->vd, txd->size, txd->sglen);
return vchan_tx_prep(&c->vc, &txd->vd, flags);
@@ -693,8 +693,8 @@ static int sa11x0_dma_device_config(struct dma_chan *chan,
if (maxburst == 8)
ddar |= DDAR_BS;
- dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
- &c->vc, addr, width, maxburst);
+ dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %pad width %u burst %u\n",
+ &c->vc, &addr, width, maxburst);
c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 0dd953884d1d..2e441d0ccd79 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -118,14 +118,34 @@ struct rcar_dmac_desc_page {
sizeof(struct rcar_dmac_xfer_chunk))
/*
+ * struct rcar_dmac_chan_slave - Slave configuration
+ * @slave_addr: slave memory address
+ * @xfer_size: size (in bytes) of hardware transfers
+ */
+struct rcar_dmac_chan_slave {
+ phys_addr_t slave_addr;
+ unsigned int xfer_size;
+};
+
+/*
+ * struct rcar_dmac_chan_map - Map of slave device phys to dma address
+ * @addr: slave dma address
+ * @dir: direction of mapping
+ * @slave: slave configuration that is mapped
+ */
+struct rcar_dmac_chan_map {
+ dma_addr_t addr;
+ enum dma_data_direction dir;
+ struct rcar_dmac_chan_slave slave;
+};
+
+/*
* struct rcar_dmac_chan - R-Car Gen2 DMA Controller Channel
* @chan: base DMA channel object
* @iomem: channel I/O memory base
* @index: index of this channel in the controller
- * @src_xfer_size: size (in bytes) of hardware transfers on the source side
- * @dst_xfer_size: size (in bytes) of hardware transfers on the destination side
- * @src_slave_addr: slave source memory address
- * @dst_slave_addr: slave destination memory address
+ * @src: slave memory address and size on the source side
+ * @dst: slave memory address and size on the destination side
* @mid_rid: hardware MID/RID for the DMA client using this channel
* @lock: protects the channel CHCR register and the desc members
* @desc.free: list of free descriptors
@@ -142,10 +162,9 @@ struct rcar_dmac_chan {
void __iomem *iomem;
unsigned int index;
- unsigned int src_xfer_size;
- unsigned int dst_xfer_size;
- dma_addr_t src_slave_addr;
- dma_addr_t dst_slave_addr;
+ struct rcar_dmac_chan_slave src;
+ struct rcar_dmac_chan_slave dst;
+ struct rcar_dmac_chan_map map;
int mid_rid;
spinlock_t lock;
@@ -793,13 +812,13 @@ static void rcar_dmac_chan_configure_desc(struct rcar_dmac_chan *chan,
case DMA_DEV_TO_MEM:
chcr = RCAR_DMACHCR_DM_INC | RCAR_DMACHCR_SM_FIXED
| RCAR_DMACHCR_RS_DMARS;
- xfer_size = chan->src_xfer_size;
+ xfer_size = chan->src.xfer_size;
break;
case DMA_MEM_TO_DEV:
chcr = RCAR_DMACHCR_DM_FIXED | RCAR_DMACHCR_SM_INC
| RCAR_DMACHCR_RS_DMARS;
- xfer_size = chan->dst_xfer_size;
+ xfer_size = chan->dst.xfer_size;
break;
case DMA_MEM_TO_MEM:
@@ -1023,13 +1042,65 @@ rcar_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
DMA_MEM_TO_MEM, flags, false);
}
+static int rcar_dmac_map_slave_addr(struct dma_chan *chan,
+ enum dma_transfer_direction dir)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ struct rcar_dmac_chan_map *map = &rchan->map;
+ phys_addr_t dev_addr;
+ size_t dev_size;
+ enum dma_data_direction dev_dir;
+
+ if (dir == DMA_DEV_TO_MEM) {
+ dev_addr = rchan->src.slave_addr;
+ dev_size = rchan->src.xfer_size;
+ dev_dir = DMA_TO_DEVICE;
+ } else {
+ dev_addr = rchan->dst.slave_addr;
+ dev_size = rchan->dst.xfer_size;
+ dev_dir = DMA_FROM_DEVICE;
+ }
+
+ /* Reuse current map if possible. */
+ if (dev_addr == map->slave.slave_addr &&
+ dev_size == map->slave.xfer_size &&
+ dev_dir == map->dir)
+ return 0;
+
+ /* Remove old mapping if present. */
+ if (map->slave.xfer_size)
+ dma_unmap_resource(chan->device->dev, map->addr,
+ map->slave.xfer_size, map->dir, 0);
+ map->slave.xfer_size = 0;
+
+ /* Create new slave address map. */
+ map->addr = dma_map_resource(chan->device->dev, dev_addr, dev_size,
+ dev_dir, 0);
+
+ if (dma_mapping_error(chan->device->dev, map->addr)) {
+ dev_err(chan->device->dev,
+ "chan%u: failed to map %zx@%pap", rchan->index,
+ dev_size, &dev_addr);
+ return -EIO;
+ }
+
+ dev_dbg(chan->device->dev, "chan%u: map %zx@%pap to %pad dir: %s\n",
+ rchan->index, dev_size, &dev_addr, &map->addr,
+ dev_dir == DMA_TO_DEVICE ? "DMA_TO_DEVICE" : "DMA_FROM_DEVICE");
+
+ map->slave.slave_addr = dev_addr;
+ map->slave.xfer_size = dev_size;
+ map->dir = dev_dir;
+
+ return 0;
+}
+
static struct dma_async_tx_descriptor *
rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction dir,
unsigned long flags, void *context)
{
struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
- dma_addr_t dev_addr;
/* Someone calling slave DMA on a generic channel? */
if (rchan->mid_rid < 0 || !sg_len) {
@@ -1039,9 +1110,10 @@ rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return NULL;
}
- dev_addr = dir == DMA_DEV_TO_MEM
- ? rchan->src_slave_addr : rchan->dst_slave_addr;
- return rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, dev_addr,
+ if (rcar_dmac_map_slave_addr(chan, dir))
+ return NULL;
+
+ return rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, rchan->map.addr,
dir, flags, false);
}
@@ -1055,7 +1127,6 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
struct dma_async_tx_descriptor *desc;
struct scatterlist *sgl;
- dma_addr_t dev_addr;
unsigned int sg_len;
unsigned int i;
@@ -1067,6 +1138,9 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
return NULL;
}
+ if (rcar_dmac_map_slave_addr(chan, dir))
+ return NULL;
+
sg_len = buf_len / period_len;
if (sg_len > RCAR_DMAC_MAX_SG_LEN) {
dev_err(chan->device->dev,
@@ -1094,9 +1168,7 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
sg_dma_len(&sgl[i]) = period_len;
}
- dev_addr = dir == DMA_DEV_TO_MEM
- ? rchan->src_slave_addr : rchan->dst_slave_addr;
- desc = rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, dev_addr,
+ desc = rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, rchan->map.addr,
dir, flags, true);
kfree(sgl);
@@ -1112,10 +1184,10 @@ static int rcar_dmac_device_config(struct dma_chan *chan,
* We could lock this, but you shouldn't be configuring the
* channel, while using it...
*/
- rchan->src_slave_addr = cfg->src_addr;
- rchan->dst_slave_addr = cfg->dst_addr;
- rchan->src_xfer_size = cfg->src_addr_width;
- rchan->dst_xfer_size = cfg->dst_addr_width;
+ rchan->src.slave_addr = cfg->src_addr;
+ rchan->dst.slave_addr = cfg->dst_addr;
+ rchan->src.xfer_size = cfg->src_addr_width;
+ rchan->dst.xfer_size = cfg->dst_addr_width;
return 0;
}
@@ -1389,21 +1461,18 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev)
{
struct rcar_dmac_chan *chan = dev;
struct rcar_dmac_desc *desc;
+ struct dmaengine_desc_callback cb;
spin_lock_irq(&chan->lock);
/* For cyclic transfers notify the user after every chunk. */
if (chan->desc.running && chan->desc.running->cyclic) {
- dma_async_tx_callback callback;
- void *callback_param;
-
desc = chan->desc.running;
- callback = desc->async_tx.callback;
- callback_param = desc->async_tx.callback_param;
+ dmaengine_desc_get_callback(&desc->async_tx, &cb);
- if (callback) {
+ if (dmaengine_desc_callback_valid(&cb)) {
spin_unlock_irq(&chan->lock);
- callback(callback_param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock_irq(&chan->lock);
}
}
@@ -1418,14 +1487,15 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev)
dma_cookie_complete(&desc->async_tx);
list_del(&desc->node);
- if (desc->async_tx.callback) {
+ dmaengine_desc_get_callback(&desc->async_tx, &cb);
+ if (dmaengine_desc_callback_valid(&cb)) {
spin_unlock_irq(&chan->lock);
/*
* We own the only reference to this descriptor, we can
* safely dereference it without holding the channel
* lock.
*/
- desc->async_tx.callback(desc->async_tx.callback_param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock_irq(&chan->lock);
}
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 10fcabad80f3..12fa48e380cf 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -330,10 +330,11 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
bool head_acked = false;
dma_cookie_t cookie = 0;
dma_async_tx_callback callback = NULL;
- void *param = NULL;
+ struct dmaengine_desc_callback cb;
unsigned long flags;
LIST_HEAD(cyclic_list);
+ memset(&cb, 0, sizeof(cb));
spin_lock_irqsave(&schan->chan_lock, flags);
list_for_each_entry_safe(desc, _desc, &schan->ld_queue, node) {
struct dma_async_tx_descriptor *tx = &desc->async_tx;
@@ -367,8 +368,8 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
/* Call callback on the last chunk */
if (desc->mark == DESC_COMPLETED && tx->callback) {
desc->mark = DESC_WAITING;
+ dmaengine_desc_get_callback(tx, &cb);
callback = tx->callback;
- param = tx->callback_param;
dev_dbg(schan->dev, "descriptor #%d@%p on %d callback\n",
tx->cookie, tx, schan->id);
BUG_ON(desc->chunks != 1);
@@ -430,8 +431,7 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
spin_unlock_irqrestore(&schan->chan_lock, flags);
- if (callback)
- callback(param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
return callback;
}
@@ -885,9 +885,9 @@ bool shdma_reset(struct shdma_dev *sdev)
/* Complete all */
list_for_each_entry(sdesc, &dl, node) {
struct dma_async_tx_descriptor *tx = &sdesc->async_tx;
+
sdesc->mark = DESC_IDLE;
- if (tx->callback)
- tx->callback(tx->callback_param);
+ dmaengine_desc_get_callback_invoke(tx, NULL);
}
spin_lock(&schan->chan_lock);
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index d8bc3f2a71db..8f62edad51be 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -360,9 +360,7 @@ static void sirfsoc_dma_process_completed(struct sirfsoc_dma *sdma)
list_for_each_entry(sdesc, &list, node) {
desc = &sdesc->desc;
- if (desc->callback)
- desc->callback(desc->callback_param);
-
+ dmaengine_desc_get_callback_invoke(desc, NULL);
last_cookie = desc->cookie;
dma_run_dependencies(desc);
}
@@ -388,8 +386,7 @@ static void sirfsoc_dma_process_completed(struct sirfsoc_dma *sdma)
desc = &sdesc->desc;
while (happened_cyclic != schan->completed_cyclic) {
- if (desc->callback)
- desc->callback(desc->callback_param);
+ dmaengine_desc_get_callback_invoke(desc, NULL);
schan->completed_cyclic++;
}
}
@@ -869,7 +866,7 @@ static int sirfsoc_dma_probe(struct platform_device *op)
}
sdma->irq = irq_of_parse_and_map(dn, 0);
- if (sdma->irq == NO_IRQ) {
+ if (!sdma->irq) {
dev_err(dev, "Error mapping IRQ!\n");
return -EINVAL;
}
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 8b18e44a02d5..8684d11b29bb 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -874,7 +874,7 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc)
}
if (curr_lcla < 0)
- goto out;
+ goto set_current;
for (; lli_current < lli_len; lli_current++) {
unsigned int lcla_offset = chan->phy_chan->num * 1024 +
@@ -925,8 +925,7 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc)
break;
}
}
-
-out:
+ set_current:
desc->lli_current = lli_current;
}
@@ -941,15 +940,7 @@ static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
{
- struct d40_desc *d;
-
- if (list_empty(&d40c->active))
- return NULL;
-
- d = list_first_entry(&d40c->active,
- struct d40_desc,
- node);
- return d;
+ return list_first_entry_or_null(&d40c->active, struct d40_desc, node);
}
/* remove desc from current queue and add it to the pending_queue */
@@ -962,36 +953,18 @@ static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
static struct d40_desc *d40_first_pending(struct d40_chan *d40c)
{
- struct d40_desc *d;
-
- if (list_empty(&d40c->pending_queue))
- return NULL;
-
- d = list_first_entry(&d40c->pending_queue,
- struct d40_desc,
- node);
- return d;
+ return list_first_entry_or_null(&d40c->pending_queue, struct d40_desc,
+ node);
}
static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
{
- struct d40_desc *d;
-
- if (list_empty(&d40c->queue))
- return NULL;
-
- d = list_first_entry(&d40c->queue,
- struct d40_desc,
- node);
- return d;
+ return list_first_entry_or_null(&d40c->queue, struct d40_desc, node);
}
static struct d40_desc *d40_first_done(struct d40_chan *d40c)
{
- if (list_empty(&d40c->done))
- return NULL;
-
- return list_first_entry(&d40c->done, struct d40_desc, node);
+ return list_first_entry_or_null(&d40c->done, struct d40_desc, node);
}
static int d40_psize_2_burst_size(bool is_log, int psize)
@@ -1083,7 +1056,7 @@ static int __d40_execute_command_phy(struct d40_chan *d40c,
D40_CHAN_POS(d40c->phy_chan->num);
if (status == D40_DMA_SUSPENDED || status == D40_DMA_STOP)
- goto done;
+ goto unlock;
}
wmask = 0xffffffff & ~(D40_CHAN_POS_MASK(d40c->phy_chan->num));
@@ -1119,7 +1092,7 @@ static int __d40_execute_command_phy(struct d40_chan *d40c,
}
}
-done:
+ unlock:
spin_unlock_irqrestore(&d40c->base->execmd_lock, flags);
return ret;
}
@@ -1596,8 +1569,7 @@ static void dma_tasklet(unsigned long data)
struct d40_desc *d40d;
unsigned long flags;
bool callback_active;
- dma_async_tx_callback callback;
- void *callback_param;
+ struct dmaengine_desc_callback cb;
spin_lock_irqsave(&d40c->lock, flags);
@@ -1607,7 +1579,7 @@ static void dma_tasklet(unsigned long data)
/* Check if we have reached here for cyclic job */
d40d = d40_first_active_get(d40c);
if (d40d == NULL || !d40d->cyclic)
- goto err;
+ goto check_pending_tx;
}
if (!d40d->cyclic)
@@ -1624,8 +1596,7 @@ static void dma_tasklet(unsigned long data)
/* Callback to client */
callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT);
- callback = d40d->txd.callback;
- callback_param = d40d->txd.callback_param;
+ dmaengine_desc_get_callback(&d40d->txd, &cb);
if (!d40d->cyclic) {
if (async_tx_test_ack(&d40d->txd)) {
@@ -1646,12 +1617,11 @@ static void dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&d40c->lock, flags);
- if (callback_active && callback)
- callback(callback_param);
+ if (callback_active)
+ dmaengine_desc_callback_invoke(&cb, NULL);
return;
-
-err:
+ check_pending_tx:
/* Rescue manouver if receiving double interrupts */
if (d40c->pending_tx > 0)
d40c->pending_tx--;
@@ -1780,42 +1750,40 @@ static bool d40_alloc_mask_set(struct d40_phy_res *phy,
phy->allocated_dst == D40_ALLOC_FREE) {
phy->allocated_dst = D40_ALLOC_PHY;
phy->allocated_src = D40_ALLOC_PHY;
- goto found;
+ goto found_unlock;
} else
- goto not_found;
+ goto not_found_unlock;
}
/* Logical channel */
if (is_src) {
if (phy->allocated_src == D40_ALLOC_PHY)
- goto not_found;
+ goto not_found_unlock;
if (phy->allocated_src == D40_ALLOC_FREE)
phy->allocated_src = D40_ALLOC_LOG_FREE;
if (!(phy->allocated_src & BIT(log_event_line))) {
phy->allocated_src |= BIT(log_event_line);
- goto found;
+ goto found_unlock;
} else
- goto not_found;
+ goto not_found_unlock;
} else {
if (phy->allocated_dst == D40_ALLOC_PHY)
- goto not_found;
+ goto not_found_unlock;
if (phy->allocated_dst == D40_ALLOC_FREE)
phy->allocated_dst = D40_ALLOC_LOG_FREE;
if (!(phy->allocated_dst & BIT(log_event_line))) {
phy->allocated_dst |= BIT(log_event_line);
- goto found;
- } else
- goto not_found;
+ goto found_unlock;
+ }
}
-
-not_found:
+ not_found_unlock:
spin_unlock_irqrestore(&phy->lock, flags);
return false;
-found:
+ found_unlock:
spin_unlock_irqrestore(&phy->lock, flags);
return true;
}
@@ -1831,7 +1799,7 @@ static bool d40_alloc_mask_free(struct d40_phy_res *phy, bool is_src,
phy->allocated_dst = D40_ALLOC_FREE;
phy->allocated_src = D40_ALLOC_FREE;
is_free = true;
- goto out;
+ goto unlock;
}
/* Logical channel */
@@ -1847,8 +1815,7 @@ static bool d40_alloc_mask_free(struct d40_phy_res *phy, bool is_src,
is_free = ((phy->allocated_src | phy->allocated_dst) ==
D40_ALLOC_FREE);
-
-out:
+ unlock:
spin_unlock_irqrestore(&phy->lock, flags);
return is_free;
@@ -2047,7 +2014,7 @@ static int d40_free_dma(struct d40_chan *d40c)
res = d40_channel_execute_command(d40c, D40_DMA_STOP);
if (res) {
chan_err(d40c, "stop failed\n");
- goto out;
+ goto mark_last_busy;
}
d40_alloc_mask_free(phy, is_src, chan_is_logical(d40c) ? event : 0);
@@ -2065,8 +2032,7 @@ static int d40_free_dma(struct d40_chan *d40c)
d40c->busy = false;
d40c->phy_chan = NULL;
d40c->configured = false;
-out:
-
+ mark_last_busy:
pm_runtime_mark_last_busy(d40c->base->dev);
pm_runtime_put_autosuspend(d40c->base->dev);
return res;
@@ -2094,8 +2060,7 @@ static bool d40_is_paused(struct d40_chan *d40c)
D40_CHAN_POS(d40c->phy_chan->num);
if (status == D40_DMA_SUSPENDED || status == D40_DMA_STOP)
is_paused = true;
-
- goto _exit;
+ goto unlock;
}
if (d40c->dma_cfg.dir == DMA_MEM_TO_DEV ||
@@ -2105,7 +2070,7 @@ static bool d40_is_paused(struct d40_chan *d40c)
status = readl(chanbase + D40_CHAN_REG_SSLNK);
} else {
chan_err(d40c, "Unknown direction\n");
- goto _exit;
+ goto unlock;
}
status = (status & D40_EVENTLINE_MASK(event)) >>
@@ -2113,7 +2078,7 @@ static bool d40_is_paused(struct d40_chan *d40c)
if (status != D40_DMA_RUN)
is_paused = true;
-_exit:
+ unlock:
spin_unlock_irqrestore(&d40c->lock, flags);
return is_paused;
@@ -2198,7 +2163,7 @@ static struct d40_desc *
d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg,
unsigned int sg_len, unsigned long dma_flags)
{
- struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
+ struct stedma40_chan_cfg *cfg;
struct d40_desc *desc;
int ret;
@@ -2206,17 +2171,18 @@ d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg,
if (!desc)
return NULL;
+ cfg = &chan->dma_cfg;
desc->lli_len = d40_sg_2_dmalen(sg, sg_len, cfg->src_info.data_width,
cfg->dst_info.data_width);
if (desc->lli_len < 0) {
chan_err(chan, "Unaligned size\n");
- goto err;
+ goto free_desc;
}
ret = d40_pool_lli_alloc(chan, desc, desc->lli_len);
if (ret < 0) {
chan_err(chan, "Could not allocate lli\n");
- goto err;
+ goto free_desc;
}
desc->lli_current = 0;
@@ -2226,8 +2192,7 @@ d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg,
dma_async_tx_descriptor_init(&desc->txd, &chan->chan);
return desc;
-
-err:
+ free_desc:
d40_desc_free(chan, desc);
return NULL;
}
@@ -2238,8 +2203,8 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
enum dma_transfer_direction direction, unsigned long dma_flags)
{
struct d40_chan *chan = container_of(dchan, struct d40_chan, chan);
- dma_addr_t src_dev_addr = 0;
- dma_addr_t dst_dev_addr = 0;
+ dma_addr_t src_dev_addr;
+ dma_addr_t dst_dev_addr;
struct d40_desc *desc;
unsigned long flags;
int ret;
@@ -2253,11 +2218,13 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
desc = d40_prep_desc(chan, sg_src, sg_len, dma_flags);
if (desc == NULL)
- goto err;
+ goto unlock;
if (sg_next(&sg_src[sg_len - 1]) == sg_src)
desc->cyclic = true;
+ src_dev_addr = 0;
+ dst_dev_addr = 0;
if (direction == DMA_DEV_TO_MEM)
src_dev_addr = chan->runtime_addr;
else if (direction == DMA_MEM_TO_DEV)
@@ -2273,7 +2240,7 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
if (ret) {
chan_err(chan, "Failed to prepare %s sg job: %d\n",
chan_is_logical(chan) ? "log" : "phy", ret);
- goto err;
+ goto free_desc;
}
/*
@@ -2285,10 +2252,9 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
spin_unlock_irqrestore(&chan->lock, flags);
return &desc->txd;
-
-err:
- if (desc)
- d40_desc_free(chan, desc);
+ free_desc:
+ d40_desc_free(chan, desc);
+ unlock:
spin_unlock_irqrestore(&chan->lock, flags);
return NULL;
}
@@ -2426,7 +2392,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
err = d40_config_memcpy(d40c);
if (err) {
chan_err(d40c, "Failed to configure memcpy channel\n");
- goto fail;
+ goto mark_last_busy;
}
}
@@ -2434,7 +2400,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
if (err) {
chan_err(d40c, "Failed to allocate channel\n");
d40c->configured = false;
- goto fail;
+ goto mark_last_busy;
}
pm_runtime_get_sync(d40c->base->dev);
@@ -2468,7 +2434,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
*/
if (is_free_phy)
d40_config_write(d40c);
-fail:
+ mark_last_busy:
pm_runtime_mark_last_busy(d40c->base->dev);
pm_runtime_put_autosuspend(d40c->base->dev);
spin_unlock_irqrestore(&d40c->lock, flags);
@@ -2891,7 +2857,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
if (err) {
d40_err(base->dev, "Failed to register slave channels\n");
- goto failure1;
+ goto exit;
}
d40_chan_init(base, &base->dma_memcpy, base->log_chans,
@@ -2908,7 +2874,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
if (err) {
d40_err(base->dev,
"Failed to register memcpy only channels\n");
- goto failure2;
+ goto unregister_slave;
}
d40_chan_init(base, &base->dma_both, base->phy_chans,
@@ -2926,14 +2892,14 @@ static int __init d40_dmaengine_init(struct d40_base *base,
if (err) {
d40_err(base->dev,
"Failed to register logical and physical capable channels\n");
- goto failure3;
+ goto unregister_memcpy;
}
return 0;
-failure3:
+ unregister_memcpy:
dma_async_device_unregister(&base->dma_memcpy);
-failure2:
+ unregister_slave:
dma_async_device_unregister(&base->dma_slave);
-failure1:
+ exit:
return err;
}
@@ -3144,11 +3110,11 @@ static int __init d40_phy_res_init(struct d40_base *base)
static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
{
struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev);
- struct clk *clk = NULL;
- void __iomem *virtbase = NULL;
- struct resource *res = NULL;
- struct d40_base *base = NULL;
- int num_log_chans = 0;
+ struct clk *clk;
+ void __iomem *virtbase;
+ struct resource *res;
+ struct d40_base *base;
+ int num_log_chans;
int num_phy_chans;
int num_memcpy_chans;
int clk_ret = -EINVAL;
@@ -3160,27 +3126,27 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
d40_err(&pdev->dev, "No matching clock found\n");
- goto failure;
+ goto check_prepare_enabled;
}
clk_ret = clk_prepare_enable(clk);
if (clk_ret) {
d40_err(&pdev->dev, "Failed to prepare/enable clock\n");
- goto failure;
+ goto disable_unprepare;
}
/* Get IO for DMAC base address */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
if (!res)
- goto failure;
+ goto disable_unprepare;
if (request_mem_region(res->start, resource_size(res),
D40_NAME " I/O base") == NULL)
- goto failure;
+ goto release_region;
virtbase = ioremap(res->start, resource_size(res));
if (!virtbase)
- goto failure;
+ goto release_region;
/* This is just a regular AMBA PrimeCell ID actually */
for (pid = 0, i = 0; i < 4; i++)
@@ -3192,13 +3158,13 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
if (cid != AMBA_CID) {
d40_err(&pdev->dev, "Unknown hardware! No PrimeCell ID\n");
- goto failure;
+ goto unmap_io;
}
if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) {
d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n",
AMBA_MANF_BITS(pid),
AMBA_VENDOR_ST);
- goto failure;
+ goto unmap_io;
}
/*
* HW revision:
@@ -3212,7 +3178,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
rev = AMBA_REV_BITS(pid);
if (rev < 2) {
d40_err(&pdev->dev, "hardware revision: %d is not supported", rev);
- goto failure;
+ goto unmap_io;
}
/* The number of physical channels on this HW */
@@ -3238,7 +3204,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
sizeof(struct d40_chan), GFP_KERNEL);
if (base == NULL)
- goto failure;
+ goto unmap_io;
base->rev = rev;
base->clk = clk;
@@ -3283,65 +3249,66 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
base->gen_dmac.init_reg_size = ARRAY_SIZE(dma_init_reg_v4a);
}
- base->phy_res = kzalloc(num_phy_chans * sizeof(struct d40_phy_res),
+ base->phy_res = kcalloc(num_phy_chans,
+ sizeof(*base->phy_res),
GFP_KERNEL);
if (!base->phy_res)
- goto failure;
+ goto free_base;
- base->lookup_phy_chans = kzalloc(num_phy_chans *
- sizeof(struct d40_chan *),
+ base->lookup_phy_chans = kcalloc(num_phy_chans,
+ sizeof(*base->lookup_phy_chans),
GFP_KERNEL);
if (!base->lookup_phy_chans)
- goto failure;
+ goto free_phy_res;
- base->lookup_log_chans = kzalloc(num_log_chans *
- sizeof(struct d40_chan *),
+ base->lookup_log_chans = kcalloc(num_log_chans,
+ sizeof(*base->lookup_log_chans),
GFP_KERNEL);
if (!base->lookup_log_chans)
- goto failure;
+ goto free_phy_chans;
- base->reg_val_backup_chan = kmalloc(base->num_phy_chans *
- sizeof(d40_backup_regs_chan),
- GFP_KERNEL);
+ base->reg_val_backup_chan = kmalloc_array(base->num_phy_chans,
+ sizeof(d40_backup_regs_chan),
+ GFP_KERNEL);
if (!base->reg_val_backup_chan)
- goto failure;
+ goto free_log_chans;
- base->lcla_pool.alloc_map =
- kzalloc(num_phy_chans * sizeof(struct d40_desc *)
- * D40_LCLA_LINK_PER_EVENT_GRP, GFP_KERNEL);
+ base->lcla_pool.alloc_map = kcalloc(num_phy_chans
+ * D40_LCLA_LINK_PER_EVENT_GRP,
+ sizeof(*base->lcla_pool.alloc_map),
+ GFP_KERNEL);
if (!base->lcla_pool.alloc_map)
- goto failure;
+ goto free_backup_chan;
base->desc_slab = kmem_cache_create(D40_NAME, sizeof(struct d40_desc),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (base->desc_slab == NULL)
- goto failure;
+ goto free_map;
return base;
-
-failure:
+ free_map:
+ kfree(base->lcla_pool.alloc_map);
+ free_backup_chan:
+ kfree(base->reg_val_backup_chan);
+ free_log_chans:
+ kfree(base->lookup_log_chans);
+ free_phy_chans:
+ kfree(base->lookup_phy_chans);
+ free_phy_res:
+ kfree(base->phy_res);
+ free_base:
+ kfree(base);
+ unmap_io:
+ iounmap(virtbase);
+ release_region:
+ release_mem_region(res->start, resource_size(res));
+ check_prepare_enabled:
if (!clk_ret)
+ disable_unprepare:
clk_disable_unprepare(clk);
if (!IS_ERR(clk))
clk_put(clk);
- if (virtbase)
- iounmap(virtbase);
- if (res)
- release_mem_region(res->start,
- resource_size(res));
- if (virtbase)
- iounmap(virtbase);
-
- if (base) {
- kfree(base->lcla_pool.alloc_map);
- kfree(base->reg_val_backup_chan);
- kfree(base->lookup_log_chans);
- kfree(base->lookup_phy_chans);
- kfree(base->phy_res);
- kfree(base);
- }
-
return NULL;
}
@@ -3404,20 +3371,18 @@ static int __init d40_lcla_allocate(struct d40_base *base)
struct d40_lcla_pool *pool = &base->lcla_pool;
unsigned long *page_list;
int i, j;
- int ret = 0;
+ int ret;
/*
* This is somewhat ugly. We need 8192 bytes that are 18 bit aligned,
* To full fill this hardware requirement without wasting 256 kb
* we allocate pages until we get an aligned one.
*/
- page_list = kmalloc(sizeof(unsigned long) * MAX_LCLA_ALLOC_ATTEMPTS,
- GFP_KERNEL);
-
- if (!page_list) {
- ret = -ENOMEM;
- goto failure;
- }
+ page_list = kmalloc_array(MAX_LCLA_ALLOC_ATTEMPTS,
+ sizeof(*page_list),
+ GFP_KERNEL);
+ if (!page_list)
+ return -ENOMEM;
/* Calculating how many pages that are required */
base->lcla_pool.pages = SZ_1K * base->num_phy_chans / PAGE_SIZE;
@@ -3433,7 +3398,7 @@ static int __init d40_lcla_allocate(struct d40_base *base)
for (j = 0; j < i; j++)
free_pages(page_list[j], base->lcla_pool.pages);
- goto failure;
+ goto free_page_list;
}
if ((virt_to_phys((void *)page_list[i]) &
@@ -3460,7 +3425,7 @@ static int __init d40_lcla_allocate(struct d40_base *base)
GFP_KERNEL);
if (!base->lcla_pool.base_unaligned) {
ret = -ENOMEM;
- goto failure;
+ goto free_page_list;
}
base->lcla_pool.base = PTR_ALIGN(base->lcla_pool.base_unaligned,
@@ -3473,12 +3438,13 @@ static int __init d40_lcla_allocate(struct d40_base *base)
if (dma_mapping_error(base->dev, pool->dma_addr)) {
pool->dma_addr = 0;
ret = -ENOMEM;
- goto failure;
+ goto free_page_list;
}
writel(virt_to_phys(base->lcla_pool.base),
base->virtbase + D40_DREG_LCLA);
-failure:
+ ret = 0;
+ free_page_list:
kfree(page_list);
return ret;
}
@@ -3490,9 +3456,7 @@ static int __init d40_of_probe(struct platform_device *pdev,
int num_phy = 0, num_memcpy = 0, num_disabled = 0;
const __be32 *list;
- pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct stedma40_platform_data),
- GFP_KERNEL);
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -3574,7 +3538,7 @@ static int __init d40_probe(struct platform_device *pdev)
if (!res) {
ret = -ENOENT;
d40_err(&pdev->dev, "No \"lcpa\" memory resource\n");
- goto failure;
+ goto destroy_cache;
}
base->lcpa_size = resource_size(res);
base->phy_lcpa = res->start;
@@ -3583,7 +3547,7 @@ static int __init d40_probe(struct platform_device *pdev)
D40_NAME " I/O lcpa") == NULL) {
ret = -EBUSY;
d40_err(&pdev->dev, "Failed to request LCPA region %pR\n", res);
- goto failure;
+ goto destroy_cache;
}
/* We make use of ESRAM memory for this. */
@@ -3599,7 +3563,7 @@ static int __init d40_probe(struct platform_device *pdev)
if (!base->lcpa_base) {
ret = -ENOMEM;
d40_err(&pdev->dev, "Failed to ioremap LCPA region\n");
- goto failure;
+ goto destroy_cache;
}
/* If lcla has to be located in ESRAM we don't need to allocate */
if (base->plat_data->use_esram_lcla) {
@@ -3609,14 +3573,14 @@ static int __init d40_probe(struct platform_device *pdev)
ret = -ENOENT;
d40_err(&pdev->dev,
"No \"lcla_esram\" memory resource\n");
- goto failure;
+ goto destroy_cache;
}
base->lcla_pool.base = ioremap(res->start,
resource_size(res));
if (!base->lcla_pool.base) {
ret = -ENOMEM;
d40_err(&pdev->dev, "Failed to ioremap LCLA region\n");
- goto failure;
+ goto destroy_cache;
}
writel(res->start, base->virtbase + D40_DREG_LCLA);
@@ -3624,7 +3588,7 @@ static int __init d40_probe(struct platform_device *pdev)
ret = d40_lcla_allocate(base);
if (ret) {
d40_err(&pdev->dev, "Failed to allocate LCLA area\n");
- goto failure;
+ goto destroy_cache;
}
}
@@ -3635,7 +3599,7 @@ static int __init d40_probe(struct platform_device *pdev)
ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
if (ret) {
d40_err(&pdev->dev, "No IRQ defined\n");
- goto failure;
+ goto destroy_cache;
}
if (base->plat_data->use_esram_lcla) {
@@ -3645,7 +3609,7 @@ static int __init d40_probe(struct platform_device *pdev)
d40_err(&pdev->dev, "Failed to get lcpa_regulator\n");
ret = PTR_ERR(base->lcpa_regulator);
base->lcpa_regulator = NULL;
- goto failure;
+ goto destroy_cache;
}
ret = regulator_enable(base->lcpa_regulator);
@@ -3654,7 +3618,7 @@ static int __init d40_probe(struct platform_device *pdev)
"Failed to enable lcpa_regulator\n");
regulator_put(base->lcpa_regulator);
base->lcpa_regulator = NULL;
- goto failure;
+ goto destroy_cache;
}
}
@@ -3669,13 +3633,13 @@ static int __init d40_probe(struct platform_device *pdev)
ret = d40_dmaengine_init(base, num_reserved_chans);
if (ret)
- goto failure;
+ goto destroy_cache;
base->dev->dma_parms = &base->dma_parms;
ret = dma_set_max_seg_size(base->dev, STEDMA40_MAX_SEG_SIZE);
if (ret) {
d40_err(&pdev->dev, "Failed to set dma max seg size\n");
- goto failure;
+ goto destroy_cache;
}
d40_hw_init(base);
@@ -3689,8 +3653,7 @@ static int __init d40_probe(struct platform_device *pdev)
dev_info(base->dev, "initialized\n");
return 0;
-
-failure:
+ destroy_cache:
kmem_cache_destroy(base->desc_slab);
if (base->virtbase)
iounmap(base->virtbase);
@@ -3732,7 +3695,7 @@ failure:
kfree(base->lookup_phy_chans);
kfree(base->phy_res);
kfree(base);
-report_failure:
+ report_failure:
d40_err(&pdev->dev, "probe failed\n");
return ret;
}
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 047476a1383d..307547f4848d 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -954,7 +954,7 @@ static void stm32_dma_desc_free(struct virt_dma_desc *vdesc)
kfree(container_of(vdesc, struct stm32_dma_desc, vdesc));
}
-void stm32_dma_set_config(struct stm32_dma_chan *chan,
+static void stm32_dma_set_config(struct stm32_dma_chan *chan,
struct stm32_dma_cfg *cfg)
{
stm32_dma_clear_reg(&chan->chan_reg);
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 3835fcde3545..83461994e418 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -1011,6 +1011,12 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
.nr_max_vchans = 37,
};
+static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
+ .nr_max_channels = 8,
+ .nr_max_requests = 28,
+ .nr_max_vchans = 39,
+};
+
/*
* The H3 has 12 physical channels, a maximum DRQ port id of 27,
* and a total of 34 usable source and destination endpoints.
@@ -1025,6 +1031,7 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
static const struct of_device_id sun6i_dma_match[] = {
{ .compatible = "allwinner,sun6i-a31-dma", .data = &sun6i_a31_dma_cfg },
{ .compatible = "allwinner,sun8i-a23-dma", .data = &sun8i_a23_dma_cfg },
+ { .compatible = "allwinner,sun8i-a83t-dma", .data = &sun8i_a83t_dma_cfg },
{ .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
{ /* sentinel */ }
};
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 6ab9eb98588a..3722b9d8d9fe 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -655,8 +655,7 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
static void tegra_dma_tasklet(unsigned long data)
{
struct tegra_dma_channel *tdc = (struct tegra_dma_channel *)data;
- dma_async_tx_callback callback = NULL;
- void *callback_param = NULL;
+ struct dmaengine_desc_callback cb;
struct tegra_dma_desc *dma_desc;
unsigned long flags;
int cb_count;
@@ -666,13 +665,12 @@ static void tegra_dma_tasklet(unsigned long data)
dma_desc = list_first_entry(&tdc->cb_desc,
typeof(*dma_desc), cb_node);
list_del(&dma_desc->cb_node);
- callback = dma_desc->txd.callback;
- callback_param = dma_desc->txd.callback_param;
+ dmaengine_desc_get_callback(&dma_desc->txd, &cb);
cb_count = dma_desc->cb_count;
dma_desc->cb_count = 0;
spin_unlock_irqrestore(&tdc->lock, flags);
- while (cb_count-- && callback)
- callback(callback_param);
+ while (cb_count--)
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock_irqsave(&tdc->lock, flags);
}
spin_unlock_irqrestore(&tdc->lock, flags);
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index c4b121c4559d..b10cbaa82ff5 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -670,7 +670,6 @@ static int tegra_adma_probe(struct platform_device *pdev)
const struct tegra_adma_chip_data *cdata;
struct tegra_adma *tdma;
struct resource *res;
- struct clk *clk;
int ret, i;
cdata = of_device_get_match_data(&pdev->dev);
@@ -697,18 +696,9 @@ static int tegra_adma_probe(struct platform_device *pdev)
if (ret)
return ret;
- clk = clk_get(&pdev->dev, "d_audio");
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "ADMA clock not found\n");
- ret = PTR_ERR(clk);
- goto clk_destroy;
- }
-
- ret = pm_clk_add_clk(&pdev->dev, clk);
- if (ret) {
- clk_put(clk);
+ ret = of_pm_clk_add_clk(&pdev->dev, "d_audio");
+ if (ret)
goto clk_destroy;
- }
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c
index 5ae294b256a7..3f24aeb48c0e 100644
--- a/drivers/dma/ti-dma-crossbar.c
+++ b/drivers/dma/ti-dma-crossbar.c
@@ -18,15 +18,19 @@
#define TI_XBAR_DRA7 0
#define TI_XBAR_AM335X 1
+static const u32 ti_xbar_type[] = {
+ [TI_XBAR_DRA7] = TI_XBAR_DRA7,
+ [TI_XBAR_AM335X] = TI_XBAR_AM335X,
+};
static const struct of_device_id ti_dma_xbar_match[] = {
{
.compatible = "ti,dra7-dma-crossbar",
- .data = (void *)TI_XBAR_DRA7,
+ .data = &ti_xbar_type[TI_XBAR_DRA7],
},
{
.compatible = "ti,am335x-edma-crossbar",
- .data = (void *)TI_XBAR_AM335X,
+ .data = &ti_xbar_type[TI_XBAR_AM335X],
},
{},
};
@@ -190,9 +194,6 @@ static int ti_am335x_xbar_probe(struct platform_device *pdev)
#define TI_DRA7_XBAR_OUTPUTS 127
#define TI_DRA7_XBAR_INPUTS 256
-#define TI_XBAR_EDMA_OFFSET 0
-#define TI_XBAR_SDMA_OFFSET 1
-
struct ti_dra7_xbar_data {
void __iomem *iomem;
@@ -280,18 +281,25 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
return map;
}
+#define TI_XBAR_EDMA_OFFSET 0
+#define TI_XBAR_SDMA_OFFSET 1
+static const u32 ti_dma_offset[] = {
+ [TI_XBAR_EDMA_OFFSET] = 0,
+ [TI_XBAR_SDMA_OFFSET] = 1,
+};
+
static const struct of_device_id ti_dra7_master_match[] = {
{
.compatible = "ti,omap4430-sdma",
- .data = (void *)TI_XBAR_SDMA_OFFSET,
+ .data = &ti_dma_offset[TI_XBAR_SDMA_OFFSET],
},
{
.compatible = "ti,edma3",
- .data = (void *)TI_XBAR_EDMA_OFFSET,
+ .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
},
{
.compatible = "ti,edma3-tpcc",
- .data = (void *)TI_XBAR_EDMA_OFFSET,
+ .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
},
{},
};
@@ -311,7 +319,7 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
struct property *prop;
struct resource *res;
u32 safe_val;
- size_t sz;
+ int sz;
void __iomem *iomem;
int i, ret;
@@ -395,7 +403,7 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
xbar->dmarouter.dev = &pdev->dev;
xbar->dmarouter.route_free = ti_dra7_xbar_free;
- xbar->dma_offset = (u32)match->data;
+ xbar->dma_offset = *(u32 *)match->data;
mutex_init(&xbar->mutex);
platform_set_drvdata(pdev, xbar);
@@ -428,7 +436,7 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
if (unlikely(!match))
return -EINVAL;
- switch ((u32)match->data) {
+ switch (*(u32 *)match->data) {
case TI_XBAR_DRA7:
ret = ti_dra7_xbar_probe(pdev);
break;
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index e82745aa42a8..896bafb7a532 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -226,8 +226,7 @@ static void __td_start_dma(struct timb_dma_chan *td_chan)
static void __td_finish(struct timb_dma_chan *td_chan)
{
- dma_async_tx_callback callback;
- void *param;
+ struct dmaengine_desc_callback cb;
struct dma_async_tx_descriptor *txd;
struct timb_dma_desc *td_desc;
@@ -252,8 +251,7 @@ static void __td_finish(struct timb_dma_chan *td_chan)
dma_cookie_complete(txd);
td_chan->ongoing = false;
- callback = txd->callback;
- param = txd->callback_param;
+ dmaengine_desc_get_callback(txd, &cb);
list_move(&td_desc->desc_node, &td_chan->free_list);
@@ -262,8 +260,7 @@ static void __td_finish(struct timb_dma_chan *td_chan)
* The API requires that no submissions are done from a
* callback, so we don't need to drop the lock here
*/
- if (callback)
- callback(param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
}
static u32 __td_ier_mask(struct timb_dma *td)
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index 7632290e7c14..4d8c7b9078fd 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -403,16 +403,14 @@ static void
txx9dmac_descriptor_complete(struct txx9dmac_chan *dc,
struct txx9dmac_desc *desc)
{
- dma_async_tx_callback callback;
- void *param;
+ struct dmaengine_desc_callback cb;
struct dma_async_tx_descriptor *txd = &desc->txd;
dev_vdbg(chan2dev(&dc->chan), "descriptor %u %p complete\n",
txd->cookie, desc);
dma_cookie_complete(txd);
- callback = txd->callback;
- param = txd->callback_param;
+ dmaengine_desc_get_callback(txd, &cb);
txx9dmac_sync_desc_for_cpu(dc, desc);
list_splice_init(&desc->tx_list, &dc->free_list);
@@ -423,8 +421,7 @@ txx9dmac_descriptor_complete(struct txx9dmac_chan *dc,
* The API requires that no submissions are done from a
* callback, so we don't need to drop the lock here
*/
- if (callback)
- callback(param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
dma_run_dependencies(txd);
}
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index a35c211857dd..e47fc9b0944f 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -87,8 +87,7 @@ static void vchan_complete(unsigned long arg)
{
struct virt_dma_chan *vc = (struct virt_dma_chan *)arg;
struct virt_dma_desc *vd;
- dma_async_tx_callback cb = NULL;
- void *cb_data = NULL;
+ struct dmaengine_desc_callback cb;
LIST_HEAD(head);
spin_lock_irq(&vc->lock);
@@ -96,18 +95,17 @@ static void vchan_complete(unsigned long arg)
vd = vc->cyclic;
if (vd) {
vc->cyclic = NULL;
- cb = vd->tx.callback;
- cb_data = vd->tx.callback_param;
+ dmaengine_desc_get_callback(&vd->tx, &cb);
+ } else {
+ memset(&cb, 0, sizeof(cb));
}
spin_unlock_irq(&vc->lock);
- if (cb)
- cb(cb_data);
+ dmaengine_desc_callback_invoke(&cb, NULL);
while (!list_empty(&head)) {
vd = list_first_entry(&head, struct virt_dma_desc, node);
- cb = vd->tx.callback;
- cb_data = vd->tx.callback_param;
+ dmaengine_desc_get_callback(&vd->tx, &cb);
list_del(&vd->node);
if (dmaengine_desc_test_reuse(&vd->tx))
@@ -115,8 +113,7 @@ static void vchan_complete(unsigned long arg)
else
vc->desc_free(vd);
- if (cb)
- cb(cb_data);
+ dmaengine_desc_callback_invoke(&cb, NULL);
}
}
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index d9731ca5e262..3f776a46a29c 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -45,6 +45,8 @@ static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head);
void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev);
struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *, dma_cookie_t);
+extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
+extern int vchan_tx_desc_free(struct dma_async_tx_descriptor *);
/**
* vchan_tx_prep - prepare a descriptor
@@ -55,8 +57,6 @@ struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *, dma_cookie_t);
static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan *vc,
struct virt_dma_desc *vd, unsigned long tx_flags)
{
- extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
- extern int vchan_tx_desc_free(struct dma_async_tx_descriptor *);
unsigned long flags;
dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
@@ -123,10 +123,8 @@ static inline void vchan_cyclic_callback(struct virt_dma_desc *vd)
*/
static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
{
- if (list_empty(&vc->desc_issued))
- return NULL;
-
- return list_first_entry(&vc->desc_issued, struct virt_dma_desc, node);
+ return list_first_entry_or_null(&vc->desc_issued,
+ struct virt_dma_desc, node);
}
/**
diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c
index 9cb93c5b655d..8b693b712d0f 100644
--- a/drivers/dma/xgene-dma.c
+++ b/drivers/dma/xgene-dma.c
@@ -606,12 +606,10 @@ static void xgene_dma_run_tx_complete_actions(struct xgene_dma_chan *chan,
return;
dma_cookie_complete(tx);
+ dma_descriptor_unmap(tx);
/* Run the link descriptor callback function */
- if (tx->callback)
- tx->callback(tx->callback_param);
-
- dma_descriptor_unmap(tx);
+ dmaengine_desc_get_callback_invoke(tx, NULL);
/* Run any dependencies */
dma_run_dependencies(tx);
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 4e223d094433..8288fe4d17c3 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -755,8 +755,7 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
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;
+ struct dmaengine_desc_callback cb;
if (desc->cyclic) {
xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
@@ -767,11 +766,10 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
list_del(&desc->node);
/* Run the link descriptor callback function */
- callback = desc->async_tx.callback;
- callback_param = desc->async_tx.callback_param;
- if (callback) {
+ dmaengine_desc_get_callback(&desc->async_tx, &cb);
+ if (dmaengine_desc_callback_valid(&cb)) {
spin_unlock_irqrestore(&chan->lock, flags);
- callback(callback_param);
+ dmaengine_desc_callback_invoke(&cb, NULL);
spin_lock_irqsave(&chan->lock, flags);
}
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 0e22f241403b..bca172d42c74 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -209,5 +209,6 @@ config HAVE_ARM_SMCCC
source "drivers/firmware/broadcom/Kconfig"
source "drivers/firmware/google/Kconfig"
source "drivers/firmware/efi/Kconfig"
+source "drivers/firmware/meson/Kconfig"
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 44a59dcfc398..898ac41fa8b3 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
obj-y += broadcom/
+obj-y += meson/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_UEFI_CPER) += efi/
diff --git a/drivers/firmware/meson/Kconfig b/drivers/firmware/meson/Kconfig
new file mode 100644
index 000000000000..170d7e8bcdfb
--- /dev/null
+++ b/drivers/firmware/meson/Kconfig
@@ -0,0 +1,9 @@
+#
+# Amlogic Secure Monitor driver
+#
+config MESON_SM
+ bool
+ default ARCH_MESON
+ depends on ARM64_4K_PAGES
+ help
+ Say y here to enable the Amlogic secure monitor driver
diff --git a/drivers/firmware/meson/Makefile b/drivers/firmware/meson/Makefile
new file mode 100644
index 000000000000..9ab3884f96bc
--- /dev/null
+++ b/drivers/firmware/meson/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MESON_SM) += meson_sm.o
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
new file mode 100644
index 000000000000..b0d254930ed3
--- /dev/null
+++ b/drivers/firmware/meson/meson_sm.c
@@ -0,0 +1,248 @@
+/*
+ * Amlogic Secure Monitor driver
+ *
+ * Copyright (C) 2016 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "meson-sm: " fmt
+
+#include <linux/arm-smccc.h>
+#include <linux/bug.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+
+#include <linux/firmware/meson/meson_sm.h>
+
+struct meson_sm_cmd {
+ unsigned int index;
+ u32 smc_id;
+};
+#define CMD(d, s) { .index = (d), .smc_id = (s), }
+
+struct meson_sm_chip {
+ unsigned int shmem_size;
+ u32 cmd_shmem_in_base;
+ u32 cmd_shmem_out_base;
+ struct meson_sm_cmd cmd[];
+};
+
+struct meson_sm_chip gxbb_chip = {
+ .shmem_size = SZ_4K,
+ .cmd_shmem_in_base = 0x82000020,
+ .cmd_shmem_out_base = 0x82000021,
+ .cmd = {
+ CMD(SM_EFUSE_READ, 0x82000030),
+ CMD(SM_EFUSE_WRITE, 0x82000031),
+ CMD(SM_EFUSE_USER_MAX, 0x82000033),
+ { /* sentinel */ },
+ },
+};
+
+struct meson_sm_firmware {
+ const struct meson_sm_chip *chip;
+ void __iomem *sm_shmem_in_base;
+ void __iomem *sm_shmem_out_base;
+};
+
+static struct meson_sm_firmware fw;
+
+static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
+ unsigned int cmd_index)
+{
+ const struct meson_sm_cmd *cmd = chip->cmd;
+
+ while (cmd->smc_id && cmd->index != cmd_index)
+ cmd++;
+
+ return cmd->smc_id;
+}
+
+static u32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2,
+ u32 arg3, u32 arg4)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(cmd, arg0, arg1, arg2, arg3, arg4, 0, 0, &res);
+ return res.a0;
+}
+
+static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
+{
+ u32 sm_phy_base;
+
+ sm_phy_base = __meson_sm_call(cmd_shmem, 0, 0, 0, 0, 0);
+ if (!sm_phy_base)
+ return 0;
+
+ return ioremap_cache(sm_phy_base, size);
+}
+
+/**
+ * meson_sm_call - generic SMC32 call to the secure-monitor
+ *
+ * @cmd_index: Index of the SMC32 function ID
+ * @ret: Returned value
+ * @arg0: SMC32 Argument 0
+ * @arg1: SMC32 Argument 1
+ * @arg2: SMC32 Argument 2
+ * @arg3: SMC32 Argument 3
+ * @arg4: SMC32 Argument 4
+ *
+ * Return: 0 on success, a negative value on error
+ */
+int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0,
+ u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+{
+ u32 cmd, lret;
+
+ if (!fw.chip)
+ return -ENOENT;
+
+ cmd = meson_sm_get_cmd(fw.chip, cmd_index);
+ if (!cmd)
+ return -EINVAL;
+
+ lret = __meson_sm_call(cmd, arg0, arg1, arg2, arg3, arg4);
+
+ if (ret)
+ *ret = lret;
+
+ return 0;
+}
+EXPORT_SYMBOL(meson_sm_call);
+
+/**
+ * meson_sm_call_read - retrieve data from secure-monitor
+ *
+ * @buffer: Buffer to store the retrieved data
+ * @cmd_index: Index of the SMC32 function ID
+ * @arg0: SMC32 Argument 0
+ * @arg1: SMC32 Argument 1
+ * @arg2: SMC32 Argument 2
+ * @arg3: SMC32 Argument 3
+ * @arg4: SMC32 Argument 4
+ *
+ * Return: size of read data on success, a negative value on error
+ */
+int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0,
+ u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+{
+ u32 size;
+
+ if (!fw.chip)
+ return -ENOENT;
+
+ if (!fw.chip->cmd_shmem_out_base)
+ return -EINVAL;
+
+ if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
+ return -EINVAL;
+
+ if (!size || size > fw.chip->shmem_size)
+ return -EINVAL;
+
+ if (buffer)
+ memcpy(buffer, fw.sm_shmem_out_base, size);
+
+ return size;
+}
+EXPORT_SYMBOL(meson_sm_call_read);
+
+/**
+ * meson_sm_call_write - send data to secure-monitor
+ *
+ * @buffer: Buffer containing data to send
+ * @size: Size of the data to send
+ * @cmd_index: Index of the SMC32 function ID
+ * @arg0: SMC32 Argument 0
+ * @arg1: SMC32 Argument 1
+ * @arg2: SMC32 Argument 2
+ * @arg3: SMC32 Argument 3
+ * @arg4: SMC32 Argument 4
+ *
+ * Return: size of sent data on success, a negative value on error
+ */
+int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
+ u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+{
+ u32 written;
+
+ if (!fw.chip)
+ return -ENOENT;
+
+ if (size > fw.chip->shmem_size)
+ return -EINVAL;
+
+ if (!fw.chip->cmd_shmem_in_base)
+ return -EINVAL;
+
+ memcpy(fw.sm_shmem_in_base, buffer, size);
+
+ if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
+ return -EINVAL;
+
+ if (!written)
+ return -EINVAL;
+
+ return written;
+}
+EXPORT_SYMBOL(meson_sm_call_write);
+
+static const struct of_device_id meson_sm_ids[] = {
+ { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip },
+ { /* sentinel */ },
+};
+
+int __init meson_sm_init(void)
+{
+ const struct meson_sm_chip *chip;
+ const struct of_device_id *matched_np;
+ struct device_node *np;
+
+ np = of_find_matching_node_and_match(NULL, meson_sm_ids, &matched_np);
+ if (!np)
+ return -ENODEV;
+
+ chip = matched_np->data;
+ if (!chip) {
+ pr_err("unable to setup secure-monitor data\n");
+ goto out;
+ }
+
+ if (chip->cmd_shmem_in_base) {
+ fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
+ chip->shmem_size);
+ if (WARN_ON(!fw.sm_shmem_in_base))
+ goto out;
+ }
+
+ if (chip->cmd_shmem_out_base) {
+ fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
+ chip->shmem_size);
+ if (WARN_ON(!fw.sm_shmem_out_base))
+ goto out_in_base;
+ }
+
+ fw.chip = chip;
+ pr_info("secure-monitor enabled\n");
+
+ return 0;
+
+out_in_base:
+ iounmap(fw.sm_shmem_in_base);
+out:
+ return -EINVAL;
+}
+device_initcall(meson_sm_init);
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index e64a501adbf4..d95c70227c05 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1,4 +1,7 @@
-/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
+/*
+ * Qualcomm SCM driver
+ *
+ * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
@@ -12,7 +15,7 @@
*
*/
#include <linux/platform_device.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/dma-mapping.h>
@@ -376,8 +379,6 @@ static const struct of_device_id qcom_scm_dt_match[] = {
{}
};
-MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
-
static struct platform_driver qcom_scm_driver = {
.driver = {
.name = "qcom_scm",
@@ -414,14 +415,4 @@ static int __init qcom_scm_init(void)
return platform_driver_register(&qcom_scm_driver);
}
-
subsys_initcall(qcom_scm_init);
-
-static void __exit qcom_scm_exit(void)
-{
- platform_driver_unregister(&qcom_scm_driver);
-}
-module_exit(qcom_scm_exit);
-
-MODULE_DESCRIPTION("Qualcomm SCM driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 5d059866d17a..45c8817d068c 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -732,7 +732,7 @@ out:
static const struct of_device_id pca953x_dt_ids[];
static int pca953x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *i2c_id)
{
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
@@ -773,27 +773,29 @@ static int pca953x_probe(struct i2c_client *client,
}
chip->regulator = reg;
- if (id) {
- chip->driver_data = id->driver_data;
+ if (i2c_id) {
+ chip->driver_data = i2c_id->driver_data;
} else {
- const struct acpi_device_id *id;
+ const struct acpi_device_id *acpi_id;
const struct of_device_id *match;
match = of_match_device(pca953x_dt_ids, &client->dev);
if (match) {
chip->driver_data = (int)(uintptr_t)match->data;
} else {
- id = acpi_match_device(pca953x_acpi_ids, &client->dev);
- if (!id) {
+ acpi_id = acpi_match_device(pca953x_acpi_ids, &client->dev);
+ if (!acpi_id) {
ret = -ENODEV;
goto err_exit;
}
- chip->driver_data = id->driver_data;
+ chip->driver_data = acpi_id->driver_data;
}
}
mutex_init(&chip->i2c_lock);
+ lockdep_set_subclass(&chip->i2c_lock,
+ i2c_adapter_depth(client->adapter));
/* initialize cached registers from their original values.
* we can't share this chip with another i2c master.
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index cb8f0347b934..ff843160c600 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -387,7 +387,7 @@ int armada_gem_pwrite_ioctl(struct drm_device *dev, void *data,
if (!access_ok(VERIFY_READ, ptr, args->size))
return -EFAULT;
- ret = fault_in_multipages_readable(ptr, args->size);
+ ret = fault_in_pages_readable(ptr, args->size);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index fa10cef2ba37..1205790ed960 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -104,8 +104,8 @@ int drm_debugfs_create_files(const struct drm_info_list *files, int count,
ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
root, tmp, &drm_debugfs_fops);
if (!ent) {
- DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
- root->d_name.name, files[i].name);
+ DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/%s\n",
+ root, files[i].name);
kfree(tmp);
ret = -1;
goto fail;
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index eae5ef963cb7..2bd064493ae7 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -790,6 +790,12 @@ static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags)
mutex_unlock(&i2c_to_aux(i2c)->hw_mutex);
}
+static const struct i2c_lock_operations drm_dp_i2c_lock_ops = {
+ .lock_bus = lock_bus,
+ .trylock_bus = trylock_bus,
+ .unlock_bus = unlock_bus,
+};
+
/**
* drm_dp_aux_init() - minimally initialise an aux channel
* @aux: DisplayPort AUX channel
@@ -807,9 +813,7 @@ void drm_dp_aux_init(struct drm_dp_aux *aux)
aux->ddc.algo_data = aux;
aux->ddc.retries = 3;
- aux->ddc.lock_bus = lock_bus;
- aux->ddc.trylock_bus = trylock_bus;
- aux->ddc.unlock_bus = unlock_bus;
+ aux->ddc.lock_ops = &drm_dp_i2c_lock_ops;
}
EXPORT_SYMBOL(drm_dp_aux_init);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index a77ce9983f69..ccf56c60e6e8 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -675,7 +675,7 @@ i915_gem_gtt_pread(struct drm_device *dev,
mutex_unlock(&dev->struct_mutex);
if (likely(!i915.prefault_disable)) {
- ret = fault_in_multipages_writeable(user_data, remain);
+ ret = fault_in_pages_writeable(user_data, remain);
if (ret) {
mutex_lock(&dev->struct_mutex);
goto out_unpin;
@@ -803,7 +803,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
mutex_unlock(&dev->struct_mutex);
if (likely(!i915.prefault_disable) && !prefaulted) {
- ret = fault_in_multipages_writeable(user_data, remain);
+ ret = fault_in_pages_writeable(user_data, remain);
/* Userspace is tricking us, but we've already clobbered
* its pages with the prefault and promised to write the
* data up to the first fault. Hence ignore any errors
@@ -1267,7 +1267,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
return -EFAULT;
if (likely(!i915.prefault_disable)) {
- ret = fault_in_multipages_readable(u64_to_user_ptr(args->data_ptr),
+ ret = fault_in_pages_readable(u64_to_user_ptr(args->data_ptr),
args->size);
if (ret)
return -EFAULT;
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index b35e5b6475b2..72628edda376 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1048,7 +1048,7 @@ validate_exec_list(struct drm_device *dev,
return -EFAULT;
if (likely(!i915.prefault_disable)) {
- if (fault_in_multipages_readable(ptr, length))
+ if (fault_in_pages_readable(ptr, length))
return -EFAULT;
}
}
diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c
index 17fe4e53e0d1..1627294575cb 100644
--- a/drivers/gpu/drm/msm/msm_perf.c
+++ b/drivers/gpu/drm/msm/msm_perf.c
@@ -229,8 +229,8 @@ int msm_perf_debugfs_init(struct drm_minor *minor)
perf->ent = debugfs_create_file("perf", S_IFREG | S_IRUGO,
minor->debugfs_root, perf, &perf_debugfs_fops);
if (!perf->ent) {
- DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/perf\n",
- minor->debugfs_root->d_name.name);
+ DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/perf\n",
+ minor->debugfs_root);
goto fail;
}
diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
index 3a5fdfcd67ae..8487f461f05f 100644
--- a/drivers/gpu/drm/msm/msm_rd.c
+++ b/drivers/gpu/drm/msm/msm_rd.c
@@ -243,8 +243,8 @@ int msm_rd_debugfs_init(struct drm_minor *minor)
rd->ent = debugfs_create_file("rd", S_IFREG | S_IRUGO,
minor->debugfs_root, rd, &rd_debugfs_fops);
if (!rd->ent) {
- DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/rd\n",
- minor->debugfs_root->d_name.name);
+ DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/rd\n",
+ minor->debugfs_root);
goto fail;
}
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 78ac4811bd3c..cd4599c0523b 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -457,8 +457,6 @@ config LOGITECH_FF
- Logitech WingMan Cordless RumblePad
- Logitech WingMan Cordless RumblePad 2
- Logitech WingMan Force 3D
- - Logitech Formula Force EX
- - Logitech WingMan Formula Force GP
and if you want to enable force feedback for them.
Note: if you say N here, this device will still be supported, but without
@@ -488,15 +486,22 @@ config LOGIWHEELS_FF
select INPUT_FF_MEMLESS
default LOGITECH_FF
help
- Say Y here if you want to enable force feedback and range setting
+ Say Y here if you want to enable force feedback and range setting(*)
support for following Logitech wheels:
+ - Logitech G25 (*)
+ - Logitech G27 (*)
+ - Logitech G29 (*)
- Logitech Driving Force
- - Logitech Driving Force Pro
- - Logitech Driving Force GT
- - Logitech G25
- - Logitech G27
- - Logitech MOMO/MOMO 2
- - Logitech Formula Force EX
+ - Logitech Driving Force Pro (*)
+ - Logitech Driving Force GT (*)
+ - Logitech Driving Force EX/RX
+ - Logitech Driving Force Wireless
+ - Logitech Speed Force Wireless
+ - Logitech MOMO Force
+ - Logitech MOMO Racing Force
+ - Logitech Formula Force GP
+ - Logitech Formula Force EX/RX
+ - Logitech Wingman Formula Force GP
config HID_MAGICMOUSE
tristate "Apple Magic Mouse/Trackpad multi-touch support"
@@ -862,6 +867,7 @@ config HID_WACOM
select POWER_SUPPLY
select NEW_LEDS
select LEDS_CLASS
+ select LEDS_TRIGGERS
help
Say Y here if you want to use the USB or BT version of the Wacom Intuos
or Graphire tablet.
@@ -967,4 +973,6 @@ source "drivers/hid/usbhid/Kconfig"
source "drivers/hid/i2c-hid/Kconfig"
+source "drivers/hid/intel-ish-hid/Kconfig"
+
endmenu
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fc4b2aa47f2e..86b2b5785fd2 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -113,3 +113,5 @@ obj-$(CONFIG_USB_MOUSE) += usbhid/
obj-$(CONFIG_USB_KBD) += usbhid/
obj-$(CONFIG_I2C_HID) += i2c-hid/
+
+obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c
index 048befde295a..ed9c0ea5b026 100644
--- a/drivers/hid/hid-alps.c
+++ b/drivers/hid/hid-alps.c
@@ -139,8 +139,8 @@ static int u1_read_write_register(struct hid_device *hdev, u32 address,
if (read_flag) {
readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
if (!readbuf) {
- kfree(input);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit;
}
ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf,
@@ -149,6 +149,7 @@ static int u1_read_write_register(struct hid_device *hdev, u32 address,
if (ret < 0) {
dev_err(&hdev->dev, "failed read register (%d)\n", ret);
+ kfree(readbuf);
goto exit;
}
@@ -190,16 +191,16 @@ static int alps_raw_event(struct hid_device *hdev,
if (z != 0) {
input_mt_report_slot_state(hdata->input,
MT_TOOL_FINGER, 1);
+ input_report_abs(hdata->input,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(hdata->input,
+ ABS_MT_POSITION_Y, y);
+ input_report_abs(hdata->input,
+ ABS_MT_PRESSURE, z);
} else {
input_mt_report_slot_state(hdata->input,
MT_TOOL_FINGER, 0);
- break;
}
-
- input_report_abs(hdata->input, ABS_MT_POSITION_X, x);
- input_report_abs(hdata->input, ABS_MT_POSITION_Y, y);
- input_report_abs(hdata->input, ABS_MT_PRESSURE, z);
-
}
input_mt_sync_frame(hdata->input);
@@ -244,13 +245,13 @@ static int alps_raw_event(struct hid_device *hdev,
static int alps_post_reset(struct hid_device *hdev)
{
return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
- NULL, U1_TP_ABS_MODE, false);
+ NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false);
}
static int alps_post_resume(struct hid_device *hdev)
{
return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
- NULL, U1_TP_ABS_MODE, false);
+ NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false);
}
#endif /* CONFIG_PM */
@@ -383,7 +384,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
input2 = input_allocate_device();
if (!input2) {
- input_free_device(input2);
+ ret = -ENOMEM;
goto exit;
}
@@ -425,7 +426,8 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
__set_bit(INPUT_PROP_POINTER, input2->propbit);
__set_bit(INPUT_PROP_POINTING_STICK, input2->propbit);
- if (input_register_device(data->input2)) {
+ ret = input_register_device(data->input2);
+ if (ret) {
input_free_device(input2);
goto exit;
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 08f53c7fd513..2b89c701076f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -727,6 +727,7 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
(hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
+ hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
hid->group == HID_GROUP_MULTITOUCH)
@@ -1916,7 +1917,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
- { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
@@ -1982,6 +1983,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
@@ -2037,6 +2039,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT9) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
@@ -2083,6 +2086,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
@@ -2480,7 +2488,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
-#if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE)
+#if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4ed9a4fdfea7..cd59c79eebdd 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -268,6 +268,7 @@
#define USB_DEVICE_ID_CORSAIR_K95RGB 0x1b11
#define USB_DEVICE_ID_CORSAIR_M65RGB 0x1b12
#define USB_DEVICE_ID_CORSAIR_K70RGB 0x1b13
+#define USB_DEVICE_ID_CORSAIR_STRAFE 0x1b15
#define USB_DEVICE_ID_CORSAIR_K65RGB 0x1b17
#define USB_VENDOR_ID_CREATIVELABS 0x041e
@@ -565,7 +566,7 @@
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
#define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011
-#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2 0x501a
+#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501a
#define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013
#define USB_DEVICE_ID_KYE_PENSKETCH_M912 0x5015
@@ -713,6 +714,7 @@
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd
+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
@@ -859,6 +861,7 @@
#define USB_DEVICE_ID_SAITEK_PS1000 0x0621
#define USB_DEVICE_ID_SAITEK_RAT7_OLD 0x0ccb
#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7
+#define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
#define USB_VENDOR_ID_SAMSUNG 0x0419
@@ -996,6 +999,10 @@
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781
+#define USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 0x3031
+#define USB_DEVICE_ID_UGEE_TABLET_81 0x0081
+#define USB_DEVICE_ID_UGEE_TABLET_45 0x0045
+#define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d
#define USB_VENDOR_ID_UNITEC 0x227d
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
@@ -1085,4 +1092,7 @@
#define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002
#define USB_DEVICE_ID_RAPHNET_4NES4SNES 0x0003
+#define USB_VENDOR_ID_UGTIZER 0x2179
+#define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053
+
#endif
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index bcfaf32d9e5e..fb9ace1cef8b 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -604,6 +604,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
}
+ /*
+ * Some lazy vendors declare 255 usages for System Control,
+ * leading to the creation of ABS_X|Y axis and too many others.
+ * It wouldn't be a problem if joydev doesn't consider the
+ * device as a joystick then.
+ */
+ if (field->application == HID_GD_SYSTEM_CONTROL)
+ goto ignore;
+
if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
switch (usage->hid) {
case HID_GD_UP: usage->hat_dir = 1; break;
@@ -953,6 +962,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_HPVENDOR2:
set_bit(EV_REP, input->evbit);
switch (usage->hid & HID_USAGE) {
+ case 0x001: map_key_clear(KEY_MICMUTE); break;
case 0x003: map_key_clear(KEY_BRIGHTNESSDOWN); break;
case 0x004: map_key_clear(KEY_BRIGHTNESSUP); break;
default: goto ignore;
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index 32e6d8d9ded0..0dd1167b2c9b 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -19,11 +19,6 @@
#include "hid-ids.h"
-/*
- * See EasyPen i405X description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=KYE_EasyPen_i405X
- */
-
/* Original EasyPen i405X report descriptor size */
#define EASYPEN_I405X_RDESC_ORIG_SIZE 476
@@ -82,11 +77,6 @@ static __u8 easypen_i405x_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See MousePen i608X description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=KYE_MousePen_i608X
- */
-
/* Original MousePen i608X report descriptor size */
#define MOUSEPEN_I608X_RDESC_ORIG_SIZE 476
@@ -186,10 +176,104 @@ static __u8 mousepen_i608x_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See EasyPen M610X description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=KYE_EasyPen_M610X
- */
+/* Original MousePen i608X v2 report descriptor size */
+#define MOUSEPEN_I608X_V2_RDESC_ORIG_SIZE 482
+
+/* Fixed MousePen i608X v2 report descriptor */
+static __u8 mousepen_i608x_v2_rdesc_fixed[] = {
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x09, 0x01, /* Usage (01h), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x05, /* Report ID (5), */
+ 0x09, 0x01, /* Usage (01h), */
+ 0x15, 0x80, /* Logical Minimum (-128), */
+ 0x25, 0x7F, /* Logical Maximum (127), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x07, /* Report Count (7), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x04, /* Report Count (4), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x27, 0x00, 0xA0, 0x00, 0x00, /* Logical Maximum (40960), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */
+ 0x26, 0x00, 0x78, /* Logical Maximum (30720), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x11, /* Report ID (17), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x03, /* Usage Maximum (03h), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xB4, /* Pop, */
+ 0x95, 0x01, /* Report Count (1), */
+ 0xA4, /* Push, */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x27, 0x00, 0xA0, 0x00, 0x00, /* Logical Maximum (40960), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */
+ 0x26, 0x00, 0x78, /* Logical Maximum (30720), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
/* Original EasyPen M610X report descriptor size */
#define EASYPEN_M610X_RDESC_ORIG_SIZE 476
@@ -454,12 +538,17 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
}
break;
case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
- case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2:
if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) {
rdesc = mousepen_i608x_rdesc_fixed;
*rsize = sizeof(mousepen_i608x_rdesc_fixed);
}
break;
+ case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:
+ if (*rsize == MOUSEPEN_I608X_V2_RDESC_ORIG_SIZE) {
+ rdesc = mousepen_i608x_v2_rdesc_fixed;
+ *rsize = sizeof(mousepen_i608x_v2_rdesc_fixed);
+ }
+ break;
case USB_DEVICE_ID_KYE_EASYPEN_M610X:
if (*rsize == EASYPEN_M610X_RDESC_ORIG_SIZE) {
rdesc = easypen_m610x_rdesc_fixed;
@@ -553,7 +642,7 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id)
switch (id->product) {
case USB_DEVICE_ID_KYE_EASYPEN_I405X:
case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
- case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2:
+ case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:
case USB_DEVICE_ID_KYE_EASYPEN_M610X:
case USB_DEVICE_ID_KYE_PENSKETCH_M912:
ret = kye_tablet_enable(hdev);
@@ -586,7 +675,7 @@ static const struct hid_device_id kye_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
- USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) },
+ USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index feb2be71f77c..76f644deb0a7 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -49,6 +49,7 @@
#define FV_RDESC_ORIG_SIZE 130
#define MOMO_RDESC_ORIG_SIZE 87
#define MOMO2_RDESC_ORIG_SIZE 87
+#define FFG_RDESC_ORIG_SIZE 85
/* Fixed report descriptors for Logitech Driving Force (and Pro)
* wheel controllers
@@ -334,6 +335,52 @@ static __u8 momo2_rdesc_fixed[] = {
0xC0 /* End Collection */
};
+static __u8 ffg_rdesc_fixed[] = {
+0x05, 0x01, /* Usage Page (Desktop), */
+0x09, 0x04, /* Usage (Joystik), */
+0xA1, 0x01, /* Collection (Application), */
+0xA1, 0x02, /* Collection (Logical), */
+0x95, 0x01, /* Report Count (1), */
+0x75, 0x0A, /* Report Size (10), */
+0x15, 0x00, /* Logical Minimum (0), */
+0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+0x35, 0x00, /* Physical Minimum (0), */
+0x46, 0xFF, 0x03, /* Physical Maximum (1023), */
+0x09, 0x30, /* Usage (X), */
+0x81, 0x02, /* Input (Variable), */
+0x95, 0x06, /* Report Count (6), */
+0x75, 0x01, /* Report Size (1), */
+0x25, 0x01, /* Logical Maximum (1), */
+0x45, 0x01, /* Physical Maximum (1), */
+0x05, 0x09, /* Usage Page (Button), */
+0x19, 0x01, /* Usage Minimum (01h), */
+0x29, 0x06, /* Usage Maximum (06h), */
+0x81, 0x02, /* Input (Variable), */
+0x95, 0x01, /* Report Count (1), */
+0x75, 0x08, /* Report Size (8), */
+0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+0x46, 0xFF, 0x00, /* Physical Maximum (255), */
+0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+0x09, 0x01, /* Usage (01h), */
+0x81, 0x02, /* Input (Variable), */
+0x05, 0x01, /* Usage Page (Desktop), */
+0x81, 0x01, /* Input (Constant), */
+0x09, 0x31, /* Usage (Y), */
+0x81, 0x02, /* Input (Variable), */
+0x09, 0x32, /* Usage (Z), */
+0x81, 0x02, /* Input (Variable), */
+0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+0x09, 0x01, /* Usage (01h), */
+0x81, 0x02, /* Input (Variable), */
+0xC0, /* End Collection, */
+0xA1, 0x02, /* Collection (Logical), */
+0x09, 0x02, /* Usage (02h), */
+0x95, 0x07, /* Report Count (7), */
+0x91, 0x02, /* Output (Variable), */
+0xC0, /* End Collection, */
+0xC0 /* End Collection */
+};
+
/*
* Certain Logitech keyboards send in report #3 keys which are far
* above the logical maximum described in descriptor. This extends
@@ -343,8 +390,6 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
- struct usb_device_descriptor *udesc;
- __u16 bcdDevice, rev_maj, rev_min;
if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
@@ -363,20 +408,18 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
switch (hdev->product) {
- /* Several wheels report as this id when operating in emulation mode. */
- case USB_DEVICE_ID_LOGITECH_WHEEL:
- udesc = &(hid_to_usb_dev(hdev)->descriptor);
- if (!udesc) {
- hid_err(hdev, "NULL USB device descriptor\n");
- break;
+ case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
+ if (*rsize == FFG_RDESC_ORIG_SIZE) {
+ hid_info(hdev,
+ "fixing up Logitech Wingman Formula Force GP report descriptor\n");
+ rdesc = ffg_rdesc_fixed;
+ *rsize = sizeof(ffg_rdesc_fixed);
}
- bcdDevice = le16_to_cpu(udesc->bcdDevice);
- rev_maj = bcdDevice >> 8;
- rev_min = bcdDevice & 0xff;
+ break;
- /* Update the report descriptor for only the Driving Force wheel */
- if (rev_maj == 1 && rev_min == 2 &&
- *rsize == DF_RDESC_ORIG_SIZE) {
+ /* Several wheels report as this id when operating in emulation mode. */
+ case USB_DEVICE_ID_LOGITECH_WHEEL:
+ if (*rsize == DF_RDESC_ORIG_SIZE) {
hid_info(hdev,
"fixing up Logitech Driving Force report descriptor\n");
rdesc = df_rdesc_fixed;
@@ -621,6 +664,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
usage->code == ABS_RZ)) {
switch (hdev->product) {
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
case USB_DEVICE_ID_LOGITECH_WHEEL:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
@@ -657,6 +701,17 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
return 0;
}
+static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *rd, int size)
+{
+ struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
+
+ if (drv_data->quirks & LG_FF4)
+ return lg4ff_raw_event(hdev, report, rd, size, drv_data);
+
+ return 0;
+}
+
static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
@@ -809,7 +864,7 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
- .driver_data = LG_FF },
+ .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
.driver_data = LG_FF2 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
@@ -830,6 +885,7 @@ static struct hid_driver lg_driver = {
.input_mapping = lg_input_mapping,
.input_mapped = lg_input_mapped,
.event = lg_event,
+ .raw_event = lg_raw_event,
.probe = lg_probe,
.remove = lg_remove,
};
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index af3a8ec8a746..1fc12e357035 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -75,6 +75,7 @@ static void lg4ff_set_range_g25(struct hid_device *hid, u16 range);
struct lg4ff_wheel_data {
const u32 product_id;
+ u16 combine;
u16 range;
const u16 min_range;
const u16 max_range;
@@ -136,6 +137,7 @@ struct lg4ff_alternate_mode {
};
static const struct lg4ff_wheel lg4ff_devices[] = {
+ {USB_DEVICE_ID_LOGITECH_WINGMAN_FFG, lg4ff_wheel_effects, 40, 180, NULL},
{USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
{USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_dfp},
@@ -328,6 +330,56 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
}
}
+int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *rd, int size, struct lg_drv_data *drv_data)
+{
+ int offset;
+ struct lg4ff_device_entry *entry = drv_data->device_props;
+
+ if (!entry)
+ return 0;
+
+ /* adjust HID report present combined pedals data */
+ if (entry->wdata.combine) {
+ switch (entry->wdata.product_id) {
+ case USB_DEVICE_ID_LOGITECH_WHEEL:
+ rd[5] = rd[3];
+ rd[6] = 0x7F;
+ return 1;
+ case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
+ case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
+ rd[4] = rd[3];
+ rd[5] = 0x7F;
+ return 1;
+ case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
+ rd[5] = rd[4];
+ rd[6] = 0x7F;
+ return 1;
+ case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
+ offset = 5;
+ break;
+ case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
+ offset = 6;
+ break;
+ case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
+ offset = 3;
+ break;
+ default:
+ return 0;
+ }
+
+ /* Compute a combined axis when wheel does not supply it */
+ rd[offset] = (0xFF + rd[offset] - rd[offset+1]) >> 1;
+ rd[offset+1] = 0x7F;
+ return 1;
+ }
+
+ return 0;
+}
+
static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const struct lg4ff_wheel *wheel,
const struct lg4ff_multimode_wheel *mmode_wheel,
const u16 real_product_id)
@@ -345,6 +397,7 @@ static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const s
{
struct lg4ff_wheel_data t_wdata = { .product_id = wheel->product_id,
.real_product_id = real_product_id,
+ .combine = 0,
.min_range = wheel->min_range,
.max_range = wheel->max_range,
.set_range = wheel->set_range,
@@ -885,6 +938,58 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att
}
static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store);
+static ssize_t lg4ff_combine_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
+ size_t count;
+
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Private driver data not found!\n");
+ return 0;
+ }
+
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Device properties not found!\n");
+ return 0;
+ }
+
+ count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.combine);
+ return count;
+}
+
+static ssize_t lg4ff_combine_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
+ u16 combine = simple_strtoul(buf, NULL, 10);
+
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Device properties not found!\n");
+ return -EINVAL;
+ }
+
+ if (combine > 1)
+ combine = 1;
+
+ entry->wdata.combine = combine;
+ return count;
+}
+static DEVICE_ATTR(combine_pedals, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_combine_show, lg4ff_combine_store);
+
/* Export the currently set range of the wheel */
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1259,6 +1364,9 @@ int lg4ff_init(struct hid_device *hid)
}
/* Create sysfs interface */
+ error = device_create_file(&hid->dev, &dev_attr_combine_pedals);
+ if (error)
+ hid_warn(hid, "Unable to create sysfs interface for \"combine\", errno %d\n", error);
error = device_create_file(&hid->dev, &dev_attr_range);
if (error)
hid_warn(hid, "Unable to create sysfs interface for \"range\", errno %d\n", error);
@@ -1358,6 +1466,7 @@ int lg4ff_deinit(struct hid_device *hid)
device_remove_file(&hid->dev, &dev_attr_alternate_modes);
}
+ device_remove_file(&hid->dev, &dev_attr_combine_pedals);
device_remove_file(&hid->dev, &dev_attr_range);
#ifdef CONFIG_LEDS_CLASS
{
diff --git a/drivers/hid/hid-lg4ff.h b/drivers/hid/hid-lg4ff.h
index 66201af44da3..de1f350e0bd3 100644
--- a/drivers/hid/hid-lg4ff.h
+++ b/drivers/hid/hid-lg4ff.h
@@ -6,11 +6,15 @@ extern int lg4ff_no_autoswitch; /* From hid-lg.c */
int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data);
+int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *rd, int size, struct lg_drv_data *drv_data);
int lg4ff_init(struct hid_device *hdev);
int lg4ff_deinit(struct hid_device *hdev);
#else
static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data) { return 0; }
+static inline int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *rd, int size, struct lg_drv_data *drv_data) { return 0; }
static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
#endif
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index e924d555536c..c6cd392e9f99 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -28,7 +28,6 @@
#define MS_RDESC 0x08
#define MS_NOGET 0x10
#define MS_DUPLICATE_USAGES 0x20
-#define MS_RDESC_3K 0x40
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
@@ -45,13 +44,6 @@ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[557] = 0x35;
rdesc[559] = 0x45;
}
- /* the same as above (s/usage/physical/) */
- if ((quirks & MS_RDESC_3K) && *rsize == 106 && rdesc[94] == 0x19 &&
- rdesc[95] == 0x00 && rdesc[96] == 0x29 &&
- rdesc[97] == 0xff) {
- rdesc[94] = 0x35;
- rdesc[96] = 0x45;
- }
return rdesc;
}
@@ -271,7 +263,7 @@ static const struct hid_device_id ms_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
.driver_data = MS_PRESENTER },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
- .driver_data = MS_ERGONOMY | MS_RDESC_3K },
+ .driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600),
@@ -288,6 +280,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
.driver_data = MS_HIDINPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP),
+ .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c
index 2f84b26f1167..39e642686ff0 100644
--- a/drivers/hid/hid-saitek.c
+++ b/drivers/hid/hid-saitek.c
@@ -183,6 +183,8 @@ static const struct hid_device_id saitek_devices[] = {
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT9),
+ .driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9),
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7),
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 3d5ba5b51af3..658a607dc6d9 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -16,6 +16,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -798,6 +799,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
USB_DEVICE_ID_ITE_LENOVO_YOGA900),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_0,
+ 0x22D8),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
HID_ANY_ID) },
{ }
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 310436a54a3f..b0bb99a821bd 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -8,7 +8,7 @@
* Copyright (c) 2012 David Dillow <dave@thedillows.org>
* Copyright (c) 2006-2013 Jiri Kosina
* Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
- * Copyright (c) 2014 Frank Praznik <frank.praznik@gmail.com>
+ * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>
*/
/*
@@ -51,6 +51,7 @@
#define NAVIGATION_CONTROLLER_USB BIT(9)
#define NAVIGATION_CONTROLLER_BT BIT(10)
#define SINO_LITE_CONTROLLER BIT(11)
+#define FUTUREMAX_DANCE_MAT BIT(12)
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
@@ -65,6 +66,8 @@
MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER)
#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\
MOTION_CONTROLLER)
+#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\
+ MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT)
#define MAX_LEDS 4
@@ -1048,6 +1051,7 @@ struct sony_sc {
u8 mac_address[6];
u8 worker_initialized;
+ u8 defer_initialization;
u8 cable_state;
u8 battery_charging;
u8 battery_capacity;
@@ -1058,6 +1062,12 @@ struct sony_sc {
u8 led_count;
};
+static inline void sony_schedule_work(struct sony_sc *sc)
+{
+ if (!sc->defer_initialization)
+ schedule_work(&sc->state_worker);
+}
+
static u8 *sixaxis_fixup(struct hid_device *hdev, u8 *rdesc,
unsigned int *rsize)
{
@@ -1125,7 +1135,7 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
{
struct sony_sc *sc = hid_get_drvdata(hdev);
- if (sc->quirks & SINO_LITE_CONTROLLER)
+ if (sc->quirks & (SINO_LITE_CONTROLLER | FUTUREMAX_DANCE_MAT))
return rdesc;
/*
@@ -1317,6 +1327,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
dualshock4_parse_report(sc, rd, size);
}
+ if (sc->defer_initialization) {
+ sc->defer_initialization = 0;
+ sony_schedule_work(sc);
+ }
+
return 0;
}
@@ -1554,7 +1569,7 @@ static void buzz_set_leds(struct sony_sc *sc)
static void sony_set_leds(struct sony_sc *sc)
{
if (!(sc->quirks & BUZZ_CONTROLLER))
- schedule_work(&sc->state_worker);
+ sony_schedule_work(sc);
else
buzz_set_leds(sc);
}
@@ -1665,7 +1680,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
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);
+ sony_schedule_work(drv_data);
}
return 0;
@@ -1865,6 +1880,17 @@ static void dualshock4_send_output_report(struct sony_sc *sc)
u8 *buf = sc->output_report_dmabuf;
int offset;
+ /*
+ * NOTE: The buf[1] field of the Bluetooth report controls
+ * the Dualshock 4 reporting rate.
+ *
+ * Known values include:
+ *
+ * 0x80 - 1000hz (full speed)
+ * 0xA0 - 31hz
+ * 0xB0 - 20hz
+ * 0xD0 - 66hz
+ */
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
memset(buf, 0, DS4_REPORT_0x05_SIZE);
buf[0] = 0x05;
@@ -1976,7 +2002,7 @@ static int sony_play_effect(struct input_dev *dev, void *data,
sc->left = effect->u.rumble.strong_magnitude / 256;
sc->right = effect->u.rumble.weak_magnitude / 256;
- schedule_work(&sc->state_worker);
+ sony_schedule_work(sc);
return 0;
}
@@ -2039,8 +2065,11 @@ static int sony_battery_get_property(struct power_supply *psy,
return ret;
}
-static int sony_battery_probe(struct sony_sc *sc)
+static int sony_battery_probe(struct sony_sc *sc, int append_dev_id)
{
+ const char *battery_str_fmt = append_dev_id ?
+ "sony_controller_battery_%pMR_%i" :
+ "sony_controller_battery_%pMR";
struct power_supply_config psy_cfg = { .drv_data = sc, };
struct hid_device *hdev = sc->hdev;
int ret;
@@ -2056,9 +2085,8 @@ static int sony_battery_probe(struct sony_sc *sc)
sc->battery_desc.get_property = sony_battery_get_property;
sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
sc->battery_desc.use_for_apm = 0;
- sc->battery_desc.name = kasprintf(GFP_KERNEL,
- "sony_controller_battery_%pMR",
- sc->mac_address);
+ sc->battery_desc.name = kasprintf(GFP_KERNEL, battery_str_fmt,
+ sc->mac_address, sc->device_id);
if (!sc->battery_desc.name)
return -ENOMEM;
@@ -2094,7 +2122,21 @@ static void sony_battery_remove(struct sony_sc *sc)
* it will show up as two devices. A global list of connected controllers and
* their MAC addresses is maintained to ensure that a device is only connected
* once.
+ *
+ * Some USB-only devices masquerade as Sixaxis controllers and all have the
+ * same dummy Bluetooth address, so a comparison of the connection type is
+ * required. Devices are only rejected in the case where two devices have
+ * matching Bluetooth addresses on different bus types.
*/
+static inline int sony_compare_connection_type(struct sony_sc *sc0,
+ struct sony_sc *sc1)
+{
+ const int sc0_not_bt = !(sc0->quirks & SONY_BT_DEVICE);
+ const int sc1_not_bt = !(sc1->quirks & SONY_BT_DEVICE);
+
+ return sc0_not_bt == sc1_not_bt;
+}
+
static int sony_check_add_dev_list(struct sony_sc *sc)
{
struct sony_sc *entry;
@@ -2107,9 +2149,14 @@ static int sony_check_add_dev_list(struct sony_sc *sc)
ret = memcmp(sc->mac_address, entry->mac_address,
sizeof(sc->mac_address));
if (!ret) {
- ret = -EEXIST;
- hid_info(sc->hdev, "controller with MAC address %pMR already connected\n",
+ if (sony_compare_connection_type(sc, entry)) {
+ ret = 1;
+ } else {
+ ret = -EEXIST;
+ hid_info(sc->hdev,
+ "controller with MAC address %pMR already connected\n",
sc->mac_address);
+ }
goto unlock;
}
}
@@ -2285,10 +2332,14 @@ static inline void sony_cancel_work_sync(struct sony_sc *sc)
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
+ int append_dev_id;
unsigned long quirks = id->driver_data;
struct sony_sc *sc;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
+ if (!strcmp(hdev->name, "FutureMax Dance Mat"))
+ quirks |= FUTUREMAX_DANCE_MAT;
+
sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
hid_err(hdev, "can't alloc sony descriptor\n");
@@ -2341,9 +2392,16 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
* the Sixaxis does not want the report_id as part of the data
* packet, so we have to discard buf[0] when sending the actual
* control message, even for numbered reports, humpf!
+ *
+ * Additionally, the Sixaxis on USB isn't properly initialized
+ * until the PS logo button is pressed and as such won't retain
+ * any state set by an output report, so the initial
+ * configuration report is deferred until the first input
+ * report arrives.
*/
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
+ sc->defer_initialization = 1;
ret = sixaxis_set_operational_usb(hdev);
sony_init_output_report(sc, sixaxis_send_output_report);
} else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) ||
@@ -2379,7 +2437,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
- ret = sony_check_add(sc);
+ ret = append_dev_id = sony_check_add(sc);
if (ret < 0)
goto err_stop;
@@ -2390,7 +2448,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & SONY_BATTERY_SUPPORT) {
- ret = sony_battery_probe(sc);
+ ret = sony_battery_probe(sc, append_dev_id);
if (ret < 0)
goto err_stop;
@@ -2486,8 +2544,10 @@ static int sony_resume(struct hid_device *hdev)
* reinitialized on resume or they won't behave properly.
*/
if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
- (sc->quirks & NAVIGATION_CONTROLLER_USB))
+ (sc->quirks & NAVIGATION_CONTROLLER_USB)) {
sixaxis_set_operational_usb(sc->hdev);
+ sc->defer_initialization = 1;
+ }
sony_set_leds(sc);
}
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 85ac43517e3f..1509d7287ff3 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -21,13 +21,6 @@
#include "hid-ids.h"
-/*
- * See WPXXXXU model descriptions, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP4030U
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP5540U
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP8060U
- */
-
/* Size of the original descriptor of WPXXXXU tablets */
#define WPXXXXU_RDESC_ORIG_SIZE 212
@@ -221,11 +214,6 @@ static __u8 wp8060u_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See WP1062 description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP1062
- */
-
/* Size of the original descriptor of WP1062 tablet */
#define WP1062_RDESC_ORIG_SIZE 254
@@ -274,11 +262,6 @@ static __u8 wp1062_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See PF1209 description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_PF1209
- */
-
/* Size of the original descriptor of PF1209 tablet */
#define PF1209_RDESC_ORIG_SIZE 234
@@ -356,11 +339,6 @@ static __u8 pf1209_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See TWHL850 description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
- */
-
/* Size of the original descriptors of TWHL850 tablet */
#define TWHL850_RDESC_ORIG_SIZE0 182
#define TWHL850_RDESC_ORIG_SIZE1 161
@@ -469,11 +447,6 @@ static __u8 twhl850_rdesc_fixed2[] = {
0xC0 /* End Collection */
};
-/*
- * See TWHA60 description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60
- */
-
/* Size of the original descriptors of TWHA60 tablet */
#define TWHA60_RDESC_ORIG_SIZE0 254
#define TWHA60_RDESC_ORIG_SIZE1 139
@@ -613,6 +586,27 @@ static const __u8 uclogic_tablet_rdesc_template[] = {
0xC0 /* End Collection */
};
+/* Fixed virtual pad report descriptor */
+static const __u8 uclogic_buttonpad_rdesc[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x07, /* Usage (Keypad), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0xF7, /* Report ID (247), */
+ 0x05, 0x0D, /* Usage Page (Digitizers), */
+ 0x09, 0x39, /* Usage (Tablet Function Keys), */
+ 0xA0, /* Collection (Physical), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x18, /* Report Count (24), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x08, /* Usage Maximum (08h), */
+ 0x95, 0x08, /* Report Count (8), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection */
+ 0xC0 /* End Collection */
+};
+
/* Parameter indices */
enum uclogic_prm {
UCLOGIC_PRM_X_LM = 1,
@@ -628,6 +622,7 @@ struct uclogic_drvdata {
unsigned int rsize;
bool invert_pen_inrange;
bool ignore_pen_usage;
+ bool has_virtual_pad_interface;
};
static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -637,6 +632,12 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
+ if (drvdata->rdesc != NULL) {
+ rdesc = drvdata->rdesc;
+ *rsize = drvdata->rsize;
+ return rdesc;
+ }
+
switch (hdev->product) {
case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
if (*rsize == PF1209_RDESC_ORIG_SIZE) {
@@ -706,11 +707,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
break;
}
break;
- default:
- if (drvdata->rdesc != NULL) {
- rdesc = drvdata->rdesc;
- *rsize = drvdata->rsize;
- }
}
return rdesc;
@@ -804,7 +800,6 @@ static int uclogic_tablet_enable(struct hid_device *hdev)
len = UCLOGIC_PRM_NUM * sizeof(*buf);
buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL) {
- hid_err(hdev, "failed to allocate parameter buffer\n");
rc = -ENOMEM;
goto cleanup;
}
@@ -848,7 +843,6 @@ static int uclogic_tablet_enable(struct hid_device *hdev)
sizeof(uclogic_tablet_rdesc_template),
GFP_KERNEL);
if (drvdata->rdesc == NULL) {
- hid_err(hdev, "failed to allocate fixed rdesc\n");
rc = -ENOMEM;
goto cleanup;
}
@@ -876,11 +870,75 @@ cleanup:
return rc;
}
+/**
+ * Enable actual button mode.
+ *
+ * @hdev: HID device
+ */
+static int uclogic_button_enable(struct hid_device *hdev)
+{
+ int rc;
+ struct usb_device *usb_dev = hid_to_usb_dev(hdev);
+ struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
+ char *str_buf;
+ size_t str_len = 16;
+ unsigned char *rdesc;
+ size_t rdesc_len;
+
+ str_buf = kzalloc(str_len, GFP_KERNEL);
+ if (str_buf == NULL) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* Enable abstract keyboard mode */
+ rc = usb_string(usb_dev, 0x7b, str_buf, str_len);
+ if (rc == -EPIPE) {
+ hid_info(hdev, "button mode setting not found\n");
+ rc = 0;
+ goto cleanup;
+ } else if (rc < 0) {
+ hid_err(hdev, "failed to enable abstract keyboard\n");
+ goto cleanup;
+ } else if (strncmp(str_buf, "HK On", rc)) {
+ hid_info(hdev, "invalid answer when requesting buttons: '%s'\n",
+ str_buf);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ /* Re-allocate fixed report descriptor */
+ rdesc_len = drvdata->rsize + sizeof(uclogic_buttonpad_rdesc);
+ rdesc = devm_kzalloc(&hdev->dev, rdesc_len, GFP_KERNEL);
+ if (!rdesc) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+
+ memcpy(rdesc, drvdata->rdesc, drvdata->rsize);
+
+ /* Append the buttonpad descriptor */
+ memcpy(rdesc + drvdata->rsize, uclogic_buttonpad_rdesc,
+ sizeof(uclogic_buttonpad_rdesc));
+
+ /* clean up old rdesc and use the new one */
+ drvdata->rsize = rdesc_len;
+ devm_kfree(&hdev->dev, drvdata->rdesc);
+ drvdata->rdesc = rdesc;
+
+ rc = 0;
+
+cleanup:
+ kfree(str_buf);
+ return rc;
+}
+
static int uclogic_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int rc;
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *udev = hid_to_usb_dev(hdev);
struct uclogic_drvdata *drvdata;
/*
@@ -899,6 +957,10 @@ static int uclogic_probe(struct hid_device *hdev,
switch (id->product) {
case USB_DEVICE_ID_HUION_TABLET:
+ case USB_DEVICE_ID_YIYNOVA_TABLET:
+ case USB_DEVICE_ID_UGEE_TABLET_81:
+ case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3:
+ case USB_DEVICE_ID_UGEE_TABLET_45:
/* If this is the pen interface */
if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
rc = uclogic_tablet_enable(hdev);
@@ -907,10 +969,48 @@ static int uclogic_probe(struct hid_device *hdev,
return rc;
}
drvdata->invert_pen_inrange = true;
+
+ rc = uclogic_button_enable(hdev);
+ drvdata->has_virtual_pad_interface = !rc;
} else {
drvdata->ignore_pen_usage = true;
}
break;
+ case USB_DEVICE_ID_UGTIZER_TABLET_GP0610:
+ /* If this is the pen interface */
+ if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+ rc = uclogic_tablet_enable(hdev);
+ if (rc) {
+ hid_err(hdev, "tablet enabling failed\n");
+ return rc;
+ }
+ drvdata->invert_pen_inrange = true;
+ } else {
+ drvdata->ignore_pen_usage = true;
+ }
+ break;
+ case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
+ /*
+ * If it is the three-interface version, which is known to
+ * respond to initialization.
+ */
+ if (udev->config->desc.bNumInterfaces == 3) {
+ /* If it is the pen interface */
+ if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+ rc = uclogic_tablet_enable(hdev);
+ if (rc) {
+ hid_err(hdev, "tablet enabling failed\n");
+ return rc;
+ }
+ drvdata->invert_pen_inrange = true;
+
+ rc = uclogic_button_enable(hdev);
+ drvdata->has_virtual_pad_interface = !rc;
+ } else {
+ drvdata->ignore_pen_usage = true;
+ }
+ }
+ break;
}
rc = hid_parse(hdev);
@@ -933,12 +1033,16 @@ static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
{
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
- if ((drvdata->invert_pen_inrange) &&
- (report->type == HID_INPUT_REPORT) &&
+ if ((report->type == HID_INPUT_REPORT) &&
(report->id == UCLOGIC_PEN_REPORT_ID) &&
- (size >= 2))
- /* Invert the in-range bit */
- data[1] ^= 0x40;
+ (size >= 2)) {
+ if (drvdata->has_virtual_pad_interface && (data[1] & 0x20))
+ /* Change to virtual frame button report ID */
+ data[0] = 0xf7;
+ else if (drvdata->invert_pen_inrange)
+ /* Invert the in-range bit */
+ data[1] ^= 0x40;
+ }
return 0;
}
@@ -960,6 +1064,11 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
{ }
};
MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
index 059931d7b392..a91aabe4a70a 100644
--- a/drivers/hid/hid-waltop.c
+++ b/drivers/hid/hid-waltop.c
@@ -42,11 +42,6 @@
* 02 16 02 ink
*/
-/*
- * See Slim Tablet 5.8 inch description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Slim_Tablet_5.8%22
- */
-
/* Size of the original report descriptor of Slim Tablet 5.8 inch */
#define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE 222
@@ -98,11 +93,6 @@ static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See Slim Tablet 12.1 inch description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Slim_Tablet_12.1%22
- */
-
/* Size of the original report descriptor of Slim Tablet 12.1 inch */
#define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE 269
@@ -154,11 +144,6 @@ static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See Q Pad description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Q_Pad
- */
-
/* Size of the original report descriptor of Q Pad */
#define Q_PAD_RDESC_ORIG_SIZE 241
@@ -210,11 +195,6 @@ static __u8 q_pad_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See description, device and HID report descriptors of tablet with PID 0038 at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_PID_0038
- */
-
/* Size of the original report descriptor of tablet with PID 0038 */
#define PID_0038_RDESC_ORIG_SIZE 241
@@ -268,11 +248,6 @@ static __u8 pid_0038_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See Media Tablet 10.6 inch description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Media_Tablet_10.6%22
- */
-
/* Size of the original report descriptor of Media Tablet 10.6 inch */
#define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE 300
@@ -386,11 +361,6 @@ static __u8 media_tablet_10_6_inch_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See Media Tablet 14.1 inch description, device and HID report descriptors at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Media_Tablet_14.1%22
- */
-
/* Size of the original report descriptor of Media Tablet 14.1 inch */
#define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE 309
@@ -502,12 +472,6 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-/*
- * See Sirius Battery Free Tablet description, device and HID report descriptors
- * at
- * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
- */
-
/* Size of the original report descriptor of Sirius Battery Free Tablet */
#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE 335
diff --git a/drivers/hid/intel-ish-hid/Kconfig b/drivers/hid/intel-ish-hid/Kconfig
new file mode 100644
index 000000000000..ea065b3684a2
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/Kconfig
@@ -0,0 +1,17 @@
+menu "Intel ISH HID support"
+ depends on X86_64 && PCI
+
+config INTEL_ISH_HID
+ tristate "Intel Integrated Sensor Hub"
+ default n
+ select HID
+ help
+ The Integrated Sensor Hub (ISH) enables the ability to offload
+ sensor polling and algorithm processing to a dedicated low power
+ processor in the chipset. This allows the core processor to go into
+ low power modes more often, resulting in the increased battery life.
+ The current processors that support ISH are: Cherrytrail, Skylake,
+ Broxton and Kaby Lake.
+
+ Say Y here if you want to support Intel ISH. If unsure, say N.
+endmenu
diff --git a/drivers/hid/intel-ish-hid/Makefile b/drivers/hid/intel-ish-hid/Makefile
new file mode 100644
index 000000000000..8c08b0b358b1
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile - Intel ISH HID drivers
+# Copyright (c) 2014-2016, Intel Corporation.
+#
+#
+obj-$(CONFIG_INTEL_ISH_HID) += intel-ishtp.o
+intel-ishtp-objs := ishtp/init.o
+intel-ishtp-objs += ishtp/hbm.o
+intel-ishtp-objs += ishtp/client.o
+intel-ishtp-objs += ishtp/bus.o
+intel-ishtp-objs += ishtp/dma-if.o
+intel-ishtp-objs += ishtp/client-buffers.o
+
+obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-ipc.o
+intel-ish-ipc-objs := ipc/ipc.o
+intel-ish-ipc-objs += ipc/pci-ish.o
+
+obj-$(CONFIG_INTEL_ISH_HID) += intel-ishtp-hid.o
+intel-ishtp-hid-objs := ishtp-hid.o
+intel-ishtp-hid-objs += ishtp-hid-client.o
+
+ccflags-y += -Idrivers/hid/intel-ish-hid/ishtp
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h b/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h
new file mode 100644
index 000000000000..ab68afcba2a2
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h
@@ -0,0 +1,220 @@
+/*
+ * ISH registers definitions
+ *
+ * Copyright (c) 2012-2016, 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.
+ */
+
+#ifndef _ISHTP_ISH_REGS_H_
+#define _ISHTP_ISH_REGS_H_
+
+
+/*** IPC PCI Offsets and sizes ***/
+/* ISH IPC Base Address */
+#define IPC_REG_BASE 0x0000
+/* Peripheral Interrupt Status Register */
+#define IPC_REG_PISR_CHV_AB (IPC_REG_BASE + 0x00)
+/* Peripheral Interrupt Mask Register */
+#define IPC_REG_PIMR_CHV_AB (IPC_REG_BASE + 0x04)
+/*BXT, CHV_K0*/
+/*Peripheral Interrupt Status Register */
+#define IPC_REG_PISR_BXT (IPC_REG_BASE + 0x0C)
+/*Peripheral Interrupt Mask Register */
+#define IPC_REG_PIMR_BXT (IPC_REG_BASE + 0x08)
+/***********************************/
+/* ISH Host Firmware status Register */
+#define IPC_REG_ISH_HOST_FWSTS (IPC_REG_BASE + 0x34)
+/* Host Communication Register */
+#define IPC_REG_HOST_COMM (IPC_REG_BASE + 0x38)
+/* Reset register */
+#define IPC_REG_ISH_RST (IPC_REG_BASE + 0x44)
+
+/* Inbound doorbell register Host to ISH */
+#define IPC_REG_HOST2ISH_DRBL (IPC_REG_BASE + 0x48)
+/* Outbound doorbell register ISH to Host */
+#define IPC_REG_ISH2HOST_DRBL (IPC_REG_BASE + 0x54)
+/* ISH to HOST message registers */
+#define IPC_REG_ISH2HOST_MSG (IPC_REG_BASE + 0x60)
+/* HOST to ISH message registers */
+#define IPC_REG_HOST2ISH_MSG (IPC_REG_BASE + 0xE0)
+/* REMAP2 to enable DMA (D3 RCR) */
+#define IPC_REG_ISH_RMP2 (IPC_REG_BASE + 0x368)
+
+#define IPC_REG_MAX (IPC_REG_BASE + 0x400)
+
+/*** register bits - HISR ***/
+/* bit corresponds HOST2ISH interrupt in PISR and PIMR registers */
+#define IPC_INT_HOST2ISH_BIT (1<<0)
+/***********************************/
+/*CHV_A0, CHV_B0*/
+/* bit corresponds ISH2HOST interrupt in PISR and PIMR registers */
+#define IPC_INT_ISH2HOST_BIT_CHV_AB (1<<3)
+/*BXT, CHV_K0*/
+/* bit corresponds ISH2HOST interrupt in PISR and PIMR registers */
+#define IPC_INT_ISH2HOST_BIT_BXT (1<<0)
+/***********************************/
+
+/* bit corresponds ISH2HOST busy clear interrupt in PIMR register */
+#define IPC_INT_ISH2HOST_CLR_MASK_BIT (1<<11)
+
+/* offset of ISH2HOST busy clear interrupt in IPC_BUSY_CLR register */
+#define IPC_INT_ISH2HOST_CLR_OFFS (0)
+
+/* bit corresponds ISH2HOST busy clear interrupt in IPC_BUSY_CLR register */
+#define IPC_INT_ISH2HOST_CLR_BIT (1<<IPC_INT_ISH2HOST_CLR_OFFS)
+
+/* bit corresponds busy bit in doorbell registers */
+#define IPC_DRBL_BUSY_OFFS (31)
+#define IPC_DRBL_BUSY_BIT (1<<IPC_DRBL_BUSY_OFFS)
+
+#define IPC_HOST_OWNS_MSG_OFFS (30)
+
+/*
+ * A0: bit means that host owns MSGnn registers and is reading them.
+ * ISH FW may not write to them
+ */
+#define IPC_HOST_OWNS_MSG_BIT (1<<IPC_HOST_OWNS_MSG_OFFS)
+
+/*
+ * Host status bits (HOSTCOMM)
+ */
+/* bit corresponds host ready bit in Host Status Register (HOST_COMM) */
+#define IPC_HOSTCOMM_READY_OFFS (7)
+#define IPC_HOSTCOMM_READY_BIT (1<<IPC_HOSTCOMM_READY_OFFS)
+
+/***********************************/
+/*CHV_A0, CHV_B0*/
+#define IPC_HOSTCOMM_INT_EN_OFFS_CHV_AB (31)
+#define IPC_HOSTCOMM_INT_EN_BIT_CHV_AB \
+ (1<<IPC_HOSTCOMM_INT_EN_OFFS_CHV_AB)
+/*BXT, CHV_K0*/
+#define IPC_PIMR_INT_EN_OFFS_BXT (0)
+#define IPC_PIMR_INT_EN_BIT_BXT (1<<IPC_PIMR_INT_EN_OFFS_BXT)
+
+#define IPC_HOST2ISH_BUSYCLEAR_MASK_OFFS_BXT (8)
+#define IPC_HOST2ISH_BUSYCLEAR_MASK_BIT \
+ (1<<IPC_HOST2ISH_BUSYCLEAR_MASK_OFFS_BXT)
+/***********************************/
+/*
+ * both Host and ISH have ILUP at bit 0
+ * bit corresponds host ready bit in both status registers
+ */
+#define IPC_ILUP_OFFS (0)
+#define IPC_ILUP_BIT (1<<IPC_ILUP_OFFS)
+
+/*
+ * FW status bits (relevant)
+ */
+#define IPC_FWSTS_ILUP 0x1
+#define IPC_FWSTS_ISHTP_UP (1<<1)
+#define IPC_FWSTS_DMA0 (1<<16)
+#define IPC_FWSTS_DMA1 (1<<17)
+#define IPC_FWSTS_DMA2 (1<<18)
+#define IPC_FWSTS_DMA3 (1<<19)
+
+#define IPC_ISH_IN_DMA \
+ (IPC_FWSTS_DMA0 | IPC_FWSTS_DMA1 | IPC_FWSTS_DMA2 | IPC_FWSTS_DMA3)
+
+/* bit corresponds host ready bit in ISH FW Status Register */
+#define IPC_ISH_ISHTP_READY_OFFS (1)
+#define IPC_ISH_ISHTP_READY_BIT (1<<IPC_ISH_ISHTP_READY_OFFS)
+
+#define IPC_RMP2_DMA_ENABLED 0x1 /* Value to enable DMA, per D3 RCR */
+
+#define IPC_MSG_MAX_SIZE 0x80
+
+
+#define IPC_HEADER_LENGTH_MASK 0x03FF
+#define IPC_HEADER_PROTOCOL_MASK 0x0F
+#define IPC_HEADER_MNG_CMD_MASK 0x0F
+
+#define IPC_HEADER_LENGTH_OFFSET 0
+#define IPC_HEADER_PROTOCOL_OFFSET 10
+#define IPC_HEADER_MNG_CMD_OFFSET 16
+
+#define IPC_HEADER_GET_LENGTH(drbl_reg) \
+ (((drbl_reg) >> IPC_HEADER_LENGTH_OFFSET)&IPC_HEADER_LENGTH_MASK)
+#define IPC_HEADER_GET_PROTOCOL(drbl_reg) \
+ (((drbl_reg) >> IPC_HEADER_PROTOCOL_OFFSET)&IPC_HEADER_PROTOCOL_MASK)
+#define IPC_HEADER_GET_MNG_CMD(drbl_reg) \
+ (((drbl_reg) >> IPC_HEADER_MNG_CMD_OFFSET)&IPC_HEADER_MNG_CMD_MASK)
+
+#define IPC_IS_BUSY(drbl_reg) \
+ (((drbl_reg)&IPC_DRBL_BUSY_BIT) == ((uint32_t)IPC_DRBL_BUSY_BIT))
+
+/***********************************/
+/*CHV_A0, CHV_B0*/
+#define IPC_INT_FROM_ISH_TO_HOST_CHV_AB(drbl_reg) \
+ (((drbl_reg)&IPC_INT_ISH2HOST_BIT_CHV_AB) == \
+ ((u32)IPC_INT_ISH2HOST_BIT_CHV_AB))
+/*BXT, CHV_K0*/
+#define IPC_INT_FROM_ISH_TO_HOST_BXT(drbl_reg) \
+ (((drbl_reg)&IPC_INT_ISH2HOST_BIT_BXT) == \
+ ((u32)IPC_INT_ISH2HOST_BIT_BXT))
+/***********************************/
+
+#define IPC_BUILD_HEADER(length, protocol, busy) \
+ (((busy)<<IPC_DRBL_BUSY_OFFS) | \
+ ((protocol) << IPC_HEADER_PROTOCOL_OFFSET) | \
+ ((length)<<IPC_HEADER_LENGTH_OFFSET))
+
+#define IPC_BUILD_MNG_MSG(cmd, length) \
+ (((1)<<IPC_DRBL_BUSY_OFFS)| \
+ ((IPC_PROTOCOL_MNG)<<IPC_HEADER_PROTOCOL_OFFSET)| \
+ ((cmd)<<IPC_HEADER_MNG_CMD_OFFSET)| \
+ ((length)<<IPC_HEADER_LENGTH_OFFSET))
+
+
+#define IPC_SET_HOST_READY(host_status) \
+ ((host_status) |= (IPC_HOSTCOMM_READY_BIT))
+
+#define IPC_SET_HOST_ILUP(host_status) \
+ ((host_status) |= (IPC_ILUP_BIT))
+
+#define IPC_CLEAR_HOST_READY(host_status) \
+ ((host_status) ^= (IPC_HOSTCOMM_READY_BIT))
+
+#define IPC_CLEAR_HOST_ILUP(host_status) \
+ ((host_status) ^= (IPC_ILUP_BIT))
+
+/* todo - temp until PIMR HW ready */
+#define IPC_HOST_BUSY_READING_OFFS 6
+
+/* bit corresponds host ready bit in Host Status Register (HOST_COMM) */
+#define IPC_HOST_BUSY_READING_BIT (1<<IPC_HOST_BUSY_READING_OFFS)
+
+#define IPC_SET_HOST_BUSY_READING(host_status) \
+ ((host_status) |= (IPC_HOST_BUSY_READING_BIT))
+
+#define IPC_CLEAR_HOST_BUSY_READING(host_status)\
+ ((host_status) ^= (IPC_HOST_BUSY_READING_BIT))
+
+
+#define IPC_IS_ISH_ISHTP_READY(ish_status) \
+ (((ish_status) & IPC_ISH_ISHTP_READY_BIT) == \
+ ((uint32_t)IPC_ISH_ISHTP_READY_BIT))
+
+#define IPC_IS_ISH_ILUP(ish_status) \
+ (((ish_status) & IPC_ILUP_BIT) == ((uint32_t)IPC_ILUP_BIT))
+
+
+#define IPC_PROTOCOL_ISHTP 1
+#define IPC_PROTOCOL_MNG 3
+
+#define MNG_RX_CMPL_ENABLE 0
+#define MNG_RX_CMPL_DISABLE 1
+#define MNG_RX_CMPL_INDICATION 2
+#define MNG_RESET_NOTIFY 3
+#define MNG_RESET_NOTIFY_ACK 4
+#define MNG_SYNC_FW_CLOCK 5
+#define MNG_ILLEGAL_CMD 0xFF
+
+#endif /* _ISHTP_ISH_REGS_H_ */
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
new file mode 100644
index 000000000000..46615a03e78f
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -0,0 +1,71 @@
+/*
+ * H/W layer of ISHTP provider device (ISH)
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+
+#ifndef _ISHTP_HW_ISH_H_
+#define _ISHTP_HW_ISH_H_
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include "hw-ish-regs.h"
+#include "ishtp-dev.h"
+
+#define CHV_DEVICE_ID 0x22D8
+#define BXT_Ax_DEVICE_ID 0x0AA2
+#define BXT_Bx_DEVICE_ID 0x1AA2
+#define APL_Ax_DEVICE_ID 0x5AA2
+#define SPT_Ax_DEVICE_ID 0x9D35
+
+#define REVISION_ID_CHT_A0 0x6
+#define REVISION_ID_CHT_Ax_SI 0x0
+#define REVISION_ID_CHT_Bx_SI 0x10
+#define REVISION_ID_CHT_Kx_SI 0x20
+#define REVISION_ID_CHT_Dx_SI 0x30
+#define REVISION_ID_CHT_B0 0xB0
+#define REVISION_ID_SI_MASK 0x70
+
+struct ipc_rst_payload_type {
+ uint16_t reset_id;
+ uint16_t reserved;
+};
+
+struct time_sync_format {
+ uint8_t ts1_source;
+ uint8_t ts2_source;
+ uint16_t reserved;
+} __packed;
+
+struct ipc_time_update_msg {
+ uint64_t primary_host_time;
+ struct time_sync_format sync_info;
+ uint64_t secondary_host_time;
+} __packed;
+
+enum {
+ HOST_UTC_TIME_USEC = 0,
+ HOST_SYSTEM_TIME_USEC = 1
+};
+
+struct ish_hw {
+ void __iomem *mem_addr;
+};
+
+#define to_ish_hw(dev) (struct ish_hw *)((dev)->hw)
+
+irqreturn_t ish_irq_handler(int irq, void *dev_id);
+struct ishtp_device *ish_dev_init(struct pci_dev *pdev);
+int ish_hw_start(struct ishtp_device *dev);
+void ish_device_disable(struct ishtp_device *dev);
+
+#endif /* _ISHTP_HW_ISH_H_ */
diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c
new file mode 100644
index 000000000000..e2517c11e0ee
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ipc/ipc.c
@@ -0,0 +1,881 @@
+/*
+ * H/W layer of ISHTP provider device (ISH)
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include "client.h"
+#include "hw-ish.h"
+#include "utils.h"
+#include "hbm.h"
+
+/* For FW reset flow */
+static struct work_struct fw_reset_work;
+static struct ishtp_device *ishtp_dev;
+
+/**
+ * ish_reg_read() - Read register
+ * @dev: ISHTP device pointer
+ * @offset: Register offset
+ *
+ * Read 32 bit register at a given offset
+ *
+ * Return: Read register value
+ */
+static inline uint32_t ish_reg_read(const struct ishtp_device *dev,
+ unsigned long offset)
+{
+ struct ish_hw *hw = to_ish_hw(dev);
+
+ return readl(hw->mem_addr + offset);
+}
+
+/**
+ * ish_reg_write() - Write register
+ * @dev: ISHTP device pointer
+ * @offset: Register offset
+ * @value: Value to write
+ *
+ * Writes 32 bit register at a give offset
+ */
+static inline void ish_reg_write(struct ishtp_device *dev,
+ unsigned long offset,
+ uint32_t value)
+{
+ struct ish_hw *hw = to_ish_hw(dev);
+
+ writel(value, hw->mem_addr + offset);
+}
+
+/**
+ * _ish_read_fw_sts_reg() - Read FW status register
+ * @dev: ISHTP device pointer
+ *
+ * Read FW status register
+ *
+ * Return: Read register value
+ */
+static inline uint32_t _ish_read_fw_sts_reg(struct ishtp_device *dev)
+{
+ return ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+}
+
+/**
+ * check_generated_interrupt() - Check if ISH interrupt
+ * @dev: ISHTP device pointer
+ *
+ * Check if an interrupt was generated for ISH
+ *
+ * Return: Read true or false
+ */
+static bool check_generated_interrupt(struct ishtp_device *dev)
+{
+ bool interrupt_generated = true;
+ uint32_t pisr_val = 0;
+
+ if (dev->pdev->device == CHV_DEVICE_ID) {
+ pisr_val = ish_reg_read(dev, IPC_REG_PISR_CHV_AB);
+ interrupt_generated =
+ IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val);
+ } else {
+ pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT);
+ interrupt_generated = IPC_INT_FROM_ISH_TO_HOST_BXT(pisr_val);
+ }
+
+ return interrupt_generated;
+}
+
+/**
+ * ish_is_input_ready() - Check if FW ready for RX
+ * @dev: ISHTP device pointer
+ *
+ * Check if ISH FW is ready for receiving data
+ *
+ * Return: Read true or false
+ */
+static bool ish_is_input_ready(struct ishtp_device *dev)
+{
+ uint32_t doorbell_val;
+
+ doorbell_val = ish_reg_read(dev, IPC_REG_HOST2ISH_DRBL);
+ return !IPC_IS_BUSY(doorbell_val);
+}
+
+/**
+ * set_host_ready() - Indicate host ready
+ * @dev: ISHTP device pointer
+ *
+ * Set host ready indication to FW
+ */
+static void set_host_ready(struct ishtp_device *dev)
+{
+ if (dev->pdev->device == CHV_DEVICE_ID) {
+ if (dev->pdev->revision == REVISION_ID_CHT_A0 ||
+ (dev->pdev->revision & REVISION_ID_SI_MASK) ==
+ REVISION_ID_CHT_Ax_SI)
+ ish_reg_write(dev, IPC_REG_HOST_COMM, 0x81);
+ else if (dev->pdev->revision == REVISION_ID_CHT_B0 ||
+ (dev->pdev->revision & REVISION_ID_SI_MASK) ==
+ REVISION_ID_CHT_Bx_SI ||
+ (dev->pdev->revision & REVISION_ID_SI_MASK) ==
+ REVISION_ID_CHT_Kx_SI ||
+ (dev->pdev->revision & REVISION_ID_SI_MASK) ==
+ REVISION_ID_CHT_Dx_SI) {
+ uint32_t host_comm_val;
+
+ host_comm_val = ish_reg_read(dev, IPC_REG_HOST_COMM);
+ host_comm_val |= IPC_HOSTCOMM_INT_EN_BIT_CHV_AB | 0x81;
+ ish_reg_write(dev, IPC_REG_HOST_COMM, host_comm_val);
+ }
+ } else {
+ uint32_t host_pimr_val;
+
+ host_pimr_val = ish_reg_read(dev, IPC_REG_PIMR_BXT);
+ host_pimr_val |= IPC_PIMR_INT_EN_BIT_BXT;
+ /*
+ * disable interrupt generated instead of
+ * RX_complete_msg
+ */
+ host_pimr_val &= ~IPC_HOST2ISH_BUSYCLEAR_MASK_BIT;
+
+ ish_reg_write(dev, IPC_REG_PIMR_BXT, host_pimr_val);
+ }
+}
+
+/**
+ * ishtp_fw_is_ready() - Check if FW ready
+ * @dev: ISHTP device pointer
+ *
+ * Check if ISH FW is ready
+ *
+ * Return: Read true or false
+ */
+static bool ishtp_fw_is_ready(struct ishtp_device *dev)
+{
+ uint32_t ish_status = _ish_read_fw_sts_reg(dev);
+
+ return IPC_IS_ISH_ILUP(ish_status) &&
+ IPC_IS_ISH_ISHTP_READY(ish_status);
+}
+
+/**
+ * ish_set_host_rdy() - Indicate host ready
+ * @dev: ISHTP device pointer
+ *
+ * Set host ready indication to FW
+ */
+static void ish_set_host_rdy(struct ishtp_device *dev)
+{
+ uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);
+
+ IPC_SET_HOST_READY(host_status);
+ ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);
+}
+
+/**
+ * ish_clr_host_rdy() - Indicate host not ready
+ * @dev: ISHTP device pointer
+ *
+ * Send host not ready indication to FW
+ */
+static void ish_clr_host_rdy(struct ishtp_device *dev)
+{
+ uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);
+
+ IPC_CLEAR_HOST_READY(host_status);
+ ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);
+}
+
+/**
+ * _ishtp_read_hdr() - Read message header
+ * @dev: ISHTP device pointer
+ *
+ * Read header of 32bit length
+ *
+ * Return: Read register value
+ */
+static uint32_t _ishtp_read_hdr(const struct ishtp_device *dev)
+{
+ return ish_reg_read(dev, IPC_REG_ISH2HOST_MSG);
+}
+
+/**
+ * _ishtp_read - Read message
+ * @dev: ISHTP device pointer
+ * @buffer: message buffer
+ * @buffer_length: length of message buffer
+ *
+ * Read message from FW
+ *
+ * Return: Always 0
+ */
+static int _ishtp_read(struct ishtp_device *dev, unsigned char *buffer,
+ unsigned long buffer_length)
+{
+ uint32_t i;
+ uint32_t *r_buf = (uint32_t *)buffer;
+ uint32_t msg_offs;
+
+ msg_offs = IPC_REG_ISH2HOST_MSG + sizeof(struct ishtp_msg_hdr);
+ for (i = 0; i < buffer_length; i += sizeof(uint32_t))
+ *r_buf++ = ish_reg_read(dev, msg_offs + i);
+
+ return 0;
+}
+
+/**
+ * write_ipc_from_queue() - try to write ipc msg from Tx queue to device
+ * @dev: ishtp device pointer
+ *
+ * Check if DRBL is cleared. if it is - write the first IPC msg, then call
+ * the callback function (unless it's NULL)
+ *
+ * Return: 0 for success else failure code
+ */
+static int write_ipc_from_queue(struct ishtp_device *dev)
+{
+ struct wr_msg_ctl_info *ipc_link;
+ unsigned long length;
+ unsigned long rem;
+ unsigned long flags;
+ uint32_t doorbell_val;
+ uint32_t *r_buf;
+ uint32_t reg_addr;
+ int i;
+ void (*ipc_send_compl)(void *);
+ void *ipc_send_compl_prm;
+ static int out_ipc_locked;
+ unsigned long out_ipc_flags;
+
+ if (dev->dev_state == ISHTP_DEV_DISABLED)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->out_ipc_spinlock, out_ipc_flags);
+ if (out_ipc_locked) {
+ spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
+ return -EBUSY;
+ }
+ out_ipc_locked = 1;
+ if (!ish_is_input_ready(dev)) {
+ out_ipc_locked = 0;
+ spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
+
+ spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
+ /*
+ * if tx send list is empty - return 0;
+ * may happen, as RX_COMPLETE handler doesn't check list emptiness.
+ */
+ if (list_empty(&dev->wr_processing_list_head.link)) {
+ spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
+ out_ipc_locked = 0;
+ return 0;
+ }
+
+ ipc_link = list_entry(dev->wr_processing_list_head.link.next,
+ struct wr_msg_ctl_info, link);
+ /* first 4 bytes of the data is the doorbell value (IPC header) */
+ length = ipc_link->length - sizeof(uint32_t);
+ doorbell_val = *(uint32_t *)ipc_link->inline_data;
+ r_buf = (uint32_t *)(ipc_link->inline_data + sizeof(uint32_t));
+
+ /* If sending MNG_SYNC_FW_CLOCK, update clock again */
+ if (IPC_HEADER_GET_PROTOCOL(doorbell_val) == IPC_PROTOCOL_MNG &&
+ IPC_HEADER_GET_MNG_CMD(doorbell_val) == MNG_SYNC_FW_CLOCK) {
+ struct timespec ts_system;
+ struct timeval tv_utc;
+ uint64_t usec_system, usec_utc;
+ struct ipc_time_update_msg time_update;
+ struct time_sync_format ts_format;
+
+ get_monotonic_boottime(&ts_system);
+ do_gettimeofday(&tv_utc);
+ usec_system = (timespec_to_ns(&ts_system)) / NSEC_PER_USEC;
+ usec_utc = (uint64_t)tv_utc.tv_sec * 1000000 +
+ ((uint32_t)tv_utc.tv_usec);
+ ts_format.ts1_source = HOST_SYSTEM_TIME_USEC;
+ ts_format.ts2_source = HOST_UTC_TIME_USEC;
+
+ time_update.primary_host_time = usec_system;
+ time_update.secondary_host_time = usec_utc;
+ time_update.sync_info = ts_format;
+
+ memcpy(r_buf, &time_update,
+ sizeof(struct ipc_time_update_msg));
+ }
+
+ for (i = 0, reg_addr = IPC_REG_HOST2ISH_MSG; i < length >> 2; i++,
+ reg_addr += 4)
+ ish_reg_write(dev, reg_addr, r_buf[i]);
+
+ rem = length & 0x3;
+ if (rem > 0) {
+ uint32_t reg = 0;
+
+ memcpy(&reg, &r_buf[length >> 2], rem);
+ ish_reg_write(dev, reg_addr, reg);
+ }
+ /* Flush writes to msg registers and doorbell */
+ ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+
+ /* Update IPC counters */
+ ++dev->ipc_tx_cnt;
+ dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
+
+ ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
+ out_ipc_locked = 0;
+
+ ipc_send_compl = ipc_link->ipc_send_compl;
+ ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
+ list_del_init(&ipc_link->link);
+ list_add_tail(&ipc_link->link, &dev->wr_free_list_head.link);
+ spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
+
+ /*
+ * callback will be called out of spinlock,
+ * after ipc_link returned to free list
+ */
+ if (ipc_send_compl)
+ ipc_send_compl(ipc_send_compl_prm);
+
+ return 0;
+}
+
+/**
+ * write_ipc_to_queue() - write ipc msg to Tx queue
+ * @dev: ishtp device instance
+ * @ipc_send_compl: Send complete callback
+ * @ipc_send_compl_prm: Parameter to send in complete callback
+ * @msg: Pointer to message
+ * @length: Length of message
+ *
+ * Recived msg with IPC (and upper protocol) header and add it to the device
+ * Tx-to-write list then try to send the first IPC waiting msg
+ * (if DRBL is cleared)
+ * This function returns negative value for failure (means free list
+ * is empty, or msg too long) and 0 for success.
+ *
+ * Return: 0 for success else failure code
+ */
+static int write_ipc_to_queue(struct ishtp_device *dev,
+ void (*ipc_send_compl)(void *), void *ipc_send_compl_prm,
+ unsigned char *msg, int length)
+{
+ struct wr_msg_ctl_info *ipc_link;
+ unsigned long flags;
+
+ if (length > IPC_FULL_MSG_SIZE)
+ return -EMSGSIZE;
+
+ spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
+ if (list_empty(&dev->wr_free_list_head.link)) {
+ spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
+ return -ENOMEM;
+ }
+ ipc_link = list_entry(dev->wr_free_list_head.link.next,
+ struct wr_msg_ctl_info, link);
+ list_del_init(&ipc_link->link);
+
+ ipc_link->ipc_send_compl = ipc_send_compl;
+ ipc_link->ipc_send_compl_prm = ipc_send_compl_prm;
+ ipc_link->length = length;
+ memcpy(ipc_link->inline_data, msg, length);
+
+ list_add_tail(&ipc_link->link, &dev->wr_processing_list_head.link);
+ spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
+
+ write_ipc_from_queue(dev);
+
+ return 0;
+}
+
+/**
+ * ipc_send_mng_msg() - Send management message
+ * @dev: ishtp device instance
+ * @msg_code: Message code
+ * @msg: Pointer to message
+ * @size: Length of message
+ *
+ * Send management message to FW
+ *
+ * Return: 0 for success else failure code
+ */
+static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code,
+ void *msg, size_t size)
+{
+ unsigned char ipc_msg[IPC_FULL_MSG_SIZE];
+ uint32_t drbl_val = IPC_BUILD_MNG_MSG(msg_code, size);
+
+ memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));
+ memcpy(ipc_msg + sizeof(uint32_t), msg, size);
+ return write_ipc_to_queue(dev, NULL, NULL, ipc_msg,
+ sizeof(uint32_t) + size);
+}
+
+/**
+ * ish_fw_reset_handler() - FW reset handler
+ * @dev: ishtp device pointer
+ *
+ * Handle FW reset
+ *
+ * Return: 0 for success else failure code
+ */
+static int ish_fw_reset_handler(struct ishtp_device *dev)
+{
+ uint32_t reset_id;
+ unsigned long flags;
+ struct wr_msg_ctl_info *processing, *next;
+
+ /* Read reset ID */
+ reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
+
+ /* Clear IPC output queue */
+ spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
+ list_for_each_entry_safe(processing, next,
+ &dev->wr_processing_list_head.link, link) {
+ list_move_tail(&processing->link, &dev->wr_free_list_head.link);
+ }
+ spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
+
+ /* ISHTP notification in IPC_RESET */
+ ishtp_reset_handler(dev);
+
+ if (!ish_is_input_ready(dev))
+ timed_wait_for_timeout(WAIT_FOR_SEND_SLICE,
+ ish_is_input_ready(dev), (2 * HZ));
+
+ /* ISH FW is dead */
+ if (!ish_is_input_ready(dev))
+ return -EPIPE;
+ /*
+ * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending
+ * RESET_NOTIFY_ACK - FW will be checking for it
+ */
+ ish_set_host_rdy(dev);
+ /* Send RESET_NOTIFY_ACK (with reset_id) */
+ ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id,
+ sizeof(uint32_t));
+
+ /* Wait for ISH FW'es ILUP and ISHTP_READY */
+ timed_wait_for_timeout(WAIT_FOR_SEND_SLICE, ishtp_fw_is_ready(dev),
+ (2 * HZ));
+ if (!ishtp_fw_is_ready(dev)) {
+ /* ISH FW is dead */
+ uint32_t ish_status;
+
+ ish_status = _ish_read_fw_sts_reg(dev);
+ dev_err(dev->devc,
+ "[ishtp-ish]: completed reset, ISH is dead (FWSTS = %08X)\n",
+ ish_status);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * ish_fw_reset_work_fn() - FW reset worker function
+ * @unused: not used
+ *
+ * Call ish_fw_reset_handler to complete FW reset
+ */
+static void fw_reset_work_fn(struct work_struct *unused)
+{
+ int rv;
+
+ rv = ish_fw_reset_handler(ishtp_dev);
+ if (!rv) {
+ /* ISH is ILUP & ISHTP-ready. Restart ISHTP */
+ schedule_timeout(HZ / 3);
+ ishtp_dev->recvd_hw_ready = 1;
+ wake_up_interruptible(&ishtp_dev->wait_hw_ready);
+
+ /* ISHTP notification in IPC_RESET sequence completion */
+ ishtp_reset_compl_handler(ishtp_dev);
+ } else
+ dev_err(ishtp_dev->devc, "[ishtp-ish]: FW reset failed (%d)\n",
+ rv);
+}
+
+/**
+ * _ish_sync_fw_clock() -Sync FW clock with the OS clock
+ * @dev: ishtp device pointer
+ *
+ * Sync FW and OS time
+ */
+static void _ish_sync_fw_clock(struct ishtp_device *dev)
+{
+ static unsigned long prev_sync;
+ struct timespec ts;
+ uint64_t usec;
+
+ if (prev_sync && jiffies - prev_sync < 20 * HZ)
+ return;
+
+ prev_sync = jiffies;
+ get_monotonic_boottime(&ts);
+ usec = (timespec_to_ns(&ts)) / NSEC_PER_USEC;
+ ipc_send_mng_msg(dev, MNG_SYNC_FW_CLOCK, &usec, sizeof(uint64_t));
+}
+
+/**
+ * recv_ipc() - Receive and process IPC management messages
+ * @dev: ishtp device instance
+ * @doorbell_val: doorbell value
+ *
+ * This function runs in ISR context.
+ * NOTE: Any other mng command than reset_notify and reset_notify_ack
+ * won't wake BH handler
+ */
+static void recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)
+{
+ uint32_t mng_cmd;
+
+ mng_cmd = IPC_HEADER_GET_MNG_CMD(doorbell_val);
+
+ switch (mng_cmd) {
+ default:
+ break;
+
+ case MNG_RX_CMPL_INDICATION:
+ if (dev->suspend_flag) {
+ dev->suspend_flag = 0;
+ wake_up_interruptible(&dev->suspend_wait);
+ }
+ if (dev->resume_flag) {
+ dev->resume_flag = 0;
+ wake_up_interruptible(&dev->resume_wait);
+ }
+
+ write_ipc_from_queue(dev);
+ break;
+
+ case MNG_RESET_NOTIFY:
+ if (!ishtp_dev) {
+ ishtp_dev = dev;
+ INIT_WORK(&fw_reset_work, fw_reset_work_fn);
+ }
+ schedule_work(&fw_reset_work);
+ break;
+
+ case MNG_RESET_NOTIFY_ACK:
+ dev->recvd_hw_ready = 1;
+ wake_up_interruptible(&dev->wait_hw_ready);
+ break;
+ }
+}
+
+/**
+ * ish_irq_handler() - ISH IRQ handler
+ * @irq: irq number
+ * @dev_id: ishtp device pointer
+ *
+ * ISH IRQ handler. If interrupt is generated and is for ISH it will process
+ * the interrupt.
+ */
+irqreturn_t ish_irq_handler(int irq, void *dev_id)
+{
+ struct ishtp_device *dev = dev_id;
+ uint32_t doorbell_val;
+ bool interrupt_generated;
+
+ /* Check that it's interrupt from ISH (may be shared) */
+ interrupt_generated = check_generated_interrupt(dev);
+
+ if (!interrupt_generated)
+ return IRQ_NONE;
+
+ doorbell_val = ish_reg_read(dev, IPC_REG_ISH2HOST_DRBL);
+ if (!IPC_IS_BUSY(doorbell_val))
+ return IRQ_HANDLED;
+
+ if (dev->dev_state == ISHTP_DEV_DISABLED)
+ return IRQ_HANDLED;
+
+ /* Sanity check: IPC dgram length in header */
+ if (IPC_HEADER_GET_LENGTH(doorbell_val) > IPC_PAYLOAD_SIZE) {
+ dev_err(dev->devc,
+ "IPC hdr - bad length: %u; dropped\n",
+ (unsigned int)IPC_HEADER_GET_LENGTH(doorbell_val));
+ goto eoi;
+ }
+
+ switch (IPC_HEADER_GET_PROTOCOL(doorbell_val)) {
+ default:
+ break;
+ case IPC_PROTOCOL_MNG:
+ recv_ipc(dev, doorbell_val);
+ break;
+ case IPC_PROTOCOL_ISHTP:
+ ishtp_recv(dev);
+ break;
+ }
+
+eoi:
+ /* Update IPC counters */
+ ++dev->ipc_rx_cnt;
+ dev->ipc_rx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
+
+ ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);
+ /* Flush write to doorbell */
+ ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * _ish_hw_reset() - HW reset
+ * @dev: ishtp device pointer
+ *
+ * Reset ISH HW to recover if any error
+ *
+ * Return: 0 for success else error fault code
+ */
+static int _ish_hw_reset(struct ishtp_device *dev)
+{
+ struct pci_dev *pdev = dev->pdev;
+ int rv;
+ unsigned int dma_delay;
+ uint16_t csr;
+
+ if (!pdev)
+ return -ENODEV;
+
+ rv = pci_reset_function(pdev);
+ if (!rv)
+ dev->dev_state = ISHTP_DEV_RESETTING;
+
+ if (!pdev->pm_cap) {
+ dev_err(&pdev->dev, "Can't reset - no PM caps\n");
+ return -EINVAL;
+ }
+
+ /* Now trigger reset to FW */
+ ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);
+
+ for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&
+ _ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);
+ dma_delay += 5)
+ mdelay(5);
+
+ if (dma_delay >= MAX_DMA_DELAY) {
+ dev_err(&pdev->dev,
+ "Can't reset - stuck with DMA in-progress\n");
+ return -EBUSY;
+ }
+
+ pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &csr);
+
+ csr &= ~PCI_PM_CTRL_STATE_MASK;
+ csr |= PCI_D3hot;
+ pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
+
+ mdelay(pdev->d3_delay);
+
+ csr &= ~PCI_PM_CTRL_STATE_MASK;
+ csr |= PCI_D0;
+ pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
+
+ ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
+
+ /*
+ * Send 0 IPC message so that ISH FW wakes up if it was already
+ * asleep
+ */
+ ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
+
+ /* Flush writes to doorbell and REMAP2 */
+ ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+
+ return 0;
+}
+
+/**
+ * _ish_ipc_reset() - IPC reset
+ * @dev: ishtp device pointer
+ *
+ * Resets host and fw IPC and upper layers
+ *
+ * Return: 0 for success else error fault code
+ */
+static int _ish_ipc_reset(struct ishtp_device *dev)
+{
+ struct ipc_rst_payload_type ipc_mng_msg;
+ int rv = 0;
+
+ ipc_mng_msg.reset_id = 1;
+ ipc_mng_msg.reserved = 0;
+
+ set_host_ready(dev);
+
+ /* Clear the incoming doorbell */
+ ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);
+ /* Flush write to doorbell */
+ ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+
+ dev->recvd_hw_ready = 0;
+
+ /* send message */
+ rv = ipc_send_mng_msg(dev, MNG_RESET_NOTIFY, &ipc_mng_msg,
+ sizeof(struct ipc_rst_payload_type));
+ if (rv) {
+ dev_err(dev->devc, "Failed to send IPC MNG_RESET_NOTIFY\n");
+ return rv;
+ }
+
+ wait_event_interruptible_timeout(dev->wait_hw_ready,
+ dev->recvd_hw_ready, 2 * HZ);
+ if (!dev->recvd_hw_ready) {
+ dev_err(dev->devc, "Timed out waiting for HW ready\n");
+ rv = -ENODEV;
+ }
+
+ return rv;
+}
+
+/**
+ * ish_hw_start() -Start ISH HW
+ * @dev: ishtp device pointer
+ *
+ * Set host to ready state and wait for FW reset
+ *
+ * Return: 0 for success else error fault code
+ */
+int ish_hw_start(struct ishtp_device *dev)
+{
+ ish_set_host_rdy(dev);
+ /* After that we can enable ISH DMA operation */
+ ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
+
+ /*
+ * Send 0 IPC message so that ISH FW wakes up if it was already
+ * asleep
+ */
+ ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
+ /* Flush write to doorbell */
+ ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+
+ set_host_ready(dev);
+
+ /* wait for FW-initiated reset flow */
+ if (!dev->recvd_hw_ready)
+ wait_event_interruptible_timeout(dev->wait_hw_ready,
+ dev->recvd_hw_ready,
+ 10 * HZ);
+
+ if (!dev->recvd_hw_ready) {
+ dev_err(dev->devc,
+ "[ishtp-ish]: Timed out waiting for FW-initiated reset\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * ish_ipc_get_header() -Get doorbell value
+ * @dev: ishtp device pointer
+ * @length: length of message
+ * @busy: busy status
+ *
+ * Get door bell value from message header
+ *
+ * Return: door bell value
+ */
+static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,
+ int busy)
+{
+ uint32_t drbl_val;
+
+ drbl_val = IPC_BUILD_HEADER(length, IPC_PROTOCOL_ISHTP, busy);
+
+ return drbl_val;
+}
+
+static const struct ishtp_hw_ops ish_hw_ops = {
+ .hw_reset = _ish_hw_reset,
+ .ipc_reset = _ish_ipc_reset,
+ .ipc_get_header = ish_ipc_get_header,
+ .ishtp_read = _ishtp_read,
+ .write = write_ipc_to_queue,
+ .get_fw_status = _ish_read_fw_sts_reg,
+ .sync_fw_clock = _ish_sync_fw_clock,
+ .ishtp_read_hdr = _ishtp_read_hdr
+};
+
+/**
+ * ish_dev_init() -Initialize ISH devoce
+ * @pdev: PCI device
+ *
+ * Allocate ISHTP device and initialize IPC processing
+ *
+ * Return: ISHTP device instance on success else NULL
+ */
+struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
+{
+ struct ishtp_device *dev;
+ int i;
+
+ dev = kzalloc(sizeof(struct ishtp_device) + sizeof(struct ish_hw),
+ GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ ishtp_device_init(dev);
+
+ init_waitqueue_head(&dev->wait_hw_ready);
+
+ spin_lock_init(&dev->wr_processing_spinlock);
+ spin_lock_init(&dev->out_ipc_spinlock);
+
+ /* Init IPC processing and free lists */
+ INIT_LIST_HEAD(&dev->wr_processing_list_head.link);
+ INIT_LIST_HEAD(&dev->wr_free_list_head.link);
+ for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) {
+ struct wr_msg_ctl_info *tx_buf;
+
+ tx_buf = kzalloc(sizeof(struct wr_msg_ctl_info), GFP_KERNEL);
+ if (!tx_buf) {
+ /*
+ * IPC buffers may be limited or not available
+ * at all - although this shouldn't happen
+ */
+ dev_err(dev->devc,
+ "[ishtp-ish]: failure in Tx FIFO allocations (%d)\n",
+ i);
+ break;
+ }
+ list_add_tail(&tx_buf->link, &dev->wr_free_list_head.link);
+ }
+
+ dev->ops = &ish_hw_ops;
+ dev->devc = &pdev->dev;
+ dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr);
+ return dev;
+}
+
+/**
+ * ish_device_disable() - Disable ISH device
+ * @dev: ISHTP device pointer
+ *
+ * Disable ISH by clearing host ready to inform firmware.
+ */
+void ish_device_disable(struct ishtp_device *dev)
+{
+ dev->dev_state = ISHTP_DEV_DISABLED;
+ ish_clr_host_rdy(dev);
+}
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
new file mode 100644
index 000000000000..42f0beeb09fd
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -0,0 +1,322 @@
+/*
+ * PCI glue for ISHTP provider device (ISH) driver
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/miscdevice.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/intel_ish.h>
+#include "ishtp-dev.h"
+#include "hw-ish.h"
+
+static const struct pci_device_id ish_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CHV_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Ax_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Bx_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, APL_Ax_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)},
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
+
+/**
+ * ish_event_tracer() - Callback function to dump trace messages
+ * @dev: ishtp device
+ * @format: printf style format
+ *
+ * Callback to direct log messages to Linux trace buffers
+ */
+static void ish_event_tracer(struct ishtp_device *dev, char *format, ...)
+{
+ if (trace_ishtp_dump_enabled()) {
+ va_list args;
+ char tmp_buf[100];
+
+ va_start(args, format);
+ vsnprintf(tmp_buf, sizeof(tmp_buf), format, args);
+ va_end(args);
+
+ trace_ishtp_dump(tmp_buf);
+ }
+}
+
+/**
+ * ish_init() - Init function
+ * @dev: ishtp device
+ *
+ * This function initialize wait queues for suspend/resume and call
+ * calls hadware initialization function. This will initiate
+ * startup sequence
+ *
+ * Return: 0 for success or error code for failure
+ */
+static int ish_init(struct ishtp_device *dev)
+{
+ int ret;
+
+ /* Set the state of ISH HW to start */
+ ret = ish_hw_start(dev);
+ if (ret) {
+ dev_err(dev->devc, "ISH: hw start failed.\n");
+ return ret;
+ }
+
+ /* Start the inter process communication to ISH processor */
+ ret = ishtp_start(dev);
+ if (ret) {
+ dev_err(dev->devc, "ISHTP: Protocol init failed.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * ish_probe() - PCI driver probe callback
+ * @pdev: pci device
+ * @ent: pci device id
+ *
+ * Initialize PCI function, setup interrupt and call for ISH initialization
+ *
+ * Return: 0 for success or error code for failure
+ */
+static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct ishtp_device *dev;
+ struct ish_hw *hw;
+ int ret;
+
+ /* enable pci dev */
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n");
+ return ret;
+ }
+
+ /* set PCI host mastering */
+ pci_set_master(pdev);
+
+ /* pci request regions for ISH driver */
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n");
+ goto disable_device;
+ }
+
+ /* allocates and initializes the ISH dev structure */
+ dev = ish_dev_init(pdev);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto release_regions;
+ }
+ hw = to_ish_hw(dev);
+ dev->print_log = ish_event_tracer;
+
+ /* mapping IO device memory */
+ hw->mem_addr = pci_iomap(pdev, 0, 0);
+ if (!hw->mem_addr) {
+ dev_err(&pdev->dev, "ISH: mapping I/O range failure\n");
+ ret = -ENOMEM;
+ goto free_device;
+ }
+
+ dev->pdev = pdev;
+
+ pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
+
+ /* request and enable interrupt */
+ ret = request_irq(pdev->irq, ish_irq_handler, IRQF_NO_SUSPEND,
+ KBUILD_MODNAME, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n",
+ pdev->irq);
+ goto free_device;
+ }
+
+ dev_set_drvdata(dev->devc, dev);
+
+ init_waitqueue_head(&dev->suspend_wait);
+ init_waitqueue_head(&dev->resume_wait);
+
+ ret = ish_init(dev);
+ if (ret)
+ goto free_irq;
+
+ return 0;
+
+free_irq:
+ free_irq(pdev->irq, dev);
+free_device:
+ pci_iounmap(pdev, hw->mem_addr);
+ kfree(dev);
+release_regions:
+ pci_release_regions(pdev);
+disable_device:
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+ dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n");
+
+ return ret;
+}
+
+/**
+ * ish_remove() - PCI driver remove callback
+ * @pdev: pci device
+ *
+ * This function does cleanup of ISH on pci remove callback
+ */
+static void ish_remove(struct pci_dev *pdev)
+{
+ struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
+ struct ish_hw *hw = to_ish_hw(ishtp_dev);
+
+ ishtp_bus_remove_all_clients(ishtp_dev, false);
+ ish_device_disable(ishtp_dev);
+
+ free_irq(pdev->irq, ishtp_dev);
+ pci_iounmap(pdev, hw->mem_addr);
+ pci_release_regions(pdev);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+ kfree(ishtp_dev);
+}
+
+static struct device *ish_resume_device;
+
+/**
+ * ish_resume_handler() - Work function to complete resume
+ * @work: work struct
+ *
+ * The resume work function to complete resume function asynchronously.
+ * There are two types of platforms, one where ISH is not powered off,
+ * in that case a simple resume message is enough, others we need
+ * a reset sequence.
+ */
+static void ish_resume_handler(struct work_struct *work)
+{
+ struct pci_dev *pdev = to_pci_dev(ish_resume_device);
+ struct ishtp_device *dev = pci_get_drvdata(pdev);
+ int ret;
+
+ ishtp_send_resume(dev);
+
+ /* 50 ms to get resume response */
+ if (dev->resume_flag)
+ ret = wait_event_interruptible_timeout(dev->resume_wait,
+ !dev->resume_flag,
+ msecs_to_jiffies(50));
+
+ /*
+ * If no resume response. This platform is not S0ix compatible
+ * So on resume full reboot of ISH processor will happen, so
+ * need to go through init sequence again
+ */
+ if (dev->resume_flag)
+ ish_init(dev);
+}
+
+/**
+ * ish_suspend() - ISH suspend callback
+ * @device: device pointer
+ *
+ * ISH suspend callback
+ *
+ * Return: 0 to the pm core
+ */
+static int ish_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct ishtp_device *dev = pci_get_drvdata(pdev);
+
+ enable_irq_wake(pdev->irq);
+ /*
+ * If previous suspend hasn't been asnwered then ISH is likely dead,
+ * don't attempt nested notification
+ */
+ if (dev->suspend_flag)
+ return 0;
+
+ dev->resume_flag = 0;
+ dev->suspend_flag = 1;
+ ishtp_send_suspend(dev);
+
+ /* 25 ms should be enough for live ISH to flush all IPC buf */
+ if (dev->suspend_flag)
+ wait_event_interruptible_timeout(dev->suspend_wait,
+ !dev->suspend_flag,
+ msecs_to_jiffies(25));
+
+ return 0;
+}
+
+static DECLARE_WORK(resume_work, ish_resume_handler);
+/**
+ * ish_resume() - ISH resume callback
+ * @device: device pointer
+ *
+ * ISH resume callback
+ *
+ * Return: 0 to the pm core
+ */
+static int ish_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct ishtp_device *dev = pci_get_drvdata(pdev);
+
+ ish_resume_device = device;
+ dev->resume_flag = 1;
+
+ disable_irq_wake(pdev->irq);
+ schedule_work(&resume_work);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops ish_pm_ops = {
+ .suspend = ish_suspend,
+ .resume = ish_resume,
+};
+#define ISHTP_ISH_PM_OPS (&ish_pm_ops)
+#else
+#define ISHTP_ISH_PM_OPS NULL
+#endif
+
+static struct pci_driver ish_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ish_pci_tbl,
+ .probe = ish_probe,
+ .remove = ish_remove,
+ .driver.pm = ISHTP_ISH_PM_OPS,
+};
+
+module_pci_driver(ish_driver);
+
+/* Original author */
+MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
+/* Adoption to upstream Linux kernel */
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+
+MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/intel-ish-hid/ipc/utils.h b/drivers/hid/intel-ish-hid/ipc/utils.h
new file mode 100644
index 000000000000..5a82123dc7b4
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ipc/utils.h
@@ -0,0 +1,64 @@
+/*
+ * Utility macros of ISH
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+#ifndef UTILS__H
+#define UTILS__H
+
+#define WAIT_FOR_SEND_SLICE (HZ / 10)
+#define WAIT_FOR_CONNECT_SLICE (HZ / 10)
+
+/*
+ * Waits for specified event when a thread that triggers event can't signal
+ * Also, waits *at_least* `timeinc` after condition is satisfied
+ */
+#define timed_wait_for(timeinc, condition) \
+ do { \
+ int completed = 0; \
+ do { \
+ unsigned long j; \
+ int done = 0; \
+ \
+ completed = (condition); \
+ for (j = jiffies, done = 0; !done; ) { \
+ schedule_timeout(timeinc); \
+ if (time_is_before_eq_jiffies(j + timeinc)) \
+ done = 1; \
+ } \
+ } while (!(completed)); \
+ } while (0)
+
+
+/*
+ * Waits for specified event when a thread that triggers event
+ * can't signal with timeout (use whenever we may hang)
+ */
+#define timed_wait_for_timeout(timeinc, condition, timeout) \
+ do { \
+ int t = timeout; \
+ do { \
+ unsigned long j; \
+ int done = 0; \
+ \
+ for (j = jiffies, done = 0; !done; ) { \
+ schedule_timeout(timeinc); \
+ if (time_is_before_eq_jiffies(j + timeinc)) \
+ done = 1; \
+ } \
+ t -= timeinc; \
+ if (t <= 0) \
+ break; \
+ } while (!(condition)); \
+ } while (0)
+
+#endif /* UTILS__H */
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
new file mode 100644
index 000000000000..5c643d7a07b2
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
@@ -0,0 +1,978 @@
+/*
+ * ISHTP client driver for HID (ISH)
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/hid.h>
+#include <linux/sched.h>
+#include "ishtp/ishtp-dev.h"
+#include "ishtp/client.h"
+#include "ishtp-hid.h"
+
+/* Rx ring buffer pool size */
+#define HID_CL_RX_RING_SIZE 32
+#define HID_CL_TX_RING_SIZE 16
+
+/**
+ * report_bad_packets() - Report bad packets
+ * @hid_ishtp_cl: Client instance to get stats
+ * @recv_buf: Raw received host interface message
+ * @cur_pos: Current position index in payload
+ * @payload_len: Length of payload expected
+ *
+ * Dumps error in case bad packet is received
+ */
+static void report_bad_packet(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
+ size_t cur_pos, size_t payload_len)
+{
+ struct hostif_msg *recv_msg = recv_buf;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+
+ dev_err(&client_data->cl_device->dev, "[hid-ish]: BAD packet %02X\n"
+ "total_bad=%u cur_pos=%u\n"
+ "[%02X %02X %02X %02X]\n"
+ "payload_len=%u\n"
+ "multi_packet_cnt=%u\n"
+ "is_response=%02X\n",
+ recv_msg->hdr.command, client_data->bad_recv_cnt,
+ (unsigned int)cur_pos,
+ ((unsigned char *)recv_msg)[0], ((unsigned char *)recv_msg)[1],
+ ((unsigned char *)recv_msg)[2], ((unsigned char *)recv_msg)[3],
+ (unsigned int)payload_len, client_data->multi_packet_cnt,
+ recv_msg->hdr.command & ~CMD_MASK);
+}
+
+/**
+ * process_recv() - Received and parse incoming packet
+ * @hid_ishtp_cl: Client instance to get stats
+ * @recv_buf: Raw received host interface message
+ * @data_len: length of the message
+ *
+ * Parse the incoming packet. If it is a response packet then it will update
+ * per instance flags and wake up the caller waiting to for the response.
+ */
+static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
+ size_t data_len)
+{
+ struct hostif_msg *recv_msg;
+ unsigned char *payload;
+ struct device_info *dev_info;
+ int i, j;
+ size_t payload_len, total_len, cur_pos;
+ int report_type;
+ struct report_list *reports_list;
+ char *reports;
+ size_t report_len;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+ int curr_hid_dev = client_data->cur_hid_dev;
+
+ if (data_len < sizeof(struct hostif_msg_hdr)) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: error, received %u which is less than data header %u\n",
+ (unsigned int)data_len,
+ (unsigned int)sizeof(struct hostif_msg_hdr));
+ ++client_data->bad_recv_cnt;
+ ish_hw_reset(hid_ishtp_cl->dev);
+ return;
+ }
+
+ payload = recv_buf + sizeof(struct hostif_msg_hdr);
+ total_len = data_len;
+ cur_pos = 0;
+
+ do {
+ recv_msg = (struct hostif_msg *)(recv_buf + cur_pos);
+ payload_len = recv_msg->hdr.size;
+
+ /* Sanity checks */
+ if (cur_pos + payload_len + sizeof(struct hostif_msg) >
+ total_len) {
+ ++client_data->bad_recv_cnt;
+ report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
+ payload_len);
+ ish_hw_reset(hid_ishtp_cl->dev);
+ break;
+ }
+
+ hid_ishtp_trace(client_data, "%s %d\n",
+ __func__, recv_msg->hdr.command & CMD_MASK);
+
+ switch (recv_msg->hdr.command & CMD_MASK) {
+ case HOSTIF_DM_ENUM_DEVICES:
+ if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
+ client_data->init_done)) {
+ ++client_data->bad_recv_cnt;
+ report_bad_packet(hid_ishtp_cl, recv_msg,
+ cur_pos,
+ payload_len);
+ ish_hw_reset(hid_ishtp_cl->dev);
+ break;
+ }
+ client_data->hid_dev_count = (unsigned int)*payload;
+ if (!client_data->hid_devices)
+ client_data->hid_devices = devm_kzalloc(
+ &client_data->cl_device->dev,
+ client_data->hid_dev_count *
+ sizeof(struct device_info),
+ GFP_KERNEL);
+ if (!client_data->hid_devices) {
+ dev_err(&client_data->cl_device->dev,
+ "Mem alloc failed for hid device info\n");
+ wake_up_interruptible(&client_data->init_wait);
+ break;
+ }
+ for (i = 0; i < client_data->hid_dev_count; ++i) {
+ if (1 + sizeof(struct device_info) * i >=
+ payload_len) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: [ENUM_DEVICES]: content size %lu is bigger than payload_len %u\n",
+ 1 + sizeof(struct device_info)
+ * i,
+ (unsigned int)payload_len);
+ }
+
+ if (1 + sizeof(struct device_info) * i >=
+ data_len)
+ break;
+
+ dev_info = (struct device_info *)(payload + 1 +
+ sizeof(struct device_info) * i);
+ if (client_data->hid_devices)
+ memcpy(client_data->hid_devices + i,
+ dev_info,
+ sizeof(struct device_info));
+ }
+
+ client_data->enum_devices_done = true;
+ wake_up_interruptible(&client_data->init_wait);
+
+ break;
+
+ case HOSTIF_GET_HID_DESCRIPTOR:
+ if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
+ client_data->init_done)) {
+ ++client_data->bad_recv_cnt;
+ report_bad_packet(hid_ishtp_cl, recv_msg,
+ cur_pos,
+ payload_len);
+ ish_hw_reset(hid_ishtp_cl->dev);
+ break;
+ }
+ if (!client_data->hid_descr[curr_hid_dev])
+ client_data->hid_descr[curr_hid_dev] =
+ devm_kmalloc(&client_data->cl_device->dev,
+ payload_len, GFP_KERNEL);
+ if (client_data->hid_descr[curr_hid_dev]) {
+ memcpy(client_data->hid_descr[curr_hid_dev],
+ payload, payload_len);
+ client_data->hid_descr_size[curr_hid_dev] =
+ payload_len;
+ client_data->hid_descr_done = true;
+ }
+ wake_up_interruptible(&client_data->init_wait);
+
+ break;
+
+ case HOSTIF_GET_REPORT_DESCRIPTOR:
+ if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
+ client_data->init_done)) {
+ ++client_data->bad_recv_cnt;
+ report_bad_packet(hid_ishtp_cl, recv_msg,
+ cur_pos,
+ payload_len);
+ ish_hw_reset(hid_ishtp_cl->dev);
+ break;
+ }
+ if (!client_data->report_descr[curr_hid_dev])
+ client_data->report_descr[curr_hid_dev] =
+ devm_kmalloc(&client_data->cl_device->dev,
+ payload_len, GFP_KERNEL);
+ if (client_data->report_descr[curr_hid_dev]) {
+ memcpy(client_data->report_descr[curr_hid_dev],
+ payload,
+ payload_len);
+ client_data->report_descr_size[curr_hid_dev] =
+ payload_len;
+ client_data->report_descr_done = true;
+ }
+ wake_up_interruptible(&client_data->init_wait);
+
+ break;
+
+ case HOSTIF_GET_FEATURE_REPORT:
+ report_type = HID_FEATURE_REPORT;
+ goto do_get_report;
+
+ case HOSTIF_GET_INPUT_REPORT:
+ report_type = HID_INPUT_REPORT;
+do_get_report:
+ /* Get index of device that matches this id */
+ for (i = 0; i < client_data->num_hid_devices; ++i) {
+ if (recv_msg->hdr.device_id ==
+ client_data->hid_devices[i].dev_id)
+ if (client_data->hid_sensor_hubs[i]) {
+ hid_input_report(
+ client_data->hid_sensor_hubs[
+ i],
+ report_type, payload,
+ payload_len, 0);
+ ishtp_hid_wakeup(
+ client_data->hid_sensor_hubs[
+ i]);
+ break;
+ }
+ }
+ break;
+
+ case HOSTIF_SET_FEATURE_REPORT:
+ /* Get index of device that matches this id */
+ for (i = 0; i < client_data->num_hid_devices; ++i) {
+ if (recv_msg->hdr.device_id ==
+ client_data->hid_devices[i].dev_id)
+ if (client_data->hid_sensor_hubs[i]) {
+ ishtp_hid_wakeup(
+ client_data->hid_sensor_hubs[
+ i]);
+ break;
+ }
+ }
+ break;
+
+ case HOSTIF_PUBLISH_INPUT_REPORT:
+ report_type = HID_INPUT_REPORT;
+ for (i = 0; i < client_data->num_hid_devices; ++i)
+ if (recv_msg->hdr.device_id ==
+ client_data->hid_devices[i].dev_id)
+ if (client_data->hid_sensor_hubs[i])
+ hid_input_report(
+ client_data->hid_sensor_hubs[
+ i],
+ report_type, payload,
+ payload_len, 0);
+ break;
+
+ case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
+ report_type = HID_INPUT_REPORT;
+ reports_list = (struct report_list *)payload;
+ reports = (char *)reports_list->reports;
+
+ for (j = 0; j < reports_list->num_of_reports; j++) {
+ recv_msg = (struct hostif_msg *)(reports +
+ sizeof(uint16_t));
+ report_len = *(uint16_t *)reports;
+ payload = reports + sizeof(uint16_t) +
+ sizeof(struct hostif_msg_hdr);
+ payload_len = report_len -
+ sizeof(struct hostif_msg_hdr);
+
+ for (i = 0; i < client_data->num_hid_devices;
+ ++i)
+ if (recv_msg->hdr.device_id ==
+ client_data->hid_devices[i].dev_id &&
+ client_data->hid_sensor_hubs[i]) {
+ hid_input_report(
+ client_data->hid_sensor_hubs[
+ i],
+ report_type,
+ payload, payload_len,
+ 0);
+ }
+
+ reports += sizeof(uint16_t) + report_len;
+ }
+ break;
+ default:
+ ++client_data->bad_recv_cnt;
+ report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
+ payload_len);
+ ish_hw_reset(hid_ishtp_cl->dev);
+ break;
+
+ }
+
+ if (!cur_pos && cur_pos + payload_len +
+ sizeof(struct hostif_msg) < total_len)
+ ++client_data->multi_packet_cnt;
+
+ cur_pos += payload_len + sizeof(struct hostif_msg);
+ payload += payload_len + sizeof(struct hostif_msg);
+
+ } while (cur_pos < total_len);
+}
+
+/**
+ * ish_cl_event_cb() - bus driver callback for incoming message/packet
+ * @device: Pointer to the the ishtp client device for which this message
+ * is targeted
+ *
+ * Remove the packet from the list and process the message by calling
+ * process_recv
+ */
+static void ish_cl_event_cb(struct ishtp_cl_device *device)
+{
+ struct ishtp_cl *hid_ishtp_cl = device->driver_data;
+ struct ishtp_cl_rb *rb_in_proc;
+ size_t r_length;
+ unsigned long flags;
+
+ if (!hid_ishtp_cl)
+ return;
+
+ spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
+ while (!list_empty(&hid_ishtp_cl->in_process_list.list)) {
+ rb_in_proc = list_entry(
+ hid_ishtp_cl->in_process_list.list.next,
+ struct ishtp_cl_rb, list);
+ list_del_init(&rb_in_proc->list);
+ spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock,
+ flags);
+
+ if (!rb_in_proc->buffer.data)
+ return;
+
+ r_length = rb_in_proc->buf_idx;
+
+ /* decide what to do with received data */
+ process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
+
+ ishtp_cl_io_rb_recycle(rb_in_proc);
+ spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
+ }
+ spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags);
+}
+
+/**
+ * hid_ishtp_set_feature() - send request to ISH FW to set a feature request
+ * @hid: hid device instance for this request
+ * @buf: feature buffer
+ * @len: Length of feature buffer
+ * @report_id: Report id for the feature set request
+ *
+ * This is called from hid core .request() callback. This function doesn't wait
+ * for response.
+ */
+void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len,
+ int report_id)
+{
+ struct ishtp_hid_data *hid_data = hid->driver_data;
+ struct ishtp_cl_data *client_data = hid_data->client_data;
+ struct hostif_msg *msg = (struct hostif_msg *)buf;
+ int rv;
+ int i;
+
+ hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid);
+
+ rv = ishtp_hid_link_ready_wait(client_data);
+ if (rv) {
+ hid_ishtp_trace(client_data, "%s hid %p link not ready\n",
+ __func__, hid);
+ return;
+ }
+
+ memset(msg, 0, sizeof(struct hostif_msg));
+ msg->hdr.command = HOSTIF_SET_FEATURE_REPORT;
+ for (i = 0; i < client_data->num_hid_devices; ++i) {
+ if (hid == client_data->hid_sensor_hubs[i]) {
+ msg->hdr.device_id =
+ client_data->hid_devices[i].dev_id;
+ break;
+ }
+ }
+
+ if (i == client_data->num_hid_devices)
+ return;
+
+ rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len);
+ if (rv)
+ hid_ishtp_trace(client_data, "%s hid %p send failed\n",
+ __func__, hid);
+}
+
+/**
+ * hid_ishtp_get_report() - request to get feature/input report
+ * @hid: hid device instance for this request
+ * @report_id: Report id for the get request
+ * @report_type: Report type for the this request
+ *
+ * This is called from hid core .request() callback. This function will send
+ * request to FW and return without waiting for response.
+ */
+void hid_ishtp_get_report(struct hid_device *hid, int report_id,
+ int report_type)
+{
+ struct ishtp_hid_data *hid_data = hid->driver_data;
+ struct ishtp_cl_data *client_data = hid_data->client_data;
+ static unsigned char buf[10];
+ unsigned int len;
+ struct hostif_msg_to_sensor *msg = (struct hostif_msg_to_sensor *)buf;
+ int rv;
+ int i;
+
+ hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid);
+ rv = ishtp_hid_link_ready_wait(client_data);
+ if (rv) {
+ hid_ishtp_trace(client_data, "%s hid %p link not ready\n",
+ __func__, hid);
+ return;
+ }
+
+ len = sizeof(struct hostif_msg_to_sensor);
+
+ memset(msg, 0, sizeof(struct hostif_msg_to_sensor));
+ msg->hdr.command = (report_type == HID_FEATURE_REPORT) ?
+ HOSTIF_GET_FEATURE_REPORT : HOSTIF_GET_INPUT_REPORT;
+ for (i = 0; i < client_data->num_hid_devices; ++i) {
+ if (hid == client_data->hid_sensor_hubs[i]) {
+ msg->hdr.device_id =
+ client_data->hid_devices[i].dev_id;
+ break;
+ }
+ }
+
+ if (i == client_data->num_hid_devices)
+ return;
+
+ msg->report_id = report_id;
+ rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len);
+ if (rv)
+ hid_ishtp_trace(client_data, "%s hid %p send failed\n",
+ __func__, hid);
+}
+
+/**
+ * ishtp_hid_link_ready_wait() - Wait for link ready
+ * @client_data: client data instance
+ *
+ * If the transport link started suspend process, then wait, till either
+ * resumed or timeout
+ *
+ * Return: 0 on success, non zero on error
+ */
+int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data)
+{
+ int rc;
+
+ if (client_data->suspended) {
+ hid_ishtp_trace(client_data, "wait for link ready\n");
+ rc = wait_event_interruptible_timeout(
+ client_data->ishtp_resume_wait,
+ !client_data->suspended,
+ 5 * HZ);
+
+ if (rc == 0) {
+ hid_ishtp_trace(client_data, "link not ready\n");
+ return -EIO;
+ }
+ hid_ishtp_trace(client_data, "link ready\n");
+ }
+
+ return 0;
+}
+
+/**
+ * ishtp_enum_enum_devices() - Enumerate hid devices
+ * @hid_ishtp_cl: client instance
+ *
+ * Helper function to send request to firmware to enumerate HID devices
+ *
+ * Return: 0 on success, non zero on error
+ */
+static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl)
+{
+ struct hostif_msg msg;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+ int retry_count;
+ int rv;
+
+ /* Send HOSTIF_DM_ENUM_DEVICES */
+ memset(&msg, 0, sizeof(struct hostif_msg));
+ msg.hdr.command = HOSTIF_DM_ENUM_DEVICES;
+ rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg,
+ sizeof(struct hostif_msg));
+ if (rv)
+ return rv;
+
+ retry_count = 0;
+ while (!client_data->enum_devices_done &&
+ retry_count < 10) {
+ wait_event_interruptible_timeout(client_data->init_wait,
+ client_data->enum_devices_done,
+ 3 * HZ);
+ ++retry_count;
+ if (!client_data->enum_devices_done)
+ /* Send HOSTIF_DM_ENUM_DEVICES */
+ rv = ishtp_cl_send(hid_ishtp_cl,
+ (unsigned char *) &msg,
+ sizeof(struct hostif_msg));
+ }
+ if (!client_data->enum_devices_done) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: timed out waiting for enum_devices\n");
+ return -ETIMEDOUT;
+ }
+ if (!client_data->hid_devices) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: failed to allocate HID dev structures\n");
+ return -ENOMEM;
+ }
+
+ client_data->num_hid_devices = client_data->hid_dev_count;
+ dev_info(&hid_ishtp_cl->device->dev,
+ "[hid-ish]: enum_devices_done OK, num_hid_devices=%d\n",
+ client_data->num_hid_devices);
+
+ return 0;
+}
+
+/**
+ * ishtp_get_hid_descriptor() - Get hid descriptor
+ * @hid_ishtp_cl: client instance
+ * @index: Index into the hid_descr array
+ *
+ * Helper function to send request to firmware get HID descriptor of a device
+ *
+ * Return: 0 on success, non zero on error
+ */
+static int ishtp_get_hid_descriptor(struct ishtp_cl *hid_ishtp_cl, int index)
+{
+ struct hostif_msg msg;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+ int rv;
+
+ /* Get HID descriptor */
+ client_data->hid_descr_done = false;
+ memset(&msg, 0, sizeof(struct hostif_msg));
+ msg.hdr.command = HOSTIF_GET_HID_DESCRIPTOR;
+ msg.hdr.device_id = client_data->hid_devices[index].dev_id;
+ rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
+ sizeof(struct hostif_msg));
+ if (rv)
+ return rv;
+
+ if (!client_data->hid_descr_done) {
+ wait_event_interruptible_timeout(client_data->init_wait,
+ client_data->hid_descr_done,
+ 3 * HZ);
+ if (!client_data->hid_descr_done) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: timed out for hid_descr_done\n");
+ return -EIO;
+ }
+
+ if (!client_data->hid_descr[index]) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: allocation HID desc fail\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ishtp_get_report_descriptor() - Get report descriptor
+ * @hid_ishtp_cl: client instance
+ * @index: Index into the hid_descr array
+ *
+ * Helper function to send request to firmware get HID report descriptor of
+ * a device
+ *
+ * Return: 0 on success, non zero on error
+ */
+static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
+ int index)
+{
+ struct hostif_msg msg;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+ int rv;
+
+ /* Get report descriptor */
+ client_data->report_descr_done = false;
+ memset(&msg, 0, sizeof(struct hostif_msg));
+ msg.hdr.command = HOSTIF_GET_REPORT_DESCRIPTOR;
+ msg.hdr.device_id = client_data->hid_devices[index].dev_id;
+ rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
+ sizeof(struct hostif_msg));
+ if (rv)
+ return rv;
+
+ if (!client_data->report_descr_done)
+ wait_event_interruptible_timeout(client_data->init_wait,
+ client_data->report_descr_done,
+ 3 * HZ);
+ if (!client_data->report_descr_done) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: timed out for report descr\n");
+ return -EIO;
+ }
+ if (!client_data->report_descr[index]) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: failed to alloc report descr\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * hid_ishtp_cl_init() - Init function for ISHTP client
+ * @hid_ishtp_cl: ISHTP client instance
+ * @reset: true if called for init after reset
+ *
+ * This function complete the initializtion of the client. The summary of
+ * processing:
+ * - Send request to enumerate the hid clients
+ * Get the HID descriptor for each enumearated device
+ * Get report description of each device
+ * Register each device wik hid core by calling ishtp_hid_probe
+ *
+ * Return: 0 on success, non zero on error
+ */
+static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
+{
+ struct ishtp_device *dev;
+ unsigned long flags;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+ int i;
+ int rv;
+
+ dev_dbg(&client_data->cl_device->dev, "%s\n", __func__);
+ hid_ishtp_trace(client_data, "%s reset flag: %d\n", __func__, reset);
+
+ rv = ishtp_cl_link(hid_ishtp_cl, ISHTP_HOST_CLIENT_ID_ANY);
+ if (rv) {
+ dev_err(&client_data->cl_device->dev,
+ "ishtp_cl_link failed\n");
+ return -ENOMEM;
+ }
+
+ client_data->init_done = 0;
+
+ dev = hid_ishtp_cl->dev;
+
+ /* Connect to FW client */
+ hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE;
+ hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE;
+
+ spin_lock_irqsave(&dev->fw_clients_lock, flags);
+ i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid);
+ if (i < 0) {
+ spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
+ dev_err(&client_data->cl_device->dev,
+ "ish client uuid not found\n");
+ return i;
+ }
+ hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id;
+ spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
+ hid_ishtp_cl->state = ISHTP_CL_CONNECTING;
+
+ rv = ishtp_cl_connect(hid_ishtp_cl);
+ if (rv) {
+ dev_err(&client_data->cl_device->dev,
+ "client connect fail\n");
+ goto err_cl_unlink;
+ }
+
+ hid_ishtp_trace(client_data, "%s client connected\n", __func__);
+
+ /* Register read callback */
+ ishtp_register_event_cb(hid_ishtp_cl->device, ish_cl_event_cb);
+
+ rv = ishtp_enum_enum_devices(hid_ishtp_cl);
+ if (rv)
+ goto err_cl_disconnect;
+
+ hid_ishtp_trace(client_data, "%s enumerated device count %d\n",
+ __func__, client_data->num_hid_devices);
+
+ for (i = 0; i < client_data->num_hid_devices; ++i) {
+ client_data->cur_hid_dev = i;
+
+ rv = ishtp_get_hid_descriptor(hid_ishtp_cl, i);
+ if (rv)
+ goto err_cl_disconnect;
+
+ rv = ishtp_get_report_descriptor(hid_ishtp_cl, i);
+ if (rv)
+ goto err_cl_disconnect;
+
+ if (!reset) {
+ rv = ishtp_hid_probe(i, client_data);
+ if (rv) {
+ dev_err(&client_data->cl_device->dev,
+ "[hid-ish]: HID probe for #%u failed: %d\n",
+ i, rv);
+ goto err_cl_disconnect;
+ }
+ }
+ } /* for() on all hid devices */
+
+ client_data->init_done = 1;
+ client_data->suspended = false;
+ wake_up_interruptible(&client_data->ishtp_resume_wait);
+ hid_ishtp_trace(client_data, "%s successful init\n", __func__);
+ return 0;
+
+err_cl_disconnect:
+ hid_ishtp_cl->state = ISHTP_CL_DISCONNECTING;
+ ishtp_cl_disconnect(hid_ishtp_cl);
+err_cl_unlink:
+ ishtp_cl_unlink(hid_ishtp_cl);
+ return rv;
+}
+
+/**
+ * hid_ishtp_cl_deinit() - Deinit function for ISHTP client
+ * @hid_ishtp_cl: ISHTP client instance
+ *
+ * Unlink and free hid client
+ */
+static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl)
+{
+ ishtp_cl_unlink(hid_ishtp_cl);
+ ishtp_cl_flush_queues(hid_ishtp_cl);
+
+ /* disband and free all Tx and Rx client-level rings */
+ ishtp_cl_free(hid_ishtp_cl);
+}
+
+static void hid_ishtp_cl_reset_handler(struct work_struct *work)
+{
+ struct ishtp_cl_data *client_data;
+ struct ishtp_cl *hid_ishtp_cl;
+ struct ishtp_cl_device *cl_device;
+ int retry;
+ int rv;
+
+ client_data = container_of(work, struct ishtp_cl_data, work);
+
+ hid_ishtp_cl = client_data->hid_ishtp_cl;
+ cl_device = client_data->cl_device;
+
+ hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
+ hid_ishtp_cl);
+ dev_dbg(&cl_device->dev, "%s\n", __func__);
+
+ hid_ishtp_cl_deinit(hid_ishtp_cl);
+
+ hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev);
+ if (!hid_ishtp_cl)
+ return;
+
+ cl_device->driver_data = hid_ishtp_cl;
+ hid_ishtp_cl->client_data = client_data;
+ client_data->hid_ishtp_cl = hid_ishtp_cl;
+
+ client_data->num_hid_devices = 0;
+
+ for (retry = 0; retry < 3; ++retry) {
+ rv = hid_ishtp_cl_init(hid_ishtp_cl, 1);
+ if (!rv)
+ break;
+ dev_err(&client_data->cl_device->dev, "Retry reset init\n");
+ }
+ if (rv) {
+ dev_err(&client_data->cl_device->dev, "Reset Failed\n");
+ hid_ishtp_trace(client_data, "%s Failed hid_ishtp_cl %p\n",
+ __func__, hid_ishtp_cl);
+ }
+}
+
+/**
+ * hid_ishtp_cl_probe() - ISHTP client driver probe
+ * @cl_device: ISHTP client device instance
+ *
+ * This function gets called on device create on ISHTP bus
+ *
+ * Return: 0 on success, non zero on error
+ */
+static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
+{
+ struct ishtp_cl *hid_ishtp_cl;
+ struct ishtp_cl_data *client_data;
+ int rv;
+
+ if (!cl_device)
+ return -ENODEV;
+
+ if (uuid_le_cmp(hid_ishtp_guid,
+ cl_device->fw_client->props.protocol_name) != 0)
+ return -ENODEV;
+
+ client_data = devm_kzalloc(&cl_device->dev, sizeof(*client_data),
+ GFP_KERNEL);
+ if (!client_data)
+ return -ENOMEM;
+
+ hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev);
+ if (!hid_ishtp_cl)
+ return -ENOMEM;
+
+ cl_device->driver_data = hid_ishtp_cl;
+ hid_ishtp_cl->client_data = client_data;
+ client_data->hid_ishtp_cl = hid_ishtp_cl;
+ client_data->cl_device = cl_device;
+
+ init_waitqueue_head(&client_data->init_wait);
+ init_waitqueue_head(&client_data->ishtp_resume_wait);
+
+ INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
+
+ rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
+ if (rv) {
+ ishtp_cl_free(hid_ishtp_cl);
+ return rv;
+ }
+ ishtp_get_device(cl_device);
+
+ return 0;
+}
+
+/**
+ * hid_ishtp_cl_remove() - ISHTP client driver remove
+ * @cl_device: ISHTP client device instance
+ *
+ * This function gets called on device remove on ISHTP bus
+ *
+ * Return: 0
+ */
+static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
+{
+ struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+
+ hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
+ hid_ishtp_cl);
+
+ dev_dbg(&cl_device->dev, "%s\n", __func__);
+ hid_ishtp_cl->state = ISHTP_CL_DISCONNECTING;
+ ishtp_cl_disconnect(hid_ishtp_cl);
+ ishtp_put_device(cl_device);
+ ishtp_hid_remove(client_data);
+ hid_ishtp_cl_deinit(hid_ishtp_cl);
+
+ hid_ishtp_cl = NULL;
+
+ client_data->num_hid_devices = 0;
+
+ return 0;
+}
+
+/**
+ * hid_ishtp_cl_reset() - ISHTP client driver reset
+ * @cl_device: ISHTP client device instance
+ *
+ * This function gets called on device reset on ISHTP bus
+ *
+ * Return: 0
+ */
+static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
+{
+ struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+
+ hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
+ hid_ishtp_cl);
+
+ schedule_work(&client_data->work);
+
+ return 0;
+}
+
+#define to_ishtp_cl_device(d) container_of(d, struct ishtp_cl_device, dev)
+
+/**
+ * hid_ishtp_cl_suspend() - ISHTP client driver suspend
+ * @device: device instance
+ *
+ * This function gets called on system suspend
+ *
+ * Return: 0
+ */
+static int hid_ishtp_cl_suspend(struct device *device)
+{
+ struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
+ struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+
+ hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
+ hid_ishtp_cl);
+ client_data->suspended = true;
+
+ return 0;
+}
+
+/**
+ * hid_ishtp_cl_resume() - ISHTP client driver resume
+ * @device: device instance
+ *
+ * This function gets called on system resume
+ *
+ * Return: 0
+ */
+static int hid_ishtp_cl_resume(struct device *device)
+{
+ struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
+ struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+
+ hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
+ hid_ishtp_cl);
+ client_data->suspended = false;
+ return 0;
+}
+
+static const struct dev_pm_ops hid_ishtp_pm_ops = {
+ .suspend = hid_ishtp_cl_suspend,
+ .resume = hid_ishtp_cl_resume,
+};
+
+static struct ishtp_cl_driver hid_ishtp_cl_driver = {
+ .name = "ish-hid",
+ .probe = hid_ishtp_cl_probe,
+ .remove = hid_ishtp_cl_remove,
+ .reset = hid_ishtp_cl_reset,
+ .driver.pm = &hid_ishtp_pm_ops,
+};
+
+static int __init ish_hid_init(void)
+{
+ int rv;
+
+ /* Register ISHTP client device driver with ISHTP Bus */
+ rv = ishtp_cl_driver_register(&hid_ishtp_cl_driver);
+
+ return rv;
+
+}
+
+static void __exit ish_hid_exit(void)
+{
+ ishtp_cl_driver_unregister(&hid_ishtp_cl_driver);
+}
+
+late_initcall(ish_hid_init);
+module_exit(ish_hid_exit);
+
+MODULE_DESCRIPTION("ISH ISHTP HID client driver");
+/* Primary author */
+MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
+/*
+ * Several modification for multi instance support
+ * suspend/resume and clean up
+ */
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ishtp:*");
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c
new file mode 100644
index 000000000000..277983aa1d90
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp-hid.c
@@ -0,0 +1,246 @@
+/*
+ * ISHTP-HID glue driver.
+ *
+ * Copyright (c) 2012-2016, 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.
+ */
+
+#include <linux/hid.h>
+#include <uapi/linux/input.h>
+#include "ishtp/client.h"
+#include "ishtp-hid.h"
+
+/**
+ * ishtp_hid_parse() - hid-core .parse() callback
+ * @hid: hid device instance
+ *
+ * This function gets called during call to hid_add_device
+ *
+ * Return: 0 on success and non zero on error
+ */
+static int ishtp_hid_parse(struct hid_device *hid)
+{
+ struct ishtp_hid_data *hid_data = hid->driver_data;
+ struct ishtp_cl_data *client_data = hid_data->client_data;
+ int rv;
+
+ rv = hid_parse_report(hid, client_data->report_descr[hid_data->index],
+ client_data->report_descr_size[hid_data->index]);
+ if (rv)
+ return rv;
+
+ return 0;
+}
+
+/* Empty callbacks with success return code */
+static int ishtp_hid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void ishtp_hid_stop(struct hid_device *hid)
+{
+}
+
+static int ishtp_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void ishtp_hid_close(struct hid_device *hid)
+{
+}
+
+static int ishtp_raw_request(struct hid_device *hdev, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype, int reqtype)
+{
+ return 0;
+}
+
+/**
+ * ishtp_hid_request() - hid-core .request() callback
+ * @hid: hid device instance
+ * @rep: pointer to hid_report
+ * @reqtype: type of req. [GET|SET]_REPORT
+ *
+ * This function is used to set/get feaure/input report.
+ */
+static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
+ int reqtype)
+{
+ struct ishtp_hid_data *hid_data = hid->driver_data;
+ /* the specific report length, just HID part of it */
+ unsigned int len = ((rep->size - 1) >> 3) + 1 + (rep->id > 0);
+ char *buf;
+ unsigned int header_size = sizeof(struct hostif_msg);
+
+ len += header_size;
+
+ hid_data->request_done = false;
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ hid_ishtp_get_report(hid, rep->id, rep->type);
+ break;
+ case HID_REQ_SET_REPORT:
+ /*
+ * Spare 7 bytes for 64b accesses through
+ * get/put_unaligned_le64()
+ */
+ buf = kzalloc(len + 7, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ hid_output_report(rep, buf + header_size);
+ hid_ishtp_set_feature(hid, buf, len, rep->id);
+ kfree(buf);
+ break;
+ }
+}
+
+/**
+ * ishtp_wait_for_response() - hid-core .wait() callback
+ * @hid: hid device instance
+ *
+ * This function is used to wait after get feaure/input report.
+ *
+ * Return: 0 on success and non zero on error
+ */
+static int ishtp_wait_for_response(struct hid_device *hid)
+{
+ struct ishtp_hid_data *hid_data = hid->driver_data;
+ struct ishtp_cl_data *client_data = hid_data->client_data;
+ int rv;
+
+ hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid);
+
+ rv = ishtp_hid_link_ready_wait(hid_data->client_data);
+ if (rv)
+ return rv;
+
+ if (!hid_data->request_done)
+ wait_event_interruptible_timeout(hid_data->hid_wait,
+ hid_data->request_done, 3 * HZ);
+
+ if (!hid_data->request_done) {
+ hid_err(hid,
+ "timeout waiting for response from ISHTP device\n");
+ return -ETIMEDOUT;
+ }
+ hid_ishtp_trace(client_data, "%s hid %p done\n", __func__, hid);
+
+ hid_data->request_done = false;
+
+ return 0;
+}
+
+/**
+ * ishtp_hid_wakeup() - Wakeup caller
+ * @hid: hid device instance
+ *
+ * This function will wakeup caller waiting for Get/Set feature report
+ */
+void ishtp_hid_wakeup(struct hid_device *hid)
+{
+ struct ishtp_hid_data *hid_data = hid->driver_data;
+
+ hid_data->request_done = true;
+ wake_up_interruptible(&hid_data->hid_wait);
+}
+
+static struct hid_ll_driver ishtp_hid_ll_driver = {
+ .parse = ishtp_hid_parse,
+ .start = ishtp_hid_start,
+ .stop = ishtp_hid_stop,
+ .open = ishtp_hid_open,
+ .close = ishtp_hid_close,
+ .request = ishtp_hid_request,
+ .wait = ishtp_wait_for_response,
+ .raw_request = ishtp_raw_request
+};
+
+/**
+ * ishtp_hid_probe() - hid register ll driver
+ * @cur_hid_dev: Index of hid device calling to register
+ * @client_data: Client data pointer
+ *
+ * This function is used to allocate and add HID device.
+ *
+ * Return: 0 on success, non zero on error
+ */
+int ishtp_hid_probe(unsigned int cur_hid_dev,
+ struct ishtp_cl_data *client_data)
+{
+ int rv;
+ struct hid_device *hid;
+ struct ishtp_hid_data *hid_data;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ rv = PTR_ERR(hid);
+ return -ENOMEM;
+ }
+
+ hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
+ if (!hid_data) {
+ rv = -ENOMEM;
+ goto err_hid_data;
+ }
+
+ hid_data->index = cur_hid_dev;
+ hid_data->client_data = client_data;
+ init_waitqueue_head(&hid_data->hid_wait);
+
+ hid->driver_data = hid_data;
+
+ client_data->hid_sensor_hubs[cur_hid_dev] = hid;
+
+ hid->ll_driver = &ishtp_hid_ll_driver;
+ hid->bus = BUS_INTEL_ISHTP;
+ hid->dev.parent = &client_data->cl_device->dev;
+ hid->version = le16_to_cpu(ISH_HID_VERSION);
+ hid->vendor = le16_to_cpu(ISH_HID_VENDOR);
+ hid->product = le16_to_cpu(ISH_HID_PRODUCT);
+ snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX", "hid-ishtp",
+ hid->vendor, hid->product);
+
+ rv = hid_add_device(hid);
+ if (rv)
+ goto err_hid_device;
+
+ hid_ishtp_trace(client_data, "%s allocated hid %p\n", __func__, hid);
+
+ return 0;
+
+err_hid_device:
+ kfree(hid_data);
+err_hid_data:
+ kfree(hid);
+ return rv;
+}
+
+/**
+ * ishtp_hid_probe() - Remove registered hid device
+ * @client_data: client data pointer
+ *
+ * This function is used to destroy allocatd HID device.
+ */
+void ishtp_hid_remove(struct ishtp_cl_data *client_data)
+{
+ int i;
+
+ for (i = 0; i < client_data->num_hid_devices; ++i) {
+ if (client_data->hid_sensor_hubs[i]) {
+ kfree(client_data->hid_sensor_hubs[i]->driver_data);
+ hid_destroy_device(client_data->hid_sensor_hubs[i]);
+ client_data->hid_sensor_hubs[i] = NULL;
+ }
+ }
+}
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.h b/drivers/hid/intel-ish-hid/ishtp-hid.h
new file mode 100644
index 000000000000..f5c7eb79b7b5
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp-hid.h
@@ -0,0 +1,182 @@
+/*
+ * ISHTP-HID glue driver's definitions.
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+#ifndef ISHTP_HID__H
+#define ISHTP_HID__H
+
+/* The fixed ISH product and vendor id */
+#define ISH_HID_VENDOR 0x8086
+#define ISH_HID_PRODUCT 0x22D8
+#define ISH_HID_VERSION 0x0200
+
+#define CMD_MASK 0x7F
+#define IS_RESPONSE 0x80
+
+/* Used to dump to Linux trace buffer, if enabled */
+#define hid_ishtp_trace(client, ...) \
+ client->cl_device->ishtp_dev->print_log(\
+ client->cl_device->ishtp_dev, __VA_ARGS__)
+
+/* ISH Transport protocol (ISHTP in short) GUID */
+static const uuid_le hid_ishtp_guid = UUID_LE(0x33AECD58, 0xB679, 0x4E54,
+ 0x9B, 0xD9, 0xA0, 0x4D, 0x34,
+ 0xF0, 0xC2, 0x26);
+
+/* ISH HID message structure */
+struct hostif_msg_hdr {
+ uint8_t command; /* Bit 7: is_response */
+ uint8_t device_id;
+ uint8_t status;
+ uint8_t flags;
+ uint16_t size;
+} __packed;
+
+struct hostif_msg {
+ struct hostif_msg_hdr hdr;
+} __packed;
+
+struct hostif_msg_to_sensor {
+ struct hostif_msg_hdr hdr;
+ uint8_t report_id;
+} __packed;
+
+struct device_info {
+ uint32_t dev_id;
+ uint8_t dev_class;
+ uint16_t pid;
+ uint16_t vid;
+} __packed;
+
+struct ishtp_version {
+ uint8_t major;
+ uint8_t minor;
+ uint8_t hotfix;
+ uint16_t build;
+} __packed;
+
+/* struct for ISHTP aggregated input data */
+struct report_list {
+ uint16_t total_size;
+ uint8_t num_of_reports;
+ uint8_t flags;
+ struct {
+ uint16_t size_of_report;
+ uint8_t report[1];
+ } __packed reports[1];
+} __packed;
+
+/* HOSTIF commands */
+#define HOSTIF_HID_COMMAND_BASE 0
+#define HOSTIF_GET_HID_DESCRIPTOR 0
+#define HOSTIF_GET_REPORT_DESCRIPTOR 1
+#define HOSTIF_GET_FEATURE_REPORT 2
+#define HOSTIF_SET_FEATURE_REPORT 3
+#define HOSTIF_GET_INPUT_REPORT 4
+#define HOSTIF_PUBLISH_INPUT_REPORT 5
+#define HOSTIF_PUBLISH_INPUT_REPORT_LIST 6
+#define HOSTIF_DM_COMMAND_BASE 32
+#define HOSTIF_DM_ENUM_DEVICES 33
+#define HOSTIF_DM_ADD_DEVICE 34
+
+#define MAX_HID_DEVICES 32
+
+/**
+ * struct ishtp_cl_data - Encapsulate per ISH TP HID Client
+ * @enum_device_done: Enum devices response complete flag
+ * @hid_descr_done: HID descriptor complete flag
+ * @report_descr_done: Get report descriptor complete flag
+ * @init_done: Init process completed successfully
+ * @suspended: System is under suspend state or in progress
+ * @num_hid_devices: Number of HID devices enumerated in this client
+ * @cur_hid_dev: This keeps track of the device index for which
+ * initialization and registration with HID core
+ * in progress.
+ * @hid_devices: Store vid/pid/devid for each enumerated HID device
+ * @report_descr: Stores the raw report descriptors for each HID device
+ * @report_descr_size: Report description of size of above repo_descr[]
+ * @hid_sensor_hubs: Pointer to hid_device for all HID device, so that
+ * when clients are removed, they can be freed
+ * @hid_descr: Pointer to hid descriptor for each enumerated hid
+ * device
+ * @hid_descr_size: Size of each above report descriptor
+ * @init_wait: Wait queue to wait during initialization, where the
+ * client send message to ISH FW and wait for response
+ * @ishtp_hid_wait: The wait for get report during wait callback from hid
+ * core
+ * @bad_recv_cnt: Running count of packets received with error
+ * @multi_packet_cnt: Count of fragmented packet count
+ *
+ * This structure is used to store completion flags and per client data like
+ * like report description, number of HID devices etc.
+ */
+struct ishtp_cl_data {
+ /* completion flags */
+ bool enum_devices_done;
+ bool hid_descr_done;
+ bool report_descr_done;
+ bool init_done;
+ bool suspended;
+
+ unsigned int num_hid_devices;
+ unsigned int cur_hid_dev;
+ unsigned int hid_dev_count;
+
+ struct device_info *hid_devices;
+ unsigned char *report_descr[MAX_HID_DEVICES];
+ int report_descr_size[MAX_HID_DEVICES];
+ struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES];
+ unsigned char *hid_descr[MAX_HID_DEVICES];
+ int hid_descr_size[MAX_HID_DEVICES];
+
+ wait_queue_head_t init_wait;
+ wait_queue_head_t ishtp_resume_wait;
+ struct ishtp_cl *hid_ishtp_cl;
+
+ /* Statistics */
+ unsigned int bad_recv_cnt;
+ int multi_packet_cnt;
+
+ struct work_struct work;
+ struct ishtp_cl_device *cl_device;
+};
+
+/**
+ * struct ishtp_hid_data - Per instance HID data
+ * @index: Device index in the order of enumeration
+ * @request_done: Get Feature/Input report complete flag
+ * used during get/set request from hid core
+ * @client_data: Link to the client instance
+ * @hid_wait: Completion waitq
+ *
+ * Used to tie hid hid->driver data to driver client instance
+ */
+struct ishtp_hid_data {
+ int index;
+ bool request_done;
+ struct ishtp_cl_data *client_data;
+ wait_queue_head_t hid_wait;
+};
+
+/* Interface functions between HID LL driver and ISH TP client */
+void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len,
+ int report_id);
+void hid_ishtp_get_report(struct hid_device *hid, int report_id,
+ int report_type);
+int ishtp_hid_probe(unsigned int cur_hid_dev,
+ struct ishtp_cl_data *client_data);
+void ishtp_hid_remove(struct ishtp_cl_data *client_data);
+int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data);
+void ishtp_hid_wakeup(struct hid_device *hid);
+
+#endif /* ISHTP_HID__H */
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
new file mode 100644
index 000000000000..256521509d20
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -0,0 +1,788 @@
+/*
+ * ISHTP bus driver
+ *
+ * Copyright (c) 2012-2016, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include "bus.h"
+#include "ishtp-dev.h"
+#include "client.h"
+#include "hbm.h"
+
+static int ishtp_use_dma;
+module_param_named(ishtp_use_dma, ishtp_use_dma, int, 0600);
+MODULE_PARM_DESC(ishtp_use_dma, "Use DMA to send messages");
+
+#define to_ishtp_cl_driver(d) container_of(d, struct ishtp_cl_driver, driver)
+#define to_ishtp_cl_device(d) container_of(d, struct ishtp_cl_device, dev)
+static bool ishtp_device_ready;
+
+/**
+ * ishtp_recv() - process ishtp message
+ * @dev: ishtp device
+ *
+ * If a message with valid header and size is received, then
+ * this function calls appropriate handler. The host or firmware
+ * address is zero, then they are host bus management message,
+ * otherwise they are message fo clients.
+ */
+void ishtp_recv(struct ishtp_device *dev)
+{
+ uint32_t msg_hdr;
+ struct ishtp_msg_hdr *ishtp_hdr;
+
+ /* Read ISHTP header dword */
+ msg_hdr = dev->ops->ishtp_read_hdr(dev);
+ if (!msg_hdr)
+ return;
+
+ dev->ops->sync_fw_clock(dev);
+
+ ishtp_hdr = (struct ishtp_msg_hdr *)&msg_hdr;
+ dev->ishtp_msg_hdr = msg_hdr;
+
+ /* Sanity check: ISHTP frag. length in header */
+ if (ishtp_hdr->length > dev->mtu) {
+ dev_err(dev->devc,
+ "ISHTP hdr - bad length: %u; dropped [%08X]\n",
+ (unsigned int)ishtp_hdr->length, msg_hdr);
+ return;
+ }
+
+ /* ISHTP bus message */
+ if (!ishtp_hdr->host_addr && !ishtp_hdr->fw_addr)
+ recv_hbm(dev, ishtp_hdr);
+ /* ISHTP fixed-client message */
+ else if (!ishtp_hdr->host_addr)
+ recv_fixed_cl_msg(dev, ishtp_hdr);
+ else
+ /* ISHTP client message */
+ recv_ishtp_cl_msg(dev, ishtp_hdr);
+}
+EXPORT_SYMBOL(ishtp_recv);
+
+/**
+ * ishtp_send_msg() - Send ishtp message
+ * @dev: ishtp device
+ * @hdr: Message header
+ * @msg: Message contents
+ * @ipc_send_compl: completion callback
+ * @ipc_send_compl_prm: completion callback parameter
+ *
+ * Send a multi fragment message via IPC. After sending the first fragment
+ * the completion callback is called to schedule transmit of next fragment.
+ *
+ * Return: This returns IPC send message status.
+ */
+int ishtp_send_msg(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
+ void *msg, void(*ipc_send_compl)(void *),
+ void *ipc_send_compl_prm)
+{
+ unsigned char ipc_msg[IPC_FULL_MSG_SIZE];
+ uint32_t drbl_val;
+
+ drbl_val = dev->ops->ipc_get_header(dev, hdr->length +
+ sizeof(struct ishtp_msg_hdr),
+ 1);
+
+ memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));
+ memcpy(ipc_msg + sizeof(uint32_t), hdr, sizeof(uint32_t));
+ memcpy(ipc_msg + 2 * sizeof(uint32_t), msg, hdr->length);
+ return dev->ops->write(dev, ipc_send_compl, ipc_send_compl_prm,
+ ipc_msg, 2 * sizeof(uint32_t) + hdr->length);
+}
+
+/**
+ * ishtp_write_message() - Send ishtp single fragment message
+ * @dev: ishtp device
+ * @hdr: Message header
+ * @buf: message data
+ *
+ * Send a single fragment message via IPC. This returns IPC send message
+ * status.
+ *
+ * Return: This returns IPC send message status.
+ */
+int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
+ unsigned char *buf)
+{
+ return ishtp_send_msg(dev, hdr, buf, NULL, NULL);
+}
+
+/**
+ * ishtp_fw_cl_by_uuid() - locate index of fw client
+ * @dev: ishtp device
+ * @uuid: uuid of the client to search
+ *
+ * Search firmware client using UUID.
+ *
+ * Return: fw client index or -ENOENT if not found
+ */
+int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid)
+{
+ int i, res = -ENOENT;
+
+ for (i = 0; i < dev->fw_clients_num; ++i) {
+ if (uuid_le_cmp(*uuid, dev->fw_clients[i].props.protocol_name)
+ == 0) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
+
+/**
+ * ishtp_fw_cl_by_id() - return index to fw_clients for client_id
+ * @dev: the ishtp device structure
+ * @client_id: fw client id to search
+ *
+ * Search firmware client using client id.
+ *
+ * Return: index on success, -ENOENT on failure.
+ */
+int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id)
+{
+ int i, res = -ENOENT;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->fw_clients_lock, flags);
+ for (i = 0; i < dev->fw_clients_num; i++) {
+ if (dev->fw_clients[i].client_id == client_id) {
+ res = i;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
+
+ return res;
+}
+
+/**
+ * ishtp_cl_device_probe() - Bus probe() callback
+ * @dev: the device structure
+ *
+ * This is a bus probe callback and calls the drive probe function.
+ *
+ * Return: Return value from driver probe() call.
+ */
+static int ishtp_cl_device_probe(struct device *dev)
+{
+ struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
+ struct ishtp_cl_driver *driver;
+
+ if (!device)
+ return 0;
+
+ driver = to_ishtp_cl_driver(dev->driver);
+ if (!driver || !driver->probe)
+ return -ENODEV;
+
+ return driver->probe(device);
+}
+
+/**
+ * ishtp_cl_device_remove() - Bus remove() callback
+ * @dev: the device structure
+ *
+ * This is a bus remove callback and calls the drive remove function.
+ * Since the ISH driver model supports only built in, this is
+ * primarily can be called during pci driver init failure.
+ *
+ * Return: Return value from driver remove() call.
+ */
+static int ishtp_cl_device_remove(struct device *dev)
+{
+ struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
+ struct ishtp_cl_driver *driver;
+
+ if (!device || !dev->driver)
+ return 0;
+
+ if (device->event_cb) {
+ device->event_cb = NULL;
+ cancel_work_sync(&device->event_work);
+ }
+
+ driver = to_ishtp_cl_driver(dev->driver);
+ if (!driver->remove) {
+ dev->driver = NULL;
+
+ return 0;
+ }
+
+ return driver->remove(device);
+}
+
+/**
+ * ishtp_cl_device_suspend() - Bus suspend callback
+ * @dev: device
+ *
+ * Called during device suspend process.
+ *
+ * Return: Return value from driver suspend() call.
+ */
+static int ishtp_cl_device_suspend(struct device *dev)
+{
+ struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
+ struct ishtp_cl_driver *driver;
+ int ret = 0;
+
+ if (!device)
+ return 0;
+
+ driver = to_ishtp_cl_driver(dev->driver);
+ if (driver && driver->driver.pm) {
+ if (driver->driver.pm->suspend)
+ ret = driver->driver.pm->suspend(dev);
+ }
+
+ return ret;
+}
+
+/**
+ * ishtp_cl_device_resume() - Bus resume callback
+ * @dev: device
+ *
+ * Called during device resume process.
+ *
+ * Return: Return value from driver resume() call.
+ */
+static int ishtp_cl_device_resume(struct device *dev)
+{
+ struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
+ struct ishtp_cl_driver *driver;
+ int ret = 0;
+
+ if (!device)
+ return 0;
+
+ /*
+ * When ISH needs hard reset, it is done asynchrnously, hence bus
+ * resume will be called before full ISH resume
+ */
+ if (device->ishtp_dev->resume_flag)
+ return 0;
+
+ driver = to_ishtp_cl_driver(dev->driver);
+ if (driver && driver->driver.pm) {
+ if (driver->driver.pm->resume)
+ ret = driver->driver.pm->resume(dev);
+ }
+
+ return ret;
+}
+
+/**
+ * ishtp_cl_device_reset() - Reset callback
+ * @device: ishtp client device instance
+ *
+ * This is a callback when HW reset is done and the device need
+ * reinit.
+ *
+ * Return: Return value from driver reset() call.
+ */
+static int ishtp_cl_device_reset(struct ishtp_cl_device *device)
+{
+ struct ishtp_cl_driver *driver;
+ int ret = 0;
+
+ device->event_cb = NULL;
+ cancel_work_sync(&device->event_work);
+
+ driver = to_ishtp_cl_driver(device->dev.driver);
+ if (driver && driver->reset)
+ ret = driver->reset(device);
+
+ return ret;
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ int len;
+
+ len = snprintf(buf, PAGE_SIZE, "ishtp:%s\n", dev_name(dev));
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute ishtp_cl_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static int ishtp_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ if (add_uevent_var(env, "MODALIAS=ishtp:%s", dev_name(dev)))
+ return -ENOMEM;
+ return 0;
+}
+
+static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = {
+ /* Suspend callbacks */
+ .suspend = ishtp_cl_device_suspend,
+ .resume = ishtp_cl_device_resume,
+ /* Hibernate callbacks */
+ .freeze = ishtp_cl_device_suspend,
+ .thaw = ishtp_cl_device_resume,
+ .restore = ishtp_cl_device_resume,
+};
+
+static struct bus_type ishtp_cl_bus_type = {
+ .name = "ishtp",
+ .dev_attrs = ishtp_cl_dev_attrs,
+ .probe = ishtp_cl_device_probe,
+ .remove = ishtp_cl_device_remove,
+ .pm = &ishtp_cl_bus_dev_pm_ops,
+ .uevent = ishtp_cl_uevent,
+};
+
+static void ishtp_cl_dev_release(struct device *dev)
+{
+ kfree(to_ishtp_cl_device(dev));
+}
+
+static struct device_type ishtp_cl_device_type = {
+ .release = ishtp_cl_dev_release,
+};
+
+/**
+ * ishtp_bus_add_device() - Function to create device on bus
+ * @dev: ishtp device
+ * @uuid: uuid of the client
+ * @name: Name of the client
+ *
+ * Allocate ISHTP bus client device, attach it to uuid
+ * and register with ISHTP bus.
+ *
+ * Return: ishtp_cl_device pointer or NULL on failure
+ */
+static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
+ uuid_le uuid, char *name)
+{
+ struct ishtp_cl_device *device;
+ int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->device_list_lock, flags);
+ list_for_each_entry(device, &dev->device_list, device_link) {
+ if (!strcmp(name, dev_name(&device->dev))) {
+ device->fw_client = &dev->fw_clients[
+ dev->fw_client_presentation_num - 1];
+ spin_unlock_irqrestore(&dev->device_list_lock, flags);
+ ishtp_cl_device_reset(device);
+ return device;
+ }
+ }
+ spin_unlock_irqrestore(&dev->device_list_lock, flags);
+
+ device = kzalloc(sizeof(struct ishtp_cl_device), GFP_KERNEL);
+ if (!device)
+ return NULL;
+
+ device->dev.parent = dev->devc;
+ device->dev.bus = &ishtp_cl_bus_type;
+ device->dev.type = &ishtp_cl_device_type;
+ device->ishtp_dev = dev;
+
+ device->fw_client =
+ &dev->fw_clients[dev->fw_client_presentation_num - 1];
+
+ dev_set_name(&device->dev, "%s", name);
+
+ spin_lock_irqsave(&dev->device_list_lock, flags);
+ list_add_tail(&device->device_link, &dev->device_list);
+ spin_unlock_irqrestore(&dev->device_list_lock, flags);
+
+ status = device_register(&device->dev);
+ if (status) {
+ spin_lock_irqsave(&dev->device_list_lock, flags);
+ list_del(&device->device_link);
+ spin_unlock_irqrestore(&dev->device_list_lock, flags);
+ dev_err(dev->devc, "Failed to register ISHTP client device\n");
+ kfree(device);
+ return NULL;
+ }
+
+ ishtp_device_ready = true;
+
+ return device;
+}
+
+/**
+ * ishtp_bus_remove_device() - Function to relase device on bus
+ * @device: client device instance
+ *
+ * This is a counterpart of ishtp_bus_add_device.
+ * Device is unregistered.
+ * the device structure is freed in 'ishtp_cl_dev_release' function
+ * Called only during error in pci driver init path.
+ */
+static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
+{
+ device_unregister(&device->dev);
+}
+
+/**
+ * __ishtp_cl_driver_register() - Client driver register
+ * @driver: the client driver instance
+ * @owner: Owner of this driver module
+ *
+ * Once a client driver is probed, it created a client
+ * instance and registers with the bus.
+ *
+ * Return: Return value of driver_register or -ENODEV if not ready
+ */
+int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
+ struct module *owner)
+{
+ int err;
+
+ if (!ishtp_device_ready)
+ return -ENODEV;
+
+ driver->driver.name = driver->name;
+ driver->driver.owner = owner;
+ driver->driver.bus = &ishtp_cl_bus_type;
+
+ err = driver_register(&driver->driver);
+ if (err)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL(__ishtp_cl_driver_register);
+
+/**
+ * ishtp_cl_driver_unregister() - Client driver unregister
+ * @driver: the client driver instance
+ *
+ * Unregister client during device removal process.
+ */
+void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver)
+{
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL(ishtp_cl_driver_unregister);
+
+/**
+ * ishtp_bus_event_work() - event work function
+ * @work: work struct pointer
+ *
+ * Once an event is received for a client this work
+ * function is called. If the device has registered a
+ * callback then the callback is called.
+ */
+static void ishtp_bus_event_work(struct work_struct *work)
+{
+ struct ishtp_cl_device *device;
+
+ device = container_of(work, struct ishtp_cl_device, event_work);
+
+ if (device->event_cb)
+ device->event_cb(device);
+}
+
+/**
+ * ishtp_cl_bus_rx_event() - schedule event work
+ * @device: client device instance
+ *
+ * Once an event is received for a client this schedules
+ * a work function to process.
+ */
+void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device)
+{
+ if (!device || !device->event_cb)
+ return;
+
+ if (device->event_cb)
+ schedule_work(&device->event_work);
+}
+
+/**
+ * ishtp_register_event_cb() - Register callback
+ * @device: client device instance
+ * @event_cb: Event processor for an client
+ *
+ * Register a callback for events, called from client driver
+ *
+ * Return: Return 0 or -EALREADY if already registered
+ */
+int ishtp_register_event_cb(struct ishtp_cl_device *device,
+ void (*event_cb)(struct ishtp_cl_device *))
+{
+ if (device->event_cb)
+ return -EALREADY;
+
+ device->event_cb = event_cb;
+ INIT_WORK(&device->event_work, ishtp_bus_event_work);
+
+ return 0;
+}
+EXPORT_SYMBOL(ishtp_register_event_cb);
+
+/**
+ * ishtp_get_device() - update usage count for the device
+ * @cl_device: client device instance
+ *
+ * Increment the usage count. The device can't be deleted
+ */
+void ishtp_get_device(struct ishtp_cl_device *cl_device)
+{
+ cl_device->reference_count++;
+}
+EXPORT_SYMBOL(ishtp_get_device);
+
+/**
+ * ishtp_put_device() - decrement usage count for the device
+ * @cl_device: client device instance
+ *
+ * Decrement the usage count. The device can be deleted is count = 0
+ */
+void ishtp_put_device(struct ishtp_cl_device *cl_device)
+{
+ cl_device->reference_count--;
+}
+EXPORT_SYMBOL(ishtp_put_device);
+
+/**
+ * ishtp_bus_new_client() - Create a new client
+ * @dev: ISHTP device instance
+ *
+ * Once bus protocol enumerates a client, this is called
+ * to add a device for the client.
+ *
+ * Return: 0 on success or error code on failure
+ */
+int ishtp_bus_new_client(struct ishtp_device *dev)
+{
+ int i;
+ char *dev_name;
+ struct ishtp_cl_device *cl_device;
+ uuid_le device_uuid;
+
+ /*
+ * For all reported clients, create an unconnected client and add its
+ * device to ISHTP bus.
+ * If appropriate driver has loaded, this will trigger its probe().
+ * Otherwise, probe() will be called when driver is loaded
+ */
+ i = dev->fw_client_presentation_num - 1;
+ device_uuid = dev->fw_clients[i].props.protocol_name;
+ dev_name = kasprintf(GFP_KERNEL,
+ "{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ device_uuid.b[3], device_uuid.b[2], device_uuid.b[1],
+ device_uuid.b[0], device_uuid.b[5], device_uuid.b[4],
+ device_uuid.b[7], device_uuid.b[6], device_uuid.b[8],
+ device_uuid.b[9], device_uuid.b[10], device_uuid.b[11],
+ device_uuid.b[12], device_uuid.b[13], device_uuid.b[14],
+ device_uuid.b[15]);
+ if (!dev_name)
+ return -ENOMEM;
+
+ cl_device = ishtp_bus_add_device(dev, device_uuid, dev_name);
+ if (!cl_device) {
+ kfree(dev_name);
+ return -ENOENT;
+ }
+
+ kfree(dev_name);
+
+ return 0;
+}
+
+/**
+ * ishtp_cl_device_bind() - bind a device
+ * @cl: ishtp client device
+ *
+ * Binds connected ishtp_cl to ISHTP bus device
+ *
+ * Return: 0 on success or fault code
+ */
+int ishtp_cl_device_bind(struct ishtp_cl *cl)
+{
+ struct ishtp_cl_device *cl_device;
+ unsigned long flags;
+ int rv;
+
+ if (!cl->fw_client_id || cl->state != ISHTP_CL_CONNECTED)
+ return -EFAULT;
+
+ rv = -ENOENT;
+ spin_lock_irqsave(&cl->dev->device_list_lock, flags);
+ list_for_each_entry(cl_device, &cl->dev->device_list,
+ device_link) {
+ if (cl_device->fw_client->client_id == cl->fw_client_id) {
+ cl->device = cl_device;
+ rv = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cl->dev->device_list_lock, flags);
+ return rv;
+}
+
+/**
+ * ishtp_bus_remove_all_clients() - Remove all clients
+ * @ishtp_dev: ishtp device
+ * @warm_reset: Reset due to FW reset dure to errors or S3 suspend
+ *
+ * This is part of reset/remove flow. This function the main processing
+ * only targets error processing, if the FW has forced reset or
+ * error to remove connected clients. When warm reset the client devices are
+ * not removed.
+ */
+void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
+ bool warm_reset)
+{
+ struct ishtp_cl_device *cl_device, *n;
+ struct ishtp_cl *cl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags);
+ list_for_each_entry(cl, &ishtp_dev->cl_list, link) {
+ cl->state = ISHTP_CL_DISCONNECTED;
+
+ /*
+ * Wake any pending process. The waiter would check dev->state
+ * and determine that it's not enabled already,
+ * and will return error to its caller
+ */
+ wake_up_interruptible(&cl->wait_ctrl_res);
+
+ /* Disband any pending read/write requests and free rb */
+ ishtp_cl_flush_queues(cl);
+
+ /* Remove all free and in_process rings, both Rx and Tx */
+ ishtp_cl_free_rx_ring(cl);
+ ishtp_cl_free_tx_ring(cl);
+
+ /*
+ * Free client and ISHTP bus client device structures
+ * don't free host client because it is part of the OS fd
+ * structure
+ */
+ }
+ spin_unlock_irqrestore(&ishtp_dev->cl_list_lock, flags);
+
+ /* Release DMA buffers for client messages */
+ ishtp_cl_free_dma_buf(ishtp_dev);
+
+ /* remove bus clients */
+ spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
+ list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list,
+ device_link) {
+ if (warm_reset && cl_device->reference_count)
+ continue;
+
+ list_del(&cl_device->device_link);
+ spin_unlock_irqrestore(&ishtp_dev->device_list_lock, flags);
+ ishtp_bus_remove_device(cl_device);
+ spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&ishtp_dev->device_list_lock, flags);
+
+ /* Free all client structures */
+ spin_lock_irqsave(&ishtp_dev->fw_clients_lock, flags);
+ kfree(ishtp_dev->fw_clients);
+ ishtp_dev->fw_clients = NULL;
+ ishtp_dev->fw_clients_num = 0;
+ ishtp_dev->fw_client_presentation_num = 0;
+ ishtp_dev->fw_client_index = 0;
+ bitmap_zero(ishtp_dev->fw_clients_map, ISHTP_CLIENTS_MAX);
+ spin_unlock_irqrestore(&ishtp_dev->fw_clients_lock, flags);
+}
+EXPORT_SYMBOL(ishtp_bus_remove_all_clients);
+
+/**
+ * ishtp_reset_handler() - IPC reset handler
+ * @dev: ishtp device
+ *
+ * ISHTP Handler for IPC_RESET notification
+ */
+void ishtp_reset_handler(struct ishtp_device *dev)
+{
+ unsigned long flags;
+
+ /* Handle FW-initiated reset */
+ dev->dev_state = ISHTP_DEV_RESETTING;
+
+ /* Clear BH processing queue - no further HBMs */
+ spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
+ dev->rd_msg_fifo_head = dev->rd_msg_fifo_tail = 0;
+ spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
+
+ /* Handle ISH FW reset against upper layers */
+ ishtp_bus_remove_all_clients(dev, true);
+}
+EXPORT_SYMBOL(ishtp_reset_handler);
+
+/**
+ * ishtp_reset_compl_handler() - Reset completion handler
+ * @dev: ishtp device
+ *
+ * ISHTP handler for IPC_RESET sequence completion to start
+ * host message bus start protocol sequence.
+ */
+void ishtp_reset_compl_handler(struct ishtp_device *dev)
+{
+ dev->dev_state = ISHTP_DEV_INIT_CLIENTS;
+ dev->hbm_state = ISHTP_HBM_START;
+ ishtp_hbm_start_req(dev);
+}
+EXPORT_SYMBOL(ishtp_reset_compl_handler);
+
+/**
+ * ishtp_use_dma_transfer() - Function to use DMA
+ *
+ * This interface is used to enable usage of DMA
+ *
+ * Return non zero if DMA can be enabled
+ */
+int ishtp_use_dma_transfer(void)
+{
+ return ishtp_use_dma;
+}
+
+/**
+ * ishtp_bus_register() - Function to register bus
+ *
+ * This register ishtp bus
+ *
+ * Return: Return output of bus_register
+ */
+static int __init ishtp_bus_register(void)
+{
+ return bus_register(&ishtp_cl_bus_type);
+}
+
+/**
+ * ishtp_bus_unregister() - Function to unregister bus
+ *
+ * This unregister ishtp bus
+ */
+static void __exit ishtp_bus_unregister(void)
+{
+ bus_unregister(&ishtp_cl_bus_type);
+}
+
+module_init(ishtp_bus_register);
+module_exit(ishtp_bus_unregister);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.h b/drivers/hid/intel-ish-hid/ishtp/bus.h
new file mode 100644
index 000000000000..a1ffae7f26ad
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.h
@@ -0,0 +1,114 @@
+/*
+ * ISHTP bus definitions
+ *
+ * Copyright (c) 2014-2016, 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.
+ */
+#ifndef _LINUX_ISHTP_CL_BUS_H
+#define _LINUX_ISHTP_CL_BUS_H
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct ishtp_cl;
+struct ishtp_cl_device;
+struct ishtp_device;
+struct ishtp_msg_hdr;
+
+/**
+ * struct ishtp_cl_device - ISHTP device handle
+ * @dev: device pointer
+ * @ishtp_dev: pointer to ishtp device structure to primarily to access
+ * hw device operation callbacks and properties
+ * @fw_client: fw_client pointer to get fw information like protocol name
+ * max message length etc.
+ * @device_link: Link to next client in the list on a bus
+ * @event_work: Used to schedule rx event for client
+ * @driver_data: Storage driver private data
+ * @reference_count: Used for get/put device
+ * @event_cb: Callback to driver to send events
+ *
+ * An ishtp_cl_device pointer is returned from ishtp_add_device()
+ * and links ISHTP bus clients to their actual host client pointer.
+ * Drivers for ISHTP devices will get an ishtp_cl_device pointer
+ * when being probed and shall use it for doing bus I/O.
+ */
+struct ishtp_cl_device {
+ struct device dev;
+ struct ishtp_device *ishtp_dev;
+ struct ishtp_fw_client *fw_client;
+ struct list_head device_link;
+ struct work_struct event_work;
+ void *driver_data;
+ int reference_count;
+ void (*event_cb)(struct ishtp_cl_device *device);
+};
+
+/**
+ * struct ishtp_cl_device - ISHTP device handle
+ * @driver: driver instance on a bus
+ * @name: Name of the device for probe
+ * @probe: driver callback for device probe
+ * @remove: driver callback on device removal
+ *
+ * Client drivers defines to get probed/removed for ISHTP client device.
+ */
+struct ishtp_cl_driver {
+ struct device_driver driver;
+ const char *name;
+ int (*probe)(struct ishtp_cl_device *dev);
+ int (*remove)(struct ishtp_cl_device *dev);
+ int (*reset)(struct ishtp_cl_device *dev);
+ const struct dev_pm_ops *pm;
+};
+
+
+int ishtp_bus_new_client(struct ishtp_device *dev);
+void ishtp_remove_all_clients(struct ishtp_device *dev);
+int ishtp_cl_device_bind(struct ishtp_cl *cl);
+void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device);
+
+/* Write a multi-fragment message */
+int ishtp_send_msg(struct ishtp_device *dev,
+ struct ishtp_msg_hdr *hdr, void *msg,
+ void (*ipc_send_compl)(void *),
+ void *ipc_send_compl_prm);
+
+/* Write a single-fragment message */
+int ishtp_write_message(struct ishtp_device *dev,
+ struct ishtp_msg_hdr *hdr,
+ unsigned char *buf);
+
+/* Use DMA to send/receive messages */
+int ishtp_use_dma_transfer(void);
+
+/* Exported functions */
+void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
+ bool warm_reset);
+
+void ishtp_recv(struct ishtp_device *dev);
+void ishtp_reset_handler(struct ishtp_device *dev);
+void ishtp_reset_compl_handler(struct ishtp_device *dev);
+
+void ishtp_put_device(struct ishtp_cl_device *);
+void ishtp_get_device(struct ishtp_cl_device *);
+
+int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
+ struct module *owner);
+#define ishtp_cl_driver_register(driver) \
+ __ishtp_cl_driver_register(driver, THIS_MODULE)
+void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver);
+
+int ishtp_register_event_cb(struct ishtp_cl_device *device,
+ void (*read_cb)(struct ishtp_cl_device *));
+int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid);
+
+#endif /* _LINUX_ISHTP_CL_BUS_H */
diff --git a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c
new file mode 100644
index 000000000000..b9b917d2d50d
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c
@@ -0,0 +1,257 @@
+/*
+ * ISHTP Ring Buffers
+ *
+ * Copyright (c) 2003-2016, 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include "client.h"
+
+/**
+ * ishtp_cl_alloc_rx_ring() - Allocate RX ring buffers
+ * @cl: client device instance
+ *
+ * Allocate and initialize RX ring buffers
+ *
+ * Return: 0 on success else -ENOMEM
+ */
+int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl)
+{
+ size_t len = cl->device->fw_client->props.max_msg_length;
+ int j;
+ struct ishtp_cl_rb *rb;
+ int ret = 0;
+ unsigned long flags;
+
+ for (j = 0; j < cl->rx_ring_size; ++j) {
+ rb = ishtp_io_rb_init(cl);
+ if (!rb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = ishtp_io_rb_alloc_buf(rb, len);
+ if (ret)
+ goto out;
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+ list_add_tail(&rb->list, &cl->free_rb_list.list);
+ spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
+ }
+
+ return 0;
+
+out:
+ dev_err(&cl->device->dev, "error in allocating Rx buffers\n");
+ ishtp_cl_free_rx_ring(cl);
+ return ret;
+}
+
+/**
+ * ishtp_cl_alloc_tx_ring() - Allocate TX ring buffers
+ * @cl: client device instance
+ *
+ * Allocate and initialize TX ring buffers
+ *
+ * Return: 0 on success else -ENOMEM
+ */
+int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
+{
+ size_t len = cl->device->fw_client->props.max_msg_length;
+ int j;
+ unsigned long flags;
+
+ /* Allocate pool to free Tx bufs */
+ for (j = 0; j < cl->tx_ring_size; ++j) {
+ struct ishtp_cl_tx_ring *tx_buf;
+
+ tx_buf = kzalloc(sizeof(struct ishtp_cl_tx_ring), GFP_KERNEL);
+ if (!tx_buf)
+ goto out;
+
+ tx_buf->send_buf.data = kmalloc(len, GFP_KERNEL);
+ if (!tx_buf->send_buf.data) {
+ kfree(tx_buf);
+ goto out;
+ }
+
+ spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
+ list_add_tail(&tx_buf->list, &cl->tx_free_list.list);
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
+ }
+ return 0;
+out:
+ dev_err(&cl->device->dev, "error in allocating Tx pool\n");
+ ishtp_cl_free_rx_ring(cl);
+ return -ENOMEM;
+}
+
+/**
+ * ishtp_cl_free_rx_ring() - Free RX ring buffers
+ * @cl: client device instance
+ *
+ * Free RX ring buffers
+ */
+void ishtp_cl_free_rx_ring(struct ishtp_cl *cl)
+{
+ struct ishtp_cl_rb *rb;
+ unsigned long flags;
+
+ /* release allocated memory - pass over free_rb_list */
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+ while (!list_empty(&cl->free_rb_list.list)) {
+ rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb,
+ list);
+ list_del(&rb->list);
+ kfree(rb->buffer.data);
+ kfree(rb);
+ }
+ spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
+ /* release allocated memory - pass over in_process_list */
+ spin_lock_irqsave(&cl->in_process_spinlock, flags);
+ while (!list_empty(&cl->in_process_list.list)) {
+ rb = list_entry(cl->in_process_list.list.next,
+ struct ishtp_cl_rb, list);
+ list_del(&rb->list);
+ kfree(rb->buffer.data);
+ kfree(rb);
+ }
+ spin_unlock_irqrestore(&cl->in_process_spinlock, flags);
+}
+
+/**
+ * ishtp_cl_free_tx_ring() - Free TX ring buffers
+ * @cl: client device instance
+ *
+ * Free TX ring buffers
+ */
+void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)
+{
+ struct ishtp_cl_tx_ring *tx_buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
+ /* release allocated memory - pass over tx_free_list */
+ while (!list_empty(&cl->tx_free_list.list)) {
+ tx_buf = list_entry(cl->tx_free_list.list.next,
+ struct ishtp_cl_tx_ring, list);
+ list_del(&tx_buf->list);
+ kfree(tx_buf->send_buf.data);
+ kfree(tx_buf);
+ }
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
+
+ spin_lock_irqsave(&cl->tx_list_spinlock, flags);
+ /* release allocated memory - pass over tx_list */
+ while (!list_empty(&cl->tx_list.list)) {
+ tx_buf = list_entry(cl->tx_list.list.next,
+ struct ishtp_cl_tx_ring, list);
+ list_del(&tx_buf->list);
+ kfree(tx_buf->send_buf.data);
+ kfree(tx_buf);
+ }
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, flags);
+}
+
+/**
+ * ishtp_io_rb_free() - Free IO request block
+ * @rb: IO request block
+ *
+ * Free io request block memory
+ */
+void ishtp_io_rb_free(struct ishtp_cl_rb *rb)
+{
+ if (rb == NULL)
+ return;
+
+ kfree(rb->buffer.data);
+ kfree(rb);
+}
+
+/**
+ * ishtp_io_rb_init() - Allocate and init IO request block
+ * @cl: client device instance
+ *
+ * Allocate and initialize request block
+ *
+ * Return: Allocted IO request block pointer
+ */
+struct ishtp_cl_rb *ishtp_io_rb_init(struct ishtp_cl *cl)
+{
+ struct ishtp_cl_rb *rb;
+
+ rb = kzalloc(sizeof(struct ishtp_cl_rb), GFP_KERNEL);
+ if (!rb)
+ return NULL;
+
+ INIT_LIST_HEAD(&rb->list);
+ rb->cl = cl;
+ rb->buf_idx = 0;
+ return rb;
+}
+
+/**
+ * ishtp_io_rb_alloc_buf() - Allocate and init response buffer
+ * @rb: IO request block
+ * @length: length of response buffer
+ *
+ * Allocate respose buffer
+ *
+ * Return: 0 on success else -ENOMEM
+ */
+int ishtp_io_rb_alloc_buf(struct ishtp_cl_rb *rb, size_t length)
+{
+ if (!rb)
+ return -EINVAL;
+
+ if (length == 0)
+ return 0;
+
+ rb->buffer.data = kmalloc(length, GFP_KERNEL);
+ if (!rb->buffer.data)
+ return -ENOMEM;
+
+ rb->buffer.size = length;
+ return 0;
+}
+
+/**
+ * ishtp_cl_io_rb_recycle() - Recycle IO request blocks
+ * @rb: IO request block
+ *
+ * Re-append rb to its client's free list and send flow control if needed
+ *
+ * Return: 0 on success else -EFAULT
+ */
+int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)
+{
+ struct ishtp_cl *cl;
+ int rets = 0;
+ unsigned long flags;
+
+ if (!rb || !rb->cl)
+ return -EFAULT;
+
+ cl = rb->cl;
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+ list_add_tail(&rb->list, &cl->free_rb_list.list);
+ spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
+
+ /*
+ * If we returned the first buffer to empty 'free' list,
+ * send flow control
+ */
+ if (!cl->out_flow_ctrl_creds)
+ rets = ishtp_cl_read_start(cl);
+
+ return rets;
+}
+EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);
diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c
new file mode 100644
index 000000000000..aad61328f282
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/client.c
@@ -0,0 +1,1054 @@
+/*
+ * ISHTP client logic
+ *
+ * Copyright (c) 2003-2016, 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include "hbm.h"
+#include "client.h"
+
+/**
+ * ishtp_read_list_flush() - Flush read queue
+ * @cl: ishtp client instance
+ *
+ * Used to remove all entries from read queue for a client
+ */
+static void ishtp_read_list_flush(struct ishtp_cl *cl)
+{
+ struct ishtp_cl_rb *rb;
+ struct ishtp_cl_rb *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cl->dev->read_list_spinlock, flags);
+ list_for_each_entry_safe(rb, next, &cl->dev->read_list.list, list)
+ if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) {
+ list_del(&rb->list);
+ ishtp_io_rb_free(rb);
+ }
+ spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags);
+}
+
+/**
+ * ishtp_cl_flush_queues() - Flush all queues for a client
+ * @cl: ishtp client instance
+ *
+ * Used to remove all queues for a client. This is called when a client device
+ * needs reset due to error, S3 resume or during module removal
+ *
+ * Return: 0 on success else -EINVAL if device is NULL
+ */
+int ishtp_cl_flush_queues(struct ishtp_cl *cl)
+{
+ if (WARN_ON(!cl || !cl->dev))
+ return -EINVAL;
+
+ ishtp_read_list_flush(cl);
+
+ return 0;
+}
+EXPORT_SYMBOL(ishtp_cl_flush_queues);
+
+/**
+ * ishtp_cl_init() - Initialize all fields of a client device
+ * @cl: ishtp client instance
+ * @dev: ishtp device
+ *
+ * Initializes a client device fields: Init spinlocks, init queues etc.
+ * This function is called during new client creation
+ */
+static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev)
+{
+ memset(cl, 0, sizeof(struct ishtp_cl));
+ init_waitqueue_head(&cl->wait_ctrl_res);
+ spin_lock_init(&cl->free_list_spinlock);
+ spin_lock_init(&cl->in_process_spinlock);
+ spin_lock_init(&cl->tx_list_spinlock);
+ spin_lock_init(&cl->tx_free_list_spinlock);
+ spin_lock_init(&cl->fc_spinlock);
+ INIT_LIST_HEAD(&cl->link);
+ cl->dev = dev;
+
+ INIT_LIST_HEAD(&cl->free_rb_list.list);
+ INIT_LIST_HEAD(&cl->tx_list.list);
+ INIT_LIST_HEAD(&cl->tx_free_list.list);
+ INIT_LIST_HEAD(&cl->in_process_list.list);
+
+ cl->rx_ring_size = CL_DEF_RX_RING_SIZE;
+ cl->tx_ring_size = CL_DEF_TX_RING_SIZE;
+
+ /* dma */
+ cl->last_tx_path = CL_TX_PATH_IPC;
+ cl->last_dma_acked = 1;
+ cl->last_dma_addr = NULL;
+ cl->last_ipc_acked = 1;
+}
+
+/**
+ * ishtp_cl_allocate() - allocates client structure and sets it up.
+ * @dev: ishtp device
+ *
+ * Allocate memory for new client device and call to initialize each field.
+ *
+ * Return: The allocated client instance or NULL on failure
+ */
+struct ishtp_cl *ishtp_cl_allocate(struct ishtp_device *dev)
+{
+ struct ishtp_cl *cl;
+
+ cl = kmalloc(sizeof(struct ishtp_cl), GFP_KERNEL);
+ if (!cl)
+ return NULL;
+
+ ishtp_cl_init(cl, dev);
+ return cl;
+}
+EXPORT_SYMBOL(ishtp_cl_allocate);
+
+/**
+ * ishtp_cl_free() - Frees a client device
+ * @cl: client device instance
+ *
+ * Frees a client device
+ */
+void ishtp_cl_free(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ unsigned long flags;
+
+ if (!cl)
+ return;
+
+ dev = cl->dev;
+ if (!dev)
+ return;
+
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ ishtp_cl_free_rx_ring(cl);
+ ishtp_cl_free_tx_ring(cl);
+ kfree(cl);
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+}
+EXPORT_SYMBOL(ishtp_cl_free);
+
+/**
+ * ishtp_cl_link() - Reserve a host id and link the client instance
+ * @cl: client device instance
+ * @id: host client id to use. It can be ISHTP_HOST_CLIENT_ID_ANY if any
+ * id from the available can be used
+ *
+ *
+ * This allocates a single bit in the hostmap. This function will make sure
+ * that not many client sessions are opened at the same time. Once allocated
+ * the client device instance is added to the ishtp device in the current
+ * client list
+ *
+ * Return: 0 or error code on failure
+ */
+int ishtp_cl_link(struct ishtp_cl *cl, int id)
+{
+ struct ishtp_device *dev;
+ unsigned long flags, flags_cl;
+ int ret = 0;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -EINVAL;
+
+ dev = cl->dev;
+
+ spin_lock_irqsave(&dev->device_lock, flags);
+
+ if (dev->open_handle_count >= ISHTP_MAX_OPEN_HANDLE_COUNT) {
+ ret = -EMFILE;
+ goto unlock_dev;
+ }
+
+ /* If Id is not assigned get one*/
+ if (id == ISHTP_HOST_CLIENT_ID_ANY)
+ id = find_first_zero_bit(dev->host_clients_map,
+ ISHTP_CLIENTS_MAX);
+
+ if (id >= ISHTP_CLIENTS_MAX) {
+ spin_unlock_irqrestore(&dev->device_lock, flags);
+ dev_err(&cl->device->dev, "id exceeded %d", ISHTP_CLIENTS_MAX);
+ return -ENOENT;
+ }
+
+ dev->open_handle_count++;
+ cl->host_client_id = id;
+ spin_lock_irqsave(&dev->cl_list_lock, flags_cl);
+ if (dev->dev_state != ISHTP_DEV_ENABLED) {
+ ret = -ENODEV;
+ goto unlock_cl;
+ }
+ list_add_tail(&cl->link, &dev->cl_list);
+ set_bit(id, dev->host_clients_map);
+ cl->state = ISHTP_CL_INITIALIZING;
+
+unlock_cl:
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags_cl);
+unlock_dev:
+ spin_unlock_irqrestore(&dev->device_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(ishtp_cl_link);
+
+/**
+ * ishtp_cl_unlink() - remove fw_cl from the client device list
+ * @cl: client device instance
+ *
+ * Remove a previously linked device to a ishtp device
+ */
+void ishtp_cl_unlink(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ struct ishtp_cl *pos;
+ unsigned long flags;
+
+ /* don't shout on error exit path */
+ if (!cl || !cl->dev)
+ return;
+
+ dev = cl->dev;
+
+ spin_lock_irqsave(&dev->device_lock, flags);
+ if (dev->open_handle_count > 0) {
+ clear_bit(cl->host_client_id, dev->host_clients_map);
+ dev->open_handle_count--;
+ }
+ spin_unlock_irqrestore(&dev->device_lock, flags);
+
+ /*
+ * This checks that 'cl' is actually linked into device's structure,
+ * before attempting 'list_del'
+ */
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ list_for_each_entry(pos, &dev->cl_list, link)
+ if (cl->host_client_id == pos->host_client_id) {
+ list_del_init(&pos->link);
+ break;
+ }
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+}
+EXPORT_SYMBOL(ishtp_cl_unlink);
+
+/**
+ * ishtp_cl_disconnect() - Send disconnect request to firmware
+ * @cl: client device instance
+ *
+ * Send a disconnect request for a client to firmware.
+ *
+ * Return: 0 if successful disconnect response from the firmware or error
+ * code on failure
+ */
+int ishtp_cl_disconnect(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ int err;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ dev->print_log(dev, "%s() state %d\n", __func__, cl->state);
+
+ if (cl->state != ISHTP_CL_DISCONNECTING) {
+ dev->print_log(dev, "%s() Disconnect in progress\n", __func__);
+ return 0;
+ }
+
+ if (ishtp_hbm_cl_disconnect_req(dev, cl)) {
+ dev->print_log(dev, "%s() Failed to disconnect\n", __func__);
+ dev_err(&cl->device->dev, "failed to disconnect.\n");
+ return -ENODEV;
+ }
+
+ err = wait_event_interruptible_timeout(cl->wait_ctrl_res,
+ (dev->dev_state != ISHTP_DEV_ENABLED ||
+ cl->state == ISHTP_CL_DISCONNECTED),
+ ishtp_secs_to_jiffies(ISHTP_CL_CONNECT_TIMEOUT));
+
+ /*
+ * If FW reset arrived, this will happen. Don't check cl->,
+ * as 'cl' may be freed already
+ */
+ if (dev->dev_state != ISHTP_DEV_ENABLED) {
+ dev->print_log(dev, "%s() dev_state != ISHTP_DEV_ENABLED\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (cl->state == ISHTP_CL_DISCONNECTED) {
+ dev->print_log(dev, "%s() successful\n", __func__);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL(ishtp_cl_disconnect);
+
+/**
+ * ishtp_cl_is_other_connecting() - Check other client is connecting
+ * @cl: client device instance
+ *
+ * Checks if other client with the same fw client id is connecting
+ *
+ * Return: true if other client is connected else false
+ */
+static bool ishtp_cl_is_other_connecting(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ struct ishtp_cl *pos;
+ unsigned long flags;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return false;
+
+ dev = cl->dev;
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ list_for_each_entry(pos, &dev->cl_list, link) {
+ if ((pos->state == ISHTP_CL_CONNECTING) && (pos != cl) &&
+ cl->fw_client_id == pos->fw_client_id) {
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+ return true;
+ }
+ }
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+
+ return false;
+}
+
+/**
+ * ishtp_cl_connect() - Send connect request to firmware
+ * @cl: client device instance
+ *
+ * Send a connect request for a client to firmware. If successful it will
+ * RX and TX ring buffers
+ *
+ * Return: 0 if successful connect response from the firmware and able
+ * to bind and allocate ring buffers or error code on failure
+ */
+int ishtp_cl_connect(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ int rets;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state);
+
+ if (ishtp_cl_is_other_connecting(cl)) {
+ dev->print_log(dev, "%s() Busy\n", __func__);
+ return -EBUSY;
+ }
+
+ if (ishtp_hbm_cl_connect_req(dev, cl)) {
+ dev->print_log(dev, "%s() HBM connect req fail\n", __func__);
+ return -ENODEV;
+ }
+
+ rets = wait_event_interruptible_timeout(cl->wait_ctrl_res,
+ (dev->dev_state == ISHTP_DEV_ENABLED &&
+ (cl->state == ISHTP_CL_CONNECTED ||
+ cl->state == ISHTP_CL_DISCONNECTED)),
+ ishtp_secs_to_jiffies(
+ ISHTP_CL_CONNECT_TIMEOUT));
+ /*
+ * If FW reset arrived, this will happen. Don't check cl->,
+ * as 'cl' may be freed already
+ */
+ if (dev->dev_state != ISHTP_DEV_ENABLED) {
+ dev->print_log(dev, "%s() dev_state != ISHTP_DEV_ENABLED\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (cl->state != ISHTP_CL_CONNECTED) {
+ dev->print_log(dev, "%s() state != ISHTP_CL_CONNECTED\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ rets = cl->status;
+ if (rets) {
+ dev->print_log(dev, "%s() Invalid status\n", __func__);
+ return rets;
+ }
+
+ rets = ishtp_cl_device_bind(cl);
+ if (rets) {
+ dev->print_log(dev, "%s() Bind error\n", __func__);
+ ishtp_cl_disconnect(cl);
+ return rets;
+ }
+
+ rets = ishtp_cl_alloc_rx_ring(cl);
+ if (rets) {
+ dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__);
+ /* if failed allocation, disconnect */
+ ishtp_cl_disconnect(cl);
+ return rets;
+ }
+
+ rets = ishtp_cl_alloc_tx_ring(cl);
+ if (rets) {
+ dev->print_log(dev, "%s() Alloc TX ring failed\n", __func__);
+ /* if failed allocation, disconnect */
+ ishtp_cl_free_rx_ring(cl);
+ ishtp_cl_disconnect(cl);
+ return rets;
+ }
+
+ /* Upon successful connection and allocation, emit flow-control */
+ rets = ishtp_cl_read_start(cl);
+
+ dev->print_log(dev, "%s() successful\n", __func__);
+
+ return rets;
+}
+EXPORT_SYMBOL(ishtp_cl_connect);
+
+/**
+ * ishtp_cl_read_start() - Prepare to read client message
+ * @cl: client device instance
+ *
+ * Get a free buffer from pool of free read buffers and add to read buffer
+ * pool to add contents. Send a flow control request to firmware to be able
+ * send next message.
+ *
+ * Return: 0 if successful or error code on failure
+ */
+int ishtp_cl_read_start(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ struct ishtp_cl_rb *rb;
+ int rets;
+ int i;
+ unsigned long flags;
+ unsigned long dev_flags;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ if (cl->state != ISHTP_CL_CONNECTED)
+ return -ENODEV;
+
+ if (dev->dev_state != ISHTP_DEV_ENABLED)
+ return -ENODEV;
+
+ i = ishtp_fw_cl_by_id(dev, cl->fw_client_id);
+ if (i < 0) {
+ dev_err(&cl->device->dev, "no such fw client %d\n",
+ cl->fw_client_id);
+ return -ENODEV;
+ }
+
+ /* The current rb is the head of the free rb list */
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+ if (list_empty(&cl->free_rb_list.list)) {
+ dev_warn(&cl->device->dev,
+ "[ishtp-ish] Rx buffers pool is empty\n");
+ rets = -ENOMEM;
+ rb = NULL;
+ spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
+ goto out;
+ }
+ rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb, list);
+ list_del_init(&rb->list);
+ spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
+
+ rb->cl = cl;
+ rb->buf_idx = 0;
+
+ INIT_LIST_HEAD(&rb->list);
+ rets = 0;
+
+ /*
+ * This must be BEFORE sending flow control -
+ * response in ISR may come too fast...
+ */
+ spin_lock_irqsave(&dev->read_list_spinlock, dev_flags);
+ list_add_tail(&rb->list, &dev->read_list.list);
+ spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags);
+ if (ishtp_hbm_cl_flow_control_req(dev, cl)) {
+ rets = -ENODEV;
+ goto out;
+ }
+out:
+ /* if ishtp_hbm_cl_flow_control_req failed, return rb to free list */
+ if (rets && rb) {
+ spin_lock_irqsave(&dev->read_list_spinlock, dev_flags);
+ list_del(&rb->list);
+ spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags);
+
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+ list_add_tail(&rb->list, &cl->free_rb_list.list);
+ spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
+ }
+ return rets;
+}
+
+/**
+ * ishtp_cl_send() - Send a message to firmware
+ * @cl: client device instance
+ * @buf: message buffer
+ * @length: length of message
+ *
+ * If the client is correct state to send message, this function gets a buffer
+ * from tx ring buffers, copy the message data and call to send the message
+ * using ishtp_cl_send_msg()
+ *
+ * Return: 0 if successful or error code on failure
+ */
+int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length)
+{
+ struct ishtp_device *dev;
+ int id;
+ struct ishtp_cl_tx_ring *cl_msg;
+ int have_msg_to_send = 0;
+ unsigned long tx_flags, tx_free_flags;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ if (cl->state != ISHTP_CL_CONNECTED) {
+ ++cl->err_send_msg;
+ return -EPIPE;
+ }
+
+ if (dev->dev_state != ISHTP_DEV_ENABLED) {
+ ++cl->err_send_msg;
+ return -ENODEV;
+ }
+
+ /* Check if we have fw client device */
+ id = ishtp_fw_cl_by_id(dev, cl->fw_client_id);
+ if (id < 0) {
+ ++cl->err_send_msg;
+ return -ENOENT;
+ }
+
+ if (length > dev->fw_clients[id].props.max_msg_length) {
+ ++cl->err_send_msg;
+ return -EMSGSIZE;
+ }
+
+ /* No free bufs */
+ spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
+ if (list_empty(&cl->tx_free_list.list)) {
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
+ tx_free_flags);
+ ++cl->err_send_msg;
+ return -ENOMEM;
+ }
+
+ cl_msg = list_first_entry(&cl->tx_free_list.list,
+ struct ishtp_cl_tx_ring, list);
+ if (!cl_msg->send_buf.data) {
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
+ tx_free_flags);
+ return -EIO;
+ /* Should not happen, as free list is pre-allocated */
+ }
+ /*
+ * This is safe, as 'length' is already checked for not exceeding
+ * max ISHTP message size per client
+ */
+ list_del_init(&cl_msg->list);
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
+ memcpy(cl_msg->send_buf.data, buf, length);
+ cl_msg->send_buf.size = length;
+ spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
+ have_msg_to_send = !list_empty(&cl->tx_list.list);
+ list_add_tail(&cl_msg->list, &cl->tx_list.list);
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+
+ if (!have_msg_to_send && cl->ishtp_flow_ctrl_creds > 0)
+ ishtp_cl_send_msg(dev, cl);
+
+ return 0;
+}
+EXPORT_SYMBOL(ishtp_cl_send);
+
+/**
+ * ishtp_cl_read_complete() - read complete
+ * @rb: Pointer to client request block
+ *
+ * If the message is completely received call ishtp_cl_bus_rx_event()
+ * to process message
+ */
+static void ishtp_cl_read_complete(struct ishtp_cl_rb *rb)
+{
+ unsigned long flags;
+ int schedule_work_flag = 0;
+ struct ishtp_cl *cl = rb->cl;
+
+ spin_lock_irqsave(&cl->in_process_spinlock, flags);
+ /*
+ * if in-process list is empty, then need to schedule
+ * the processing thread
+ */
+ schedule_work_flag = list_empty(&cl->in_process_list.list);
+ list_add_tail(&rb->list, &cl->in_process_list.list);
+ spin_unlock_irqrestore(&cl->in_process_spinlock, flags);
+
+ if (schedule_work_flag)
+ ishtp_cl_bus_rx_event(cl->device);
+}
+
+/**
+ * ipc_tx_callback() - IPC tx callback function
+ * @prm: Pointer to client device instance
+ *
+ * Send message over IPC either first time or on callback on previous message
+ * completion
+ */
+static void ipc_tx_callback(void *prm)
+{
+ struct ishtp_cl *cl = prm;
+ struct ishtp_cl_tx_ring *cl_msg;
+ size_t rem;
+ struct ishtp_device *dev = (cl ? cl->dev : NULL);
+ struct ishtp_msg_hdr ishtp_hdr;
+ unsigned long tx_flags, tx_free_flags;
+ unsigned char *pmsg;
+
+ if (!dev)
+ return;
+
+ /*
+ * Other conditions if some critical error has
+ * occurred before this callback is called
+ */
+ if (dev->dev_state != ISHTP_DEV_ENABLED)
+ return;
+
+ if (cl->state != ISHTP_CL_CONNECTED)
+ return;
+
+ spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
+ if (list_empty(&cl->tx_list.list)) {
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+ return;
+ }
+
+ if (cl->ishtp_flow_ctrl_creds != 1 && !cl->sending) {
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+ return;
+ }
+
+ if (!cl->sending) {
+ --cl->ishtp_flow_ctrl_creds;
+ cl->last_ipc_acked = 0;
+ cl->last_tx_path = CL_TX_PATH_IPC;
+ cl->sending = 1;
+ }
+
+ cl_msg = list_entry(cl->tx_list.list.next, struct ishtp_cl_tx_ring,
+ list);
+ rem = cl_msg->send_buf.size - cl->tx_offs;
+
+ ishtp_hdr.host_addr = cl->host_client_id;
+ ishtp_hdr.fw_addr = cl->fw_client_id;
+ ishtp_hdr.reserved = 0;
+ pmsg = cl_msg->send_buf.data + cl->tx_offs;
+
+ if (rem <= dev->mtu) {
+ ishtp_hdr.length = rem;
+ ishtp_hdr.msg_complete = 1;
+ cl->sending = 0;
+ list_del_init(&cl_msg->list); /* Must be before write */
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+ /* Submit to IPC queue with no callback */
+ ishtp_write_message(dev, &ishtp_hdr, pmsg);
+ spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
+ list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
+ tx_free_flags);
+ } else {
+ /* Send IPC fragment */
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+ cl->tx_offs += dev->mtu;
+ ishtp_hdr.length = dev->mtu;
+ ishtp_hdr.msg_complete = 0;
+ ishtp_send_msg(dev, &ishtp_hdr, pmsg, ipc_tx_callback, cl);
+ }
+}
+
+/**
+ * ishtp_cl_send_msg_ipc() -Send message using IPC
+ * @dev: ISHTP device instance
+ * @cl: Pointer to client device instance
+ *
+ * Send message over IPC not using DMA
+ */
+static void ishtp_cl_send_msg_ipc(struct ishtp_device *dev,
+ struct ishtp_cl *cl)
+{
+ /* If last DMA message wasn't acked yet, leave this one in Tx queue */
+ if (cl->last_tx_path == CL_TX_PATH_DMA && cl->last_dma_acked == 0)
+ return;
+
+ cl->tx_offs = 0;
+ ipc_tx_callback(cl);
+ ++cl->send_msg_cnt_ipc;
+}
+
+/**
+ * ishtp_cl_send_msg_dma() -Send message using DMA
+ * @dev: ISHTP device instance
+ * @cl: Pointer to client device instance
+ *
+ * Send message using DMA
+ */
+static void ishtp_cl_send_msg_dma(struct ishtp_device *dev,
+ struct ishtp_cl *cl)
+{
+ struct ishtp_msg_hdr hdr;
+ struct dma_xfer_hbm dma_xfer;
+ unsigned char *msg_addr;
+ int off;
+ struct ishtp_cl_tx_ring *cl_msg;
+ unsigned long tx_flags, tx_free_flags;
+
+ /* If last IPC message wasn't acked yet, leave this one in Tx queue */
+ if (cl->last_tx_path == CL_TX_PATH_IPC && cl->last_ipc_acked == 0)
+ return;
+
+ spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
+ if (list_empty(&cl->tx_list.list)) {
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+ return;
+ }
+
+ cl_msg = list_entry(cl->tx_list.list.next, struct ishtp_cl_tx_ring,
+ list);
+
+ msg_addr = ishtp_cl_get_dma_send_buf(dev, cl_msg->send_buf.size);
+ if (!msg_addr) {
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+ if (dev->transfer_path == CL_TX_PATH_DEFAULT)
+ ishtp_cl_send_msg_ipc(dev, cl);
+ return;
+ }
+
+ list_del_init(&cl_msg->list); /* Must be before write */
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+
+ --cl->ishtp_flow_ctrl_creds;
+ cl->last_dma_acked = 0;
+ cl->last_dma_addr = msg_addr;
+ cl->last_tx_path = CL_TX_PATH_DMA;
+
+ /* write msg to dma buf */
+ memcpy(msg_addr, cl_msg->send_buf.data, cl_msg->send_buf.size);
+
+ /* send dma_xfer hbm msg */
+ off = msg_addr - (unsigned char *)dev->ishtp_host_dma_tx_buf;
+ ishtp_hbm_hdr(&hdr, sizeof(struct dma_xfer_hbm));
+ dma_xfer.hbm = DMA_XFER;
+ dma_xfer.fw_client_id = cl->fw_client_id;
+ dma_xfer.host_client_id = cl->host_client_id;
+ dma_xfer.reserved = 0;
+ dma_xfer.msg_addr = dev->ishtp_host_dma_tx_buf_phys + off;
+ dma_xfer.msg_length = cl_msg->send_buf.size;
+ dma_xfer.reserved2 = 0;
+ ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer);
+ spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
+ list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
+ ++cl->send_msg_cnt_dma;
+}
+
+/**
+ * ishtp_cl_send_msg() -Send message using DMA or IPC
+ * @dev: ISHTP device instance
+ * @cl: Pointer to client device instance
+ *
+ * Send message using DMA or IPC based on transfer_path
+ */
+void ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl)
+{
+ if (dev->transfer_path == CL_TX_PATH_DMA)
+ ishtp_cl_send_msg_dma(dev, cl);
+ else
+ ishtp_cl_send_msg_ipc(dev, cl);
+}
+
+/**
+ * recv_ishtp_cl_msg() -Receive client message
+ * @dev: ISHTP device instance
+ * @ishtp_hdr: Pointer to message header
+ *
+ * Receive and dispatch ISHTP client messages. This function executes in ISR
+ * context
+ */
+void recv_ishtp_cl_msg(struct ishtp_device *dev,
+ struct ishtp_msg_hdr *ishtp_hdr)
+{
+ struct ishtp_cl *cl;
+ struct ishtp_cl_rb *rb;
+ struct ishtp_cl_rb *new_rb;
+ unsigned char *buffer = NULL;
+ struct ishtp_cl_rb *complete_rb = NULL;
+ unsigned long dev_flags;
+ unsigned long flags;
+ int rb_count;
+
+ if (ishtp_hdr->reserved) {
+ dev_err(dev->devc, "corrupted message header.\n");
+ goto eoi;
+ }
+
+ if (ishtp_hdr->length > IPC_PAYLOAD_SIZE) {
+ dev_err(dev->devc,
+ "ISHTP message length in hdr exceeds IPC MTU\n");
+ goto eoi;
+ }
+
+ spin_lock_irqsave(&dev->read_list_spinlock, dev_flags);
+ rb_count = -1;
+ list_for_each_entry(rb, &dev->read_list.list, list) {
+ ++rb_count;
+ cl = rb->cl;
+ if (!cl || !(cl->host_client_id == ishtp_hdr->host_addr &&
+ cl->fw_client_id == ishtp_hdr->fw_addr) ||
+ !(cl->state == ISHTP_CL_CONNECTED))
+ continue;
+
+ /* If no Rx buffer is allocated, disband the rb */
+ if (rb->buffer.size == 0 || rb->buffer.data == NULL) {
+ spin_unlock_irqrestore(&dev->read_list_spinlock,
+ dev_flags);
+ dev_err(&cl->device->dev,
+ "Rx buffer is not allocated.\n");
+ list_del(&rb->list);
+ ishtp_io_rb_free(rb);
+ cl->status = -ENOMEM;
+ goto eoi;
+ }
+
+ /*
+ * If message buffer overflown (exceeds max. client msg
+ * size, drop message and return to free buffer.
+ * Do we need to disconnect such a client? (We don't send
+ * back FC, so communication will be stuck anyway)
+ */
+ if (rb->buffer.size < ishtp_hdr->length + rb->buf_idx) {
+ spin_unlock_irqrestore(&dev->read_list_spinlock,
+ dev_flags);
+ dev_err(&cl->device->dev,
+ "message overflow. size %d len %d idx %ld\n",
+ rb->buffer.size, ishtp_hdr->length,
+ rb->buf_idx);
+ list_del(&rb->list);
+ ishtp_cl_io_rb_recycle(rb);
+ cl->status = -EIO;
+ goto eoi;
+ }
+
+ buffer = rb->buffer.data + rb->buf_idx;
+ dev->ops->ishtp_read(dev, buffer, ishtp_hdr->length);
+
+ rb->buf_idx += ishtp_hdr->length;
+ if (ishtp_hdr->msg_complete) {
+ /* Last fragment in message - it's complete */
+ cl->status = 0;
+ list_del(&rb->list);
+ complete_rb = rb;
+
+ --cl->out_flow_ctrl_creds;
+ /*
+ * the whole msg arrived, send a new FC, and add a new
+ * rb buffer for the next coming msg
+ */
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+
+ if (!list_empty(&cl->free_rb_list.list)) {
+ new_rb = list_entry(cl->free_rb_list.list.next,
+ struct ishtp_cl_rb, list);
+ list_del_init(&new_rb->list);
+ spin_unlock_irqrestore(&cl->free_list_spinlock,
+ flags);
+ new_rb->cl = cl;
+ new_rb->buf_idx = 0;
+ INIT_LIST_HEAD(&new_rb->list);
+ list_add_tail(&new_rb->list,
+ &dev->read_list.list);
+
+ ishtp_hbm_cl_flow_control_req(dev, cl);
+ } else {
+ spin_unlock_irqrestore(&cl->free_list_spinlock,
+ flags);
+ }
+ }
+ /* One more fragment in message (even if this was last) */
+ ++cl->recv_msg_num_frags;
+
+ /*
+ * We can safely break here (and in BH too),
+ * a single input message can go only to a single request!
+ */
+ break;
+ }
+
+ spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags);
+ /* If it's nobody's message, just read and discard it */
+ if (!buffer) {
+ uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
+
+ dev_err(dev->devc, "Dropped Rx msg - no request\n");
+ dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
+ goto eoi;
+ }
+
+ if (complete_rb) {
+ getnstimeofday(&cl->ts_rx);
+ ++cl->recv_msg_cnt_ipc;
+ ishtp_cl_read_complete(complete_rb);
+ }
+eoi:
+ return;
+}
+
+/**
+ * recv_ishtp_cl_msg_dma() -Receive client message
+ * @dev: ISHTP device instance
+ * @msg: message pointer
+ * @hbm: hbm buffer
+ *
+ * Receive and dispatch ISHTP client messages using DMA. This function executes
+ * in ISR context
+ */
+void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
+ struct dma_xfer_hbm *hbm)
+{
+ struct ishtp_cl *cl;
+ struct ishtp_cl_rb *rb;
+ struct ishtp_cl_rb *new_rb;
+ unsigned char *buffer = NULL;
+ struct ishtp_cl_rb *complete_rb = NULL;
+ unsigned long dev_flags;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->read_list_spinlock, dev_flags);
+ list_for_each_entry(rb, &dev->read_list.list, list) {
+ cl = rb->cl;
+ if (!cl || !(cl->host_client_id == hbm->host_client_id &&
+ cl->fw_client_id == hbm->fw_client_id) ||
+ !(cl->state == ISHTP_CL_CONNECTED))
+ continue;
+
+ /*
+ * If no Rx buffer is allocated, disband the rb
+ */
+ if (rb->buffer.size == 0 || rb->buffer.data == NULL) {
+ spin_unlock_irqrestore(&dev->read_list_spinlock,
+ dev_flags);
+ dev_err(&cl->device->dev,
+ "response buffer is not allocated.\n");
+ list_del(&rb->list);
+ ishtp_io_rb_free(rb);
+ cl->status = -ENOMEM;
+ goto eoi;
+ }
+
+ /*
+ * If message buffer overflown (exceeds max. client msg
+ * size, drop message and return to free buffer.
+ * Do we need to disconnect such a client? (We don't send
+ * back FC, so communication will be stuck anyway)
+ */
+ if (rb->buffer.size < hbm->msg_length) {
+ spin_unlock_irqrestore(&dev->read_list_spinlock,
+ dev_flags);
+ dev_err(&cl->device->dev,
+ "message overflow. size %d len %d idx %ld\n",
+ rb->buffer.size, hbm->msg_length, rb->buf_idx);
+ list_del(&rb->list);
+ ishtp_cl_io_rb_recycle(rb);
+ cl->status = -EIO;
+ goto eoi;
+ }
+
+ buffer = rb->buffer.data;
+ memcpy(buffer, msg, hbm->msg_length);
+ rb->buf_idx = hbm->msg_length;
+
+ /* Last fragment in message - it's complete */
+ cl->status = 0;
+ list_del(&rb->list);
+ complete_rb = rb;
+
+ --cl->out_flow_ctrl_creds;
+ /*
+ * the whole msg arrived, send a new FC, and add a new
+ * rb buffer for the next coming msg
+ */
+ spin_lock_irqsave(&cl->free_list_spinlock, flags);
+
+ if (!list_empty(&cl->free_rb_list.list)) {
+ new_rb = list_entry(cl->free_rb_list.list.next,
+ struct ishtp_cl_rb, list);
+ list_del_init(&new_rb->list);
+ spin_unlock_irqrestore(&cl->free_list_spinlock,
+ flags);
+ new_rb->cl = cl;
+ new_rb->buf_idx = 0;
+ INIT_LIST_HEAD(&new_rb->list);
+ list_add_tail(&new_rb->list,
+ &dev->read_list.list);
+
+ ishtp_hbm_cl_flow_control_req(dev, cl);
+ } else {
+ spin_unlock_irqrestore(&cl->free_list_spinlock,
+ flags);
+ }
+
+ /* One more fragment in message (this is always last) */
+ ++cl->recv_msg_num_frags;
+
+ /*
+ * We can safely break here (and in BH too),
+ * a single input message can go only to a single request!
+ */
+ break;
+ }
+
+ spin_unlock_irqrestore(&dev->read_list_spinlock, dev_flags);
+ /* If it's nobody's message, just read and discard it */
+ if (!buffer) {
+ dev_err(dev->devc, "Dropped Rx (DMA) msg - no request\n");
+ goto eoi;
+ }
+
+ if (complete_rb) {
+ getnstimeofday(&cl->ts_rx);
+ ++cl->recv_msg_cnt_dma;
+ ishtp_cl_read_complete(complete_rb);
+ }
+eoi:
+ return;
+}
diff --git a/drivers/hid/intel-ish-hid/ishtp/client.h b/drivers/hid/intel-ish-hid/ishtp/client.h
new file mode 100644
index 000000000000..444d069c2ed4
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/client.h
@@ -0,0 +1,182 @@
+/*
+ * ISHTP client logic
+ *
+ * Copyright (c) 2003-2016, 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.
+ */
+
+#ifndef _ISHTP_CLIENT_H_
+#define _ISHTP_CLIENT_H_
+
+#include <linux/types.h>
+#include "ishtp-dev.h"
+
+/* Client state */
+enum cl_state {
+ ISHTP_CL_INITIALIZING = 0,
+ ISHTP_CL_CONNECTING,
+ ISHTP_CL_CONNECTED,
+ ISHTP_CL_DISCONNECTING,
+ ISHTP_CL_DISCONNECTED
+};
+
+/* Tx and Rx ring size */
+#define CL_DEF_RX_RING_SIZE 2
+#define CL_DEF_TX_RING_SIZE 2
+#define CL_MAX_RX_RING_SIZE 32
+#define CL_MAX_TX_RING_SIZE 32
+
+#define DMA_SLOT_SIZE 4096
+/* Number of IPC fragments after which it's worth sending via DMA */
+#define DMA_WORTH_THRESHOLD 3
+
+/* DMA/IPC Tx paths. Other the default means enforcement */
+#define CL_TX_PATH_DEFAULT 0
+#define CL_TX_PATH_IPC 1
+#define CL_TX_PATH_DMA 2
+
+/* Client Tx buffer list entry */
+struct ishtp_cl_tx_ring {
+ struct list_head list;
+ struct ishtp_msg_data send_buf;
+};
+
+/* ISHTP client instance */
+struct ishtp_cl {
+ struct list_head link;
+ struct ishtp_device *dev;
+ enum cl_state state;
+ int status;
+
+ /* Link to ISHTP bus device */
+ struct ishtp_cl_device *device;
+
+ /* ID of client connected */
+ uint8_t host_client_id;
+ uint8_t fw_client_id;
+ uint8_t ishtp_flow_ctrl_creds;
+ uint8_t out_flow_ctrl_creds;
+
+ /* dma */
+ int last_tx_path;
+ /* 0: ack wasn't received,1:ack was received */
+ int last_dma_acked;
+ unsigned char *last_dma_addr;
+ /* 0: ack wasn't received,1:ack was received */
+ int last_ipc_acked;
+
+ /* Rx ring buffer pool */
+ unsigned int rx_ring_size;
+ struct ishtp_cl_rb free_rb_list;
+ spinlock_t free_list_spinlock;
+ /* Rx in-process list */
+ struct ishtp_cl_rb in_process_list;
+ spinlock_t in_process_spinlock;
+
+ /* Client Tx buffers list */
+ unsigned int tx_ring_size;
+ struct ishtp_cl_tx_ring tx_list, tx_free_list;
+ spinlock_t tx_list_spinlock;
+ spinlock_t tx_free_list_spinlock;
+ size_t tx_offs; /* Offset in buffer at head of 'tx_list' */
+
+ /**
+ * if we get a FC, and the list is not empty, we must know whether we
+ * are at the middle of sending.
+ * if so -need to increase FC counter, otherwise, need to start sending
+ * the first msg in list
+ * (!)This is for counting-FC implementation only. Within single-FC the
+ * other party may NOT send FC until it receives complete message
+ */
+ int sending;
+
+ /* Send FC spinlock */
+ spinlock_t fc_spinlock;
+
+ /* wait queue for connect and disconnect response from FW */
+ wait_queue_head_t wait_ctrl_res;
+
+ /* Error stats */
+ unsigned int err_send_msg;
+ unsigned int err_send_fc;
+
+ /* Send/recv stats */
+ unsigned int send_msg_cnt_ipc;
+ unsigned int send_msg_cnt_dma;
+ unsigned int recv_msg_cnt_ipc;
+ unsigned int recv_msg_cnt_dma;
+ unsigned int recv_msg_num_frags;
+ unsigned int ishtp_flow_ctrl_cnt;
+ unsigned int out_flow_ctrl_cnt;
+
+ /* Rx msg ... out FC timing */
+ struct timespec ts_rx;
+ struct timespec ts_out_fc;
+ struct timespec ts_max_fc_delay;
+ void *client_data;
+};
+
+/* Client connection managenment internal functions */
+int ishtp_can_client_connect(struct ishtp_device *ishtp_dev, uuid_le *uuid);
+int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id);
+void ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl);
+void recv_ishtp_cl_msg(struct ishtp_device *dev,
+ struct ishtp_msg_hdr *ishtp_hdr);
+int ishtp_cl_read_start(struct ishtp_cl *cl);
+
+/* Ring Buffer I/F */
+int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl);
+int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl);
+void ishtp_cl_free_rx_ring(struct ishtp_cl *cl);
+void ishtp_cl_free_tx_ring(struct ishtp_cl *cl);
+
+/* DMA I/F functions */
+void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
+ struct dma_xfer_hbm *hbm);
+void ishtp_cl_alloc_dma_buf(struct ishtp_device *dev);
+void ishtp_cl_free_dma_buf(struct ishtp_device *dev);
+void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev,
+ uint32_t size);
+void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev,
+ void *msg_addr,
+ uint8_t size);
+
+/* Request blocks alloc/free I/F */
+struct ishtp_cl_rb *ishtp_io_rb_init(struct ishtp_cl *cl);
+void ishtp_io_rb_free(struct ishtp_cl_rb *priv_rb);
+int ishtp_io_rb_alloc_buf(struct ishtp_cl_rb *rb, size_t length);
+
+/**
+ * ishtp_cl_cmp_id - tells if file private data have same id
+ * returns true - if ids are the same and not NULL
+ */
+static inline bool ishtp_cl_cmp_id(const struct ishtp_cl *cl1,
+ const struct ishtp_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->fw_client_id == cl2->fw_client_id);
+}
+
+/* exported functions from ISHTP under client management scope */
+struct ishtp_cl *ishtp_cl_allocate(struct ishtp_device *dev);
+void ishtp_cl_free(struct ishtp_cl *cl);
+int ishtp_cl_link(struct ishtp_cl *cl, int id);
+void ishtp_cl_unlink(struct ishtp_cl *cl);
+int ishtp_cl_disconnect(struct ishtp_cl *cl);
+int ishtp_cl_connect(struct ishtp_cl *cl);
+int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length);
+int ishtp_cl_flush_queues(struct ishtp_cl *cl);
+
+/* exported functions from ISHTP client buffer management scope */
+int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
+
+#endif /* _ISHTP_CLIENT_H_ */
diff --git a/drivers/hid/intel-ish-hid/ishtp/dma-if.c b/drivers/hid/intel-ish-hid/ishtp/dma-if.c
new file mode 100644
index 000000000000..2783f3666114
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/dma-if.c
@@ -0,0 +1,175 @@
+/*
+ * ISHTP DMA I/F functions
+ *
+ * Copyright (c) 2003-2016, 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include "ishtp-dev.h"
+#include "client.h"
+
+/**
+ * ishtp_cl_alloc_dma_buf() - Allocate DMA RX and TX buffer
+ * @dev: ishtp device
+ *
+ * Allocate RX and TX DMA buffer once during bus setup.
+ * It allocates 1MB, RX and TX DMA buffer, which are divided
+ * into slots.
+ */
+void ishtp_cl_alloc_dma_buf(struct ishtp_device *dev)
+{
+ dma_addr_t h;
+
+ if (dev->ishtp_host_dma_tx_buf)
+ return;
+
+ dev->ishtp_host_dma_tx_buf_size = 1024*1024;
+ dev->ishtp_host_dma_rx_buf_size = 1024*1024;
+
+ /* Allocate Tx buffer and init usage bitmap */
+ dev->ishtp_host_dma_tx_buf = dma_alloc_coherent(dev->devc,
+ dev->ishtp_host_dma_tx_buf_size,
+ &h, GFP_KERNEL);
+ if (dev->ishtp_host_dma_tx_buf)
+ dev->ishtp_host_dma_tx_buf_phys = h;
+
+ dev->ishtp_dma_num_slots = dev->ishtp_host_dma_tx_buf_size /
+ DMA_SLOT_SIZE;
+
+ dev->ishtp_dma_tx_map = kcalloc(dev->ishtp_dma_num_slots,
+ sizeof(uint8_t),
+ GFP_KERNEL);
+ spin_lock_init(&dev->ishtp_dma_tx_lock);
+
+ /* Allocate Rx buffer */
+ dev->ishtp_host_dma_rx_buf = dma_alloc_coherent(dev->devc,
+ dev->ishtp_host_dma_rx_buf_size,
+ &h, GFP_KERNEL);
+
+ if (dev->ishtp_host_dma_rx_buf)
+ dev->ishtp_host_dma_rx_buf_phys = h;
+}
+
+/**
+ * ishtp_cl_free_dma_buf() - Free DMA RX and TX buffer
+ * @dev: ishtp device
+ *
+ * Free DMA buffer when all clients are released. This is
+ * only happens during error path in ISH built in driver
+ * model
+ */
+void ishtp_cl_free_dma_buf(struct ishtp_device *dev)
+{
+ dma_addr_t h;
+
+ if (dev->ishtp_host_dma_tx_buf) {
+ h = dev->ishtp_host_dma_tx_buf_phys;
+ dma_free_coherent(dev->devc, dev->ishtp_host_dma_tx_buf_size,
+ dev->ishtp_host_dma_tx_buf, h);
+ }
+
+ if (dev->ishtp_host_dma_rx_buf) {
+ h = dev->ishtp_host_dma_rx_buf_phys;
+ dma_free_coherent(dev->devc, dev->ishtp_host_dma_rx_buf_size,
+ dev->ishtp_host_dma_rx_buf, h);
+ }
+
+ kfree(dev->ishtp_dma_tx_map);
+ dev->ishtp_host_dma_tx_buf = NULL;
+ dev->ishtp_host_dma_rx_buf = NULL;
+ dev->ishtp_dma_tx_map = NULL;
+}
+
+/*
+ * ishtp_cl_get_dma_send_buf() - Get a DMA memory slot
+ * @dev: ishtp device
+ * @size: Size of memory to get
+ *
+ * Find and return free address of "size" bytes in dma tx buffer.
+ * the function will mark this address as "in-used" memory.
+ *
+ * Return: NULL when no free buffer else a buffer to copy
+ */
+void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev,
+ uint32_t size)
+{
+ unsigned long flags;
+ int i, j, free;
+ /* additional slot is needed if there is rem */
+ int required_slots = (size / DMA_SLOT_SIZE)
+ + 1 * (size % DMA_SLOT_SIZE != 0);
+
+ spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags);
+ for (i = 0; i <= (dev->ishtp_dma_num_slots - required_slots); i++) {
+ free = 1;
+ for (j = 0; j < required_slots; j++)
+ if (dev->ishtp_dma_tx_map[i+j]) {
+ free = 0;
+ i += j;
+ break;
+ }
+ if (free) {
+ /* mark memory as "caught" */
+ for (j = 0; j < required_slots; j++)
+ dev->ishtp_dma_tx_map[i+j] = 1;
+ spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags);
+ return (i * DMA_SLOT_SIZE) +
+ (unsigned char *)dev->ishtp_host_dma_tx_buf;
+ }
+ }
+ spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags);
+ dev_err(dev->devc, "No free DMA buffer to send msg\n");
+ return NULL;
+}
+
+/*
+ * ishtp_cl_release_dma_acked_mem() - Release DMA memory slot
+ * @dev: ishtp device
+ * @msg_addr: message address of slot
+ * @size: Size of memory to get
+ *
+ * Release_dma_acked_mem - returnes the acked memory to free list.
+ * (from msg_addr, size bytes long)
+ */
+void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev,
+ void *msg_addr,
+ uint8_t size)
+{
+ unsigned long flags;
+ int acked_slots = (size / DMA_SLOT_SIZE)
+ + 1 * (size % DMA_SLOT_SIZE != 0);
+ int i, j;
+
+ if ((msg_addr - dev->ishtp_host_dma_tx_buf) % DMA_SLOT_SIZE) {
+ dev_err(dev->devc, "Bad DMA Tx ack address\n");
+ return;
+ }
+
+ i = (msg_addr - dev->ishtp_host_dma_tx_buf) / DMA_SLOT_SIZE;
+ spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags);
+ for (j = 0; j < acked_slots; j++) {
+ if ((i + j) >= dev->ishtp_dma_num_slots ||
+ !dev->ishtp_dma_tx_map[i+j]) {
+ /* no such slot, or memory is already free */
+ spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags);
+ dev_err(dev->devc, "Bad DMA Tx ack address\n");
+ return;
+ }
+ dev->ishtp_dma_tx_map[i+j] = 0;
+ }
+ spin_unlock_irqrestore(&dev->ishtp_dma_tx_lock, flags);
+}
diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c
new file mode 100644
index 000000000000..74bffee60774
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c
@@ -0,0 +1,1032 @@
+/*
+ * ISHTP bus layer messages handling
+ *
+ * Copyright (c) 2003-2016, 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.
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include "ishtp-dev.h"
+#include "hbm.h"
+#include "client.h"
+
+/**
+ * ishtp_hbm_fw_cl_allocate() - Allocate FW clients
+ * @dev: ISHTP device instance
+ *
+ * Allocates storage for fw clients
+ */
+static void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev)
+{
+ struct ishtp_fw_client *clients;
+ int b;
+
+ /* count how many ISH clients we have */
+ for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX)
+ dev->fw_clients_num++;
+
+ if (dev->fw_clients_num <= 0)
+ return;
+
+ /* allocate storage for fw clients representation */
+ clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client),
+ GFP_KERNEL);
+ if (!clients) {
+ dev->dev_state = ISHTP_DEV_RESETTING;
+ ish_hw_reset(dev);
+ return;
+ }
+ dev->fw_clients = clients;
+}
+
+/**
+ * ishtp_hbm_cl_hdr() - construct client hbm header
+ * @cl: client
+ * @hbm_cmd: host bus message command
+ * @buf: buffer for cl header
+ * @len: buffer length
+ *
+ * Initialize HBM buffer
+ */
+static inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd,
+ void *buf, size_t len)
+{
+ struct ishtp_hbm_cl_cmd *cmd = buf;
+
+ memset(cmd, 0, len);
+
+ cmd->hbm_cmd = hbm_cmd;
+ cmd->host_addr = cl->host_client_id;
+ cmd->fw_addr = cl->fw_client_id;
+}
+
+/**
+ * ishtp_hbm_cl_addr_equal() - Compare client address
+ * @cl: client
+ * @buf: Client command buffer
+ *
+ * Compare client address with the address in command buffer
+ *
+ * Return: True if they have the same address
+ */
+static inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf)
+{
+ struct ishtp_hbm_cl_cmd *cmd = buf;
+
+ return cl->host_client_id == cmd->host_addr &&
+ cl->fw_client_id == cmd->fw_addr;
+}
+
+/**
+ * ishtp_hbm_start_wait() - Wait for HBM start message
+ * @dev: ISHTP device instance
+ *
+ * Wait for HBM start message from firmware
+ *
+ * Return: 0 if HBM start is/was received else timeout error
+ */
+int ishtp_hbm_start_wait(struct ishtp_device *dev)
+{
+ int ret;
+
+ if (dev->hbm_state > ISHTP_HBM_START)
+ return 0;
+
+ dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n",
+ dev->hbm_state);
+ ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg,
+ dev->hbm_state >= ISHTP_HBM_STARTED,
+ (ISHTP_INTEROP_TIMEOUT * HZ));
+
+ dev_dbg(dev->devc,
+ "Woke up from waiting for ishtp start. hbm_state=%08X\n",
+ dev->hbm_state);
+
+ if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) {
+ dev->hbm_state = ISHTP_HBM_IDLE;
+ dev_err(dev->devc,
+ "waiting for ishtp start failed. ret=%d hbm_state=%08X\n",
+ ret, dev->hbm_state);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+/**
+ * ishtp_hbm_start_req() - Send HBM start message
+ * @dev: ISHTP device instance
+ *
+ * Send HBM start message to firmware
+ *
+ * Return: 0 if success else error code
+ */
+int ishtp_hbm_start_req(struct ishtp_device *dev)
+{
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ struct hbm_host_version_request *start_req;
+ const size_t len = sizeof(struct hbm_host_version_request);
+
+ ishtp_hbm_hdr(ishtp_hdr, len);
+
+ /* host start message */
+ start_req = (struct hbm_host_version_request *)data;
+ memset(start_req, 0, len);
+ start_req->hbm_cmd = HOST_START_REQ_CMD;
+ start_req->host_version.major_version = HBM_MAJOR_VERSION;
+ start_req->host_version.minor_version = HBM_MINOR_VERSION;
+
+ /*
+ * (!) Response to HBM start may be so quick that this thread would get
+ * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START.
+ * So set it at first, change back to ISHTP_HBM_IDLE upon failure
+ */
+ dev->hbm_state = ISHTP_HBM_START;
+ if (ishtp_write_message(dev, ishtp_hdr, data)) {
+ dev_err(dev->devc, "version message send failed\n");
+ dev->dev_state = ISHTP_DEV_RESETTING;
+ dev->hbm_state = ISHTP_HBM_IDLE;
+ ish_hw_reset(dev);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * ishtp_hbm_enum_clients_req() - Send client enum req
+ * @dev: ISHTP device instance
+ *
+ * Send enumeration client request message
+ *
+ * Return: 0 if success else error code
+ */
+void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
+{
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ struct hbm_host_enum_request *enum_req;
+ const size_t len = sizeof(struct hbm_host_enum_request);
+
+ /* enumerate clients */
+ ishtp_hbm_hdr(ishtp_hdr, len);
+
+ enum_req = (struct hbm_host_enum_request *)data;
+ memset(enum_req, 0, len);
+ enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
+
+ if (ishtp_write_message(dev, ishtp_hdr, data)) {
+ dev->dev_state = ISHTP_DEV_RESETTING;
+ dev_err(dev->devc, "enumeration request send failed\n");
+ ish_hw_reset(dev);
+ }
+ dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS;
+}
+
+/**
+ * ishtp_hbm_prop_req() - Request property
+ * @dev: ISHTP device instance
+ *
+ * Request property for a single client
+ *
+ * Return: 0 if success else error code
+ */
+static int ishtp_hbm_prop_req(struct ishtp_device *dev)
+{
+
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ struct hbm_props_request *prop_req;
+ const size_t len = sizeof(struct hbm_props_request);
+ unsigned long next_client_index;
+ uint8_t client_num;
+
+ client_num = dev->fw_client_presentation_num;
+
+ next_client_index = find_next_bit(dev->fw_clients_map,
+ ISHTP_CLIENTS_MAX, dev->fw_client_index);
+
+ /* We got all client properties */
+ if (next_client_index == ISHTP_CLIENTS_MAX) {
+ dev->hbm_state = ISHTP_HBM_WORKING;
+ dev->dev_state = ISHTP_DEV_ENABLED;
+
+ for (dev->fw_client_presentation_num = 1;
+ dev->fw_client_presentation_num < client_num + 1;
+ ++dev->fw_client_presentation_num)
+ /* Add new client device */
+ ishtp_bus_new_client(dev);
+ return 0;
+ }
+
+ dev->fw_clients[client_num].client_id = next_client_index;
+
+ ishtp_hbm_hdr(ishtp_hdr, len);
+ prop_req = (struct hbm_props_request *)data;
+
+ memset(prop_req, 0, sizeof(struct hbm_props_request));
+
+ prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
+ prop_req->address = next_client_index;
+
+ if (ishtp_write_message(dev, ishtp_hdr, data)) {
+ dev->dev_state = ISHTP_DEV_RESETTING;
+ dev_err(dev->devc, "properties request send failed\n");
+ ish_hw_reset(dev);
+ return -EIO;
+ }
+
+ dev->fw_client_index = next_client_index;
+
+ return 0;
+}
+
+/**
+ * ishtp_hbm_stop_req() - Send HBM stop
+ * @dev: ISHTP device instance
+ *
+ * Send stop request message
+ */
+static void ishtp_hbm_stop_req(struct ishtp_device *dev)
+{
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ struct hbm_host_stop_request *req;
+ const size_t len = sizeof(struct hbm_host_stop_request);
+
+ ishtp_hbm_hdr(ishtp_hdr, len);
+ req = (struct hbm_host_stop_request *)data;
+
+ memset(req, 0, sizeof(struct hbm_host_stop_request));
+ req->hbm_cmd = HOST_STOP_REQ_CMD;
+ req->reason = DRIVER_STOP_REQUEST;
+
+ ishtp_write_message(dev, ishtp_hdr, data);
+}
+
+/**
+ * ishtp_hbm_cl_flow_control_req() - Send flow control request
+ * @dev: ISHTP device instance
+ * @cl: ISHTP client instance
+ *
+ * Send flow control request
+ *
+ * Return: 0 if success else error code
+ */
+int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
+ struct ishtp_cl *cl)
+{
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ const size_t len = sizeof(struct hbm_flow_control);
+ int rv;
+ unsigned int num_frags;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cl->fc_spinlock, flags);
+ ishtp_hbm_hdr(ishtp_hdr, len);
+ ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, data, len);
+
+ /*
+ * Sync possible race when RB recycle and packet receive paths
+ * both try to send an out FC
+ */
+ if (cl->out_flow_ctrl_creds) {
+ spin_unlock_irqrestore(&cl->fc_spinlock, flags);
+ return 0;
+ }
+
+ num_frags = cl->recv_msg_num_frags;
+ cl->recv_msg_num_frags = 0;
+
+ rv = ishtp_write_message(dev, ishtp_hdr, data);
+ if (!rv) {
+ ++cl->out_flow_ctrl_creds;
+ ++cl->out_flow_ctrl_cnt;
+ getnstimeofday(&cl->ts_out_fc);
+ if (cl->ts_rx.tv_sec && cl->ts_rx.tv_nsec) {
+ struct timespec ts_diff;
+
+ ts_diff = timespec_sub(cl->ts_out_fc, cl->ts_rx);
+ if (timespec_compare(&ts_diff, &cl->ts_max_fc_delay)
+ > 0)
+ cl->ts_max_fc_delay = ts_diff;
+ }
+ } else {
+ ++cl->err_send_fc;
+ }
+
+ spin_unlock_irqrestore(&cl->fc_spinlock, flags);
+ return rv;
+}
+
+/**
+ * ishtp_hbm_cl_disconnect_req() - Send disconnect request
+ * @dev: ISHTP device instance
+ * @cl: ISHTP client instance
+ *
+ * Send disconnect message to fw
+ *
+ * Return: 0 if success else error code
+ */
+int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
+{
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ const size_t len = sizeof(struct hbm_client_connect_request);
+
+ ishtp_hbm_hdr(ishtp_hdr, len);
+ ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, data, len);
+
+ return ishtp_write_message(dev, ishtp_hdr, data);
+}
+
+/**
+ * ishtp_hbm_cl_disconnect_res() - Get disconnect response
+ * @dev: ISHTP device instance
+ * @rs: Response message
+ *
+ * Received disconnect response from fw
+ */
+static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
+ struct hbm_client_connect_response *rs)
+{
+ struct ishtp_cl *cl = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ list_for_each_entry(cl, &dev->cl_list, link) {
+ if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
+ cl->state = ISHTP_CL_DISCONNECTED;
+ break;
+ }
+ }
+ if (cl)
+ wake_up_interruptible(&cl->wait_ctrl_res);
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+}
+
+/**
+ * ishtp_hbm_cl_connect_req() - Send connect request
+ * @dev: ISHTP device instance
+ * @cl: client device instance
+ *
+ * Send connection request to specific fw client
+ *
+ * Return: 0 if success else error code
+ */
+int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
+{
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[128];
+ struct ishtp_msg_hdr *ishtp_hdr = &hdr;
+ const size_t len = sizeof(struct hbm_client_connect_request);
+
+ ishtp_hbm_hdr(ishtp_hdr, len);
+ ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, data, len);
+
+ return ishtp_write_message(dev, ishtp_hdr, data);
+}
+
+/**
+ * ishtp_hbm_cl_connect_res() - Get connect response
+ * @dev: ISHTP device instance
+ * @rs: Response message
+ *
+ * Received connect response from fw
+ */
+static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
+ struct hbm_client_connect_response *rs)
+{
+ struct ishtp_cl *cl = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ list_for_each_entry(cl, &dev->cl_list, link) {
+ if (ishtp_hbm_cl_addr_equal(cl, rs)) {
+ if (!rs->status) {
+ cl->state = ISHTP_CL_CONNECTED;
+ cl->status = 0;
+ } else {
+ cl->state = ISHTP_CL_DISCONNECTED;
+ cl->status = -ENODEV;
+ }
+ break;
+ }
+ }
+ if (cl)
+ wake_up_interruptible(&cl->wait_ctrl_res);
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+}
+
+/**
+ * ishtp_client_disconnect_request() - Receive disconnect request
+ * @dev: ISHTP device instance
+ * @disconnect_req: disconnect request structure
+ *
+ * Disconnect request bus message from the fw. Send diconnect response.
+ */
+static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
+ struct hbm_client_connect_request *disconnect_req)
+{
+ struct ishtp_cl *cl;
+ const size_t len = sizeof(struct hbm_client_connect_response);
+ unsigned long flags;
+ struct ishtp_msg_hdr hdr;
+ unsigned char data[4]; /* All HBM messages are 4 bytes */
+
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ list_for_each_entry(cl, &dev->cl_list, link) {
+ if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) {
+ cl->state = ISHTP_CL_DISCONNECTED;
+
+ /* send disconnect response */
+ ishtp_hbm_hdr(&hdr, len);
+ ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data,
+ len);
+ ishtp_write_message(dev, &hdr, data);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+}
+
+/**
+ * ishtp_hbm_dma_xfer_ack(() - Receive transfer ACK
+ * @dev: ISHTP device instance
+ * @dma_xfer: HBM transfer message
+ *
+ * Receive ack for ISHTP-over-DMA client message
+ */
+static void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev,
+ struct dma_xfer_hbm *dma_xfer)
+{
+ void *msg;
+ uint64_t offs;
+ struct ishtp_msg_hdr *ishtp_hdr =
+ (struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr;
+ unsigned int msg_offs;
+ struct ishtp_cl *cl;
+
+ for (msg_offs = 0; msg_offs < ishtp_hdr->length;
+ msg_offs += sizeof(struct dma_xfer_hbm)) {
+ offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys;
+ if (offs > dev->ishtp_host_dma_tx_buf_size) {
+ dev_err(dev->devc, "Bad DMA Tx ack message address\n");
+ return;
+ }
+ if (dma_xfer->msg_length >
+ dev->ishtp_host_dma_tx_buf_size - offs) {
+ dev_err(dev->devc, "Bad DMA Tx ack message size\n");
+ return;
+ }
+
+ /* logical address of the acked mem */
+ msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs;
+ ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length);
+
+ list_for_each_entry(cl, &dev->cl_list, link) {
+ if (cl->fw_client_id == dma_xfer->fw_client_id &&
+ cl->host_client_id == dma_xfer->host_client_id)
+ /*
+ * in case that a single ack may be sent
+ * over several dma transfers, and the last msg
+ * addr was inside the acked memory, but not in
+ * its start
+ */
+ if (cl->last_dma_addr >=
+ (unsigned char *)msg &&
+ cl->last_dma_addr <
+ (unsigned char *)msg +
+ dma_xfer->msg_length) {
+ cl->last_dma_acked = 1;
+
+ if (!list_empty(&cl->tx_list.list) &&
+ cl->ishtp_flow_ctrl_creds) {
+ /*
+ * start sending the first msg
+ */
+ ishtp_cl_send_msg(dev, cl);
+ }
+ }
+ }
+ ++dma_xfer;
+ }
+}
+
+/**
+ * ishtp_hbm_dma_xfer() - Receive DMA transfer message
+ * @dev: ISHTP device instance
+ * @dma_xfer: HBM transfer message
+ *
+ * Receive ISHTP-over-DMA client message
+ */
+static void ishtp_hbm_dma_xfer(struct ishtp_device *dev,
+ struct dma_xfer_hbm *dma_xfer)
+{
+ void *msg;
+ uint64_t offs;
+ struct ishtp_msg_hdr hdr;
+ struct ishtp_msg_hdr *ishtp_hdr =
+ (struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr;
+ struct dma_xfer_hbm *prm = dma_xfer;
+ unsigned int msg_offs;
+
+ for (msg_offs = 0; msg_offs < ishtp_hdr->length;
+ msg_offs += sizeof(struct dma_xfer_hbm)) {
+
+ offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys;
+ if (offs > dev->ishtp_host_dma_rx_buf_size) {
+ dev_err(dev->devc, "Bad DMA Rx message address\n");
+ return;
+ }
+ if (dma_xfer->msg_length >
+ dev->ishtp_host_dma_rx_buf_size - offs) {
+ dev_err(dev->devc, "Bad DMA Rx message size\n");
+ return;
+ }
+ msg = dev->ishtp_host_dma_rx_buf + offs;
+ recv_ishtp_cl_msg_dma(dev, msg, dma_xfer);
+ dma_xfer->hbm = DMA_XFER_ACK; /* Prepare for response */
+ ++dma_xfer;
+ }
+
+ /* Send DMA_XFER_ACK [...] */
+ ishtp_hbm_hdr(&hdr, ishtp_hdr->length);
+ ishtp_write_message(dev, &hdr, (unsigned char *)prm);
+}
+
+/**
+ * ishtp_hbm_dispatch() - HBM dispatch function
+ * @dev: ISHTP device instance
+ * @hdr: bus message
+ *
+ * Bottom half read routine after ISR to handle the read bus message cmd
+ * processing
+ */
+void ishtp_hbm_dispatch(struct ishtp_device *dev,
+ struct ishtp_bus_message *hdr)
+{
+ struct ishtp_bus_message *ishtp_msg;
+ struct ishtp_fw_client *fw_client;
+ struct hbm_host_version_response *version_res;
+ struct hbm_client_connect_response *connect_res;
+ struct hbm_client_connect_response *disconnect_res;
+ struct hbm_client_connect_request *disconnect_req;
+ struct hbm_props_response *props_res;
+ struct hbm_host_enum_response *enum_res;
+ struct ishtp_msg_hdr ishtp_hdr;
+ struct dma_alloc_notify dma_alloc_notify;
+ struct dma_xfer_hbm *dma_xfer;
+
+ ishtp_msg = hdr;
+
+ switch (ishtp_msg->hbm_cmd) {
+ case HOST_START_RES_CMD:
+ version_res = (struct hbm_host_version_response *)ishtp_msg;
+ if (!version_res->host_version_supported) {
+ dev->version = version_res->fw_max_version;
+
+ dev->hbm_state = ISHTP_HBM_STOPPED;
+ ishtp_hbm_stop_req(dev);
+ return;
+ }
+
+ dev->version.major_version = HBM_MAJOR_VERSION;
+ dev->version.minor_version = HBM_MINOR_VERSION;
+ if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
+ dev->hbm_state == ISHTP_HBM_START) {
+ dev->hbm_state = ISHTP_HBM_STARTED;
+ ishtp_hbm_enum_clients_req(dev);
+ } else {
+ dev_err(dev->devc,
+ "reset: wrong host start response\n");
+ /* BUG: why do we arrive here? */
+ ish_hw_reset(dev);
+ return;
+ }
+
+ wake_up_interruptible(&dev->wait_hbm_recvd_msg);
+ break;
+
+ case CLIENT_CONNECT_RES_CMD:
+ connect_res = (struct hbm_client_connect_response *)ishtp_msg;
+ ishtp_hbm_cl_connect_res(dev, connect_res);
+ break;
+
+ case CLIENT_DISCONNECT_RES_CMD:
+ disconnect_res =
+ (struct hbm_client_connect_response *)ishtp_msg;
+ ishtp_hbm_cl_disconnect_res(dev, disconnect_res);
+ break;
+
+ case HOST_CLIENT_PROPERTIES_RES_CMD:
+ props_res = (struct hbm_props_response *)ishtp_msg;
+ fw_client = &dev->fw_clients[dev->fw_client_presentation_num];
+
+ if (props_res->status || !dev->fw_clients) {
+ dev_err(dev->devc,
+ "reset: properties response hbm wrong status\n");
+ ish_hw_reset(dev);
+ return;
+ }
+
+ if (fw_client->client_id != props_res->address) {
+ dev_err(dev->devc,
+ "reset: host properties response address mismatch [%02X %02X]\n",
+ fw_client->client_id, props_res->address);
+ ish_hw_reset(dev);
+ return;
+ }
+
+ if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS ||
+ dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) {
+ dev_err(dev->devc,
+ "reset: unexpected properties response\n");
+ ish_hw_reset(dev);
+ return;
+ }
+
+ fw_client->props = props_res->client_properties;
+ dev->fw_client_index++;
+ dev->fw_client_presentation_num++;
+
+ /* request property for the next client */
+ ishtp_hbm_prop_req(dev);
+
+ if (dev->dev_state != ISHTP_DEV_ENABLED)
+ break;
+
+ if (!ishtp_use_dma_transfer())
+ break;
+
+ dev_dbg(dev->devc, "Requesting to use DMA\n");
+ ishtp_cl_alloc_dma_buf(dev);
+ if (dev->ishtp_host_dma_rx_buf) {
+ const size_t len = sizeof(dma_alloc_notify);
+
+ memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify));
+ dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY;
+ dma_alloc_notify.buf_size =
+ dev->ishtp_host_dma_rx_buf_size;
+ dma_alloc_notify.buf_address =
+ dev->ishtp_host_dma_rx_buf_phys;
+ ishtp_hbm_hdr(&ishtp_hdr, len);
+ ishtp_write_message(dev, &ishtp_hdr,
+ (unsigned char *)&dma_alloc_notify);
+ }
+
+ break;
+
+ case HOST_ENUM_RES_CMD:
+ enum_res = (struct hbm_host_enum_response *) ishtp_msg;
+ memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32);
+ if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
+ dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) {
+ dev->fw_client_presentation_num = 0;
+ dev->fw_client_index = 0;
+
+ ishtp_hbm_fw_cl_allocate(dev);
+ dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES;
+
+ /* first property request */
+ ishtp_hbm_prop_req(dev);
+ } else {
+ dev_err(dev->devc,
+ "reset: unexpected enumeration response hbm\n");
+ ish_hw_reset(dev);
+ return;
+ }
+ break;
+
+ case HOST_STOP_RES_CMD:
+ if (dev->hbm_state != ISHTP_HBM_STOPPED)
+ dev_err(dev->devc, "unexpected stop response\n");
+
+ dev->dev_state = ISHTP_DEV_DISABLED;
+ dev_info(dev->devc, "reset: FW stop response\n");
+ ish_hw_reset(dev);
+ break;
+
+ case CLIENT_DISCONNECT_REQ_CMD:
+ /* search for client */
+ disconnect_req =
+ (struct hbm_client_connect_request *)ishtp_msg;
+ ishtp_hbm_fw_disconnect_req(dev, disconnect_req);
+ break;
+
+ case FW_STOP_REQ_CMD:
+ dev->hbm_state = ISHTP_HBM_STOPPED;
+ break;
+
+ case DMA_BUFFER_ALLOC_RESPONSE:
+ dev->ishtp_host_dma_enabled = 1;
+ break;
+
+ case DMA_XFER:
+ dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
+ if (!dev->ishtp_host_dma_enabled) {
+ dev_err(dev->devc,
+ "DMA XFER requested but DMA is not enabled\n");
+ break;
+ }
+ ishtp_hbm_dma_xfer(dev, dma_xfer);
+ break;
+
+ case DMA_XFER_ACK:
+ dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
+ if (!dev->ishtp_host_dma_enabled ||
+ !dev->ishtp_host_dma_tx_buf) {
+ dev_err(dev->devc,
+ "DMA XFER acked but DMA Tx is not enabled\n");
+ break;
+ }
+ ishtp_hbm_dma_xfer_ack(dev, dma_xfer);
+ break;
+
+ default:
+ dev_err(dev->devc, "unknown HBM: %u\n",
+ (unsigned int)ishtp_msg->hbm_cmd);
+
+ break;
+ }
+}
+
+/**
+ * bh_hbm_work_fn() - HBM work function
+ * @work: work struct
+ *
+ * Bottom half processing work function (instead of thread handler)
+ * for processing hbm messages
+ */
+void bh_hbm_work_fn(struct work_struct *work)
+{
+ unsigned long flags;
+ struct ishtp_device *dev;
+ unsigned char hbm[IPC_PAYLOAD_SIZE];
+
+ dev = container_of(work, struct ishtp_device, bh_hbm_work);
+ spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
+ if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) {
+ memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head,
+ IPC_PAYLOAD_SIZE);
+ dev->rd_msg_fifo_head =
+ (dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) %
+ (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
+ spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
+ ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm);
+ } else {
+ spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
+ }
+}
+
+/**
+ * recv_hbm() - Receive HBM message
+ * @dev: ISHTP device instance
+ * @ishtp_hdr: received bus message
+ *
+ * Receive and process ISHTP bus messages in ISR context. This will schedule
+ * work function to process message
+ */
+void recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
+{
+ uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
+ struct ishtp_bus_message *ishtp_msg =
+ (struct ishtp_bus_message *)rd_msg_buf;
+ unsigned long flags;
+
+ dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
+
+ /* Flow control - handle in place */
+ if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) {
+ struct hbm_flow_control *flow_control =
+ (struct hbm_flow_control *)ishtp_msg;
+ struct ishtp_cl *cl = NULL;
+ unsigned long flags, tx_flags;
+
+ spin_lock_irqsave(&dev->cl_list_lock, flags);
+ list_for_each_entry(cl, &dev->cl_list, link) {
+ if (cl->host_client_id == flow_control->host_addr &&
+ cl->fw_client_id ==
+ flow_control->fw_addr) {
+ /*
+ * NOTE: It's valid only for counting
+ * flow-control implementation to receive a
+ * FC in the middle of sending. Meanwhile not
+ * supported
+ */
+ if (cl->ishtp_flow_ctrl_creds)
+ dev_err(dev->devc,
+ "recv extra FC from FW client %u (host client %u) (FC count was %d)\n",
+ (unsigned int)cl->fw_client_id,
+ (unsigned int)cl->host_client_id,
+ cl->ishtp_flow_ctrl_creds);
+ else {
+ ++cl->ishtp_flow_ctrl_creds;
+ ++cl->ishtp_flow_ctrl_cnt;
+ cl->last_ipc_acked = 1;
+ spin_lock_irqsave(
+ &cl->tx_list_spinlock,
+ tx_flags);
+ if (!list_empty(&cl->tx_list.list)) {
+ /*
+ * start sending the first msg
+ * = the callback function
+ */
+ spin_unlock_irqrestore(
+ &cl->tx_list_spinlock,
+ tx_flags);
+ ishtp_cl_send_msg(dev, cl);
+ } else {
+ spin_unlock_irqrestore(
+ &cl->tx_list_spinlock,
+ tx_flags);
+ }
+ }
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->cl_list_lock, flags);
+ goto eoi;
+ }
+
+ /*
+ * Some messages that are safe for ISR processing and important
+ * to be done "quickly" and in-order, go here
+ */
+ if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD ||
+ ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD ||
+ ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD ||
+ ishtp_msg->hbm_cmd == DMA_XFER) {
+ ishtp_hbm_dispatch(dev, ishtp_msg);
+ goto eoi;
+ }
+
+ /*
+ * All other HBMs go here.
+ * We schedule HBMs for processing serially by using system wq,
+ * possibly there will be multiple HBMs scheduled at the same time.
+ */
+ spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
+ if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
+ (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) ==
+ dev->rd_msg_fifo_head) {
+ spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
+ dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n",
+ (unsigned int)ishtp_msg->hbm_cmd);
+ goto eoi;
+ }
+ memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg,
+ ishtp_hdr->length);
+ dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
+ (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
+ spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
+ schedule_work(&dev->bh_hbm_work);
+eoi:
+ return;
+}
+
+/**
+ * recv_fixed_cl_msg() - Receive fixed client message
+ * @dev: ISHTP device instance
+ * @ishtp_hdr: received bus message
+ *
+ * Receive and process ISHTP fixed client messages (address == 0)
+ * in ISR context
+ */
+void recv_fixed_cl_msg(struct ishtp_device *dev,
+ struct ishtp_msg_hdr *ishtp_hdr)
+{
+ uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
+
+ dev->print_log(dev,
+ "%s() got fixed client msg from client #%d\n",
+ __func__, ishtp_hdr->fw_addr);
+ dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
+ if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) {
+ struct ish_system_states_header *msg_hdr =
+ (struct ish_system_states_header *)rd_msg_buf;
+ if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE)
+ ishtp_send_resume(dev);
+ /* if FW request arrived here, the system is not suspended */
+ else
+ dev_err(dev->devc, "unknown fixed client msg [%02X]\n",
+ msg_hdr->cmd);
+ }
+}
+
+/**
+ * fix_cl_hdr() - Initialize fixed client header
+ * @hdr: message header
+ * @length: length of message
+ * @cl_addr: Client address
+ *
+ * Initialize message header for fixed client
+ */
+static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
+ uint8_t cl_addr)
+{
+ hdr->host_addr = 0;
+ hdr->fw_addr = cl_addr;
+ hdr->length = length;
+ hdr->msg_complete = 1;
+ hdr->reserved = 0;
+}
+
+/*** Suspend and resume notification ***/
+
+static uint32_t current_state;
+static uint32_t supported_states = 0 | SUSPEND_STATE_BIT;
+
+/**
+ * ishtp_send_suspend() - Send suspend message to FW
+ * @dev: ISHTP device instance
+ *
+ * Send suspend message to FW. This is useful for system freeze (non S3) case
+ */
+void ishtp_send_suspend(struct ishtp_device *dev)
+{
+ struct ishtp_msg_hdr ishtp_hdr;
+ struct ish_system_states_status state_status_msg;
+ const size_t len = sizeof(struct ish_system_states_status);
+
+ fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
+
+ memset(&state_status_msg, 0, len);
+ state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
+ state_status_msg.supported_states = supported_states;
+ current_state |= SUSPEND_STATE_BIT;
+ dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
+ state_status_msg.states_status = current_state;
+
+ ishtp_write_message(dev, &ishtp_hdr,
+ (unsigned char *)&state_status_msg);
+}
+EXPORT_SYMBOL(ishtp_send_suspend);
+
+/**
+ * ishtp_send_resume() - Send resume message to FW
+ * @dev: ISHTP device instance
+ *
+ * Send resume message to FW. This is useful for system freeze (non S3) case
+ */
+void ishtp_send_resume(struct ishtp_device *dev)
+{
+ struct ishtp_msg_hdr ishtp_hdr;
+ struct ish_system_states_status state_status_msg;
+ const size_t len = sizeof(struct ish_system_states_status);
+
+ fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
+
+ memset(&state_status_msg, 0, len);
+ state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
+ state_status_msg.supported_states = supported_states;
+ current_state &= ~SUSPEND_STATE_BIT;
+ dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
+ state_status_msg.states_status = current_state;
+
+ ishtp_write_message(dev, &ishtp_hdr,
+ (unsigned char *)&state_status_msg);
+}
+EXPORT_SYMBOL(ishtp_send_resume);
+
+/**
+ * ishtp_query_subscribers() - Send query subscribers message
+ * @dev: ISHTP device instance
+ *
+ * Send message to query subscribers
+ */
+void ishtp_query_subscribers(struct ishtp_device *dev)
+{
+ struct ishtp_msg_hdr ishtp_hdr;
+ struct ish_system_states_query_subscribers query_subscribers_msg;
+ const size_t len = sizeof(struct ish_system_states_query_subscribers);
+
+ fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
+
+ memset(&query_subscribers_msg, 0, len);
+ query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS;
+
+ ishtp_write_message(dev, &ishtp_hdr,
+ (unsigned char *)&query_subscribers_msg);
+}
diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.h b/drivers/hid/intel-ish-hid/ishtp/hbm.h
new file mode 100644
index 000000000000..d96111cef7f8
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/hbm.h
@@ -0,0 +1,321 @@
+/*
+ * ISHTP bus layer messages handling
+ *
+ * Copyright (c) 2003-2016, 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.
+ */
+
+#ifndef _ISHTP_HBM_H_
+#define _ISHTP_HBM_H_
+
+#include <linux/uuid.h>
+
+struct ishtp_device;
+struct ishtp_msg_hdr;
+struct ishtp_cl;
+
+/*
+ * Timeouts in Seconds
+ */
+#define ISHTP_INTEROP_TIMEOUT 7 /* Timeout on ready message */
+
+#define ISHTP_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */
+
+/*
+ * ISHTP Version
+ */
+#define HBM_MINOR_VERSION 0
+#define HBM_MAJOR_VERSION 1
+
+/* Host bus message command opcode */
+#define ISHTP_HBM_CMD_OP_MSK 0x7f
+/* Host bus message command RESPONSE */
+#define ISHTP_HBM_CMD_RES_MSK 0x80
+
+/*
+ * ISHTP Bus Message Command IDs
+ */
+#define HOST_START_REQ_CMD 0x01
+#define HOST_START_RES_CMD 0x81
+
+#define HOST_STOP_REQ_CMD 0x02
+#define HOST_STOP_RES_CMD 0x82
+
+#define FW_STOP_REQ_CMD 0x03
+
+#define HOST_ENUM_REQ_CMD 0x04
+#define HOST_ENUM_RES_CMD 0x84
+
+#define HOST_CLIENT_PROPERTIES_REQ_CMD 0x05
+#define HOST_CLIENT_PROPERTIES_RES_CMD 0x85
+
+#define CLIENT_CONNECT_REQ_CMD 0x06
+#define CLIENT_CONNECT_RES_CMD 0x86
+
+#define CLIENT_DISCONNECT_REQ_CMD 0x07
+#define CLIENT_DISCONNECT_RES_CMD 0x87
+
+#define ISHTP_FLOW_CONTROL_CMD 0x08
+
+#define DMA_BUFFER_ALLOC_NOTIFY 0x11
+#define DMA_BUFFER_ALLOC_RESPONSE 0x91
+
+#define DMA_XFER 0x12
+#define DMA_XFER_ACK 0x92
+
+/*
+ * ISHTP Stop Reason
+ * used by hbm_host_stop_request.reason
+ */
+#define DRIVER_STOP_REQUEST 0x00
+
+/*
+ * ISHTP BUS Interface Section
+ */
+struct ishtp_msg_hdr {
+ uint32_t fw_addr:8;
+ uint32_t host_addr:8;
+ uint32_t length:9;
+ uint32_t reserved:6;
+ uint32_t msg_complete:1;
+} __packed;
+
+struct ishtp_bus_message {
+ uint8_t hbm_cmd;
+ uint8_t data[0];
+} __packed;
+
+/**
+ * struct hbm_cl_cmd - client specific host bus command
+ * CONNECT, DISCONNECT, and FlOW CONTROL
+ *
+ * @hbm_cmd - bus message command header
+ * @fw_addr - address of the fw client
+ * @host_addr - address of the client in the driver
+ * @data
+ */
+struct ishtp_hbm_cl_cmd {
+ uint8_t hbm_cmd;
+ uint8_t fw_addr;
+ uint8_t host_addr;
+ uint8_t data;
+};
+
+struct hbm_version {
+ uint8_t minor_version;
+ uint8_t major_version;
+} __packed;
+
+struct hbm_host_version_request {
+ uint8_t hbm_cmd;
+ uint8_t reserved;
+ struct hbm_version host_version;
+} __packed;
+
+struct hbm_host_version_response {
+ uint8_t hbm_cmd;
+ uint8_t host_version_supported;
+ struct hbm_version fw_max_version;
+} __packed;
+
+struct hbm_host_stop_request {
+ uint8_t hbm_cmd;
+ uint8_t reason;
+ uint8_t reserved[2];
+} __packed;
+
+struct hbm_host_stop_response {
+ uint8_t hbm_cmd;
+ uint8_t reserved[3];
+} __packed;
+
+struct hbm_host_enum_request {
+ uint8_t hbm_cmd;
+ uint8_t reserved[3];
+} __packed;
+
+struct hbm_host_enum_response {
+ uint8_t hbm_cmd;
+ uint8_t reserved[3];
+ uint8_t valid_addresses[32];
+} __packed;
+
+struct ishtp_client_properties {
+ uuid_le protocol_name;
+ uint8_t protocol_version;
+ uint8_t max_number_of_connections;
+ uint8_t fixed_address;
+ uint8_t single_recv_buf;
+ uint32_t max_msg_length;
+ uint8_t dma_hdr_len;
+#define ISHTP_CLIENT_DMA_ENABLED 0x80
+ uint8_t reserved4;
+ uint8_t reserved5;
+ uint8_t reserved6;
+} __packed;
+
+struct hbm_props_request {
+ uint8_t hbm_cmd;
+ uint8_t address;
+ uint8_t reserved[2];
+} __packed;
+
+struct hbm_props_response {
+ uint8_t hbm_cmd;
+ uint8_t address;
+ uint8_t status;
+ uint8_t reserved[1];
+ struct ishtp_client_properties client_properties;
+} __packed;
+
+/**
+ * struct hbm_client_connect_request - connect/disconnect request
+ *
+ * @hbm_cmd - bus message command header
+ * @fw_addr - address of the fw client
+ * @host_addr - address of the client in the driver
+ * @reserved
+ */
+struct hbm_client_connect_request {
+ uint8_t hbm_cmd;
+ uint8_t fw_addr;
+ uint8_t host_addr;
+ uint8_t reserved;
+} __packed;
+
+/**
+ * struct hbm_client_connect_response - connect/disconnect response
+ *
+ * @hbm_cmd - bus message command header
+ * @fw_addr - address of the fw client
+ * @host_addr - address of the client in the driver
+ * @status - status of the request
+ */
+struct hbm_client_connect_response {
+ uint8_t hbm_cmd;
+ uint8_t fw_addr;
+ uint8_t host_addr;
+ uint8_t status;
+} __packed;
+
+
+#define ISHTP_FC_MESSAGE_RESERVED_LENGTH 5
+
+struct hbm_flow_control {
+ uint8_t hbm_cmd;
+ uint8_t fw_addr;
+ uint8_t host_addr;
+ uint8_t reserved[ISHTP_FC_MESSAGE_RESERVED_LENGTH];
+} __packed;
+
+struct dma_alloc_notify {
+ uint8_t hbm;
+ uint8_t status;
+ uint8_t reserved[2];
+ uint32_t buf_size;
+ uint64_t buf_address;
+ /* [...] May come more size/address pairs */
+} __packed;
+
+struct dma_xfer_hbm {
+ uint8_t hbm;
+ uint8_t fw_client_id;
+ uint8_t host_client_id;
+ uint8_t reserved;
+ uint64_t msg_addr;
+ uint32_t msg_length;
+ uint32_t reserved2;
+} __packed;
+
+/* System state */
+#define ISHTP_SYSTEM_STATE_CLIENT_ADDR 13
+
+#define SYSTEM_STATE_SUBSCRIBE 0x1
+#define SYSTEM_STATE_STATUS 0x2
+#define SYSTEM_STATE_QUERY_SUBSCRIBERS 0x3
+#define SYSTEM_STATE_STATE_CHANGE_REQ 0x4
+/*indicates suspend and resume states*/
+#define SUSPEND_STATE_BIT (1<<1)
+
+struct ish_system_states_header {
+ uint32_t cmd;
+ uint32_t cmd_status; /*responses will have this set*/
+} __packed;
+
+struct ish_system_states_subscribe {
+ struct ish_system_states_header hdr;
+ uint32_t states;
+} __packed;
+
+struct ish_system_states_status {
+ struct ish_system_states_header hdr;
+ uint32_t supported_states;
+ uint32_t states_status;
+} __packed;
+
+struct ish_system_states_query_subscribers {
+ struct ish_system_states_header hdr;
+} __packed;
+
+struct ish_system_states_state_change_req {
+ struct ish_system_states_header hdr;
+ uint32_t requested_states;
+ uint32_t states_status;
+} __packed;
+
+/**
+ * enum ishtp_hbm_state - host bus message protocol state
+ *
+ * @ISHTP_HBM_IDLE : protocol not started
+ * @ISHTP_HBM_START : start request message was sent
+ * @ISHTP_HBM_ENUM_CLIENTS : enumeration request was sent
+ * @ISHTP_HBM_CLIENT_PROPERTIES : acquiring clients properties
+ */
+enum ishtp_hbm_state {
+ ISHTP_HBM_IDLE = 0,
+ ISHTP_HBM_START,
+ ISHTP_HBM_STARTED,
+ ISHTP_HBM_ENUM_CLIENTS,
+ ISHTP_HBM_CLIENT_PROPERTIES,
+ ISHTP_HBM_WORKING,
+ ISHTP_HBM_STOPPED,
+};
+
+static inline void ishtp_hbm_hdr(struct ishtp_msg_hdr *hdr, size_t length)
+{
+ hdr->host_addr = 0;
+ hdr->fw_addr = 0;
+ hdr->length = length;
+ hdr->msg_complete = 1;
+ hdr->reserved = 0;
+}
+
+int ishtp_hbm_start_req(struct ishtp_device *dev);
+int ishtp_hbm_start_wait(struct ishtp_device *dev);
+int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
+ struct ishtp_cl *cl);
+int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl);
+int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl);
+void ishtp_hbm_enum_clients_req(struct ishtp_device *dev);
+void bh_hbm_work_fn(struct work_struct *work);
+void recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr);
+void recv_fixed_cl_msg(struct ishtp_device *dev,
+ struct ishtp_msg_hdr *ishtp_hdr);
+void ishtp_hbm_dispatch(struct ishtp_device *dev,
+ struct ishtp_bus_message *hdr);
+
+void ishtp_query_subscribers(struct ishtp_device *dev);
+
+/* Exported I/F */
+void ishtp_send_suspend(struct ishtp_device *dev);
+void ishtp_send_resume(struct ishtp_device *dev);
+
+#endif /* _ISHTP_HBM_H_ */
diff --git a/drivers/hid/intel-ish-hid/ishtp/init.c b/drivers/hid/intel-ish-hid/ishtp/init.c
new file mode 100644
index 000000000000..ac364418e17c
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/init.c
@@ -0,0 +1,115 @@
+/*
+ * Initialization protocol for ISHTP driver
+ *
+ * Copyright (c) 2003-2016, 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.
+ */
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include "ishtp-dev.h"
+#include "hbm.h"
+#include "client.h"
+
+/**
+ * ishtp_dev_state_str() -Convert to string format
+ * @state: state to convert
+ *
+ * Convert state to string for prints
+ *
+ * Return: character pointer to converted string
+ */
+const char *ishtp_dev_state_str(int state)
+{
+ switch (state) {
+ case ISHTP_DEV_INITIALIZING:
+ return "INITIALIZING";
+ case ISHTP_DEV_INIT_CLIENTS:
+ return "INIT_CLIENTS";
+ case ISHTP_DEV_ENABLED:
+ return "ENABLED";
+ case ISHTP_DEV_RESETTING:
+ return "RESETTING";
+ case ISHTP_DEV_DISABLED:
+ return "DISABLED";
+ case ISHTP_DEV_POWER_DOWN:
+ return "POWER_DOWN";
+ case ISHTP_DEV_POWER_UP:
+ return "POWER_UP";
+ default:
+ return "unknown";
+ }
+}
+
+/**
+ * ishtp_device_init() - ishtp device init
+ * @dev: ISHTP device instance
+ *
+ * After ISHTP device is alloacted, this function is used to initialize
+ * each field which includes spin lock, work struct and lists
+ */
+void ishtp_device_init(struct ishtp_device *dev)
+{
+ dev->dev_state = ISHTP_DEV_INITIALIZING;
+ INIT_LIST_HEAD(&dev->cl_list);
+ INIT_LIST_HEAD(&dev->device_list);
+ dev->rd_msg_fifo_head = 0;
+ dev->rd_msg_fifo_tail = 0;
+ spin_lock_init(&dev->rd_msg_spinlock);
+
+ init_waitqueue_head(&dev->wait_hbm_recvd_msg);
+ spin_lock_init(&dev->read_list_spinlock);
+ spin_lock_init(&dev->device_lock);
+ spin_lock_init(&dev->device_list_lock);
+ spin_lock_init(&dev->cl_list_lock);
+ spin_lock_init(&dev->fw_clients_lock);
+ INIT_WORK(&dev->bh_hbm_work, bh_hbm_work_fn);
+
+ bitmap_zero(dev->host_clients_map, ISHTP_CLIENTS_MAX);
+ dev->open_handle_count = 0;
+
+ /*
+ * Reserving client ID 0 for ISHTP Bus Message communications
+ */
+ bitmap_set(dev->host_clients_map, 0, 1);
+
+ INIT_LIST_HEAD(&dev->read_list.list);
+
+}
+EXPORT_SYMBOL(ishtp_device_init);
+
+/**
+ * ishtp_start() - Start ISH processing
+ * @dev: ISHTP device instance
+ *
+ * Start ISHTP processing by sending query subscriber message
+ *
+ * Return: 0 on success else -ENODEV
+ */
+int ishtp_start(struct ishtp_device *dev)
+{
+ if (ishtp_hbm_start_wait(dev)) {
+ dev_err(dev->devc, "HBM haven't started");
+ goto err;
+ }
+
+ /* suspend & resume notification - send QUERY_SUBSCRIBERS msg */
+ ishtp_query_subscribers(dev);
+
+ return 0;
+err:
+ dev_err(dev->devc, "link layer initialization failed.\n");
+ dev->dev_state = ISHTP_DEV_DISABLED;
+ return -ENODEV;
+}
+EXPORT_SYMBOL(ishtp_start);
diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
new file mode 100644
index 000000000000..a94f9a8a96a0
--- /dev/null
+++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
@@ -0,0 +1,277 @@
+/*
+ * Most ISHTP provider device and ISHTP logic declarations
+ *
+ * Copyright (c) 2003-2016, 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.
+ */
+
+#ifndef _ISHTP_DEV_H_
+#define _ISHTP_DEV_H_
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include "bus.h"
+#include "hbm.h"
+
+#define IPC_PAYLOAD_SIZE 128
+#define ISHTP_RD_MSG_BUF_SIZE IPC_PAYLOAD_SIZE
+#define IPC_FULL_MSG_SIZE 132
+
+/* Number of messages to be held in ISR->BH FIFO */
+#define RD_INT_FIFO_SIZE 64
+
+/*
+ * Number of IPC messages to be held in Tx FIFO, to be sent by ISR -
+ * Tx complete interrupt or RX_COMPLETE handler
+ */
+#define IPC_TX_FIFO_SIZE 512
+
+/*
+ * Number of Maximum ISHTP Clients
+ */
+#define ISHTP_CLIENTS_MAX 256
+
+/*
+ * Number of File descriptors/handles
+ * that can be opened to the driver.
+ *
+ * Limit to 255: 256 Total Clients
+ * minus internal client for ISHTP Bus Messages
+ */
+#define ISHTP_MAX_OPEN_HANDLE_COUNT (ISHTP_CLIENTS_MAX - 1)
+
+/* Internal Clients Number */
+#define ISHTP_HOST_CLIENT_ID_ANY (-1)
+#define ISHTP_HBM_HOST_CLIENT_ID 0
+
+#define MAX_DMA_DELAY 20
+
+/* ISHTP device states */
+enum ishtp_dev_state {
+ ISHTP_DEV_INITIALIZING = 0,
+ ISHTP_DEV_INIT_CLIENTS,
+ ISHTP_DEV_ENABLED,
+ ISHTP_DEV_RESETTING,
+ ISHTP_DEV_DISABLED,
+ ISHTP_DEV_POWER_DOWN,
+ ISHTP_DEV_POWER_UP
+};
+const char *ishtp_dev_state_str(int state);
+
+struct ishtp_cl;
+
+/**
+ * struct ishtp_fw_client - representation of fw client
+ *
+ * @props - client properties
+ * @client_id - fw client id
+ */
+struct ishtp_fw_client {
+ struct ishtp_client_properties props;
+ uint8_t client_id;
+};
+
+/**
+ * struct ishtp_msg_data - ISHTP message data struct
+ * @size: Size of data in the *data
+ * @data: Pointer to data
+ */
+struct ishtp_msg_data {
+ uint32_t size;
+ unsigned char *data;
+};
+
+/*
+ * struct ishtp_cl_rb - request block structure
+ * @list: Link to list members
+ * @cl: ISHTP client instance
+ * @buffer: message header
+ * @buf_idx: Index into buffer
+ * @read_time: unused at this time
+ */
+struct ishtp_cl_rb {
+ struct list_head list;
+ struct ishtp_cl *cl;
+ struct ishtp_msg_data buffer;
+ unsigned long buf_idx;
+ unsigned long read_time;
+};
+
+/*
+ * Control info for IPC messages ISHTP/IPC sending FIFO -
+ * list with inline data buffer
+ * This structure will be filled with parameters submitted
+ * by the caller glue layer
+ * 'buf' may be pointing to the external buffer or to 'inline_data'
+ * 'offset' will be initialized to 0 by submitting
+ *
+ * 'ipc_send_compl' is intended for use by clients that send fragmented
+ * messages. When a fragment is sent down to IPC msg regs,
+ * it will be called.
+ * If it has more fragments to send, it will do it. With last fragment
+ * it will send appropriate ISHTP "message-complete" flag.
+ * It will remove the outstanding message
+ * (mark outstanding buffer as available).
+ * If counting flow control is in work and there are more flow control
+ * credits, it can put the next client message queued in cl.
+ * structure for IPC processing.
+ *
+ */
+struct wr_msg_ctl_info {
+ /* Will be called with 'ipc_send_compl_prm' as parameter */
+ void (*ipc_send_compl)(void *);
+
+ void *ipc_send_compl_prm;
+ size_t length;
+ struct list_head link;
+ unsigned char inline_data[IPC_FULL_MSG_SIZE];
+};
+
+/*
+ * The ISHTP layer talks to hardware IPC message using the following
+ * callbacks
+ */
+struct ishtp_hw_ops {
+ int (*hw_reset)(struct ishtp_device *dev);
+ int (*ipc_reset)(struct ishtp_device *dev);
+ uint32_t (*ipc_get_header)(struct ishtp_device *dev, int length,
+ int busy);
+ int (*write)(struct ishtp_device *dev,
+ void (*ipc_send_compl)(void *), void *ipc_send_compl_prm,
+ unsigned char *msg, int length);
+ uint32_t (*ishtp_read_hdr)(const struct ishtp_device *dev);
+ int (*ishtp_read)(struct ishtp_device *dev, unsigned char *buffer,
+ unsigned long buffer_length);
+ uint32_t (*get_fw_status)(struct ishtp_device *dev);
+ void (*sync_fw_clock)(struct ishtp_device *dev);
+};
+
+/**
+ * struct ishtp_device - ISHTP private device struct
+ */
+struct ishtp_device {
+ struct device *devc; /* pointer to lowest device */
+ struct pci_dev *pdev; /* PCI device to get device ids */
+
+ /* waitq for waiting for suspend response */
+ wait_queue_head_t suspend_wait;
+ bool suspend_flag; /* Suspend is active */
+
+ /* waitq for waiting for resume response */
+ wait_queue_head_t resume_wait;
+ bool resume_flag; /*Resume is active */
+
+ /*
+ * lock for the device, for everything that doesn't have
+ * a dedicated spinlock
+ */
+ spinlock_t device_lock;
+
+ bool recvd_hw_ready;
+ struct hbm_version version;
+ int transfer_path; /* Choice of transfer path: IPC or DMA */
+
+ /* ishtp device states */
+ enum ishtp_dev_state dev_state;
+ enum ishtp_hbm_state hbm_state;
+
+ /* driver read queue */
+ struct ishtp_cl_rb read_list;
+ spinlock_t read_list_spinlock;
+
+ /* list of ishtp_cl's */
+ struct list_head cl_list;
+ spinlock_t cl_list_lock;
+ long open_handle_count;
+
+ /* List of bus devices */
+ struct list_head device_list;
+ spinlock_t device_list_lock;
+
+ /* waiting queues for receive message from FW */
+ wait_queue_head_t wait_hw_ready;
+ wait_queue_head_t wait_hbm_recvd_msg;
+
+ /* FIFO for input messages for BH processing */
+ unsigned char rd_msg_fifo[RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE];
+ unsigned int rd_msg_fifo_head, rd_msg_fifo_tail;
+ spinlock_t rd_msg_spinlock;
+ struct work_struct bh_hbm_work;
+
+ /* IPC write queue */
+ struct wr_msg_ctl_info wr_processing_list_head, wr_free_list_head;
+ /* For both processing list and free list */
+ spinlock_t wr_processing_spinlock;
+
+ spinlock_t out_ipc_spinlock;
+
+ struct ishtp_fw_client *fw_clients; /*Note:memory has to be allocated*/
+ DECLARE_BITMAP(fw_clients_map, ISHTP_CLIENTS_MAX);
+ DECLARE_BITMAP(host_clients_map, ISHTP_CLIENTS_MAX);
+ uint8_t fw_clients_num;
+ uint8_t fw_client_presentation_num;
+ uint8_t fw_client_index;
+ spinlock_t fw_clients_lock;
+
+ /* TX DMA buffers and slots */
+ int ishtp_host_dma_enabled;
+ void *ishtp_host_dma_tx_buf;
+ unsigned int ishtp_host_dma_tx_buf_size;
+ uint64_t ishtp_host_dma_tx_buf_phys;
+ int ishtp_dma_num_slots;
+
+ /* map of 4k blocks in Tx dma buf: 0-free, 1-used */
+ uint8_t *ishtp_dma_tx_map;
+ spinlock_t ishtp_dma_tx_lock;
+
+ /* RX DMA buffers and slots */
+ void *ishtp_host_dma_rx_buf;
+ unsigned int ishtp_host_dma_rx_buf_size;
+ uint64_t ishtp_host_dma_rx_buf_phys;
+
+ /* Dump to trace buffers if enabled*/
+ void (*print_log)(struct ishtp_device *dev, char *format, ...);
+
+ /* Debug stats */
+ unsigned int ipc_rx_cnt;
+ unsigned long long ipc_rx_bytes_cnt;
+ unsigned int ipc_tx_cnt;
+ unsigned long long ipc_tx_bytes_cnt;
+
+ const struct ishtp_hw_ops *ops;
+ size_t mtu;
+ uint32_t ishtp_msg_hdr;
+ char hw[0] __aligned(sizeof(void *));
+};
+
+static inline unsigned long ishtp_secs_to_jiffies(unsigned long sec)
+{
+ return msecs_to_jiffies(sec * MSEC_PER_SEC);
+}
+
+/*
+ * Register Access Function
+ */
+static inline int ish_ipc_reset(struct ishtp_device *dev)
+{
+ return dev->ops->ipc_reset(dev);
+}
+
+static inline int ish_hw_reset(struct ishtp_device *dev)
+{
+ return dev->ops->hw_reset(dev);
+}
+
+/* Exported function */
+void ishtp_device_init(struct ishtp_device *dev);
+int ishtp_start(struct ishtp_device *dev);
+
+#endif /*_ISHTP_DEV_H_*/
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index b4b8c6abb03e..0a0eca5da47d 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -76,6 +76,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
@@ -98,6 +99,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
@@ -143,7 +145,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
index 4681a65a4579..b4800ea891cb 100644
--- a/drivers/hid/wacom.h
+++ b/drivers/hid/wacom.h
@@ -90,6 +90,8 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/hid.h>
+#include <linux/kfifo.h>
+#include <linux/leds.h>
#include <linux/usb/input.h>
#include <linux/power_supply.h>
#include <asm/unaligned.h>
@@ -105,32 +107,95 @@
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_VENDOR_ID_LENOVO 0x17ef
+enum wacom_worker {
+ WACOM_WORKER_WIRELESS,
+ WACOM_WORKER_BATTERY,
+ WACOM_WORKER_REMOTE,
+};
+
+struct wacom;
+
+struct wacom_led {
+ struct led_classdev cdev;
+ struct led_trigger trigger;
+ struct wacom *wacom;
+ unsigned int group;
+ unsigned int id;
+ u8 llv;
+ u8 hlv;
+ bool held;
+};
+
+struct wacom_group_leds {
+ u8 select; /* status led selector (0..3) */
+ struct wacom_led *leds;
+ unsigned int count;
+ struct device *dev;
+};
+
+struct wacom_battery {
+ struct wacom *wacom;
+ struct power_supply_desc bat_desc;
+ struct power_supply *battery;
+ char bat_name[WACOM_NAME_MAX];
+ int battery_capacity;
+ int bat_charging;
+ int bat_connected;
+ int ps_connected;
+};
+
+struct wacom_remote {
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
+ struct kobject *remote_dir;
+ struct {
+ struct attribute_group group;
+ u32 serial;
+ struct input_dev *input;
+ bool registered;
+ struct wacom_battery battery;
+ } remotes[WACOM_MAX_REMOTES];
+};
+
struct wacom {
struct usb_device *usbdev;
struct usb_interface *intf;
struct wacom_wac wacom_wac;
struct hid_device *hdev;
struct mutex lock;
- struct work_struct work;
- struct wacom_led {
- u8 select[5]; /* status led selector (0..3) */
+ struct work_struct wireless_work;
+ struct work_struct battery_work;
+ struct work_struct remote_work;
+ struct wacom_remote *remote;
+ struct wacom_leds {
+ struct wacom_group_leds *groups;
+ unsigned int count;
u8 llv; /* status led brightness no button (1..127) */
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
+ u8 max_llv; /* maximum brightness of LED (llv) */
+ u8 max_hlv; /* maximum brightness of LED (hlv) */
} led;
- bool led_initialized;
- struct power_supply *battery;
- struct power_supply *ac;
- struct power_supply_desc battery_desc;
- struct power_supply_desc ac_desc;
- struct kobject *remote_dir;
- struct attribute_group remote_group[5];
+ struct wacom_battery battery;
+ bool resources;
};
-static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
+ enum wacom_worker which)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- schedule_work(&wacom->work);
+
+ switch (which) {
+ case WACOM_WORKER_WIRELESS:
+ schedule_work(&wacom->wireless_work);
+ break;
+ case WACOM_WORKER_BATTERY:
+ schedule_work(&wacom->battery_work);
+ break;
+ case WACOM_WORKER_REMOTE:
+ schedule_work(&wacom->remote_work);
+ break;
+ }
}
extern const struct hid_device_id wacom_ids[];
@@ -149,7 +214,8 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value);
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
void wacom_battery_work(struct work_struct *work);
-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
- int index);
-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial);
+enum led_brightness wacom_leds_brightness_get(struct wacom_led *led);
+struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group,
+ unsigned int id);
+struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur);
#endif
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 499cc8213cfe..5e7a5648e708 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -25,7 +25,6 @@
#define WAC_CMD_RETRIES 10
#define WAC_CMD_DELETE_PAIRING 0x20
#define WAC_CMD_UNPAIR_ALL 0xFF
-#define WAC_REMOTE_SERIAL_MAX_STRLEN 9
#define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
#define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
@@ -91,7 +90,12 @@ static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
- hid_hw_close(wacom->hdev);
+ /*
+ * wacom->hdev should never be null, but surprisingly, I had the case
+ * once while unplugging the Wacom Wireless Receiver.
+ */
+ if (wacom->hdev)
+ hid_hw_close(wacom->hdev);
}
/*
@@ -523,36 +527,95 @@ struct wacom_hdev_data {
static LIST_HEAD(wacom_udev_list);
static DEFINE_MUTEX(wacom_udev_list_lock);
+static bool compare_device_paths(struct hid_device *hdev_a,
+ struct hid_device *hdev_b, char separator)
+{
+ int n1 = strrchr(hdev_a->phys, separator) - hdev_a->phys;
+ int n2 = strrchr(hdev_b->phys, separator) - hdev_b->phys;
+
+ if (n1 != n2 || n1 <= 0 || n2 <= 0)
+ return false;
+
+ return !strncmp(hdev_a->phys, hdev_b->phys, n1);
+}
+
static bool wacom_are_sibling(struct hid_device *hdev,
struct hid_device *sibling)
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_features *features = &wacom->wacom_wac.features;
- int vid = features->oVid;
- int pid = features->oPid;
- int n1,n2;
+ struct wacom *sibling_wacom = hid_get_drvdata(sibling);
+ struct wacom_features *sibling_features = &sibling_wacom->wacom_wac.features;
+ __u32 oVid = features->oVid ? features->oVid : hdev->vendor;
+ __u32 oPid = features->oPid ? features->oPid : hdev->product;
+
+ /* The defined oVid/oPid must match that of the sibling */
+ if (features->oVid != HID_ANY_ID && sibling->vendor != oVid)
+ return false;
+ if (features->oPid != HID_ANY_ID && sibling->product != oPid)
+ return false;
- if (vid == 0 && pid == 0) {
- vid = hdev->vendor;
- pid = hdev->product;
+ /*
+ * Devices with the same VID/PID must share the same physical
+ * device path, while those with different VID/PID must share
+ * the same physical parent device path.
+ */
+ if (hdev->vendor == sibling->vendor && hdev->product == sibling->product) {
+ if (!compare_device_paths(hdev, sibling, '/'))
+ return false;
+ } else {
+ if (!compare_device_paths(hdev, sibling, '.'))
+ return false;
}
- if (vid != sibling->vendor || pid != sibling->product)
+ /* Skip the remaining heuristics unless you are a HID_GENERIC device */
+ if (features->type != HID_GENERIC)
+ return true;
+
+ /*
+ * Direct-input devices may not be siblings of indirect-input
+ * devices.
+ */
+ if ((features->device_type & WACOM_DEVICETYPE_DIRECT) &&
+ !(sibling_features->device_type & WACOM_DEVICETYPE_DIRECT))
return false;
- /* Compare the physical path. */
- n1 = strrchr(hdev->phys, '.') - hdev->phys;
- n2 = strrchr(sibling->phys, '.') - sibling->phys;
- if (n1 != n2 || n1 <= 0 || n2 <= 0)
+ /*
+ * Indirect-input devices may not be siblings of direct-input
+ * devices.
+ */
+ if (!(features->device_type & WACOM_DEVICETYPE_DIRECT) &&
+ (sibling_features->device_type & WACOM_DEVICETYPE_DIRECT))
+ return false;
+
+ /* Pen devices may only be siblings of touch devices */
+ if ((features->device_type & WACOM_DEVICETYPE_PEN) &&
+ !(sibling_features->device_type & WACOM_DEVICETYPE_TOUCH))
return false;
- return !strncmp(hdev->phys, sibling->phys, n1);
+ /* Touch devices may only be siblings of pen devices */
+ if ((features->device_type & WACOM_DEVICETYPE_TOUCH) &&
+ !(sibling_features->device_type & WACOM_DEVICETYPE_PEN))
+ return false;
+
+ /*
+ * No reason could be found for these two devices to NOT be
+ * siblings, so there's a good chance they ARE siblings
+ */
+ return true;
}
static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
{
struct wacom_hdev_data *data;
+ /* Try to find an already-probed interface from the same device */
+ list_for_each_entry(data, &wacom_udev_list, list) {
+ if (compare_device_paths(hdev, data->dev, '/'))
+ return data;
+ }
+
+ /* Fallback to finding devices that appear to be "siblings" */
list_for_each_entry(data, &wacom_udev_list, list) {
if (wacom_are_sibling(hdev, data->dev)) {
kref_get(&data->kref);
@@ -563,6 +626,38 @@ static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
return NULL;
}
+static void wacom_release_shared_data(struct kref *kref)
+{
+ struct wacom_hdev_data *data =
+ container_of(kref, struct wacom_hdev_data, kref);
+
+ mutex_lock(&wacom_udev_list_lock);
+ list_del(&data->list);
+ mutex_unlock(&wacom_udev_list_lock);
+
+ kfree(data);
+}
+
+static void wacom_remove_shared_data(void *res)
+{
+ struct wacom *wacom = res;
+ struct wacom_hdev_data *data;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+ if (wacom_wac->shared) {
+ data = container_of(wacom_wac->shared, struct wacom_hdev_data,
+ shared);
+
+ if (wacom_wac->shared->touch == wacom->hdev)
+ wacom_wac->shared->touch = NULL;
+ else if (wacom_wac->shared->pen == wacom->hdev)
+ wacom_wac->shared->pen = NULL;
+
+ kref_put(&data->kref, wacom_release_shared_data);
+ wacom_wac->shared = NULL;
+ }
+}
+
static int wacom_add_shared_data(struct hid_device *hdev)
{
struct wacom *wacom = hid_get_drvdata(hdev);
@@ -587,6 +682,13 @@ static int wacom_add_shared_data(struct hid_device *hdev)
wacom_wac->shared = &data->shared;
+ retval = devm_add_action(&hdev->dev, wacom_remove_shared_data, wacom);
+ if (retval) {
+ mutex_unlock(&wacom_udev_list_lock);
+ wacom_remove_shared_data(wacom);
+ return retval;
+ }
+
if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
wacom_wac->shared->touch = hdev;
else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
@@ -597,37 +699,6 @@ out:
return retval;
}
-static void wacom_release_shared_data(struct kref *kref)
-{
- struct wacom_hdev_data *data =
- container_of(kref, struct wacom_hdev_data, kref);
-
- mutex_lock(&wacom_udev_list_lock);
- list_del(&data->list);
- mutex_unlock(&wacom_udev_list_lock);
-
- kfree(data);
-}
-
-static void wacom_remove_shared_data(struct wacom *wacom)
-{
- struct wacom_hdev_data *data;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-
- if (wacom_wac->shared) {
- data = container_of(wacom_wac->shared, struct wacom_hdev_data,
- shared);
-
- if (wacom_wac->shared->touch == wacom->hdev)
- wacom_wac->shared->touch = NULL;
- else if (wacom_wac->shared->pen == wacom->hdev)
- wacom_wac->shared->pen = NULL;
-
- kref_put(&data->kref, wacom_release_shared_data);
- wacom_wac->shared = NULL;
- }
-}
-
static int wacom_led_control(struct wacom *wacom)
{
unsigned char *buf;
@@ -635,6 +706,12 @@ static int wacom_led_control(struct wacom *wacom)
unsigned char report_id = WAC_CMD_LED_CONTROL;
int buf_size = 9;
+ if (!hid_get_drvdata(wacom->hdev))
+ return -ENODEV;
+
+ if (!wacom->led.groups)
+ return -ENOTSUPP;
+
if (wacom->wacom_wac.pid) { /* wireless connected */
report_id = WAC_CMD_WL_LED_CONTROL;
buf_size = 13;
@@ -650,7 +727,7 @@ static int wacom_led_control(struct wacom *wacom)
* one of four values:
* 0 = Low; 1 = Medium; 2 = High; 3 = Off
*/
- int ring_led = wacom->led.select[0] & 0x03;
+ int ring_led = wacom->led.groups[0].select & 0x03;
int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
int crop_lum = 0;
unsigned char led_bits = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
@@ -665,11 +742,11 @@ static int wacom_led_control(struct wacom *wacom)
buf[1] = led_bits;
}
else {
- int led = wacom->led.select[0] | 0x4;
+ int led = wacom->led.groups[0].select | 0x4;
if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
wacom->wacom_wac.features.type == WACOM_24HD)
- led |= (wacom->led.select[1] << 4) | 0x40;
+ led |= (wacom->led.groups[1].select << 4) | 0x40;
buf[0] = report_id;
buf[1] = led;
@@ -741,7 +818,7 @@ static ssize_t wacom_led_select_store(struct device *dev, int set_id,
mutex_lock(&wacom->lock);
- wacom->led.select[set_id] = id & 0x3;
+ wacom->led.groups[set_id].select = id & 0x3;
err = wacom_led_control(wacom);
mutex_unlock(&wacom->lock);
@@ -761,7 +838,7 @@ static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct hid_device *hdev = to_hid_device(dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
return scnprintf(buf, PAGE_SIZE, "%d\n", \
- wacom->led.select[SET_ID]); \
+ wacom->led.groups[SET_ID].select); \
} \
static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM, \
wacom_led##SET_ID##_select_show, \
@@ -904,6 +981,327 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};
+struct wacom_sysfs_group_devres {
+ struct attribute_group *group;
+ struct kobject *root;
+};
+
+static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
+{
+ struct wacom_sysfs_group_devres *devres = res;
+ struct kobject *kobj = devres->root;
+
+ dev_dbg(dev, "%s: dropping reference to %s\n",
+ __func__, devres->group->name);
+ sysfs_remove_group(kobj, devres->group);
+}
+
+static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct kobject *root,
+ struct attribute_group *group)
+{
+ struct wacom_sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(wacom_devm_sysfs_group_release,
+ sizeof(struct wacom_sysfs_group_devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->group = group;
+ devres->root = root;
+
+ error = sysfs_create_group(devres->root, group);
+ if (error)
+ return error;
+
+ devres_add(&wacom->hdev->dev, devres);
+
+ return 0;
+}
+
+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj,
+ group);
+}
+
+enum led_brightness wacom_leds_brightness_get(struct wacom_led *led)
+{
+ struct wacom *wacom = led->wacom;
+
+ if (wacom->led.max_hlv)
+ return led->hlv * LED_FULL / wacom->led.max_hlv;
+
+ if (wacom->led.max_llv)
+ return led->llv * LED_FULL / wacom->led.max_llv;
+
+ /* device doesn't support brightness tuning */
+ return LED_FULL;
+}
+
+static enum led_brightness __wacom_led_brightness_get(struct led_classdev *cdev)
+{
+ struct wacom_led *led = container_of(cdev, struct wacom_led, cdev);
+ struct wacom *wacom = led->wacom;
+
+ if (wacom->led.groups[led->group].select != led->id)
+ return LED_OFF;
+
+ return wacom_leds_brightness_get(led);
+}
+
+static int wacom_led_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct wacom_led *led = container_of(cdev, struct wacom_led, cdev);
+ struct wacom *wacom = led->wacom;
+ int error;
+
+ mutex_lock(&wacom->lock);
+
+ if (!wacom->led.groups || (brightness == LED_OFF &&
+ wacom->led.groups[led->group].select != led->id)) {
+ error = 0;
+ goto out;
+ }
+
+ led->llv = wacom->led.llv = wacom->led.max_llv * brightness / LED_FULL;
+ led->hlv = wacom->led.hlv = wacom->led.max_hlv * brightness / LED_FULL;
+
+ wacom->led.groups[led->group].select = led->id;
+
+ error = wacom_led_control(wacom);
+
+out:
+ mutex_unlock(&wacom->lock);
+
+ return error;
+}
+
+static void wacom_led_readonly_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+}
+
+static int wacom_led_register_one(struct device *dev, struct wacom *wacom,
+ struct wacom_led *led, unsigned int group,
+ unsigned int id, bool read_only)
+{
+ int error;
+ char *name;
+
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s::wacom-%d.%d",
+ dev_name(dev),
+ group,
+ id);
+ if (!name)
+ return -ENOMEM;
+
+ if (!read_only) {
+ led->trigger.name = name;
+ error = devm_led_trigger_register(dev, &led->trigger);
+ if (error) {
+ hid_err(wacom->hdev,
+ "failed to register LED trigger %s: %d\n",
+ led->cdev.name, error);
+ return error;
+ }
+ }
+
+ led->group = group;
+ led->id = id;
+ led->wacom = wacom;
+ led->llv = wacom->led.llv;
+ led->hlv = wacom->led.hlv;
+ led->cdev.name = name;
+ led->cdev.max_brightness = LED_FULL;
+ led->cdev.flags = LED_HW_PLUGGABLE;
+ led->cdev.brightness_get = __wacom_led_brightness_get;
+ if (!read_only) {
+ led->cdev.brightness_set_blocking = wacom_led_brightness_set;
+ led->cdev.default_trigger = led->cdev.name;
+ } else {
+ led->cdev.brightness_set = wacom_led_readonly_brightness_set;
+ }
+
+ error = devm_led_classdev_register(dev, &led->cdev);
+ if (error) {
+ hid_err(wacom->hdev,
+ "failed to register LED %s: %d\n",
+ led->cdev.name, error);
+ led->cdev.name = NULL;
+ return error;
+ }
+
+ return 0;
+}
+
+static void wacom_led_groups_release_one(void *data)
+{
+ struct wacom_group_leds *group = data;
+
+ devres_release_group(group->dev, group);
+}
+
+static int wacom_led_groups_alloc_and_register_one(struct device *dev,
+ struct wacom *wacom,
+ int group_id, int count,
+ bool read_only)
+{
+ struct wacom_led *leds;
+ int i, error;
+
+ if (group_id >= wacom->led.count || count <= 0)
+ return -EINVAL;
+
+ if (!devres_open_group(dev, &wacom->led.groups[group_id], GFP_KERNEL))
+ return -ENOMEM;
+
+ leds = devm_kzalloc(dev, sizeof(struct wacom_led) * count, GFP_KERNEL);
+ if (!leds) {
+ error = -ENOMEM;
+ goto err;
+ }
+
+ wacom->led.groups[group_id].leds = leds;
+ wacom->led.groups[group_id].count = count;
+
+ for (i = 0; i < count; i++) {
+ error = wacom_led_register_one(dev, wacom, &leds[i],
+ group_id, i, read_only);
+ if (error)
+ goto err;
+ }
+
+ wacom->led.groups[group_id].dev = dev;
+
+ devres_close_group(dev, &wacom->led.groups[group_id]);
+
+ /*
+ * There is a bug (?) in devm_led_classdev_register() in which its
+ * increments the refcount of the parent. If the parent is an input
+ * device, that means the ref count never reaches 0 when
+ * devm_input_device_release() gets called.
+ * This means that the LEDs are still there after disconnect.
+ * Manually force the release of the group so that the leds are released
+ * once we are done using them.
+ */
+ error = devm_add_action_or_reset(&wacom->hdev->dev,
+ wacom_led_groups_release_one,
+ &wacom->led.groups[group_id]);
+ if (error)
+ return error;
+
+ return 0;
+
+err:
+ devres_release_group(dev, &wacom->led.groups[group_id]);
+ return error;
+}
+
+struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group_id,
+ unsigned int id)
+{
+ struct wacom_group_leds *group;
+
+ if (group_id >= wacom->led.count)
+ return NULL;
+
+ group = &wacom->led.groups[group_id];
+
+ if (!group->leds)
+ return NULL;
+
+ id %= group->count;
+
+ return &group->leds[id];
+}
+
+/**
+ * wacom_led_next: gives the next available led with a wacom trigger.
+ *
+ * returns the next available struct wacom_led which has its default trigger
+ * or the current one if none is available.
+ */
+struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur)
+{
+ struct wacom_led *next_led;
+ int group, next;
+
+ if (!wacom || !cur)
+ return NULL;
+
+ group = cur->group;
+ next = cur->id;
+
+ do {
+ next_led = wacom_led_find(wacom, group, ++next);
+ if (!next_led || next_led == cur)
+ return next_led;
+ } while (next_led->cdev.trigger != &next_led->trigger);
+
+ return next_led;
+}
+
+static void wacom_led_groups_release(void *data)
+{
+ struct wacom *wacom = data;
+
+ wacom->led.groups = NULL;
+ wacom->led.count = 0;
+}
+
+static int wacom_led_groups_allocate(struct wacom *wacom, int count)
+{
+ struct device *dev = &wacom->hdev->dev;
+ struct wacom_group_leds *groups;
+ int error;
+
+ groups = devm_kzalloc(dev, sizeof(struct wacom_group_leds) * count,
+ GFP_KERNEL);
+ if (!groups)
+ return -ENOMEM;
+
+ error = devm_add_action_or_reset(dev, wacom_led_groups_release, wacom);
+ if (error)
+ return error;
+
+ wacom->led.groups = groups;
+ wacom->led.count = count;
+
+ return 0;
+}
+
+static int wacom_leds_alloc_and_register(struct wacom *wacom, int group_count,
+ int led_per_group, bool read_only)
+{
+ struct device *dev;
+ int i, error;
+
+ if (!wacom->wacom_wac.pad_input)
+ return -EINVAL;
+
+ dev = &wacom->wacom_wac.pad_input->dev;
+
+ error = wacom_led_groups_allocate(wacom, group_count);
+ if (error)
+ return error;
+
+ for (i = 0; i < group_count; i++) {
+ error = wacom_led_groups_alloc_and_register_one(dev, wacom, i,
+ led_per_group,
+ read_only);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -917,25 +1315,38 @@ static int wacom_initialize_leds(struct wacom *wacom)
case INTUOS4:
case INTUOS4WL:
case INTUOS4L:
- wacom->led.select[0] = 0;
- wacom->led.select[1] = 0;
wacom->led.llv = 10;
wacom->led.hlv = 20;
+ wacom->led.max_llv = 127;
+ wacom->led.max_hlv = 127;
wacom->led.img_lum = 10;
- error = sysfs_create_group(&wacom->hdev->dev.kobj,
- &intuos4_led_attr_group);
+
+ error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos4_led_attr_group);
break;
case WACOM_24HD:
case WACOM_21UX2:
- wacom->led.select[0] = 0;
- wacom->led.select[1] = 0;
wacom->led.llv = 0;
wacom->led.hlv = 0;
wacom->led.img_lum = 0;
- error = sysfs_create_group(&wacom->hdev->dev.kobj,
- &cintiq_led_attr_group);
+ error = wacom_leds_alloc_and_register(wacom, 2, 4, false);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &cintiq_led_attr_group);
break;
case INTUOS5S:
@@ -944,16 +1355,31 @@ static int wacom_initialize_leds(struct wacom *wacom)
case INTUOSPS:
case INTUOSPM:
case INTUOSPL:
- wacom->led.select[0] = 0;
- wacom->led.select[1] = 0;
wacom->led.llv = 32;
- wacom->led.hlv = 0;
- wacom->led.img_lum = 0;
+ wacom->led.max_llv = 96;
+
+ error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
- error = sysfs_create_group(&wacom->hdev->dev.kobj,
- &intuos5_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos5_led_attr_group);
break;
+ case REMOTE:
+ wacom->led.llv = 255;
+ wacom->led.max_llv = 255;
+ error = wacom_led_groups_allocate(wacom, 5);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+ return 0;
+
default:
return 0;
}
@@ -964,86 +1390,45 @@ static int wacom_initialize_leds(struct wacom *wacom)
return error;
}
wacom_led_control(wacom);
- wacom->led_initialized = true;
return 0;
}
-static void wacom_destroy_leds(struct wacom *wacom)
-{
- if (!wacom->led_initialized)
- return;
-
- if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD))
- return;
-
- wacom->led_initialized = false;
-
- switch (wacom->wacom_wac.features.type) {
- case INTUOS4S:
- case INTUOS4:
- case INTUOS4WL:
- case INTUOS4L:
- sysfs_remove_group(&wacom->hdev->dev.kobj,
- &intuos4_led_attr_group);
- break;
-
- case WACOM_24HD:
- case WACOM_21UX2:
- sysfs_remove_group(&wacom->hdev->dev.kobj,
- &cintiq_led_attr_group);
- break;
-
- case INTUOS5S:
- case INTUOS5:
- case INTUOS5L:
- case INTUOSPS:
- case INTUOSPM:
- case INTUOSPL:
- sysfs_remove_group(&wacom->hdev->dev.kobj,
- &intuos5_led_attr_group);
- break;
- }
-}
-
static enum power_supply_property wacom_battery_props[] = {
+ POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_CAPACITY
};
-static enum power_supply_property wacom_ac_props[] = {
- POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_ONLINE,
- POWER_SUPPLY_PROP_SCOPE,
-};
-
static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
- struct wacom *wacom = power_supply_get_drvdata(psy);
+ struct wacom_battery *battery = power_supply_get_drvdata(psy);
int ret = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = battery->wacom->wacom_wac.name;
+ break;
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = wacom->wacom_wac.bat_connected;
+ val->intval = battery->bat_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- val->intval =
- wacom->wacom_wac.battery_capacity;
+ val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (wacom->wacom_wac.bat_charging)
+ if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
- else if (wacom->wacom_wac.battery_capacity == 100 &&
- wacom->wacom_wac.ps_connected)
+ else if (battery->battery_capacity == 100 &&
+ battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL;
- else if (wacom->wacom_wac.ps_connected)
+ else if (battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -1056,84 +1441,64 @@ static int wacom_battery_get_property(struct power_supply *psy,
return ret;
}
-static int wacom_ac_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
+static int __wacom_initialize_battery(struct wacom *wacom,
+ struct wacom_battery *battery)
{
- struct wacom *wacom = power_supply_get_drvdata(psy);
- int ret = 0;
+ static atomic_t battery_no = ATOMIC_INIT(0);
+ struct device *dev = &wacom->hdev->dev;
+ struct power_supply_config psy_cfg = { .drv_data = battery, };
+ struct power_supply *ps_bat;
+ struct power_supply_desc *bat_desc = &battery->bat_desc;
+ unsigned long n;
+ int error;
- switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- /* fall through */
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = wacom->wacom_wac.ps_connected;
- break;
- case POWER_SUPPLY_PROP_SCOPE:
- val->intval = POWER_SUPPLY_SCOPE_DEVICE;
- break;
- default:
- ret = -EINVAL;
- break;
+ if (!devres_open_group(dev, bat_desc, GFP_KERNEL))
+ return -ENOMEM;
+
+ battery->wacom = wacom;
+
+ n = atomic_inc_return(&battery_no) - 1;
+
+ bat_desc->properties = wacom_battery_props;
+ bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props);
+ bat_desc->get_property = wacom_battery_get_property;
+ sprintf(battery->bat_name, "wacom_battery_%ld", n);
+ bat_desc->name = battery->bat_name;
+ bat_desc->type = POWER_SUPPLY_TYPE_USB;
+ bat_desc->use_for_apm = 0;
+
+ ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg);
+ if (IS_ERR(ps_bat)) {
+ error = PTR_ERR(ps_bat);
+ goto err;
}
- return ret;
+
+ power_supply_powers(ps_bat, &wacom->hdev->dev);
+
+ battery->battery = ps_bat;
+
+ devres_close_group(dev, bat_desc);
+ return 0;
+
+err:
+ devres_release_group(dev, bat_desc);
+ return error;
}
static int wacom_initialize_battery(struct wacom *wacom)
{
- static atomic_t battery_no = ATOMIC_INIT(0);
- struct power_supply_config psy_cfg = { .drv_data = wacom, };
- unsigned long n;
-
- if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
- struct power_supply_desc *bat_desc = &wacom->battery_desc;
- struct power_supply_desc *ac_desc = &wacom->ac_desc;
- n = atomic_inc_return(&battery_no) - 1;
-
- bat_desc->properties = wacom_battery_props;
- bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props);
- bat_desc->get_property = wacom_battery_get_property;
- sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
- bat_desc->name = wacom->wacom_wac.bat_name;
- bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
- bat_desc->use_for_apm = 0;
-
- ac_desc->properties = wacom_ac_props;
- ac_desc->num_properties = ARRAY_SIZE(wacom_ac_props);
- ac_desc->get_property = wacom_ac_get_property;
- sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n);
- ac_desc->name = wacom->wacom_wac.ac_name;
- ac_desc->type = POWER_SUPPLY_TYPE_MAINS;
- ac_desc->use_for_apm = 0;
-
- wacom->battery = power_supply_register(&wacom->hdev->dev,
- &wacom->battery_desc, &psy_cfg);
- if (IS_ERR(wacom->battery))
- return PTR_ERR(wacom->battery);
-
- power_supply_powers(wacom->battery, &wacom->hdev->dev);
-
- wacom->ac = power_supply_register(&wacom->hdev->dev,
- &wacom->ac_desc,
- &psy_cfg);
- if (IS_ERR(wacom->ac)) {
- power_supply_unregister(wacom->battery);
- return PTR_ERR(wacom->ac);
- }
-
- power_supply_powers(wacom->ac, &wacom->hdev->dev);
- }
+ if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY)
+ return __wacom_initialize_battery(wacom, &wacom->battery);
return 0;
}
static void wacom_destroy_battery(struct wacom *wacom)
{
- if (wacom->battery) {
- power_supply_unregister(wacom->battery);
- wacom->battery = NULL;
- power_supply_unregister(wacom->ac);
- wacom->ac = NULL;
+ if (wacom->battery.battery) {
+ devres_release_group(&wacom->hdev->dev,
+ &wacom->battery.bat_desc);
+ wacom->battery.battery = NULL;
}
}
@@ -1179,7 +1544,7 @@ static ssize_t wacom_show_remote_mode(struct kobject *kobj,
struct wacom *wacom = hid_get_drvdata(hdev);
u8 mode;
- mode = wacom->led.select[index];
+ mode = wacom->led.groups[index].select;
if (mode >= 0 && mode < 3)
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
else
@@ -1212,54 +1577,30 @@ DEVICE_EKR_ATTR_GROUP(2);
DEVICE_EKR_ATTR_GROUP(3);
DEVICE_EKR_ATTR_GROUP(4);
-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
+static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
+ int index)
{
int error = 0;
- char *buf;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
- wacom_wac->serial[index] = serial;
-
- buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL);
- if (!buf)
+ remote->remotes[index].group.name = devm_kasprintf(&wacom->hdev->dev,
+ GFP_KERNEL,
+ "%d", serial);
+ if (!remote->remotes[index].group.name)
return -ENOMEM;
- snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial);
- wacom->remote_group[index].name = buf;
- error = sysfs_create_group(wacom->remote_dir,
- &wacom->remote_group[index]);
+ error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
+ &remote->remotes[index].group);
if (error) {
+ remote->remotes[index].group.name = NULL;
hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error);
- kobject_put(wacom->remote_dir);
return error;
}
return 0;
}
-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
-{
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
- int i;
-
- if (!serial)
- return;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial) {
- wacom_wac->serial[i] = 0;
- wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- if (wacom->remote_group[i].name) {
- sysfs_remove_group(wacom->remote_dir,
- &wacom->remote_group[i]);
- kfree(wacom->remote_group[i].name);
- wacom->remote_group[i].name = NULL;
- }
- }
- }
-}
-
static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
{
const size_t buf_size = 2;
@@ -1316,27 +1657,57 @@ static const struct attribute *remote_unpair_attrs[] = {
NULL
};
-static int wacom_initialize_remote(struct wacom *wacom)
+static void wacom_remotes_destroy(void *data)
+{
+ struct wacom *wacom = data;
+ struct wacom_remote *remote = wacom->remote;
+
+ if (!remote)
+ return;
+
+ kobject_put(remote->remote_dir);
+ kfifo_free(&remote->remote_fifo);
+ wacom->remote = NULL;
+}
+
+static int wacom_initialize_remotes(struct wacom *wacom)
{
int error = 0;
- struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ struct wacom_remote *remote;
int i;
if (wacom->wacom_wac.features.type != REMOTE)
return 0;
- wacom->remote_group[0] = remote0_serial_group;
- wacom->remote_group[1] = remote1_serial_group;
- wacom->remote_group[2] = remote2_serial_group;
- wacom->remote_group[3] = remote3_serial_group;
- wacom->remote_group[4] = remote4_serial_group;
+ remote = devm_kzalloc(&wacom->hdev->dev, sizeof(*wacom->remote),
+ GFP_KERNEL);
+ if (!remote)
+ return -ENOMEM;
+
+ wacom->remote = remote;
- wacom->remote_dir = kobject_create_and_add("wacom_remote",
- &wacom->hdev->dev.kobj);
- if (!wacom->remote_dir)
+ spin_lock_init(&remote->remote_lock);
+
+ error = kfifo_alloc(&remote->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL);
+ if (error) {
+ hid_err(wacom->hdev, "failed allocating remote_fifo\n");
return -ENOMEM;
+ }
- error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs);
+ remote->remotes[0].group = remote0_serial_group;
+ remote->remotes[1].group = remote1_serial_group;
+ remote->remotes[2].group = remote2_serial_group;
+ remote->remotes[3].group = remote3_serial_group;
+ remote->remotes[4].group = remote4_serial_group;
+
+ remote->remote_dir = kobject_create_and_add("wacom_remote",
+ &wacom->hdev->dev.kobj);
+ if (!remote->remote_dir)
+ return -ENOMEM;
+
+ error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);
if (error) {
hid_err(wacom->hdev,
@@ -1345,10 +1716,15 @@ static int wacom_initialize_remote(struct wacom *wacom)
}
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- wacom_wac->serial[i] = 0;
+ wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
+ remote->remotes[i].serial = 0;
}
+ error = devm_add_action_or_reset(&wacom->hdev->dev,
+ wacom_remotes_destroy, wacom);
+ if (error)
+ return error;
+
return 0;
}
@@ -1358,7 +1734,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
struct hid_device *hdev = wacom->hdev;
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
- input_dev = input_allocate_device();
+ input_dev = devm_input_allocate_device(&hdev->dev);
if (!input_dev)
return NULL;
@@ -1377,36 +1753,6 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
return input_dev;
}
-static void wacom_clean_inputs(struct wacom *wacom)
-{
- if (wacom->wacom_wac.pen_input) {
- if (wacom->wacom_wac.pen_registered)
- input_unregister_device(wacom->wacom_wac.pen_input);
- else
- input_free_device(wacom->wacom_wac.pen_input);
- }
- if (wacom->wacom_wac.touch_input) {
- if (wacom->wacom_wac.touch_registered)
- input_unregister_device(wacom->wacom_wac.touch_input);
- else
- input_free_device(wacom->wacom_wac.touch_input);
- }
- if (wacom->wacom_wac.pad_input) {
- if (wacom->wacom_wac.pad_registered)
- input_unregister_device(wacom->wacom_wac.pad_input);
- else
- input_free_device(wacom->wacom_wac.pad_input);
- }
- kobject_put(wacom->remote_dir);
- wacom->wacom_wac.pen_input = NULL;
- wacom->wacom_wac.touch_input = NULL;
- wacom->wacom_wac.pad_input = NULL;
- wacom->wacom_wac.pen_registered = false;
- wacom->wacom_wac.touch_registered = false;
- wacom->wacom_wac.pad_registered = false;
- wacom_destroy_leds(wacom);
-}
-
static int wacom_allocate_inputs(struct wacom *wacom)
{
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
@@ -1414,10 +1760,10 @@ static int wacom_allocate_inputs(struct wacom *wacom)
wacom_wac->pen_input = wacom_allocate_input(wacom);
wacom_wac->touch_input = wacom_allocate_input(wacom);
wacom_wac->pad_input = wacom_allocate_input(wacom);
- if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) {
- wacom_clean_inputs(wacom);
+ if (!wacom_wac->pen_input ||
+ !wacom_wac->touch_input ||
+ !wacom_wac->pad_input)
return -ENOMEM;
- }
wacom_wac->pen_input->name = wacom_wac->pen_name;
wacom_wac->touch_input->name = wacom_wac->touch_name;
@@ -1448,8 +1794,7 @@ static int wacom_register_inputs(struct wacom *wacom)
} else {
error = input_register_device(pen_input_dev);
if (error)
- goto fail_register_pen_input;
- wacom_wac->pen_registered = true;
+ goto fail;
}
error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac);
@@ -1461,8 +1806,7 @@ static int wacom_register_inputs(struct wacom *wacom)
} else {
error = input_register_device(touch_input_dev);
if (error)
- goto fail_register_touch_input;
- wacom_wac->touch_registered = true;
+ goto fail;
}
error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
@@ -1474,37 +1818,15 @@ static int wacom_register_inputs(struct wacom *wacom)
} else {
error = input_register_device(pad_input_dev);
if (error)
- goto fail_register_pad_input;
- wacom_wac->pad_registered = true;
-
- error = wacom_initialize_leds(wacom);
- if (error)
- goto fail_leds;
-
- error = wacom_initialize_remote(wacom);
- if (error)
- goto fail_remote;
+ goto fail;
}
return 0;
-fail_remote:
- wacom_destroy_leds(wacom);
-fail_leds:
- input_unregister_device(pad_input_dev);
- pad_input_dev = NULL;
- wacom_wac->pad_registered = false;
-fail_register_pad_input:
- if (touch_input_dev)
- input_unregister_device(touch_input_dev);
+fail:
+ wacom_wac->pad_input = NULL;
wacom_wac->touch_input = NULL;
- wacom_wac->touch_registered = false;
-fail_register_touch_input:
- if (pen_input_dev)
- input_unregister_device(pen_input_dev);
wacom_wac->pen_input = NULL;
- wacom_wac->pen_registered = false;
-fail_register_pen_input:
return error;
}
@@ -1543,14 +1865,14 @@ static void wacom_calculate_res(struct wacom_features *features)
void wacom_battery_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, battery_work);
if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- !wacom->battery) {
+ !wacom->battery.battery) {
wacom_initialize_battery(wacom);
}
else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- wacom->battery) {
+ wacom->battery.battery) {
wacom_destroy_battery(wacom);
}
}
@@ -1606,6 +1928,9 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
strlcpy(name, features->name, sizeof(name));
}
+ snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s%s",
+ name, suffix);
+
/* Append the device type to the name */
snprintf(wacom_wac->pen_name, sizeof(wacom_wac->pen_name),
"%s%s Pen", name, suffix);
@@ -1615,6 +1940,22 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
"%s%s Pad", name, suffix);
}
+static void wacom_release_resources(struct wacom *wacom)
+{
+ struct hid_device *hdev = wacom->hdev;
+
+ if (!wacom->resources)
+ return;
+
+ devres_release_group(&hdev->dev, wacom);
+
+ wacom->resources = false;
+
+ wacom->wacom_wac.pen_input = NULL;
+ wacom->wacom_wac.touch_input = NULL;
+ wacom->wacom_wac.pad_input = NULL;
+}
+
static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
@@ -1627,9 +1968,14 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if (features->pktlen > WACOM_PKGLEN_MAX)
return -EINVAL;
+ if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL))
+ return -ENOMEM;
+
+ wacom->resources = true;
+
error = wacom_allocate_inputs(wacom);
if (error)
- return error;
+ goto fail;
/*
* Bamboo Pad has a generic hid handling for the Pen, and we switch it
@@ -1642,7 +1988,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
} else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
(features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
error = -ENODEV;
- goto fail_allocate_inputs;
+ goto fail;
}
}
@@ -1662,7 +2008,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
error ? "Ignoring" : "Assuming pen");
if (error)
- goto fail_parsed;
+ goto fail;
features->device_type |= WACOM_DEVICETYPE_PEN;
}
@@ -1673,18 +2019,28 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
error = wacom_add_shared_data(hdev);
if (error)
- goto fail_shared_data;
+ goto fail;
if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
(features->quirks & WACOM_QUIRK_BATTERY)) {
error = wacom_initialize_battery(wacom);
if (error)
- goto fail_battery;
+ goto fail;
}
error = wacom_register_inputs(wacom);
if (error)
- goto fail_register_inputs;
+ goto fail;
+
+ if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) {
+ error = wacom_initialize_leds(wacom);
+ if (error)
+ goto fail;
+
+ error = wacom_initialize_remotes(wacom);
+ if (error)
+ goto fail;
+ }
if (features->type == HID_GENERIC)
connect_mask |= HID_CONNECT_DRIVER;
@@ -1693,7 +2049,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
error = hid_hw_start(hdev, connect_mask);
if (error) {
hid_err(hdev, "hw start failed\n");
- goto fail_hw_start;
+ goto fail;
}
if (!wireless) {
@@ -1705,7 +2061,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if ((features->type == BAMBOO_TOUCH) &&
(features->device_type & WACOM_DEVICETYPE_PEN)) {
error = -ENODEV;
- goto fail_hw_start;
+ goto fail_quirks;
}
/* pen only Bamboo neither support touch nor pad */
@@ -1713,37 +2069,33 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
(features->device_type & WACOM_DEVICETYPE_PAD))) {
error = -ENODEV;
- goto fail_hw_start;
+ goto fail_quirks;
}
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
error = hid_hw_open(hdev);
if ((wacom_wac->features.type == INTUOSHT ||
- wacom_wac->features.type == INTUOSHT2) &&
+ wacom_wac->features.type == INTUOSHT2) &&
(wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
- wacom_wac->shared->touch_input = wacom_wac->touch_input;
+ wacom_wac->shared->type = wacom_wac->features.type;
+ wacom_wac->shared->touch_input = wacom_wac->touch_input;
}
+ devres_close_group(&hdev->dev, wacom);
+
return 0;
-fail_hw_start:
+fail_quirks:
hid_hw_stop(hdev);
-fail_register_inputs:
- wacom_clean_inputs(wacom);
- wacom_destroy_battery(wacom);
-fail_battery:
- wacom_remove_shared_data(wacom);
-fail_shared_data:
-fail_parsed:
-fail_allocate_inputs:
- wacom_clean_inputs(wacom);
+fail:
+ wacom_release_resources(wacom);
return error;
}
static void wacom_wireless_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, wireless_work);
struct usb_device *usbdev = wacom->usbdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_device *hdev1, *hdev2;
@@ -1762,17 +2114,16 @@ static void wacom_wireless_work(struct work_struct *work)
hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom1 = hid_get_drvdata(hdev1);
wacom_wac1 = &(wacom1->wacom_wac);
- wacom_clean_inputs(wacom1);
+ wacom_release_resources(wacom1);
/* Touch interface */
hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom2 = hid_get_drvdata(hdev2);
wacom_wac2 = &(wacom2->wacom_wac);
- wacom_clean_inputs(wacom2);
+ wacom_release_resources(wacom2);
if (wacom_wac->pid == 0) {
hid_info(wacom->hdev, "wireless tablet disconnected\n");
- wacom_wac1->shared->type = 0;
} else {
const struct hid_device_id *id = wacom_ids;
@@ -1814,6 +2165,8 @@ static void wacom_wireless_work(struct work_struct *work)
goto fail;
}
+ strlcpy(wacom_wac->name, wacom_wac1->name,
+ sizeof(wacom_wac->name));
error = wacom_initialize_battery(wacom);
if (error)
goto fail;
@@ -1822,11 +2175,177 @@ static void wacom_wireless_work(struct work_struct *work)
return;
fail:
- wacom_clean_inputs(wacom1);
- wacom_clean_inputs(wacom2);
+ wacom_release_resources(wacom1);
+ wacom_release_resources(wacom2);
return;
}
+static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ u32 serial = remote->remotes[index].serial;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+ remote->remotes[index].registered = false;
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+ if (remote->remotes[index].battery.battery)
+ devres_release_group(&wacom->hdev->dev,
+ &remote->remotes[index].battery.bat_desc);
+
+ if (remote->remotes[index].group.name)
+ devres_release_group(&wacom->hdev->dev,
+ &remote->remotes[index]);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ remote->remotes[i].serial = 0;
+ remote->remotes[i].group.name = NULL;
+ remote->remotes[i].registered = false;
+ remote->remotes[i].battery.battery = NULL;
+ wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
+ }
+ }
+}
+
+static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ struct device *dev = &wacom->hdev->dev;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->remotes[k].serial == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->remotes[index].serial = serial;
+ return 0;
+ }
+
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
+ return -ENOMEM;
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].input = wacom_allocate_input(wacom);
+ if (!remote->remotes[index].input) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ remote->remotes[index].input->uniq = remote->remotes[index].group.name;
+ remote->remotes[index].input->name = wacom->wacom_wac.pad_name;
+
+ if (!remote->remotes[index].input->name) {
+ error = -EINVAL;
+ goto fail;
+ }
+
+ error = wacom_setup_pad_input_capabilities(remote->remotes[index].input,
+ &wacom->wacom_wac);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].serial = serial;
+
+ error = input_register_device(remote->remotes[index].input);
+ if (error)
+ goto fail;
+
+ error = wacom_led_groups_alloc_and_register_one(
+ &remote->remotes[index].input->dev,
+ wacom, index, 3, true);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].registered = true;
+
+ devres_close_group(dev, &remote->remotes[index]);
+ return 0;
+
+fail:
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
+ return error;
+}
+
+static int wacom_remote_attach_battery(struct wacom *wacom, int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error;
+
+ if (!remote->remotes[index].registered)
+ return 0;
+
+ if (remote->remotes[index].battery.battery)
+ return 0;
+
+ if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN)
+ return 0;
+
+ error = __wacom_initialize_battery(wacom,
+ &wacom->remote->remotes[index].battery);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void wacom_remote_work(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, remote_work);
+ struct wacom_remote *remote = wacom->remote;
+ struct wacom_remote_data data;
+ unsigned long flags;
+ unsigned int count;
+ u32 serial;
+ int i;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ count = kfifo_out(&remote->remote_fifo, &data, sizeof(data));
+
+ if (count != sizeof(data)) {
+ hid_err(wacom->hdev,
+ "workitem triggered without status available\n");
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return;
+ }
+
+ if (!kfifo_is_empty(&remote->remote_fifo))
+ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);
+
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ serial = data.remote[i].serial;
+ if (data.remote[i].connected) {
+
+ if (remote->remotes[i].serial == serial) {
+ wacom_remote_attach_battery(wacom, i);
+ continue;
+ }
+
+ if (remote->remotes[i].serial)
+ wacom_remote_destroy_one(wacom, i);
+
+ wacom_remote_create_one(wacom, serial, i);
+
+ } else if (remote->remotes[i].serial) {
+ wacom_remote_destroy_one(wacom, i);
+ }
+ }
+}
+
static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
@@ -1845,7 +2364,7 @@ static int wacom_probe(struct hid_device *hdev,
/* hid-core sets this quirk for the boot interface */
hdev->quirks &= ~HID_QUIRK_NOGET;
- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = devm_kzalloc(&hdev->dev, sizeof(struct wacom), GFP_KERNEL);
if (!wacom)
return -ENOMEM;
@@ -1858,7 +2377,7 @@ static int wacom_probe(struct hid_device *hdev,
if (features->check_for_hid_type && features->hid_type != hdev->type) {
error = -ENODEV;
- goto fail_type;
+ goto fail;
}
wacom_wac->hid_data.inputmode = -1;
@@ -1867,18 +2386,20 @@ static int wacom_probe(struct hid_device *hdev,
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
- INIT_WORK(&wacom->work, wacom_wireless_work);
+ INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
+ INIT_WORK(&wacom->battery_work, wacom_battery_work);
+ INIT_WORK(&wacom->remote_work, wacom_remote_work);
/* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "parse failed\n");
- goto fail_parse;
+ goto fail;
}
error = wacom_parse_and_register(wacom, false);
if (error)
- goto fail_parse;
+ goto fail;
if (hdev->bus == BUS_BLUETOOTH) {
error = device_create_file(&hdev->dev, &dev_attr_speed);
@@ -1890,9 +2411,7 @@ static int wacom_probe(struct hid_device *hdev,
return 0;
-fail_type:
-fail_parse:
- kfree(wacom);
+fail:
hid_set_drvdata(hdev, NULL);
return error;
}
@@ -1908,15 +2427,13 @@ static void wacom_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
- cancel_work_sync(&wacom->work);
- wacom_clean_inputs(wacom);
+ cancel_work_sync(&wacom->wireless_work);
+ cancel_work_sync(&wacom->battery_work);
+ cancel_work_sync(&wacom->remote_work);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
- wacom_destroy_battery(wacom);
- wacom_remove_shared_data(wacom);
hid_set_drvdata(hdev, NULL);
- kfree(wacom);
}
#ifdef CONFIG_PM
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 1eae13cdc502..1cb79925730d 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -34,6 +34,10 @@
*/
#define WACOM_CONTACT_AREA_SCALE 2607
+static bool touch_arbitration = 1;
+module_param(touch_arbitration, bool, 0644);
+MODULE_PARM_DESC(touch_arbitration, " on (Y) off (N)");
+
static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_count, int mask);
@@ -48,25 +52,34 @@ static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
*/
static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
+static void __wacom_notify_battery(struct wacom_battery *battery,
+ int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
+{
+ bool changed = battery->battery_capacity != bat_capacity ||
+ battery->bat_charging != bat_charging ||
+ battery->bat_connected != bat_connected ||
+ battery->ps_connected != ps_connected;
+
+ if (changed) {
+ battery->battery_capacity = bat_capacity;
+ battery->bat_charging = bat_charging;
+ battery->bat_connected = bat_connected;
+ battery->ps_connected = ps_connected;
+
+ if (battery->battery)
+ power_supply_changed(battery->battery);
+ }
+}
+
static void wacom_notify_battery(struct wacom_wac *wacom_wac,
int bat_capacity, bool bat_charging, bool bat_connected,
bool ps_connected)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- bool changed = wacom_wac->battery_capacity != bat_capacity ||
- wacom_wac->bat_charging != bat_charging ||
- wacom_wac->bat_connected != bat_connected ||
- wacom_wac->ps_connected != ps_connected;
- if (changed) {
- wacom_wac->battery_capacity = bat_capacity;
- wacom_wac->bat_charging = bat_charging;
- wacom_wac->bat_connected = bat_connected;
- wacom_wac->ps_connected = ps_connected;
-
- if (wacom->battery)
- power_supply_changed(wacom->battery);
- }
+ __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
+ bat_connected, ps_connected);
}
static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -751,22 +764,37 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
{
unsigned char *data = wacom_wac->data;
- struct input_dev *input = wacom_wac->pad_input;
+ struct input_dev *input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- struct wacom_features *features = &wacom_wac->features;
+ struct wacom_remote *remote = wacom->remote;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
- int i;
+ int i, index = -1;
+ unsigned long flags;
if (data[0] != WACOM_REPORT_REMOTE) {
- dev_dbg(input->dev.parent,
- "%s: received unknown report #%d", __func__, data[0]);
+ hid_dbg(wacom->hdev, "%s: received unknown report #%d",
+ __func__, data[0]);
return 0;
}
serial = data[3] + (data[4] << 8) + (data[5] << 16);
wacom_wac->id[0] = PAD_DEVICE_ID;
+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0 || !remote->remotes[index].registered)
+ goto out;
+
+ input = remote->remotes[index].input;
+
input_report_key(input, BTN_0, (data[9] & 0x01));
input_report_key(input, BTN_1, (data[9] & 0x02));
input_report_key(input, BTN_2, (data[9] & 0x04));
@@ -803,73 +831,69 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
input_event(input, EV_MSC, MSC_SERIAL, serial);
+ input_sync(input);
+
/*Which mode select (LED light) is currently on?*/
touch_ring_mode = (data[11] & 0xC0) >> 6;
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial)
- wacom->led.select[i] = touch_ring_mode;
- }
-
- if (!wacom->battery &&
- !(features->quirks & WACOM_QUIRK_BATTERY)) {
- features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ if (remote->remotes[i].serial == serial)
+ wacom->led.groups[i].select = touch_ring_mode;
}
- wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
- bat_charging);
+ __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ bat_charging, 1, bat_charging);
- return 1;
+out:
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return 0;
}
-static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
unsigned char *data = wacom_wac->data;
- int i;
+ struct wacom_remote *remote = wacom->remote;
+ struct wacom_remote_data remote_data;
+ unsigned long flags;
+ int i, ret;
if (data[0] != WACOM_REPORT_DEVICE_LIST)
- return 0;
+ return;
+
+ memset(&remote_data, 0, sizeof(struct wacom_remote_data));
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
int j = i * 6;
int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
bool connected = data[j+2];
- if (connected) {
- int k;
+ remote_data.remote[i].serial = serial;
+ remote_data.remote[i].connected = connected;
+ }
- if (wacom_wac->serial[i] == serial)
- continue;
+ spin_lock_irqsave(&remote->remote_lock, flags);
- if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
+ ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
+ if (ret != sizeof(remote_data)) {
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ hid_err(wacom->hdev, "Can't queue Remote status event.\n");
+ return;
+ }
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
- break;
- }
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
- if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
+}
- } else if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
- }
+static inline bool report_touch_events(struct wacom_wac *wacom)
+{
+ return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
+}
- return 0;
+static inline bool delay_pen_events(struct wacom_wac *wacom)
+{
+ return (wacom->shared->touch_down && touch_arbitration);
}
static int wacom_intuos_general(struct wacom_wac *wacom)
@@ -885,7 +909,7 @@ static int wacom_intuos_general(struct wacom_wac *wacom)
data[0] != WACOM_REPORT_INTUOS_PEN)
return 0;
- if (wacom->shared->touch_down)
+ if (delay_pen_events(wacom))
return 1;
/* don't report events if we don't know the tool ID */
@@ -1145,7 +1169,7 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
if (touch_max == 1)
return test_bit(BTN_TOUCH, input->key) &&
- !wacom->shared->stylus_in_proximity;
+ report_touch_events(wacom);
for (i = 0; i < input->mt->num_slots; i++) {
struct input_mt_slot *ps = &input->mt->slots[i];
@@ -1186,7 +1210,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
for (i = 0; i < contacts_to_send; i++) {
int offset = (byte_per_packet * i) + 1;
- bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
+ bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
if (slot < 0)
@@ -1250,7 +1274,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
for (i = 0; i < contacts_to_send; i++) {
int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
- bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
+ bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
int id = get_unaligned_le16(&data[offset + 1]);
int slot = input_mt_get_slot_by_key(input, id);
@@ -1284,7 +1308,7 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
for (i = 0; i < 2; i++) {
int p = data[1] & (1 << i);
- bool touch = p && !wacom->shared->stylus_in_proximity;
+ bool touch = p && report_touch_events(wacom);
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
@@ -1308,7 +1332,7 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
{
unsigned char *data = wacom->data;
struct input_dev *input = wacom->touch_input;
- bool prox = !wacom->shared->stylus_in_proximity;
+ bool prox = report_touch_events(wacom);
int x = 0, y = 0;
if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
@@ -1353,8 +1377,10 @@ static int wacom_tpc_pen(struct wacom_wac *wacom)
/* keep pen state for touch events */
wacom->shared->stylus_in_proximity = prox;
- /* send pen events only when touch is up or forced out */
- if (!wacom->shared->touch_down) {
+ /* send pen events only when touch is up or forced out
+ * or touch arbitration is off
+ */
+ if (!delay_pen_events(wacom)) {
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
@@ -1496,8 +1522,10 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
return 0;
}
- /* send pen events only when touch is up or forced out */
- if (!usage->type || wacom_wac->shared->touch_down)
+ /* send pen events only when touch is up or forced out
+ * or touch arbitration is off
+ */
+ if (!usage->type || delay_pen_events(wacom_wac))
return 0;
input_event(input, usage->type, usage->code, value);
@@ -1527,8 +1555,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
/* keep pen state for touch events */
wacom_wac->shared->stylus_in_proximity = prox;
- /* send pen events only when touch is up or forced out */
- if (!wacom_wac->shared->touch_down) {
+ if (!delay_pen_events(wacom_wac)) {
input_report_key(input, BTN_TOUCH,
wacom_wac->hid_data.tipswitch);
input_report_key(input, wacom_wac->tool[0], prox);
@@ -1544,13 +1571,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
- struct wacom_features *features = &wacom_wac->features;
struct input_dev *input = wacom_wac->touch_input;
unsigned touch_max = wacom_wac->features.touch_max;
switch (usage->hid) {
case HID_GD_X:
- features->last_slot_field = usage->hid;
if (touch_max == 1)
wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
else
@@ -1558,7 +1583,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
ABS_MT_POSITION_X, 4);
break;
case HID_GD_Y:
- features->last_slot_field = usage->hid;
if (touch_max == 1)
wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
else
@@ -1567,22 +1591,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
break;
case HID_DG_WIDTH:
case HID_DG_HEIGHT:
- features->last_slot_field = usage->hid;
wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
break;
- case HID_DG_CONTACTID:
- features->last_slot_field = usage->hid;
- break;
- case HID_DG_INRANGE:
- features->last_slot_field = usage->hid;
- break;
- case HID_DG_INVERT:
- features->last_slot_field = usage->hid;
- break;
case HID_DG_TIPSWITCH:
- features->last_slot_field = usage->hid;
wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
break;
case HID_DG_CONTACTCOUNT:
@@ -1599,7 +1612,7 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
struct hid_data *hid_data = &wacom_wac->hid_data;
bool mt = wacom_wac->features.touch_max > 1;
bool prox = hid_data->tipswitch &&
- !wacom_wac->shared->stylus_in_proximity;
+ report_touch_events(wacom_wac);
wacom_wac->hid_data.num_received++;
if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
@@ -1660,7 +1673,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
if (usage->usage_index + 1 == field->report_count) {
- if (usage->hid == wacom_wac->features.last_slot_field)
+ if (usage->hid == wacom_wac->hid_data.last_slot_field)
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
}
@@ -1673,31 +1686,35 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_data* hid_data = &wacom_wac->hid_data;
+ int i;
- if (hid_data->cc_report != 0 &&
- hid_data->cc_report != report->id) {
- int i;
-
- hid_data->cc_report = report->id;
- hid_data->cc_index = -1;
- hid_data->cc_value_index = -1;
-
- for (i = 0; i < report->maxfield; i++) {
- struct hid_field *field = report->field[i];
- int j;
-
- for (j = 0; j < field->maxusage; j++) {
- if (field->usage[j].hid == HID_DG_CONTACTCOUNT) {
- hid_data->cc_index = i;
- hid_data->cc_value_index = j;
-
- /* break */
- i = report->maxfield;
- j = field->maxusage;
- }
+ for (i = 0; i < report->maxfield; i++) {
+ struct hid_field *field = report->field[i];
+ int j;
+
+ for (j = 0; j < field->maxusage; j++) {
+ struct hid_usage *usage = &field->usage[j];
+
+ switch (usage->hid) {
+ case HID_GD_X:
+ case HID_GD_Y:
+ case HID_DG_WIDTH:
+ case HID_DG_HEIGHT:
+ case HID_DG_CONTACTID:
+ case HID_DG_INRANGE:
+ case HID_DG_INVERT:
+ case HID_DG_TIPSWITCH:
+ hid_data->last_slot_field = usage->hid;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ hid_data->cc_report = report->id;
+ hid_data->cc_index = i;
+ hid_data->cc_value_index = j;
+ break;
}
}
}
+
if (hid_data->cc_report != 0 &&
hid_data->cc_index >= 0) {
struct hid_field *field = report->field[hid_data->cc_index];
@@ -1740,10 +1757,10 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom_wac->features;
/* currently, only direct devices have proper hid report descriptors */
- __set_bit(INPUT_PROP_DIRECT, wacom_wac->pen_input->propbit);
- __set_bit(INPUT_PROP_DIRECT, wacom_wac->touch_input->propbit);
+ features->device_type |= WACOM_DEVICETYPE_DIRECT;
if (WACOM_PEN_FIELD(field))
return wacom_wac_pen_usage_mapping(hdev, field, usage);
@@ -1825,15 +1842,8 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
for (i = 0; i < 2; i++) {
int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
- bool touch = data[offset + 3] & 0x80;
-
- /*
- * Touch events need to be disabled while stylus is
- * in proximity because user's hand is resting on touchpad
- * and sending unwanted events. User expects tablet buttons
- * to continue working though.
- */
- touch = touch && !wacom->shared->stylus_in_proximity;
+ bool touch = report_touch_events(wacom)
+ && (data[offset + 3] & 0x80);
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
@@ -1870,7 +1880,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
if (slot < 0)
return;
- touch = touch && !wacom->shared->stylus_in_proximity;
+ touch = touch && report_touch_events(wacom);
input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
@@ -1942,7 +1952,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
}
/* only update touch if we actually have a touchpad and touch data changed */
- if (wacom->touch_registered && touch_changed) {
+ if (wacom->touch_input && touch_changed) {
input_mt_sync_frame(wacom->touch_input);
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
}
@@ -1983,7 +1993,7 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
}
wacom->shared->stylus_in_proximity = prox;
- if (wacom->shared->touch_down)
+ if (delay_pen_events(wacom))
return 0;
if (prox) {
@@ -2077,7 +2087,7 @@ static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
for (id = 0; id < wacom->features.touch_max; id++) {
valid = !!(prefix & BIT(id)) &&
- !wacom->shared->stylus_in_proximity;
+ report_touch_events(wacom);
input_mt_slot(input, id);
input_mt_report_slot_state(input, MT_TOOL_FINGER, valid);
@@ -2099,8 +2109,7 @@ static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
input_report_key(input, BTN_RIGHT, prefix & 0x80);
/* keep touch state for pen event */
- wacom->shared->touch_down = !!prefix &&
- !wacom->shared->stylus_in_proximity;
+ wacom->shared->touch_down = !!prefix && report_touch_events(wacom);
return 1;
}
@@ -2149,16 +2158,15 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
charging = !!(data[5] & 0x80);
if (wacom->pid != pid) {
wacom->pid = pid;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}
- if (wacom->shared->type)
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, battery, charging, 1, 0);
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
wacom_notify_battery(wacom, 0, 0, 0, 0);
}
@@ -2190,18 +2198,16 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
wacom_notify_battery(wacom_wac, battery, charging,
battery || charging, 1);
- if (!wacom->battery &&
+ if (!wacom->battery.battery &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
- wacom->battery) {
+ wacom->battery.battery) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
}
return 0;
@@ -2312,8 +2318,9 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break;
case REMOTE:
+ sync = false;
if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
- sync = wacom_remote_status_irq(wacom_wac, len);
+ wacom_remote_status_irq(wacom_wac, len);
else
sync = wacom_remote_irq(wacom_wac, len);
break;
@@ -2451,6 +2458,33 @@ void wacom_setup_device_quirks(struct wacom *wacom)
if (features->type == REMOTE)
features->device_type = WACOM_DEVICETYPE_PAD;
+ switch (features->type) {
+ case PL:
+ case DTU:
+ case DTUS:
+ case DTUSX:
+ case WACOM_21UX2:
+ case WACOM_22HD:
+ case DTK:
+ case WACOM_24HD:
+ case WACOM_27QHD:
+ case CINTIQ_HYBRID:
+ case CINTIQ_COMPANION_2:
+ case CINTIQ:
+ case WACOM_BEE:
+ case WACOM_13HD:
+ case WACOM_24HDT:
+ case WACOM_27QHDT:
+ case TABLETPC:
+ case TABLETPCE:
+ case TABLETPC2FG:
+ case MTSCREEN:
+ case MTTPC:
+ case MTTPC_B:
+ features->device_type |= WACOM_DEVICETYPE_DIRECT;
+ break;
+ }
+
if (wacom->hdev->bus == BUS_BLUETOOTH)
features->quirks |= WACOM_QUIRK_BATTERY;
@@ -2469,6 +2503,9 @@ void wacom_setup_device_quirks(struct wacom *wacom)
features->quirks |= WACOM_QUIRK_BATTERY;
}
}
+
+ if (features->type == REMOTE)
+ features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
}
int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
@@ -2481,6 +2518,11 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
if (!(features->device_type & WACOM_DEVICETYPE_PEN))
return -ENODEV;
+ if (features->device_type & WACOM_DEVICETYPE_DIRECT)
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ else
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
if (features->type == HID_GENERIC)
/* setup has already been done */
return 0;
@@ -2499,7 +2541,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
input_abs_set_res(input_dev, ABS_X, features->x_resolution);
input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
-
switch (features->type) {
case GRAPHIRE_BT:
__clear_bit(ABS_MISC, input_dev->absbit);
@@ -2523,8 +2564,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
-
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case WACOM_27QHD:
@@ -2539,7 +2578,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
case CINTIQ_COMPANION_2:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
input_abs_set_res(input_dev, ABS_Z, 287);
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac);
break;
@@ -2555,8 +2593,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
/* fall through */
case INTUOS:
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
wacom_setup_intuos(wacom_wac);
break;
@@ -2566,8 +2602,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
case INTUOSPL:
case INTUOS5S:
case INTUOSPS:
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max,
features->distance_fuzz, 0);
@@ -2597,8 +2631,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
-
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
break;
case PTU:
@@ -2609,16 +2641,12 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
-
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case INTUOSHT:
case BAMBOO_PT:
case BAMBOO_PEN:
case INTUOSHT2:
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
if (features->type == INTUOSHT2) {
wacom_setup_basic_pro_pen(wacom_wac);
} else {
@@ -2649,6 +2677,11 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
if (!(features->device_type & WACOM_DEVICETYPE_TOUCH))
return -ENODEV;
+ if (features->device_type & WACOM_DEVICETYPE_DIRECT)
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ else
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
if (features->type == HID_GENERIC)
/* setup has already been done */
return 0;
@@ -2683,8 +2716,6 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
case INTUOSPL:
case INTUOS5S:
case INTUOSPS:
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0);
input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
@@ -2707,7 +2738,6 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
case TABLETPC:
case TABLETPCE:
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
break;
case INTUOSHT:
@@ -2752,11 +2782,105 @@ static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
__set_bit(BTN_BASE + (i-16), input_dev->keybit);
}
+static void wacom_24hd_update_leds(struct wacom *wacom, int mask, int group)
+{
+ struct wacom_led *led;
+ int i;
+ bool updated = false;
+
+ /*
+ * 24HD has LED group 1 to the left and LED group 0 to the right.
+ * So group 0 matches the second half of the buttons and thus the mask
+ * needs to be shifted.
+ */
+ if (group == 0)
+ mask >>= 8;
+
+ for (i = 0; i < 3; i++) {
+ led = wacom_led_find(wacom, group, i);
+ if (!led) {
+ hid_err(wacom->hdev, "can't find LED %d in group %d\n",
+ i, group);
+ continue;
+ }
+ if (!updated && mask & BIT(i)) {
+ led->held = true;
+ led_trigger_event(&led->trigger, LED_FULL);
+ } else {
+ led->held = false;
+ }
+ }
+}
+
+static bool wacom_is_led_toggled(struct wacom *wacom, int button_count,
+ int mask, int group)
+{
+ int button_per_group;
+
+ /*
+ * 21UX2 has LED group 1 to the left and LED group 0
+ * to the right. We need to reverse the group to match this
+ * historical behavior.
+ */
+ if (wacom->wacom_wac.features.type == WACOM_21UX2)
+ group = 1 - group;
+
+ button_per_group = button_count/wacom->led.count;
+
+ return mask & (1 << (group * button_per_group));
+}
+
+static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
+ int group)
+{
+ struct wacom_led *led, *next_led;
+ int cur;
+ bool pressed;
+
+ if (wacom->wacom_wac.features.type == WACOM_24HD)
+ return wacom_24hd_update_leds(wacom, mask, group);
+
+ pressed = wacom_is_led_toggled(wacom, button_count, mask, group);
+ cur = wacom->led.groups[group].select;
+
+ led = wacom_led_find(wacom, group, cur);
+ if (!led) {
+ hid_err(wacom->hdev, "can't find current LED %d in group %d\n",
+ cur, group);
+ return;
+ }
+
+ if (!pressed) {
+ led->held = false;
+ return;
+ }
+
+ if (led->held && pressed)
+ return;
+
+ next_led = wacom_led_next(wacom, led);
+ if (!next_led) {
+ hid_err(wacom->hdev, "can't find next LED in group %d\n",
+ group);
+ return;
+ }
+ if (next_led == led)
+ return;
+
+ next_led->held = true;
+ led_trigger_event(&next_led->trigger,
+ wacom_leds_brightness_get(next_led));
+}
+
static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_count, int mask)
{
+ struct wacom *wacom = input_get_drvdata(input_dev);
int i;
+ for (i = 0; i < wacom->led.count; i++)
+ wacom_update_led(wacom, button_count, mask, i);
+
for (i = 0; i < button_count && i < 10; i++)
input_report_key(input_dev, BTN_0 + i, mask & (1 << i));
for (i = 10; i < button_count && i < 16; i++)
@@ -2773,6 +2897,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
if (!(features->device_type & WACOM_DEVICETYPE_PAD))
return -ENODEV;
+ if (features->type == REMOTE && input_dev == wacom_wac->pad_input)
+ return -ENODEV;
+
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
/* kept for making legacy xf86-input-wacom working with the wheels */
@@ -3403,7 +3530,7 @@ static const struct wacom_features wacom_features_0x343 =
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
static const struct wacom_features wacom_features_HID_ANY_ID =
- { "Wacom HID", .type = HID_GENERIC };
+ { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
#define USB_DEVICE_WACOM(prod) \
HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 53d16537fd2a..324c40b0c119 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -82,6 +82,7 @@
#define WACOM_DEVICETYPE_TOUCH 0x0002
#define WACOM_DEVICETYPE_PAD 0x0004
#define WACOM_DEVICETYPE_WL_MONITOR 0x0008
+#define WACOM_DEVICETYPE_DIRECT 0x0010
#define WACOM_VENDORDEFINED_PEN 0xff0d0001
#define WACOM_G9_PAGE 0xff090000
@@ -185,7 +186,6 @@ struct wacom_features {
int pktlen;
bool check_for_hid_type;
int hid_type;
- int last_slot_field;
};
struct wacom_shared {
@@ -214,35 +214,35 @@ struct hid_data {
int cc_report;
int cc_index;
int cc_value_index;
+ int last_slot_field;
int num_expected;
int num_received;
};
+struct wacom_remote_data {
+ struct {
+ u32 serial;
+ bool connected;
+ } remote[WACOM_MAX_REMOTES];
+};
+
struct wacom_wac {
+ char name[WACOM_NAME_MAX];
char pen_name[WACOM_NAME_MAX];
char touch_name[WACOM_NAME_MAX];
char pad_name[WACOM_NAME_MAX];
- char bat_name[WACOM_NAME_MAX];
- char ac_name[WACOM_NAME_MAX];
unsigned char data[WACOM_PKGLEN_MAX];
int tool[2];
int id[2];
- __u32 serial[5];
+ __u32 serial[2];
bool reporting_data;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *pen_input;
struct input_dev *touch_input;
struct input_dev *pad_input;
- bool pen_registered;
- bool touch_registered;
- bool pad_registered;
int pid;
- int battery_capacity;
int num_contacts_left;
- int bat_charging;
- int bat_connected;
- int ps_connected;
u8 bt_features;
u8 bt_high_speed;
int mode_report;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5c3993b26129..6d94e2ec5b4f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -836,7 +836,7 @@ config I2C_SH7760
config I2C_SH_MOBILE
tristate "SuperH Mobile I2C Controller"
depends on HAS_DMA
- depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
+ depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Renesas SH-Mobile processor.
@@ -956,6 +956,17 @@ config I2C_OCTEON
This driver can also be built as a module. If so, the module
will be called i2c-octeon.
+config I2C_THUNDERX
+ tristate "Cavium ThunderX I2C bus support"
+ depends on 64BIT && PCI && (ARM64 || COMPILE_TEST)
+ select I2C_SMBUS
+ help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-thunderx.
+
config I2C_XILINX
tristate "Xilinx I2C Controller"
depends on HAS_IOMEM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819b4560..29764cc20a44 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,10 @@ obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
+i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
+i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 6c7113d990f8..274908cd1fde 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -378,11 +378,8 @@ static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id)
amd756_ioport);
error = i2c_add_adapter(&amd756_smbus);
- if (error) {
- dev_err(&pdev->dev,
- "Adapter registration failed, module not inserted\n");
+ if (error)
goto out_err;
- }
return 0;
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 1bb97f658b47..0b86c6173e07 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -1122,8 +1122,6 @@ static int at91_twi_probe(struct platform_device *pdev)
rc = i2c_add_numbered_adapter(&dev->adapter);
if (rc) {
- dev_err(dev->dev, "Adapter %s registration failed\n",
- dev->adapter.name);
clk_disable_unprepare(dev->clk);
pm_runtime_disable(dev->dev);
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index c335cc7852f9..4351a9343058 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -545,7 +545,11 @@ static int axxia_i2c_probe(struct platform_device *pdev)
return ret;
}
- clk_prepare_enable(idev->i2c_clk);
+ ret = clk_prepare_enable(idev->i2c_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ return ret;
+ }
i2c_set_adapdata(&idev->adapter, idev);
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
@@ -560,7 +564,7 @@ static int axxia_i2c_probe(struct platform_device *pdev)
ret = i2c_add_adapter(&idev->adapter);
if (ret) {
- dev_err(&pdev->dev, "failed to add adapter\n");
+ clk_disable_unprepare(idev->i2c_clk);
return ret;
}
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index 95f7cac76f89..326b3db02c48 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -488,13 +488,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
- ret = i2c_add_adapter(adap);
- if (ret) {
- dev_err(iproc_i2c->device, "failed to add adapter\n");
- return ret;
- }
-
- return 0;
+ return i2c_add_adapter(adap);
}
static int bcm_iproc_i2c_remove(struct platform_device *pdev)
diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 258cb9a40ab3..4e489a9d16fb 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -858,10 +858,8 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev)
adap->dev.of_node = pdev->dev.of_node;
rc = i2c_add_adapter(adap);
- if (rc) {
- dev_err(dev->device, "failed to add adapter\n");
+ if (rc)
return rc;
- }
dev_info(dev->device, "device registered successfully\n");
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 025686d41640..29d00c4f7824 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -685,10 +685,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
rc = i2c_add_numbered_adapter(p_adap);
- if (rc < 0) {
- dev_err(&pdev->dev, "Can't add i2c adapter!\n");
+ if (rc < 0)
goto out_error;
- }
platform_set_drvdata(pdev, iface);
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 385b57bfcb38..0652281662a8 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -648,10 +648,8 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
rc = i2c_add_adapter(adap);
- if (rc) {
- dev_err(dev->device, "failed to add adapter\n");
+ if (rc)
goto probe_errorout;
- }
dev_info(dev->device, "%s@%dhz registered in %s mode\n",
int_name ? int_name : " ", dev->clk_freq_hz,
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 3c16a2f7c673..686971263bef 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -963,10 +963,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
}
ret = i2c_add_adapter(&id->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+ if (ret < 0)
goto err_clk_dis;
- }
/*
* Cadence I2C controller has a bug wherein it generates
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index ee57c1e865e2..d89bde2c5da2 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -665,10 +665,8 @@ static int cpm_i2c_probe(struct platform_device *ofdev)
cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1;
result = i2c_add_numbered_adapter(&cpm->adap);
- if (result < 0) {
- dev_err(&ofdev->dev, "Unable to register with I2C\n");
+ if (result < 0)
goto out_shut;
- }
dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
cpm->adap.name);
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
index 2d5ff86398d0..9b36a7b3befd 100644
--- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -281,10 +281,8 @@ static int ec_i2c_probe(struct platform_device *pdev)
bus->adap.retries = I2C_MAX_RETRIES;
err = i2c_add_adapter(&bus->adap);
- if (err) {
- dev_err(dev, "cannot register i2c adapter\n");
+ if (err)
return err;
- }
platform_set_drvdata(pdev, bus);
return err;
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index a8bdcb5292f5..9e7ef5cf5d49 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -846,10 +846,8 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
- if (r) {
- dev_err(&pdev->dev, "failure adding adapter\n");
+ if (r)
goto err_unuse_clocks;
- }
return 0;
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index fcd973d5131e..1fe93c43215c 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -42,6 +42,8 @@
#define DW_IC_SS_SCL_LCNT 0x18
#define DW_IC_FS_SCL_HCNT 0x1c
#define DW_IC_FS_SCL_LCNT 0x20
+#define DW_IC_HS_SCL_HCNT 0x24
+#define DW_IC_HS_SCL_LCNT 0x28
#define DW_IC_INTR_STAT 0x2c
#define DW_IC_INTR_MASK 0x30
#define DW_IC_RAW_INTR_STAT 0x34
@@ -89,12 +91,17 @@
DW_IC_INTR_TX_ABRT | \
DW_IC_INTR_STOP_DET)
-#define DW_IC_STATUS_ACTIVITY 0x1
+#define DW_IC_STATUS_ACTIVITY 0x1
+#define DW_IC_STATUS_TFE BIT(2)
+#define DW_IC_STATUS_MST_ACTIVITY BIT(5)
#define DW_IC_ERR_TX_ABRT 0x1
#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
+
/*
* status codes
*/
@@ -252,10 +259,15 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
{
+ dw_writel(dev, enable, DW_IC_ENABLE);
+}
+
+static void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable)
+{
int timeout = 100;
do {
- dw_writel(dev, enable, DW_IC_ENABLE);
+ __i2c_dw_enable(dev, enable);
if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
return;
@@ -282,6 +294,28 @@ static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
return dev->get_clk_rate_khz(dev);
}
+static int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
+{
+ int ret;
+
+ if (!dev->acquire_lock)
+ return 0;
+
+ ret = dev->acquire_lock(dev);
+ if (!ret)
+ return 0;
+
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+
+ return ret;
+}
+
+static void i2c_dw_release_lock(struct dw_i2c_dev *dev)
+{
+ if (dev->release_lock)
+ dev->release_lock(dev);
+}
+
/**
* i2c_dw_init() - initialize the designware i2c master hardware
* @dev: device private data
@@ -293,17 +327,13 @@ static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
int i2c_dw_init(struct dw_i2c_dev *dev)
{
u32 hcnt, lcnt;
- u32 reg;
+ u32 reg, comp_param1;
u32 sda_falling_time, scl_falling_time;
int ret;
- if (dev->acquire_lock) {
- ret = dev->acquire_lock(dev);
- if (ret) {
- dev_err(dev->dev, "couldn't acquire bus ownership\n");
- return ret;
- }
- }
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
reg = dw_readl(dev, DW_IC_COMP_TYPE);
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
@@ -315,13 +345,14 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev, "Unknown Synopsys component type: "
"0x%08x\n", reg);
- if (dev->release_lock)
- dev->release_lock(dev);
+ i2c_dw_release_lock(dev);
return -ENODEV;
}
+ comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
+
/* Disable the adapter */
- __i2c_dw_enable(dev, false);
+ __i2c_dw_enable_and_wait(dev, false);
/* set standard and fast speed deviders for high/low periods */
@@ -347,8 +378,11 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
- /* Set SCL timing parameters for fast-mode */
- if (dev->fs_hcnt && dev->fs_lcnt) {
+ /* Set SCL timing parameters for fast-mode or fast-mode plus */
+ if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) {
+ hcnt = dev->fp_hcnt;
+ lcnt = dev->fp_lcnt;
+ } else if (dev->fs_hcnt && dev->fs_lcnt) {
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
} else {
@@ -366,6 +400,23 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+ if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==
+ DW_IC_CON_SPEED_HIGH) {
+ if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+ != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
+ dev_err(dev->dev, "High Speed not supported!\n");
+ dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+ } else if (dev->hs_hcnt && dev->hs_lcnt) {
+ hcnt = dev->hs_hcnt;
+ lcnt = dev->hs_lcnt;
+ dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
+ dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
+ hcnt, lcnt);
+ }
+ }
+
/* Configure SDA Hold Time if required */
reg = dw_readl(dev, DW_IC_COMP_VERSION);
if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
@@ -387,8 +438,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* configure the i2c master */
dw_writel(dev, dev->master_cfg , DW_IC_CON);
- if (dev->release_lock)
- dev->release_lock(dev);
+ i2c_dw_release_lock(dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(i2c_dw_init);
@@ -415,27 +466,45 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
{
struct i2c_msg *msgs = dev->msgs;
- u32 ic_con, ic_tar = 0;
+ u32 ic_tar = 0;
+ bool enabled;
- /* Disable the adapter */
- __i2c_dw_enable(dev, false);
+ enabled = dw_readl(dev, DW_IC_ENABLE_STATUS) & 1;
+
+ if (enabled) {
+ u32 ic_status;
+
+ /*
+ * Only disable adapter if ic_tar and ic_con can't be
+ * dynamically updated
+ */
+ ic_status = dw_readl(dev, DW_IC_STATUS);
+ if (!dev->dynamic_tar_update_enabled ||
+ (ic_status & DW_IC_STATUS_MST_ACTIVITY) ||
+ !(ic_status & DW_IC_STATUS_TFE)) {
+ __i2c_dw_enable_and_wait(dev, false);
+ enabled = false;
+ }
+ }
/* if the slave address is ten bit address, enable 10BITADDR */
- ic_con = dw_readl(dev, DW_IC_CON);
- if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
- ic_con |= DW_IC_CON_10BITADDR_MASTER;
+ if (dev->dynamic_tar_update_enabled) {
/*
* If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
- * mode has to be enabled via bit 12 of IC_TAR register.
- * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be
- * detected from registers.
+ * mode has to be enabled via bit 12 of IC_TAR register,
+ * otherwise bit 4 of IC_CON is used.
*/
- ic_tar = DW_IC_TAR_10BITADDR_MASTER;
+ if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+ ic_tar = DW_IC_TAR_10BITADDR_MASTER;
} else {
- ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
- }
+ u32 ic_con = dw_readl(dev, DW_IC_CON);
- dw_writel(dev, ic_con, DW_IC_CON);
+ if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+ ic_con |= DW_IC_CON_10BITADDR_MASTER;
+ else
+ ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+ dw_writel(dev, ic_con, DW_IC_CON);
+ }
/*
* Set the slave (target) address and enable 10-bit addressing mode
@@ -446,8 +515,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
/* enforce disabled interrupts (due to HW issues) */
i2c_dw_disable_int(dev);
- /* Enable the adapter */
- __i2c_dw_enable(dev, true);
+ if (!enabled)
+ __i2c_dw_enable(dev, true);
/* Clear and enable interrupts */
dw_readl(dev, DW_IC_CLR_INTR);
@@ -628,7 +697,8 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
}
/*
- * Prepare controller for a transaction and call i2c_dw_xfer_msg
+ * Prepare controller for a transaction and start transfer by calling
+ * i2c_dw_xfer_init()
*/
static int
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -651,13 +721,9 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev->abort_source = 0;
dev->rx_outstanding = 0;
- if (dev->acquire_lock) {
- ret = dev->acquire_lock(dev);
- if (ret) {
- dev_err(dev->dev, "couldn't acquire bus ownership\n");
- goto done_nolock;
- }
- }
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ goto done_nolock;
ret = i2c_dw_wait_bus_not_busy(dev);
if (ret < 0)
@@ -675,16 +741,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
goto done;
}
- /*
- * We must disable the adapter before returning and signaling the end
- * of the current transfer. Otherwise the hardware might continue
- * generating interrupts which in turn causes a race condition with
- * the following transfer. Needs some more investigation if the
- * additional interrupts are a hardware bug or this driver doesn't
- * handle them correctly yet.
- */
- __i2c_dw_enable(dev, false);
-
if (dev->msg_err) {
ret = dev->msg_err;
goto done;
@@ -704,8 +760,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
ret = -EIO;
done:
- if (dev->release_lock)
- dev->release_lock(dev);
+ i2c_dw_release_lock(dev);
done_nolock:
pm_runtime_mark_last_busy(dev->dev);
@@ -822,9 +877,19 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
*/
tx_aborted:
- if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
+ if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
+ || dev->msg_err) {
+ /*
+ * We must disable interruts before returning and signaling
+ * the end of the current transfer. Otherwise the hardware
+ * might continue generating interrupts for non-existent
+ * transfers.
+ */
+ i2c_dw_disable_int(dev);
+ dw_readl(dev, DW_IC_CLR_INTR);
+
complete(&dev->cmd_complete);
- else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
+ } else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
/* workaround to trigger pending interrupt */
stat = dw_readl(dev, DW_IC_INTR_MASK);
i2c_dw_disable_int(dev);
@@ -837,7 +902,7 @@ tx_aborted:
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
/* Disable controller */
- __i2c_dw_enable(dev, false);
+ __i2c_dw_enable_and_wait(dev, false);
/* Disable all interupts */
dw_writel(dev, 0, DW_IC_INTR_MASK);
@@ -861,6 +926,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
int r;
+ u32 reg;
init_completion(&dev->cmd_complete);
@@ -868,6 +934,26 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
if (r)
return r;
+ r = i2c_dw_acquire_lock(dev);
+ if (r)
+ return r;
+
+ /*
+ * Test if dynamic TAR update is enabled in this controller by writing
+ * to IC_10BITADDR_MASTER field in IC_CON: when it is enabled this
+ * field is read-only so it should not succeed
+ */
+ reg = dw_readl(dev, DW_IC_CON);
+ dw_writel(dev, reg ^ DW_IC_CON_10BITADDR_MASTER, DW_IC_CON);
+
+ if ((dw_readl(dev, DW_IC_CON) & DW_IC_CON_10BITADDR_MASTER) ==
+ (reg & DW_IC_CON_10BITADDR_MASTER)) {
+ dev->dynamic_tar_update_enabled = true;
+ dev_dbg(dev->dev, "Dynamic TAR update enabled");
+ }
+
+ i2c_dw_release_lock(dev);
+
snprintf(adap->name, sizeof(adap->name),
"Synopsys DesignWare I2C adapter");
adap->retries = 3;
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 38493a7142ad..0d44d2ae7d4c 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -26,6 +26,7 @@
#define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2
#define DW_IC_CON_SPEED_FAST 0x4
+#define DW_IC_CON_SPEED_HIGH 0x6
#define DW_IC_CON_SPEED_MASK 0x6
#define DW_IC_CON_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20
@@ -57,10 +58,15 @@
* @tx_fifo_depth: depth of the hardware tx fifo
* @rx_fifo_depth: depth of the hardware rx fifo
* @rx_outstanding: current master-rx elements in tx fifo
+ * @clk_freq: bus clock frequency
* @ss_hcnt: standard speed HCNT value
* @ss_lcnt: standard speed LCNT value
* @fs_hcnt: fast speed HCNT value
* @fs_lcnt: fast speed LCNT value
+ * @fp_hcnt: fast plus HCNT value
+ * @fp_lcnt: fast plus LCNT value
+ * @hs_hcnt: high speed HCNT value
+ * @hs_lcnt: high speed LCNT value
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
* @pm_runtime_disabled: true if pm runtime is disabled
@@ -96,6 +102,7 @@ struct dw_i2c_dev {
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
+ u32 clk_freq;
u32 sda_hold_time;
u32 sda_falling_time;
u32 scl_falling_time;
@@ -103,9 +110,14 @@ struct dw_i2c_dev {
u16 ss_lcnt;
u16 fs_hcnt;
u16 fs_lcnt;
+ u16 fp_hcnt;
+ u16 fp_lcnt;
+ u16 hs_hcnt;
+ u16 hs_lcnt;
int (*acquire_lock)(struct dw_i2c_dev *dev);
void (*release_lock)(struct dw_i2c_dev *dev);
bool pm_runtime_disabled;
+ bool dynamic_tar_update_enabled;
};
#define ACCESS_SWAP 0x00000001
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index d656657b805c..0b42a12171f3 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -107,6 +107,8 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL);
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
+ dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL);
+ dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL);
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
@@ -155,7 +157,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
struct i2c_adapter *adap;
struct resource *mem;
int irq, r;
- u32 clk_freq, ht = 0;
+ u32 acpi_speed, ht = 0;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -175,10 +177,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
/* fast mode by default because of legacy reasons */
- clk_freq = 400000;
+ dev->clk_freq = 400000;
if (pdata) {
- clk_freq = pdata->i2c_scl_freq;
+ dev->clk_freq = pdata->i2c_scl_freq;
} else {
device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns",
&ht);
@@ -187,17 +189,24 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
&dev->scl_falling_time);
device_property_read_u32(&pdev->dev, "clock-frequency",
- &clk_freq);
+ &dev->clk_freq);
}
+ acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
+ if (acpi_speed)
+ dev->clk_freq = acpi_speed;
+
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
/*
- * Only standard mode at 100kHz and fast mode at 400kHz are supported.
+ * Only standard mode at 100kHz, fast mode at 400kHz,
+ * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
*/
- if (clk_freq != 100000 && clk_freq != 400000) {
- dev_err(&pdev->dev, "Only 100kHz and 400kHz supported");
+ if (dev->clk_freq != 100000 && dev->clk_freq != 400000
+ && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) {
+ dev_err(&pdev->dev,
+ "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported");
return -EINVAL;
}
@@ -212,12 +221,20 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
- if (clk_freq == 100000)
- dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
- DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_STD;
- else
- dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
- DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+
+ dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN;
+
+ switch (dev->clk_freq) {
+ case 100000:
+ dev->master_cfg |= DW_IC_CON_SPEED_STD;
+ break;
+ case 3400000:
+ dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
+ break;
+ default:
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+ }
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c
index b19a310bf9b3..f718ee4e3332 100644
--- a/drivers/i2c/busses/i2c-diolan-u2c.c
+++ b/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -487,10 +487,8 @@ static int diolan_u2c_probe(struct usb_interface *interface,
/* and finally attach to i2c layer */
ret = i2c_add_adapter(&dev->adapter);
- if (ret < 0) {
- dev_err(&interface->dev, "failed to add I2C adapter\n");
+ if (ret < 0)
goto error_free;
- }
dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n");
diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
index f2eb4f76591f..8acda2aa1558 100644
--- a/drivers/i2c/busses/i2c-dln2.c
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -228,10 +228,8 @@ static int dln2_i2c_probe(struct platform_device *pdev)
/* and finally attach to i2c layer */
ret = i2c_add_adapter(&dln2->adapter);
- if (ret < 0) {
- dev_err(dev, "failed to add I2C adapter: %d\n", ret);
+ if (ret < 0)
goto out_disable;
- }
return 0;
diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c
index e253598d764c..aa336ba89aa3 100644
--- a/drivers/i2c/busses/i2c-efm32.c
+++ b/drivers/i2c/busses/i2c-efm32.c
@@ -438,7 +438,6 @@ static int efm32_i2c_probe(struct platform_device *pdev)
ret = i2c_add_adapter(&ddata->adapter);
if (ret) {
- dev_err(&pdev->dev, "failed to add i2c adapter (%d)\n", ret);
free_irq(ddata->irq, ddata);
err_disable_clk:
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index c0e3ada02876..bea607149972 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -796,10 +796,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
exynos5_i2c_reset(i2c);
ret = i2c_add_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+ if (ret < 0)
goto err_clk;
- }
platform_set_drvdata(pdev, i2c);
diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c
index 7c6966434ee7..ae7f3180f7e8 100644
--- a/drivers/i2c/busses/i2c-hix5hd2.c
+++ b/drivers/i2c/busses/i2c-hix5hd2.c
@@ -478,10 +478,8 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
pm_runtime_enable(priv->dev);
ret = i2c_add_adapter(&priv->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+ if (ret < 0)
goto err_runtime;
- }
return ret;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 26298af73232..08847e8b8998 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -64,6 +64,7 @@
* Broxton (SOC) 0x5ad4 32 hard yes yes yes
* Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
* Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes
+ * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@@ -226,6 +227,7 @@
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
+#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
struct i801_mux_config {
char *gpio_chip;
@@ -1006,6 +1008,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) },
{ 0, }
};
@@ -1482,6 +1485,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS:
case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
+ case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC;
@@ -1615,7 +1619,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
"SMBus I801 adapter at %04lx", priv->smba);
err = i2c_add_adapter(&priv->adapter);
if (err) {
- dev_err(&dev->dev, "Failed to add SMBus adapter\n");
i801_acpi_remove(priv);
return err;
}
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index cdaa7be2cd1b..412b91d255ad 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -751,10 +751,8 @@ static int iic_probe(struct platform_device *ofdev)
adap->timeout = HZ;
ret = i2c_add_adapter(adap);
- if (ret < 0) {
- dev_err(&ofdev->dev, "failed to register i2c adapter\n");
+ if (ret < 0)
goto error_cleanup;
- }
dev_info(&ofdev->dev, "using %s mode\n",
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index ea20425b6972..db8e8b40569d 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -1394,10 +1394,8 @@ static int img_i2c_probe(struct platform_device *pdev)
goto disable_clk;
ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add adapter\n");
+ if (ret < 0)
goto disable_clk;
- }
return 0;
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 1844bc9f7cd5..592a8f26a708 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -984,11 +984,24 @@ static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
}
-static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
+/*
+ * We switch SCL and SDA to their GPIO function and do some bitbanging
+ * for bus recovery. These alternative pinmux settings can be
+ * described in the device tree by a separate pinctrl state "gpio". If
+ * this is missing this is not a big problem, the only implication is
+ * that we can't do bus recovery.
+ */
+static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
struct platform_device *pdev)
{
struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
+ i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!i2c_imx->pinctrl || IS_ERR(i2c_imx->pinctrl)) {
+ dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
+ return PTR_ERR(i2c_imx->pinctrl);
+ }
+
i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
@@ -1001,7 +1014,7 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
IS_ERR(i2c_imx->pinctrl_pins_default) ||
IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
dev_dbg(&pdev->dev, "recovery information incomplete\n");
- return;
+ return 0;
}
dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
@@ -1011,6 +1024,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
rinfo->recover_bus = i2c_generic_gpio_recovery;
i2c_imx->adapter.bus_recovery_info = rinfo;
+
+ return 0;
}
static u32 i2c_imx_func(struct i2c_adapter *adapter)
@@ -1081,12 +1096,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
return ret;
}
- i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(i2c_imx->pinctrl)) {
- ret = PTR_ERR(i2c_imx->pinctrl);
- goto clk_disable;
- }
-
/* Request IRQ */
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
pdev->name, i2c_imx);
@@ -1125,14 +1134,16 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx, IMX_I2C_I2CR);
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
- i2c_imx_init_recovery_info(i2c_imx, pdev);
+ /* Init optional bus recovery function */
+ ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
+ /* Give it another chance if pinctrl used is not ready yet */
+ if (ret == -EPROBE_DEFER)
+ goto rpm_disable;
/* Add I2C adapter */
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
- if (ret < 0) {
- dev_err(&pdev->dev, "registration failed\n");
+ if (ret < 0)
goto rpm_disable;
- }
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index c2f25f19d76f..0cf1379f4e80 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -288,10 +288,8 @@ static int smbus_sch_probe(struct platform_device *dev)
"SMBus SCH adapter at %04x", sch_smba);
retval = i2c_add_adapter(&sch_adapter);
- if (retval) {
- dev_err(&dev->dev, "Couldn't register adapter!\n");
+ if (retval)
sch_smba = 0;
- }
return retval;
}
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index 1c8707710098..f573448d2132 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -922,10 +922,8 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return err;
err = i2c_add_adapter(&priv->adapter);
- if (err) {
- dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n");
+ if (err)
return -ENODEV;
- }
return 0;
}
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
index cd9872594fe2..b8ea62105f42 100644
--- a/drivers/i2c/busses/i2c-jz4780.c
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -798,10 +798,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
goto err;
ret = i2c_add_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to add bus\n");
+ if (ret < 0)
goto err;
- }
return 0;
diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c
index 586a15205e61..9b1fef455a89 100644
--- a/drivers/i2c/busses/i2c-lpc2k.c
+++ b/drivers/i2c/busses/i2c-lpc2k.c
@@ -432,10 +432,8 @@ static int i2c_lpc2k_probe(struct platform_device *pdev)
i2c->adap.dev.of_node = pdev->dev.of_node;
ret = i2c_add_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add adapter!\n");
+ if (ret < 0)
goto fail_clk;
- }
dev_info(&pdev->dev, "LPC2K I2C adapter\n");
diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
index 76e28980904f..2aa61bbbd307 100644
--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -453,7 +453,6 @@ static int meson_i2c_probe(struct platform_device *pdev)
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
- dev_err(&pdev->dev, "can't register adapter\n");
clk_unprepare(i2c->clk);
return ret;
}
@@ -473,6 +472,7 @@ static int meson_i2c_remove(struct platform_device *pdev)
static const struct of_device_id meson_i2c_match[] = {
{ .compatible = "amlogic,meson6-i2c" },
+ { .compatible = "amlogic,meson-gxbb-i2c" },
{ },
};
MODULE_DEVICE_TABLE(of, meson_i2c_match);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 48ecffecc0ed..565a49a0c564 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -737,10 +737,8 @@ static int fsl_i2c_probe(struct platform_device *op)
i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
result = i2c_add_adapter(&i2c->adap);
- if (result < 0) {
- dev_err(i2c->dev, "failed to add adapter\n");
+ if (result < 0)
goto fail_add;
- }
return result;
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index d9373e60be8a..4a7d9bc2142b 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -786,10 +786,8 @@ static int mtk_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c->adap, i2c);
ret = i2c_add_adapter(&i2c->adap);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add i2c bus to i2c core\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, i2c);
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 033846cdf266..5738556b6aac 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -868,7 +868,6 @@ static int mxs_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, i2c);
err = i2c_add_numbered_adapter(adap);
if (err) {
- dev_err(dev, "Failed to add adapter (%d)\n", err);
writel(MXS_I2C_CTRL0_SFTRST,
i2c->regs + MXS_I2C_CTRL0_SET);
return err;
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 42fcc9458432..374b35e7e450 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -366,7 +366,6 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg,
error = i2c_add_adapter(&smbus->adapter);
if (error) {
- dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");
release_region(smbus->base, smbus->size);
return error;
}
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index bcd17e8cbcb4..da6609d62848 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -1046,10 +1046,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
adap->name, dev->virtbase);
ret = i2c_add_adapter(adap);
- if (ret) {
- dev_err(&adev->dev, "failed to add adapter\n");
+ if (ret)
goto err_no_adap;
- }
pm_runtime_put(&adev->dev);
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index ac88a524143e..34f1889a4073 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -494,10 +494,8 @@ static int ocores_i2c_probe(struct platform_device *pdev)
/* add i2c adapter to i2c tree */
ret = i2c_add_adapter(&i2c->adap);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add adapter\n");
+ if (ret)
goto err_clk;
- }
/* add in known devices to the bus */
if (pdata) {
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon-core.c
index 30ae35146723..419b54bfc7c7 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -4,280 +4,127 @@
*
* Portions Copyright (C) 2010 - 2016 Cavium, Inc.
*
- * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
*
* 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/atomic.h>
-#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-#include <linux/of.h>
-
-#include <asm/octeon/octeon.h>
-
-#define DRV_NAME "i2c-octeon"
-
-/* Register offsets */
-#define SW_TWSI 0x00
-#define TWSI_INT 0x10
-#define SW_TWSI_EXT 0x18
-
-/* Controller command patterns */
-#define SW_TWSI_V BIT_ULL(63) /* Valid bit */
-#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */
-#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */
-#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */
-#define SW_TWSI_SIZE_SHIFT 52
-#define SW_TWSI_ADDR_SHIFT 40
-#define SW_TWSI_IA_SHIFT 32 /* Internal address */
-
-/* Controller opcode word (bits 60:57) */
-#define SW_TWSI_OP_SHIFT 57
-#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT)
-#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT)
-#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT)
-#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT)
-#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT)
-#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
-
-/* Controller extended opcode word (bits 34:32) */
-#define SW_TWSI_EOP_SHIFT 32
-#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
-#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
-#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
-#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
-#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
-
-/* Controller command and status bits */
-#define TWSI_CTL_CE 0x80 /* High level controller enable */
-#define TWSI_CTL_ENAB 0x40 /* Bus enable */
-#define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */
-#define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */
-#define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */
-#define TWSI_CTL_AAK 0x04 /* Assert ACK */
-
-/* Status values */
-#define STAT_ERROR 0x00
-#define STAT_START 0x08
-#define STAT_REP_START 0x10
-#define STAT_TXADDR_ACK 0x18
-#define STAT_TXADDR_NAK 0x20
-#define STAT_TXDATA_ACK 0x28
-#define STAT_TXDATA_NAK 0x30
-#define STAT_LOST_ARB_38 0x38
-#define STAT_RXADDR_ACK 0x40
-#define STAT_RXADDR_NAK 0x48
-#define STAT_RXDATA_ACK 0x50
-#define STAT_RXDATA_NAK 0x58
-#define STAT_SLAVE_60 0x60
-#define STAT_LOST_ARB_68 0x68
-#define STAT_SLAVE_70 0x70
-#define STAT_LOST_ARB_78 0x78
-#define STAT_SLAVE_80 0x80
-#define STAT_SLAVE_88 0x88
-#define STAT_GENDATA_ACK 0x90
-#define STAT_GENDATA_NAK 0x98
-#define STAT_SLAVE_A0 0xA0
-#define STAT_SLAVE_A8 0xA8
-#define STAT_LOST_ARB_B0 0xB0
-#define STAT_SLAVE_LOST 0xB8
-#define STAT_SLAVE_NAK 0xC0
-#define STAT_SLAVE_ACK 0xC8
-#define STAT_AD2W_ACK 0xD0
-#define STAT_AD2W_NAK 0xD8
-#define STAT_IDLE 0xF8
-
-/* TWSI_INT values */
-#define TWSI_INT_ST_INT BIT_ULL(0)
-#define TWSI_INT_TS_INT BIT_ULL(1)
-#define TWSI_INT_CORE_INT BIT_ULL(2)
-#define TWSI_INT_ST_EN BIT_ULL(4)
-#define TWSI_INT_TS_EN BIT_ULL(5)
-#define TWSI_INT_CORE_EN BIT_ULL(6)
-#define TWSI_INT_SDA_OVR BIT_ULL(8)
-#define TWSI_INT_SCL_OVR BIT_ULL(9)
-#define TWSI_INT_SDA BIT_ULL(10)
-#define TWSI_INT_SCL BIT_ULL(11)
-
-#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */
-
-struct octeon_i2c {
- wait_queue_head_t queue;
- struct i2c_adapter adap;
- int irq;
- int hlc_irq; /* For cn7890 only */
- u32 twsi_freq;
- int sys_freq;
- void __iomem *twsi_base;
- struct device *dev;
- bool hlc_enabled;
- bool broken_irq_mode;
- bool broken_irq_check;
- void (*int_enable)(struct octeon_i2c *);
- void (*int_disable)(struct octeon_i2c *);
- void (*hlc_int_enable)(struct octeon_i2c *);
- void (*hlc_int_disable)(struct octeon_i2c *);
- atomic_t int_enable_cnt;
- atomic_t hlc_int_enable_cnt;
-};
-
-static void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
-{
- __raw_writeq(val, addr);
- __raw_readq(addr); /* wait for write to land */
-}
-
-/**
- * octeon_i2c_reg_write - write an I2C core register
- * @i2c: The struct octeon_i2c
- * @eop_reg: Register selector
- * @data: Value to be written
- *
- * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
- */
-static void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
-{
- u64 tmp;
- __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI);
- do {
- tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
- } while ((tmp & SW_TWSI_V) != 0);
-}
-
-#define octeon_i2c_ctl_write(i2c, val) \
- octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val)
-#define octeon_i2c_data_write(i2c, val) \
- octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val)
+#include "i2c-octeon-core.h"
-/**
- * octeon_i2c_reg_read - read lower bits of an I2C core register
- * @i2c: The struct octeon_i2c
- * @eop_reg: Register selector
- *
- * Returns the data.
- *
- * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
- */
-static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
{
- u64 tmp;
+ struct octeon_i2c *i2c = dev_id;
- __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI);
- do {
- tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
- } while ((tmp & SW_TWSI_V) != 0);
+ i2c->int_disable(i2c);
+ wake_up(&i2c->queue);
- return tmp & 0xFF;
+ return IRQ_HANDLED;
}
-#define octeon_i2c_ctl_read(i2c) \
- octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
-#define octeon_i2c_data_read(i2c) \
- octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
-#define octeon_i2c_stat_read(i2c) \
- octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
-
-/**
- * octeon_i2c_read_int - read the TWSI_INT register
- * @i2c: The struct octeon_i2c
- *
- * Returns the value of the register.
- */
-static u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
+static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
{
- return __raw_readq(i2c->twsi_base + TWSI_INT);
+ return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
}
-/**
- * octeon_i2c_write_int - write the TWSI_INT register
- * @i2c: The struct octeon_i2c
- * @data: Value to be written
- */
-static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first)
{
- octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT);
-}
+ if (octeon_i2c_test_iflg(i2c))
+ return true;
-/**
- * octeon_i2c_int_enable - enable the CORE interrupt
- * @i2c: The struct octeon_i2c
- *
- * The interrupt will be asserted when there is non-STAT_IDLE state in
- * the SW_TWSI_EOP_TWSI_STAT register.
- */
-static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
-{
- octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN);
-}
+ if (*first) {
+ *first = false;
+ return false;
+ }
-/* disable the CORE interrupt */
-static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
-{
- /* clear TS/ST/IFLG events */
- octeon_i2c_write_int(i2c, 0);
+ /*
+ * IRQ has signaled an event but IFLG hasn't changed.
+ * Sleep and retry once.
+ */
+ usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
+ return octeon_i2c_test_iflg(i2c);
}
/**
- * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * octeon_i2c_wait - wait for the IFLG to be set
* @i2c: The struct octeon_i2c
*
- * The interrupt will be asserted when there is non-STAT_IDLE state in the
- * SW_TWSI_EOP_TWSI_STAT register.
+ * Returns 0 on success, otherwise a negative errno.
*/
-static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
-{
- atomic_inc_return(&i2c->int_enable_cnt);
- enable_irq(i2c->irq);
-}
-
-static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
{
- int count;
+ long time_left;
+ bool first = true;
/*
- * The interrupt can be disabled in two places, but we only
- * want to make the disable_irq_nosync() call once, so keep
- * track with the atomic variable.
+ * Some chip revisions don't assert the irq in the interrupt
+ * controller. So we must poll for the IFLG change.
*/
- count = atomic_dec_if_positive(cnt);
- if (count >= 0)
- disable_irq_nosync(irq);
+ if (i2c->broken_irq_mode) {
+ u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+ while (!octeon_i2c_test_iflg(i2c) &&
+ time_before64(get_jiffies_64(), end))
+ usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+ return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+ }
+
+ i2c->int_enable(i2c);
+ time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first),
+ i2c->adap.timeout);
+ i2c->int_disable(i2c);
+
+ if (i2c->broken_irq_check && !time_left &&
+ octeon_i2c_test_iflg(i2c)) {
+ dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+ i2c->broken_irq_mode = true;
+ return 0;
+ }
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ return 0;
}
-/* disable the CORE interrupt */
-static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
{
- __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq);
+ return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0;
}
-/**
- * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
- * @i2c: The struct octeon_i2c
- *
- * The interrupt will be asserted when there is non-STAT_IDLE state in
- * the SW_TWSI_EOP_TWSI_STAT register.
- */
-static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first)
{
- atomic_inc_return(&i2c->hlc_int_enable_cnt);
- enable_irq(i2c->hlc_irq);
+ /* check if valid bit is cleared */
+ if (octeon_i2c_hlc_test_valid(i2c))
+ return true;
+
+ if (*first) {
+ *first = false;
+ return false;
+ }
+
+ /*
+ * IRQ has signaled an event but valid bit isn't cleared.
+ * Sleep and retry once.
+ */
+ usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
+ return octeon_i2c_hlc_test_valid(i2c);
}
-/* disable the ST interrupt */
-static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
{
- __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq);
+ /* clear ST/TS events, listen for neither */
+ octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT);
}
/*
@@ -321,83 +168,41 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
}
-/* interrupt service routine */
-static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
-{
- struct octeon_i2c *i2c = dev_id;
-
- i2c->int_disable(i2c);
- wake_up(&i2c->queue);
-
- return IRQ_HANDLED;
-}
-
-/* HLC interrupt service routine */
-static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
-{
- struct octeon_i2c *i2c = dev_id;
-
- i2c->hlc_int_disable(i2c);
- wake_up(&i2c->queue);
-
- return IRQ_HANDLED;
-}
-
-static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
-{
- return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
-}
-
-static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first)
-{
- if (octeon_i2c_test_iflg(i2c))
- return true;
-
- if (*first) {
- *first = false;
- return false;
- }
-
- /*
- * IRQ has signaled an event but IFLG hasn't changed.
- * Sleep and retry once.
- */
- usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
- return octeon_i2c_test_iflg(i2c);
-}
-
/**
- * octeon_i2c_wait - wait for the IFLG to be set
+ * octeon_i2c_hlc_wait - wait for an HLC operation to complete
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns 0 on success, otherwise -ETIMEDOUT.
*/
-static int octeon_i2c_wait(struct octeon_i2c *i2c)
+static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
{
- long time_left;
- bool first = 1;
+ bool first = true;
+ int time_left;
/*
- * Some chip revisions don't assert the irq in the interrupt
- * controller. So we must poll for the IFLG change.
+ * Some cn38xx boards don't assert the irq in the interrupt
+ * controller. So we must poll for the valid bit change.
*/
if (i2c->broken_irq_mode) {
u64 end = get_jiffies_64() + i2c->adap.timeout;
- while (!octeon_i2c_test_iflg(i2c) &&
+ while (!octeon_i2c_hlc_test_valid(i2c) &&
time_before64(get_jiffies_64(), end))
usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
- return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+ return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT;
}
- i2c->int_enable(i2c);
- time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first),
+ i2c->hlc_int_enable(i2c);
+ time_left = wait_event_timeout(i2c->queue,
+ octeon_i2c_hlc_test_ready(i2c, &first),
i2c->adap.timeout);
- i2c->int_disable(i2c);
+ i2c->hlc_int_disable(i2c);
+ if (!time_left)
+ octeon_i2c_hlc_int_clear(i2c);
if (i2c->broken_irq_check && !time_left &&
- octeon_i2c_test_iflg(i2c)) {
+ octeon_i2c_hlc_test_valid(i2c)) {
dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
i2c->broken_irq_mode = true;
return 0;
@@ -405,13 +210,21 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
if (!time_left)
return -ETIMEDOUT;
-
return 0;
}
static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
{
- u8 stat = octeon_i2c_stat_read(i2c);
+ u8 stat;
+
+ /*
+ * This is ugly... in HLC mode the status is not in the status register
+ * but in the lower 8 bits of SW_TWSI.
+ */
+ if (i2c->hlc_enabled)
+ stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ else
+ stat = octeon_i2c_stat_read(i2c);
switch (stat) {
/* Everything is fine */
@@ -470,83 +283,157 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
}
}
-static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
+static int octeon_i2c_recovery(struct octeon_i2c *i2c)
{
- return (__raw_readq(i2c->twsi_base + SW_TWSI) & SW_TWSI_V) == 0;
+ int ret;
+
+ ret = i2c_recover_bus(&i2c->adap);
+ if (ret)
+ /* recover failed, try hardware re-init */
+ ret = octeon_i2c_init_lowlevel(i2c);
+ return ret;
}
-static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first)
+/**
+ * octeon_i2c_start - send START to the bus
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
{
- /* check if valid bit is cleared */
- if (octeon_i2c_hlc_test_valid(i2c))
- return true;
+ int ret;
+ u8 stat;
- if (*first) {
- *first = false;
- return false;
- }
+ octeon_i2c_hlc_disable(i2c);
- /*
- * IRQ has signaled an event but valid bit isn't cleared.
- * Sleep and retry once.
- */
- usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
- return octeon_i2c_hlc_test_valid(i2c);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
+ ret = octeon_i2c_wait(i2c);
+ if (ret)
+ goto error;
+
+ stat = octeon_i2c_stat_read(i2c);
+ if (stat == STAT_START || stat == STAT_REP_START)
+ /* START successful, bail out */
+ return 0;
+
+error:
+ /* START failed, try to recover */
+ ret = octeon_i2c_recovery(i2c);
+ return (ret) ? ret : -EAGAIN;
}
-static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+/* send STOP to the bus */
+static void octeon_i2c_stop(struct octeon_i2c *i2c)
{
- octeon_i2c_write_int(i2c, TWSI_INT_ST_EN);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP);
}
-static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
+/**
+ * octeon_i2c_read - receive data from the bus via low-level controller
+ * @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the location to store the data
+ * @rlength: Length of the data
+ * @recv_len: flag for length byte
+ *
+ * The address is sent over the bus, then the data is read.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
+ u8 *data, u16 *rlength, bool recv_len)
{
- /* clear ST/TS events, listen for neither */
- octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT);
+ int i, result, length = *rlength;
+ bool final_read = false;
+
+ octeon_i2c_data_write(i2c, (target << 1) | 1);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ /* address OK ? */
+ result = octeon_i2c_check_status(i2c, false);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ /*
+ * For the last byte to receive TWSI_CTL_AAK must not be set.
+ *
+ * A special case is I2C_M_RECV_LEN where we don't know the
+ * additional length yet. If recv_len is set we assume we're
+ * not reading the final byte and therefore need to set
+ * TWSI_CTL_AAK.
+ */
+ if ((i + 1 == length) && !(recv_len && i == 0))
+ final_read = true;
+
+ /* clear iflg to allow next event */
+ if (final_read)
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+ else
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ data[i] = octeon_i2c_data_read(i2c, &result);
+ if (result)
+ return result;
+ if (recv_len && i == 0) {
+ if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
+ return -EPROTO;
+ length += data[i];
+ }
+
+ result = octeon_i2c_check_status(i2c, final_read);
+ if (result)
+ return result;
+ }
+ *rlength = length;
+ return 0;
}
/**
- * octeon_i2c_hlc_wait - wait for an HLC operation to complete
+ * octeon_i2c_write - send data to the bus via low-level controller
* @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the data to be sent
+ * @length: Length of the data
*
- * Returns 0 on success, otherwise -ETIMEDOUT.
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
*/
-static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+ const u8 *data, int length)
{
- bool first = 1;
- int time_left;
+ int i, result;
- /*
- * Some cn38xx boards don't assert the irq in the interrupt
- * controller. So we must poll for the valid bit change.
- */
- if (i2c->broken_irq_mode) {
- u64 end = get_jiffies_64() + i2c->adap.timeout;
+ octeon_i2c_data_write(i2c, target << 1);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
- while (!octeon_i2c_hlc_test_valid(i2c) &&
- time_before64(get_jiffies_64(), end))
- usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
- return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT;
- }
+ for (i = 0; i < length; i++) {
+ result = octeon_i2c_check_status(i2c, false);
+ if (result)
+ return result;
- i2c->hlc_int_enable(i2c);
- time_left = wait_event_timeout(i2c->queue,
- octeon_i2c_hlc_test_ready(i2c, &first),
- i2c->adap.timeout);
- i2c->hlc_int_disable(i2c);
- if (!time_left)
- octeon_i2c_hlc_int_clear(i2c);
+ octeon_i2c_data_write(i2c, data[i]);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
- if (i2c->broken_irq_check && !time_left &&
- octeon_i2c_hlc_test_valid(i2c)) {
- dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
- i2c->broken_irq_mode = true;
- return 0;
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
}
- if (!time_left)
- return -ETIMEDOUT;
return 0;
}
@@ -570,20 +457,20 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
else
cmd |= SW_TWSI_OP_7;
- octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
- cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
if ((cmd & SW_TWSI_R) == 0)
- return -EAGAIN;
+ return octeon_i2c_check_status(i2c, false);
for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--)
msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
if (msgs[0].len > 4) {
- cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT);
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
}
@@ -620,19 +507,17 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
ext |= (u64)msgs[0].buf[j] << (8 * i);
- octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT);
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
}
- octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
- cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
if ((cmd & SW_TWSI_R) == 0)
- return -EAGAIN;
-
- ret = octeon_i2c_check_status(i2c, false);
+ return octeon_i2c_check_status(i2c, false);
err:
return ret;
@@ -663,27 +548,27 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs
cmd |= SW_TWSI_EIA;
ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
- octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT);
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
} else {
cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
}
octeon_i2c_hlc_int_clear(i2c);
- octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
- cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
if ((cmd & SW_TWSI_R) == 0)
- return -EAGAIN;
+ return octeon_i2c_check_status(i2c, false);
for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--)
msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
if (msgs[1].len > 4) {
- cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT);
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--)
msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
}
@@ -730,27 +615,85 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
set_ext = true;
}
if (set_ext)
- octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT);
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
octeon_i2c_hlc_int_clear(i2c);
- octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
- cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
if ((cmd & SW_TWSI_R) == 0)
- return -EAGAIN;
-
- ret = octeon_i2c_check_status(i2c, false);
+ return octeon_i2c_check_status(i2c, false);
err:
return ret;
}
+/**
+ * octeon_i2c_xfer - The driver's master_xfer function
+ * @adap: Pointer to the i2c_adapter structure
+ * @msgs: Pointer to the messages to be processed
+ * @num: Length of the MSGS array
+ *
+ * Returns the number of messages processed, or a negative errno on failure.
+ */
+int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+ int i, ret = 0;
+
+ if (num == 1) {
+ if (msgs[0].len > 0 && msgs[0].len <= 8) {
+ if (msgs[0].flags & I2C_M_RD)
+ ret = octeon_i2c_hlc_read(i2c, msgs);
+ else
+ ret = octeon_i2c_hlc_write(i2c, msgs);
+ goto out;
+ }
+ } else if (num == 2) {
+ if ((msgs[0].flags & I2C_M_RD) == 0 &&
+ (msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
+ msgs[0].len > 0 && msgs[0].len <= 2 &&
+ msgs[1].len > 0 && msgs[1].len <= 8 &&
+ msgs[0].addr == msgs[1].addr) {
+ if (msgs[1].flags & I2C_M_RD)
+ ret = octeon_i2c_hlc_comp_read(i2c, msgs);
+ else
+ ret = octeon_i2c_hlc_comp_write(i2c, msgs);
+ goto out;
+ }
+ }
+
+ for (i = 0; ret == 0 && i < num; i++) {
+ struct i2c_msg *pmsg = &msgs[i];
+
+ /* zero-length messages are not supported */
+ if (!pmsg->len) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ ret = octeon_i2c_start(i2c);
+ if (ret)
+ return ret;
+
+ if (pmsg->flags & I2C_M_RD)
+ ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
+ &pmsg->len, pmsg->flags & I2C_M_RECV_LEN);
+ else
+ ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ }
+ octeon_i2c_stop(i2c);
+out:
+ return (ret != 0) ? ret : num;
+}
+
/* calculate and set clock divisors */
-static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+void octeon_i2c_set_clock(struct octeon_i2c *i2c)
{
int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
@@ -791,7 +734,7 @@ static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
}
-static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
{
u8 status = 0;
int tries;
@@ -818,219 +761,6 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
return 0;
}
-static int octeon_i2c_recovery(struct octeon_i2c *i2c)
-{
- int ret;
-
- ret = i2c_recover_bus(&i2c->adap);
- if (ret)
- /* recover failed, try hardware re-init */
- ret = octeon_i2c_init_lowlevel(i2c);
- return ret;
-}
-
-/**
- * octeon_i2c_start - send START to the bus
- * @i2c: The struct octeon_i2c
- *
- * Returns 0 on success, otherwise a negative errno.
- */
-static int octeon_i2c_start(struct octeon_i2c *i2c)
-{
- int ret;
- u8 stat;
-
- octeon_i2c_hlc_disable(i2c);
-
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
- ret = octeon_i2c_wait(i2c);
- if (ret)
- goto error;
-
- stat = octeon_i2c_stat_read(i2c);
- if (stat == STAT_START || stat == STAT_REP_START)
- /* START successful, bail out */
- return 0;
-
-error:
- /* START failed, try to recover */
- ret = octeon_i2c_recovery(i2c);
- return (ret) ? ret : -EAGAIN;
-}
-
-/* send STOP to the bus */
-static void octeon_i2c_stop(struct octeon_i2c *i2c)
-{
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP);
-}
-
-/**
- * octeon_i2c_write - send data to the bus via low-level controller
- * @i2c: The struct octeon_i2c
- * @target: Target address
- * @data: Pointer to the data to be sent
- * @length: Length of the data
- *
- * The address is sent over the bus, then the data.
- *
- * Returns 0 on success, otherwise a negative errno.
- */
-static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
- const u8 *data, int length)
-{
- int i, result;
-
- octeon_i2c_data_write(i2c, target << 1);
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
-
- result = octeon_i2c_wait(i2c);
- if (result)
- return result;
-
- for (i = 0; i < length; i++) {
- result = octeon_i2c_check_status(i2c, false);
- if (result)
- return result;
-
- octeon_i2c_data_write(i2c, data[i]);
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
-
- result = octeon_i2c_wait(i2c);
- if (result)
- return result;
- }
-
- return 0;
-}
-
-/**
- * octeon_i2c_read - receive data from the bus via low-level controller
- * @i2c: The struct octeon_i2c
- * @target: Target address
- * @data: Pointer to the location to store the data
- * @rlength: Length of the data
- * @recv_len: flag for length byte
- *
- * The address is sent over the bus, then the data is read.
- *
- * Returns 0 on success, otherwise a negative errno.
- */
-static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
- u8 *data, u16 *rlength, bool recv_len)
-{
- int i, result, length = *rlength;
- bool final_read = false;
-
- octeon_i2c_data_write(i2c, (target << 1) | 1);
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
-
- result = octeon_i2c_wait(i2c);
- if (result)
- return result;
-
- /* address OK ? */
- result = octeon_i2c_check_status(i2c, false);
- if (result)
- return result;
-
- for (i = 0; i < length; i++) {
- /*
- * For the last byte to receive TWSI_CTL_AAK must not be set.
- *
- * A special case is I2C_M_RECV_LEN where we don't know the
- * additional length yet. If recv_len is set we assume we're
- * not reading the final byte and therefore need to set
- * TWSI_CTL_AAK.
- */
- if ((i + 1 == length) && !(recv_len && i == 0))
- final_read = true;
-
- /* clear iflg to allow next event */
- if (final_read)
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
- else
- octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK);
-
- result = octeon_i2c_wait(i2c);
- if (result)
- return result;
-
- data[i] = octeon_i2c_data_read(i2c);
- if (recv_len && i == 0) {
- if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
- return -EPROTO;
- length += data[i];
- }
-
- result = octeon_i2c_check_status(i2c, final_read);
- if (result)
- return result;
- }
- *rlength = length;
- return 0;
-}
-
-/**
- * octeon_i2c_xfer - The driver's master_xfer function
- * @adap: Pointer to the i2c_adapter structure
- * @msgs: Pointer to the messages to be processed
- * @num: Length of the MSGS array
- *
- * Returns the number of messages processed, or a negative errno on failure.
- */
-static int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- int num)
-{
- struct octeon_i2c *i2c = i2c_get_adapdata(adap);
- int i, ret = 0;
-
- if (num == 1) {
- if (msgs[0].len > 0 && msgs[0].len <= 8) {
- if (msgs[0].flags & I2C_M_RD)
- ret = octeon_i2c_hlc_read(i2c, msgs);
- else
- ret = octeon_i2c_hlc_write(i2c, msgs);
- goto out;
- }
- } else if (num == 2) {
- if ((msgs[0].flags & I2C_M_RD) == 0 &&
- (msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
- msgs[0].len > 0 && msgs[0].len <= 2 &&
- msgs[1].len > 0 && msgs[1].len <= 8 &&
- msgs[0].addr == msgs[1].addr) {
- if (msgs[1].flags & I2C_M_RD)
- ret = octeon_i2c_hlc_comp_read(i2c, msgs);
- else
- ret = octeon_i2c_hlc_comp_write(i2c, msgs);
- goto out;
- }
- }
-
- for (i = 0; ret == 0 && i < num; i++) {
- struct i2c_msg *pmsg = &msgs[i];
-
- /* zero-length messages are not supported */
- if (!pmsg->len) {
- ret = -EOPNOTSUPP;
- break;
- }
-
- ret = octeon_i2c_start(i2c);
- if (ret)
- return ret;
-
- if (pmsg->flags & I2C_M_RD)
- ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
- &pmsg->len, pmsg->flags & I2C_M_RECV_LEN);
- else
- ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
- pmsg->len);
- }
- octeon_i2c_stop(i2c);
-out:
- return (ret != 0) ? ret : num;
-}
-
static int octeon_i2c_get_scl(struct i2c_adapter *adap)
{
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
@@ -1044,7 +774,7 @@ static void octeon_i2c_set_scl(struct i2c_adapter *adap, int val)
{
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
- octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR);
+ octeon_i2c_write_int(i2c, val ? 0 : TWSI_INT_SCL_OVR);
}
static int octeon_i2c_get_sda(struct i2c_adapter *adap)
@@ -1060,13 +790,14 @@ static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap)
{
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+ octeon_i2c_hlc_disable(i2c);
+
/*
- * The stop resets the state machine, does not _transmit_ STOP unless
- * engine was active.
+ * Bring control register to a good state regardless
+ * of HLC state.
*/
- octeon_i2c_stop(i2c);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
- octeon_i2c_hlc_disable(i2c);
octeon_i2c_write_int(i2c, 0);
}
@@ -1074,10 +805,19 @@ static void octeon_i2c_unprepare_recovery(struct i2c_adapter *adap)
{
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+ /*
+ * Generate STOP to finish the unfinished transaction.
+ * Can't generate STOP via the TWSI CTL register
+ * since it could bring the TWSI controller into an inoperable state.
+ */
+ octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR);
+ udelay(5);
+ octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR);
+ udelay(5);
octeon_i2c_write_int(i2c, 0);
}
-static struct i2c_bus_recovery_info octeon_i2c_recovery_info = {
+struct i2c_bus_recovery_info octeon_i2c_recovery_info = {
.recover_bus = i2c_generic_scl_recovery,
.get_scl = octeon_i2c_get_scl,
.set_scl = octeon_i2c_set_scl,
@@ -1085,171 +825,3 @@ static struct i2c_bus_recovery_info octeon_i2c_recovery_info = {
.prepare_recovery = octeon_i2c_prepare_recovery,
.unprepare_recovery = octeon_i2c_unprepare_recovery,
};
-
-static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
- I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
-}
-
-static const struct i2c_algorithm octeon_i2c_algo = {
- .master_xfer = octeon_i2c_xfer,
- .functionality = octeon_i2c_functionality,
-};
-
-static struct i2c_adapter octeon_i2c_ops = {
- .owner = THIS_MODULE,
- .name = "OCTEON adapter",
- .algo = &octeon_i2c_algo,
-};
-
-static int octeon_i2c_probe(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- int irq, result = 0, hlc_irq = 0;
- struct resource *res_mem;
- struct octeon_i2c *i2c;
- bool cn78xx_style;
-
- cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi");
- if (cn78xx_style) {
- hlc_irq = platform_get_irq(pdev, 0);
- if (hlc_irq < 0)
- return hlc_irq;
-
- irq = platform_get_irq(pdev, 2);
- if (irq < 0)
- return irq;
- } else {
- /* All adaptors have an irq. */
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
- }
-
- i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
- if (!i2c) {
- result = -ENOMEM;
- goto out;
- }
- i2c->dev = &pdev->dev;
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem);
- if (IS_ERR(i2c->twsi_base)) {
- result = PTR_ERR(i2c->twsi_base);
- goto out;
- }
-
- /*
- * "clock-rate" is a legacy binding, the official binding is
- * "clock-frequency". Try the official one first and then
- * fall back if it doesn't exist.
- */
- if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) &&
- of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) {
- dev_err(i2c->dev,
- "no I2C 'clock-rate' or 'clock-frequency' property\n");
- result = -ENXIO;
- goto out;
- }
-
- i2c->sys_freq = octeon_get_io_clock_rate();
-
- init_waitqueue_head(&i2c->queue);
-
- i2c->irq = irq;
-
- if (cn78xx_style) {
- i2c->hlc_irq = hlc_irq;
-
- i2c->int_enable = octeon_i2c_int_enable78;
- i2c->int_disable = octeon_i2c_int_disable78;
- i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78;
- i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78;
-
- irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN);
- irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN);
-
- result = devm_request_irq(&pdev->dev, i2c->hlc_irq,
- octeon_i2c_hlc_isr78, 0,
- DRV_NAME, i2c);
- if (result < 0) {
- dev_err(i2c->dev, "failed to attach interrupt\n");
- goto out;
- }
- } else {
- i2c->int_enable = octeon_i2c_int_enable;
- i2c->int_disable = octeon_i2c_int_disable;
- i2c->hlc_int_enable = octeon_i2c_hlc_int_enable;
- i2c->hlc_int_disable = octeon_i2c_int_disable;
- }
-
- result = devm_request_irq(&pdev->dev, i2c->irq,
- octeon_i2c_isr, 0, DRV_NAME, i2c);
- if (result < 0) {
- dev_err(i2c->dev, "failed to attach interrupt\n");
- goto out;
- }
-
- if (OCTEON_IS_MODEL(OCTEON_CN38XX))
- i2c->broken_irq_check = true;
-
- result = octeon_i2c_init_lowlevel(i2c);
- if (result) {
- dev_err(i2c->dev, "init low level failed\n");
- goto out;
- }
-
- octeon_i2c_set_clock(i2c);
-
- i2c->adap = octeon_i2c_ops;
- i2c->adap.timeout = msecs_to_jiffies(2);
- i2c->adap.retries = 5;
- i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
- i2c->adap.dev.parent = &pdev->dev;
- i2c->adap.dev.of_node = node;
- i2c_set_adapdata(&i2c->adap, i2c);
- platform_set_drvdata(pdev, i2c);
-
- result = i2c_add_adapter(&i2c->adap);
- if (result < 0) {
- dev_err(i2c->dev, "failed to add adapter\n");
- goto out;
- }
- dev_info(i2c->dev, "probed\n");
- return 0;
-
-out:
- return result;
-};
-
-static int octeon_i2c_remove(struct platform_device *pdev)
-{
- struct octeon_i2c *i2c = platform_get_drvdata(pdev);
-
- i2c_del_adapter(&i2c->adap);
- return 0;
-};
-
-static const struct of_device_id octeon_i2c_match[] = {
- { .compatible = "cavium,octeon-3860-twsi", },
- { .compatible = "cavium,octeon-7890-twsi", },
- {},
-};
-MODULE_DEVICE_TABLE(of, octeon_i2c_match);
-
-static struct platform_driver octeon_i2c_driver = {
- .probe = octeon_i2c_probe,
- .remove = octeon_i2c_remove,
- .driver = {
- .name = DRV_NAME,
- .of_match_table = octeon_i2c_match,
- },
-};
-
-module_platform_driver(octeon_i2c_driver);
-
-MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
-MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h
new file mode 100644
index 000000000000..1db7c835a454
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon-core.h
@@ -0,0 +1,216 @@
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/* Controller command patterns */
+#define SW_TWSI_V BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */
+#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */
+#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_ADDR_SHIFT 40
+#define SW_TWSI_IA_SHIFT 32 /* Internal address */
+
+/* Controller opcode word (bits 60:57) */
+#define SW_TWSI_OP_SHIFT 57
+#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
+
+/* Controller extended opcode word (bits 34:32) */
+#define SW_TWSI_EOP_SHIFT 32
+#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE 0x80 /* High level controller enable */
+#define TWSI_CTL_ENAB 0x40 /* Bus enable */
+#define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */
+#define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */
+#define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK 0x04 /* Assert ACK */
+
+/* Status values */
+#define STAT_ERROR 0x00
+#define STAT_START 0x08
+#define STAT_REP_START 0x10
+#define STAT_TXADDR_ACK 0x18
+#define STAT_TXADDR_NAK 0x20
+#define STAT_TXDATA_ACK 0x28
+#define STAT_TXDATA_NAK 0x30
+#define STAT_LOST_ARB_38 0x38
+#define STAT_RXADDR_ACK 0x40
+#define STAT_RXADDR_NAK 0x48
+#define STAT_RXDATA_ACK 0x50
+#define STAT_RXDATA_NAK 0x58
+#define STAT_SLAVE_60 0x60
+#define STAT_LOST_ARB_68 0x68
+#define STAT_SLAVE_70 0x70
+#define STAT_LOST_ARB_78 0x78
+#define STAT_SLAVE_80 0x80
+#define STAT_SLAVE_88 0x88
+#define STAT_GENDATA_ACK 0x90
+#define STAT_GENDATA_NAK 0x98
+#define STAT_SLAVE_A0 0xA0
+#define STAT_SLAVE_A8 0xA8
+#define STAT_LOST_ARB_B0 0xB0
+#define STAT_SLAVE_LOST 0xB8
+#define STAT_SLAVE_NAK 0xC0
+#define STAT_SLAVE_ACK 0xC8
+#define STAT_AD2W_ACK 0xD0
+#define STAT_AD2W_NAK 0xD8
+#define STAT_IDLE 0xF8
+
+/* TWSI_INT values */
+#define TWSI_INT_ST_INT BIT_ULL(0)
+#define TWSI_INT_TS_INT BIT_ULL(1)
+#define TWSI_INT_CORE_INT BIT_ULL(2)
+#define TWSI_INT_ST_EN BIT_ULL(4)
+#define TWSI_INT_TS_EN BIT_ULL(5)
+#define TWSI_INT_CORE_EN BIT_ULL(6)
+#define TWSI_INT_SDA_OVR BIT_ULL(8)
+#define TWSI_INT_SCL_OVR BIT_ULL(9)
+#define TWSI_INT_SDA BIT_ULL(10)
+#define TWSI_INT_SCL BIT_ULL(11)
+
+#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */
+
+/* Register offsets */
+struct octeon_i2c_reg_offset {
+ unsigned int sw_twsi;
+ unsigned int twsi_int;
+ unsigned int sw_twsi_ext;
+};
+
+#define SW_TWSI(x) (x->roff.sw_twsi)
+#define TWSI_INT(x) (x->roff.twsi_int)
+#define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext)
+
+struct octeon_i2c {
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ struct octeon_i2c_reg_offset roff;
+ struct clk *clk;
+ int irq;
+ int hlc_irq; /* For cn7890 only */
+ u32 twsi_freq;
+ int sys_freq;
+ void __iomem *twsi_base;
+ struct device *dev;
+ bool hlc_enabled;
+ bool broken_irq_mode;
+ bool broken_irq_check;
+ void (*int_enable)(struct octeon_i2c *);
+ void (*int_disable)(struct octeon_i2c *);
+ void (*hlc_int_enable)(struct octeon_i2c *);
+ void (*hlc_int_disable)(struct octeon_i2c *);
+ atomic_t int_enable_cnt;
+ atomic_t hlc_int_enable_cnt;
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+ struct msix_entry i2c_msix;
+#endif
+ struct i2c_smbus_alert_setup alert_data;
+ struct i2c_client *ara;
+};
+
+static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
+{
+ __raw_writeq(val, addr);
+ __raw_readq(addr); /* wait for write to land */
+}
+
+/**
+ * octeon_i2c_reg_write - write an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ * @data: Value to be written
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+{
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
+
+ readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp, tmp & SW_TWSI_V,
+ I2C_OCTEON_EVENT_WAIT, i2c->adap.timeout);
+}
+
+#define octeon_i2c_ctl_write(i2c, val) \
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val)
+#define octeon_i2c_data_write(i2c, val) \
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val)
+
+/**
+ * octeon_i2c_reg_read - read lower bits of an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
+ int *error)
+{
+ u64 tmp;
+ int ret;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
+
+ ret = readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp,
+ tmp & SW_TWSI_V, I2C_OCTEON_EVENT_WAIT,
+ i2c->adap.timeout);
+ if (error)
+ *error = ret;
+ return tmp & 0xFF;
+}
+
+#define octeon_i2c_ctl_read(i2c) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
+#define octeon_i2c_data_read(i2c, error) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
+#define octeon_i2c_stat_read(i2c) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
+
+/**
+ * octeon_i2c_read_int - read the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns the value of the register.
+ */
+static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
+{
+ return __raw_readq(i2c->twsi_base + TWSI_INT(i2c));
+}
+
+/**
+ * octeon_i2c_write_int - write the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ * @data: Value to be written
+ */
+static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+{
+ octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c));
+}
+
+/* Prototypes */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id);
+int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
+int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c);
+void octeon_i2c_set_clock(struct octeon_i2c *i2c);
+extern struct i2c_bus_recovery_info octeon_i2c_recovery_info;
diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c
new file mode 100644
index 000000000000..917524ce6890
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon-platdrv.c
@@ -0,0 +1,286 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/octeon/octeon.h>
+#include "i2c-octeon-core.h"
+
+#define DRV_NAME "i2c-octeon"
+
+/**
+ * octeon_i2c_int_enable - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
+{
+ /* clear TS/ST/IFLG events */
+ octeon_i2c_write_int(i2c, 0);
+}
+
+/**
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+ atomic_inc_return(&i2c->int_enable_cnt);
+ enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+ int count;
+
+ /*
+ * The interrupt can be disabled in two places, but we only
+ * want to make the disable_irq_nosync() call once, so keep
+ * track with the atomic variable.
+ */
+ count = atomic_dec_if_positive(cnt);
+ if (count >= 0)
+ disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+ __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+ atomic_inc_return(&i2c->hlc_int_enable_cnt);
+ enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+ __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq);
+}
+
+/* HLC interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+ struct octeon_i2c *i2c = dev_id;
+
+ i2c->hlc_int_disable(i2c);
+ wake_up(&i2c->queue);
+
+ return IRQ_HANDLED;
+}
+
+static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, TWSI_INT_ST_EN);
+}
+
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm octeon_i2c_algo = {
+ .master_xfer = octeon_i2c_xfer,
+ .functionality = octeon_i2c_functionality,
+};
+
+static struct i2c_adapter octeon_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "OCTEON adapter",
+ .algo = &octeon_i2c_algo,
+};
+
+static int octeon_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int irq, result = 0, hlc_irq = 0;
+ struct resource *res_mem;
+ struct octeon_i2c *i2c;
+ bool cn78xx_style;
+
+ cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi");
+ if (cn78xx_style) {
+ hlc_irq = platform_get_irq(pdev, 0);
+ if (hlc_irq < 0)
+ return hlc_irq;
+
+ irq = platform_get_irq(pdev, 2);
+ if (irq < 0)
+ return irq;
+ } else {
+ /* All adaptors have an irq. */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ }
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c) {
+ result = -ENOMEM;
+ goto out;
+ }
+ i2c->dev = &pdev->dev;
+
+ i2c->roff.sw_twsi = 0x00;
+ i2c->roff.twsi_int = 0x10;
+ i2c->roff.sw_twsi_ext = 0x18;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem);
+ if (IS_ERR(i2c->twsi_base)) {
+ result = PTR_ERR(i2c->twsi_base);
+ goto out;
+ }
+
+ /*
+ * "clock-rate" is a legacy binding, the official binding is
+ * "clock-frequency". Try the official one first and then
+ * fall back if it doesn't exist.
+ */
+ if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) &&
+ of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) {
+ dev_err(i2c->dev,
+ "no I2C 'clock-rate' or 'clock-frequency' property\n");
+ result = -ENXIO;
+ goto out;
+ }
+
+ i2c->sys_freq = octeon_get_io_clock_rate();
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->irq = irq;
+
+ if (cn78xx_style) {
+ i2c->hlc_irq = hlc_irq;
+
+ i2c->int_enable = octeon_i2c_int_enable78;
+ i2c->int_disable = octeon_i2c_int_disable78;
+ i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78;
+ i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78;
+
+ irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN);
+ irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN);
+
+ result = devm_request_irq(&pdev->dev, i2c->hlc_irq,
+ octeon_i2c_hlc_isr78, 0,
+ DRV_NAME, i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto out;
+ }
+ } else {
+ i2c->int_enable = octeon_i2c_int_enable;
+ i2c->int_disable = octeon_i2c_int_disable;
+ i2c->hlc_int_enable = octeon_i2c_hlc_int_enable;
+ i2c->hlc_int_disable = octeon_i2c_int_disable;
+ }
+
+ result = devm_request_irq(&pdev->dev, i2c->irq,
+ octeon_i2c_isr, 0, DRV_NAME, i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto out;
+ }
+
+ if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+ i2c->broken_irq_check = true;
+
+ result = octeon_i2c_init_lowlevel(i2c);
+ if (result) {
+ dev_err(i2c->dev, "init low level failed\n");
+ goto out;
+ }
+
+ octeon_i2c_set_clock(i2c);
+
+ i2c->adap = octeon_i2c_ops;
+ i2c->adap.timeout = msecs_to_jiffies(2);
+ i2c->adap.retries = 5;
+ i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = node;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ result = i2c_add_adapter(&i2c->adap);
+ if (result < 0)
+ goto out;
+ dev_info(i2c->dev, "probed\n");
+ return 0;
+
+out:
+ return result;
+};
+
+static int octeon_i2c_remove(struct platform_device *pdev)
+{
+ struct octeon_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+};
+
+static const struct of_device_id octeon_i2c_match[] = {
+ { .compatible = "cavium,octeon-3860-twsi", },
+ { .compatible = "cavium,octeon-7890-twsi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_i2c_match);
+
+static struct platform_driver octeon_i2c_driver = {
+ .probe = octeon_i2c_probe,
+ .remove = octeon_i2c_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = octeon_i2c_match,
+ },
+};
+
+module_platform_driver(octeon_i2c_driver);
+
+MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index ab1279b8e240..c7da0c42baee 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1425,10 +1425,8 @@ omap_i2c_probe(struct platform_device *pdev)
/* i2c device drivers may be active on return from add_adapter() */
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
- if (r) {
- dev_err(omap->dev, "failure adding adapter\n");
+ if (r)
goto err_unuse_clocks;
- }
dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr,
major, minor, omap->speed);
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 23d1c167b5d7..c2268cdf38e8 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -694,7 +694,6 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
retval = i2c_add_adapter(adap);
if (retval) {
- dev_err(&dev->dev, "Couldn't register adapter!\n");
kfree(adapdata);
kfree(adap);
release_region(smba, SMBIOSIZE);
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index 2c40edbf6224..217c78711d65 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -329,10 +329,8 @@ static int pmcmsptwi_probe(struct platform_device *pldev)
i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
rc = i2c_add_adapter(&pmcmsptwi_adapter);
- if (rc) {
- dev_err(&pldev->dev, "Unable to register I2C adapter\n");
+ if (rc)
goto ret_unmap;
- }
return 0;
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 7ea67aa46fb7..fd5f9d2bf6d9 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -714,10 +714,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
/* Register this adapter with the I2C subsystem */
ret = i2c_add_numbered_adapter(&alg_data->adapter);
- if (ret < 0) {
- dev_err(&pdev->dev, "I2C: Failed to add bus\n");
+ if (ret < 0)
goto out_clock;
- }
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
alg_data->adapter.name, res->start, alg_data->irq);
diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c
index 82b6f02544da..0c8b1571886d 100644
--- a/drivers/i2c/busses/i2c-puv3.c
+++ b/drivers/i2c/busses/i2c-puv3.c
@@ -212,11 +212,8 @@ static int puv3_i2c_probe(struct platform_device *pdev)
adapter->nr = pdev->id;
rc = i2c_add_numbered_adapter(adapter);
- if (rc) {
- dev_err(&pdev->dev, "Adapter '%s' registration failed\n",
- adapter->name);
+ if (rc)
goto fail_add_adapter;
- }
dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n");
return 0;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 0d351954db02..e28b825b0433 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1292,10 +1292,8 @@ static int i2c_pxa_probe(struct platform_device *dev)
#endif
ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&dev->dev, "failed to add bus: %d\n", ret);
+ if (ret < 0)
goto ereqirq;
- }
platform_set_drvdata(dev, i2c);
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 9bd849dacee8..726615e54f2a 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -802,6 +802,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
+ { .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 },
{},
};
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@@ -875,10 +876,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
ret = i2c_add_numbered_adapter(adap);
- if (ret < 0) {
- dev_err(dev, "reg adap failed: %d\n", ret);
+ if (ret < 0)
goto out_pm_disable;
- }
dev_info(dev, "probed\n");
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index d7e3af671543..6263ea82d6ac 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -383,10 +383,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
ret = i2c_add_adapter(adap);
- if (ret) {
- dev_err(&pdev->dev, "failed to add adapter\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, riic);
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 5c5b7cada8be..50702c7bb244 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -58,7 +58,7 @@ enum {
#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */
#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */
-#define REG_CON_TUNING_MASK GENMASK(15, 8)
+#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8)
#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
@@ -742,7 +742,7 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
struct i2c_timings *t,
struct rk3x_i2c_calced_timings *t_calc)
{
- unsigned long min_low_ns, min_high_ns, min_total_ns;
+ unsigned long min_low_ns, min_high_ns;
unsigned long min_setup_start_ns, min_setup_data_ns;
unsigned long min_setup_stop_ns, max_hold_data_ns;
@@ -793,7 +793,6 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
/* These are the min dividers needed for min hold times. */
min_div_for_hold = (min_low_div + min_high_div);
- min_total_ns = min_low_ns + min_high_ns;
/*
* This is the maximum divider so we don't go over the maximum.
@@ -1312,10 +1311,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
rk3x_i2c_adapt_div(i2c, clk_rate);
ret = i2c_add_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register adapter\n");
+ if (ret < 0)
goto err_clk_notifier;
- }
dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 38dc1cacfd8b..499af26e736e 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -1215,7 +1215,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core\n");
pm_runtime_disable(&pdev->dev);
s3c24xx_i2c_deregister_cpufreq(i2c);
clk_unprepare(i2c->clk);
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
index 24968384b401..c2005c789d2b 100644
--- a/drivers/i2c/busses/i2c-sh7760.c
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -510,10 +510,8 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
}
ret = i2c_add_numbered_adapter(&id->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+ if (ret < 0)
goto out4;
- }
platform_set_drvdata(pdev, id);
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 05b1eeab9cf5..192f36f00e4d 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -981,7 +981,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
ret = i2c_add_numbered_adapter(adap);
if (ret < 0) {
sh_mobile_i2c_release_dma(pd);
- dev_err(&dev->dev, "cannot add numbered adapter\n");
return ret;
}
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 792a42bdd335..95e81d0f72b4 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -387,10 +387,8 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
err = i2c_add_numbered_adapter(adap);
- if (err < 0) {
- dev_err(&pdev->dev, "Can't add new i2c adapter\n");
+ if (err < 0)
goto out;
- }
clk_disable(clk);
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 944ec4205084..1371547ce1a3 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -874,10 +874,8 @@ static int st_i2c_probe(struct platform_device *pdev)
init_completion(&i2c_dev->complete);
ret = i2c_add_adapter(adap);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add adapter\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, i2c_dev);
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
index 460c134832ac..dc63236b45b2 100644
--- a/drivers/i2c/busses/i2c-stu300.c
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -920,11 +920,8 @@ static int stu300_probe(struct platform_device *pdev)
/* i2c device drivers may be active on return from add_adapter() */
ret = i2c_add_numbered_adapter(adap);
- if (ret) {
- dev_err(&pdev->dev, "failure adding ST Micro DDC "
- "I2C adapter\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, dev);
dev_info(&pdev->dev, "ST DDC I2C @ %p, irq %d\n",
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index b126dbaa47e3..4af9bbae20df 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -28,6 +28,9 @@
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/reset.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
#include <asm/unaligned.h>
@@ -36,21 +39,21 @@
#define I2C_CNFG 0x000
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
-#define I2C_CNFG_PACKET_MODE_EN (1<<10)
-#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
-#define I2C_CNFG_MULTI_MASTER_MODE (1<<17)
+#define I2C_CNFG_PACKET_MODE_EN BIT(10)
+#define I2C_CNFG_NEW_MASTER_FSM BIT(11)
+#define I2C_CNFG_MULTI_MASTER_MODE BIT(17)
#define I2C_STATUS 0x01C
#define I2C_SL_CNFG 0x020
-#define I2C_SL_CNFG_NACK (1<<1)
-#define I2C_SL_CNFG_NEWSL (1<<2)
+#define I2C_SL_CNFG_NACK BIT(1)
+#define I2C_SL_CNFG_NEWSL BIT(2)
#define I2C_SL_ADDR1 0x02c
#define I2C_SL_ADDR2 0x030
#define I2C_TX_FIFO 0x050
#define I2C_RX_FIFO 0x054
#define I2C_PACKET_TRANSFER_STATUS 0x058
#define I2C_FIFO_CONTROL 0x05c
-#define I2C_FIFO_CONTROL_TX_FLUSH (1<<1)
-#define I2C_FIFO_CONTROL_RX_FLUSH (1<<0)
+#define I2C_FIFO_CONTROL_TX_FLUSH BIT(1)
+#define I2C_FIFO_CONTROL_RX_FLUSH BIT(0)
#define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5
#define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2
#define I2C_FIFO_STATUS 0x060
@@ -60,26 +63,26 @@
#define I2C_FIFO_STATUS_RX_SHIFT 0
#define I2C_INT_MASK 0x064
#define I2C_INT_STATUS 0x068
-#define I2C_INT_PACKET_XFER_COMPLETE (1<<7)
-#define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1<<6)
-#define I2C_INT_TX_FIFO_OVERFLOW (1<<5)
-#define I2C_INT_RX_FIFO_UNDERFLOW (1<<4)
-#define I2C_INT_NO_ACK (1<<3)
-#define I2C_INT_ARBITRATION_LOST (1<<2)
-#define I2C_INT_TX_FIFO_DATA_REQ (1<<1)
-#define I2C_INT_RX_FIFO_DATA_REQ (1<<0)
+#define I2C_INT_PACKET_XFER_COMPLETE BIT(7)
+#define I2C_INT_ALL_PACKETS_XFER_COMPLETE BIT(6)
+#define I2C_INT_TX_FIFO_OVERFLOW BIT(5)
+#define I2C_INT_RX_FIFO_UNDERFLOW BIT(4)
+#define I2C_INT_NO_ACK BIT(3)
+#define I2C_INT_ARBITRATION_LOST BIT(2)
+#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
+#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
#define I2C_CLK_DIVISOR 0x06c
#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8
#define DVC_CTRL_REG1 0x000
-#define DVC_CTRL_REG1_INTR_EN (1<<10)
+#define DVC_CTRL_REG1_INTR_EN BIT(10)
#define DVC_CTRL_REG2 0x004
#define DVC_CTRL_REG3 0x008
-#define DVC_CTRL_REG3_SW_PROG (1<<26)
-#define DVC_CTRL_REG3_I2C_DONE_INTR_EN (1<<30)
+#define DVC_CTRL_REG3_SW_PROG BIT(26)
+#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30)
#define DVC_STATUS 0x00c
-#define DVC_STATUS_I2C_DONE_INTR (1<<30)
+#define DVC_STATUS_I2C_DONE_INTR BIT(30)
#define I2C_ERR_NONE 0x00
#define I2C_ERR_NO_ACK 0x01
@@ -89,26 +92,28 @@
#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
#define PACKET_HEADER0_PACKET_ID_SHIFT 16
#define PACKET_HEADER0_CONT_ID_SHIFT 12
-#define PACKET_HEADER0_PROTOCOL_I2C (1<<4)
-
-#define I2C_HEADER_HIGHSPEED_MODE (1<<22)
-#define I2C_HEADER_CONT_ON_NAK (1<<21)
-#define I2C_HEADER_SEND_START_BYTE (1<<20)
-#define I2C_HEADER_READ (1<<19)
-#define I2C_HEADER_10BIT_ADDR (1<<18)
-#define I2C_HEADER_IE_ENABLE (1<<17)
-#define I2C_HEADER_REPEAT_START (1<<16)
-#define I2C_HEADER_CONTINUE_XFER (1<<15)
+#define PACKET_HEADER0_PROTOCOL_I2C BIT(4)
+
+#define I2C_HEADER_HIGHSPEED_MODE BIT(22)
+#define I2C_HEADER_CONT_ON_NAK BIT(21)
+#define I2C_HEADER_SEND_START_BYTE BIT(20)
+#define I2C_HEADER_READ BIT(19)
+#define I2C_HEADER_10BIT_ADDR BIT(18)
+#define I2C_HEADER_IE_ENABLE BIT(17)
+#define I2C_HEADER_REPEAT_START BIT(16)
+#define I2C_HEADER_CONTINUE_XFER BIT(15)
#define I2C_HEADER_MASTER_ADDR_SHIFT 12
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
#define I2C_CONFIG_LOAD 0x08C
-#define I2C_MSTR_CONFIG_LOAD (1 << 0)
-#define I2C_SLV_CONFIG_LOAD (1 << 1)
-#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2)
+#define I2C_MSTR_CONFIG_LOAD BIT(0)
+#define I2C_SLV_CONFIG_LOAD BIT(1)
+#define I2C_TIMEOUT_CONFIG_LOAD BIT(2)
#define I2C_CLKEN_OVERRIDE 0x090
-#define I2C_MST_CORE_CLKEN_OVR (1 << 0)
+#define I2C_MST_CORE_CLKEN_OVR BIT(0)
+
+#define I2C_CONFIG_LOAD_TIMEOUT 1000000
/*
* msg_end_type: The bus control which need to be send at end of transfer.
@@ -191,9 +196,11 @@ struct tegra_i2c_dev {
u16 clk_divisor_non_hs_mode;
bool is_suspended;
bool is_multimaster_mode;
+ spinlock_t xfer_lock;
};
-static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
+static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
+ unsigned long reg)
{
writel(val, i2c_dev->base + reg);
}
@@ -244,15 +251,17 @@ static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
{
- u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
- int_mask &= ~mask;
+ u32 int_mask;
+
+ int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) & ~mask;
i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
}
static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
{
- u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
- int_mask |= mask;
+ u32 int_mask;
+
+ int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask;
i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
}
@@ -260,6 +269,7 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
{
unsigned long timeout = jiffies + HZ;
u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL);
+
val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH;
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
@@ -385,7 +395,8 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
*/
static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
{
- u32 val = 0;
+ u32 val;
+
val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
val |= DVC_CTRL_REG3_SW_PROG;
val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
@@ -396,9 +407,15 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
}
-static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
+static int tegra_i2c_runtime_resume(struct device *dev)
{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int ret;
+
+ ret = pinctrl_pm_select_default_state(i2c_dev->dev);
+ if (ret)
+ return ret;
+
if (!i2c_dev->hw->has_single_clk_source) {
ret = clk_enable(i2c_dev->fast_clk);
if (ret < 0) {
@@ -407,32 +424,66 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
return ret;
}
}
+
ret = clk_enable(i2c_dev->div_clk);
if (ret < 0) {
dev_err(i2c_dev->dev,
"Enabling div clk failed, err %d\n", ret);
clk_disable(i2c_dev->fast_clk);
+ return ret;
}
- return ret;
+
+ return 0;
}
-static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev)
+static int tegra_i2c_runtime_suspend(struct device *dev)
{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
clk_disable(i2c_dev->div_clk);
if (!i2c_dev->hw->has_single_clk_source)
clk_disable(i2c_dev->fast_clk);
+
+ return pinctrl_pm_select_idle_state(i2c_dev->dev);
+}
+
+static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
+{
+ unsigned long reg_offset;
+ void __iomem *addr;
+ u32 val;
+ int err;
+
+ if (i2c_dev->hw->has_config_load_reg) {
+ reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
+ addr = i2c_dev->base + reg_offset;
+ i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
+ if (in_interrupt())
+ err = readl_poll_timeout_atomic(addr, val, val == 0,
+ 1000, I2C_CONFIG_LOAD_TIMEOUT);
+ else
+ err = readl_poll_timeout(addr, val, val == 0,
+ 1000, I2C_CONFIG_LOAD_TIMEOUT);
+
+ if (err) {
+ dev_warn(i2c_dev->dev,
+ "timeout waiting for config load\n");
+ return err;
+ }
+ }
+
+ return 0;
}
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
{
u32 val;
- int err = 0;
+ int err;
u32 clk_divisor;
- unsigned long timeout = jiffies + HZ;
- err = tegra_i2c_clock_enable(i2c_dev);
+ err = pm_runtime_get_sync(i2c_dev->dev);
if (err < 0) {
- dev_err(i2c_dev->dev, "Clock enable failed %d\n", err);
+ dev_err(i2c_dev->dev, "runtime resume failed %d\n", err);
return err;
}
@@ -460,54 +511,59 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (!i2c_dev->is_dvc) {
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
-
}
val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
- if (tegra_i2c_flush_fifos(i2c_dev))
- err = -ETIMEDOUT;
+ err = tegra_i2c_flush_fifos(i2c_dev);
+ if (err)
+ goto err;
if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
- if (i2c_dev->hw->has_config_load_reg) {
- i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
- while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
- if (time_after(jiffies, timeout)) {
- dev_warn(i2c_dev->dev,
- "timeout waiting for config load\n");
- err = -ETIMEDOUT;
- goto err;
- }
- msleep(1);
- }
- }
+ err = tegra_i2c_wait_for_config_load(i2c_dev);
+ if (err)
+ goto err;
if (i2c_dev->irq_disabled) {
- i2c_dev->irq_disabled = 0;
+ i2c_dev->irq_disabled = false;
enable_irq(i2c_dev->irq);
}
err:
- tegra_i2c_clock_disable(i2c_dev);
+ pm_runtime_put(i2c_dev->dev);
return err;
}
+static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 cnfg;
+
+ cnfg = i2c_readl(i2c_dev, I2C_CNFG);
+ if (cnfg & I2C_CNFG_PACKET_MODE_EN)
+ i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
+
+ return tegra_i2c_wait_for_config_load(i2c_dev);
+}
+
static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
{
u32 status;
const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
struct tegra_i2c_dev *i2c_dev = dev_id;
+ unsigned long flags;
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+ spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
if (status == 0) {
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
@@ -517,12 +573,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (!i2c_dev->irq_disabled) {
disable_irq_nosync(i2c_dev->irq);
- i2c_dev->irq_disabled = 1;
+ i2c_dev->irq_disabled = true;
}
goto err;
}
if (unlikely(status & status_err)) {
+ tegra_i2c_disable_packet_mode(i2c_dev);
if (status & I2C_INT_NO_ACK)
i2c_dev->msg_err |= I2C_ERR_NO_ACK;
if (status & I2C_INT_ARBITRATION_LOST)
@@ -552,7 +609,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
BUG_ON(i2c_dev->msg_buf_remaining);
complete(&i2c_dev->msg_complete);
}
- return IRQ_HANDLED;
+ goto done;
err:
/* An error occurred, mask all interrupts */
tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
@@ -563,6 +620,8 @@ err:
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
complete(&i2c_dev->msg_complete);
+done:
+ spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
return IRQ_HANDLED;
}
@@ -572,6 +631,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
u32 packet_header;
u32 int_mask;
unsigned long time_left;
+ unsigned long flags;
tegra_i2c_flush_fifos(i2c_dev);
@@ -584,6 +644,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
i2c_dev->msg_read = (msg->flags & I2C_M_RD);
reinit_completion(&i2c_dev->msg_complete);
+ spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
+
+ int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ tegra_i2c_unmask_irq(i2c_dev, int_mask);
+
packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
PACKET_HEADER0_PROTOCOL_I2C |
(i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
@@ -613,14 +678,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
if (!(msg->flags & I2C_M_RD))
tegra_i2c_fill_tx_fifo(i2c_dev);
- int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
if (msg->flags & I2C_M_RD)
int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
else if (i2c_dev->msg_buf_remaining)
int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+
tegra_i2c_unmask_irq(i2c_dev, int_mask);
+ spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
i2c_readl(i2c_dev, I2C_INT_MASK));
@@ -643,9 +709,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
return 0;
/*
- * NACK interrupt is generated before the I2C controller generates the
- * STOP condition on the bus. So wait for 2 clock periods before resetting
- * the controller so that STOP condition has been delivered properly.
+ * NACK interrupt is generated before the I2C controller generates
+ * the STOP condition on the bus. So wait for 2 clock periods
+ * before resetting the controller so that the STOP condition has
+ * been delivered properly.
*/
if (i2c_dev->msg_err == I2C_ERR_NO_ACK)
udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate));
@@ -670,14 +737,15 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
if (i2c_dev->is_suspended)
return -EBUSY;
- ret = tegra_i2c_clock_enable(i2c_dev);
+ ret = pm_runtime_get_sync(i2c_dev->dev);
if (ret < 0) {
- dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret);
+ dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret);
return ret;
}
for (i = 0; i < num; i++) {
enum msg_end_type end_type = MSG_END_STOP;
+
if (i < (num - 1)) {
if (msgs[i + 1].flags & I2C_M_NOSTART)
end_type = MSG_END_CONTINUE;
@@ -688,7 +756,9 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
if (ret)
break;
}
- tegra_i2c_clock_disable(i2c_dev);
+
+ pm_runtime_put(i2c_dev->dev);
+
return ret ?: i;
}
@@ -825,7 +895,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
div_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(div_clk)) {
- dev_err(&pdev->dev, "missing controller clock");
+ dev_err(&pdev->dev, "missing controller clock\n");
return PTR_ERR(div_clk);
}
@@ -843,27 +913,22 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->rst = devm_reset_control_get(&pdev->dev, "i2c");
if (IS_ERR(i2c_dev->rst)) {
- dev_err(&pdev->dev, "missing controller reset");
+ dev_err(&pdev->dev, "missing controller reset\n");
return PTR_ERR(i2c_dev->rst);
}
tegra_i2c_parse_dt(i2c_dev);
- i2c_dev->hw = &tegra20_i2c_hw;
-
- if (pdev->dev.of_node) {
- i2c_dev->hw = of_device_get_match_data(&pdev->dev);
- i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
- "nvidia,tegra20-i2c-dvc");
- } else if (pdev->id == 3) {
- i2c_dev->is_dvc = 1;
- }
+ i2c_dev->hw = of_device_get_match_data(&pdev->dev);
+ i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
+ "nvidia,tegra20-i2c-dvc");
init_completion(&i2c_dev->msg_complete);
+ spin_lock_init(&i2c_dev->xfer_lock);
if (!i2c_dev->hw->has_single_clk_source) {
fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
if (IS_ERR(fast_clk)) {
- dev_err(&pdev->dev, "missing fast clock");
+ dev_err(&pdev->dev, "missing fast clock\n");
return PTR_ERR(fast_clk);
}
i2c_dev->fast_clk = fast_clk;
@@ -900,18 +965,27 @@ static int tegra_i2c_probe(struct platform_device *pdev)
goto unprepare_fast_clk;
}
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra_i2c_runtime_resume(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "runtime resume failed\n");
+ goto unprepare_div_clk;
+ }
+ }
+
if (i2c_dev->is_multimaster_mode) {
ret = clk_enable(i2c_dev->div_clk);
if (ret < 0) {
dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
ret);
- goto unprepare_div_clk;
+ goto disable_rpm;
}
}
ret = tegra_i2c_init(i2c_dev);
if (ret) {
- dev_err(&pdev->dev, "Failed to initialize i2c controller");
+ dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
goto disable_div_clk;
}
@@ -925,17 +999,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
i2c_dev->adapter.owner = THIS_MODULE;
i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
- strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
+ strlcpy(i2c_dev->adapter.name, dev_name(&pdev->dev),
sizeof(i2c_dev->adapter.name));
i2c_dev->adapter.dev.parent = &pdev->dev;
i2c_dev->adapter.nr = pdev->id;
i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add I2C adapter\n");
+ if (ret)
goto disable_div_clk;
- }
return 0;
@@ -943,6 +1015,11 @@ disable_div_clk:
if (i2c_dev->is_multimaster_mode)
clk_disable(i2c_dev->div_clk);
+disable_rpm:
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_i2c_runtime_suspend(&pdev->dev);
+
unprepare_div_clk:
clk_unprepare(i2c_dev->div_clk);
@@ -956,11 +1033,16 @@ unprepare_fast_clk:
static int tegra_i2c_remove(struct platform_device *pdev)
{
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
i2c_del_adapter(&i2c_dev->adapter);
if (i2c_dev->is_multimaster_mode)
clk_disable(i2c_dev->div_clk);
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_i2c_runtime_suspend(&pdev->dev);
+
clk_unprepare(i2c_dev->div_clk);
if (!i2c_dev->hw->has_single_clk_source)
clk_unprepare(i2c_dev->fast_clk);
@@ -988,20 +1070,19 @@ static int tegra_i2c_resume(struct device *dev)
i2c_lock_adapter(&i2c_dev->adapter);
ret = tegra_i2c_init(i2c_dev);
-
- if (ret) {
- i2c_unlock_adapter(&i2c_dev->adapter);
- return ret;
- }
-
- i2c_dev->is_suspended = false;
+ if (!ret)
+ i2c_dev->is_suspended = false;
i2c_unlock_adapter(&i2c_dev->adapter);
- return 0;
+ return ret;
}
-static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume);
+static const struct dev_pm_ops tegra_i2c_pm = {
+ SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
+};
#define TEGRA_I2C_PM (&tegra_i2c_pm)
#else
#define TEGRA_I2C_PM NULL
diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
new file mode 100644
index 000000000000..bba5b429f69c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -0,0 +1,259 @@
+/*
+ * Cavium ThunderX i2c driver.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Authors: Fred Martin <fmartin@caviumnetworks.com>
+ * Jan Glauber <jglauber@cavium.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/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+
+#include "i2c-octeon-core.h"
+
+#define DRV_NAME "i2c-thunderx"
+
+#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012
+
+#define SYS_FREQ_DEFAULT 700000000
+
+#define TWSI_INT_ENA_W1C 0x1028
+#define TWSI_INT_ENA_W1S 0x1030
+
+/*
+ * Enable the CORE interrupt.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+/*
+ * Disable the CORE interrupt.
+ */
+static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+static void thunder_i2c_hlc_int_disable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static u32 thunderx_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm thunderx_i2c_algo = {
+ .master_xfer = octeon_i2c_xfer,
+ .functionality = thunderx_i2c_functionality,
+};
+
+static struct i2c_adapter thunderx_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "ThunderX adapter",
+ .algo = &thunderx_i2c_algo,
+};
+
+static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
+{
+ int ret;
+
+ i2c->clk = clk_get(dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ i2c->clk = NULL;
+ goto skip;
+ }
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret)
+ goto skip;
+ i2c->sys_freq = clk_get_rate(i2c->clk);
+
+skip:
+ if (!i2c->sys_freq)
+ i2c->sys_freq = SYS_FREQ_DEFAULT;
+}
+
+static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
+{
+ if (!clk)
+ return;
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+}
+
+static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
+ struct device_node *node)
+{
+ u32 type;
+
+ if (!node)
+ return -EINVAL;
+
+ i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+ if (!i2c->alert_data.irq)
+ return -EINVAL;
+
+ type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
+ i2c->alert_data.alert_edge_triggered =
+ (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
+
+ i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
+ if (!i2c->ara)
+ return -ENODEV;
+ return 0;
+}
+
+static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+ struct device_node *node)
+{
+ /* TODO: ACPI support */
+ if (!acpi_disabled)
+ return -EOPNOTSUPP;
+
+ return thunder_i2c_smbus_setup_of(i2c, node);
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+ if (i2c->ara)
+ i2c_unregister_device(i2c->ara);
+}
+
+static int thunder_i2c_probe_pci(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct octeon_i2c *i2c;
+ int ret;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->roff.sw_twsi = 0x1000;
+ i2c->roff.twsi_int = 0x1010;
+ i2c->roff.sw_twsi_ext = 0x1018;
+
+ i2c->dev = dev;
+ pci_set_drvdata(pdev, i2c);
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = pci_request_regions(pdev, DRV_NAME);
+ if (ret)
+ return ret;
+
+ i2c->twsi_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!i2c->twsi_base)
+ return -EINVAL;
+
+ thunder_i2c_clock_enable(dev, i2c);
+ ret = device_property_read_u32(dev, "clock-frequency", &i2c->twsi_freq);
+ if (ret)
+ i2c->twsi_freq = 100000;
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->int_enable = thunder_i2c_int_enable;
+ i2c->int_disable = thunder_i2c_int_disable;
+ i2c->hlc_int_enable = thunder_i2c_hlc_int_enable;
+ i2c->hlc_int_disable = thunder_i2c_hlc_int_disable;
+
+ ret = pci_enable_msix(pdev, &i2c->i2c_msix, 1);
+ if (ret)
+ goto error;
+
+ ret = devm_request_irq(dev, i2c->i2c_msix.vector, octeon_i2c_isr, 0,
+ DRV_NAME, i2c);
+ if (ret)
+ goto error;
+
+ ret = octeon_i2c_init_lowlevel(i2c);
+ if (ret)
+ goto error;
+
+ octeon_i2c_set_clock(i2c);
+
+ i2c->adap = thunderx_i2c_ops;
+ i2c->adap.retries = 5;
+ i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
+ i2c->adap.dev.parent = dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "Cavium ThunderX i2c adapter at %s", dev_name(dev));
+ i2c_set_adapdata(&i2c->adap, i2c);
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ goto error;
+
+ dev_info(i2c->dev, "Probed. Set system clock to %u\n", i2c->sys_freq);
+
+ ret = thunder_i2c_smbus_setup(i2c, pdev->dev.of_node);
+ if (ret)
+ dev_info(dev, "SMBUS alert not active on this bus\n");
+
+ return 0;
+
+error:
+ thunder_i2c_clock_disable(dev, i2c->clk);
+ return ret;
+}
+
+static void thunder_i2c_remove_pci(struct pci_dev *pdev)
+{
+ struct octeon_i2c *i2c = pci_get_drvdata(pdev);
+
+ thunder_i2c_smbus_remove(i2c);
+ thunder_i2c_clock_disable(&pdev->dev, i2c->clk);
+ i2c_del_adapter(&i2c->adap);
+}
+
+static const struct pci_device_id thunder_i2c_pci_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_TWSI) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, thunder_i2c_pci_id_table);
+
+static struct pci_driver thunder_i2c_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = thunder_i2c_pci_id_table,
+ .probe = thunder_i2c_probe_pci,
+ .remove = thunder_i2c_remove_pci,
+};
+
+module_pci_driver(thunder_i2c_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fred Martin <fmartin@caviumnetworks.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC");
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index aeead0d27d10..db9105e52c79 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -14,6 +14,7 @@
#include <linux/clk.h>
#include <linux/i2c.h>
+#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -348,14 +349,19 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
dev_dbg(&adap->dev, "complete\n");
if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) {
- u32 status = readl(priv->membase + UNIPHIER_FI2C_SR);
-
- if (!(status & UNIPHIER_FI2C_SR_STS) ||
- status & UNIPHIER_FI2C_SR_BB) {
+ u32 status;
+ int ret;
+
+ ret = readl_poll_timeout(priv->membase + UNIPHIER_FI2C_SR,
+ status,
+ (status & UNIPHIER_FI2C_SR_STS) &&
+ !(status & UNIPHIER_FI2C_SR_BB),
+ 1, 20);
+ if (ret) {
dev_err(&adap->dev,
"stop condition was not completed.\n");
uniphier_fi2c_recover(priv);
- return -EBUSY;
+ return ret;
}
}
@@ -455,54 +461,25 @@ static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = {
.unprepare_recovery = uniphier_fi2c_unprepare_recovery,
};
-static int uniphier_fi2c_clk_init(struct device *dev,
- struct uniphier_fi2c_priv *priv)
+static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv,
+ u32 bus_speed, unsigned long clk_rate)
{
- struct device_node *np = dev->of_node;
- unsigned long clk_rate;
- u32 bus_speed, clk_count;
- int ret;
-
- if (of_property_read_u32(np, "clock-frequency", &bus_speed))
- bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
-
- if (!bus_speed) {
- dev_err(dev, "clock-frequency should not be zero\n");
- return -EINVAL;
- }
-
- if (bus_speed > UNIPHIER_FI2C_MAX_SPEED)
- bus_speed = UNIPHIER_FI2C_MAX_SPEED;
-
- /* Get input clk rate through clk driver */
- priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get clock\n");
- return PTR_ERR(priv->clk);
- }
+ u32 tmp;
- ret = clk_prepare_enable(priv->clk);
- if (ret)
- return ret;
-
- clk_rate = clk_get_rate(priv->clk);
- if (!clk_rate) {
- dev_err(dev, "input clock rate should not be zero\n");
- return -EINVAL;
- }
+ tmp = readl(priv->membase + UNIPHIER_FI2C_CR);
+ tmp |= UNIPHIER_FI2C_CR_MST;
+ writel(tmp, priv->membase + UNIPHIER_FI2C_CR);
uniphier_fi2c_reset(priv);
- clk_count = clk_rate / bus_speed;
+ tmp = clk_rate / bus_speed;
- writel(clk_count, priv->membase + UNIPHIER_FI2C_CYC);
- writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_LCTL);
- writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_SSUT);
- writel(clk_count / 16, priv->membase + UNIPHIER_FI2C_DSUT);
+ writel(tmp, priv->membase + UNIPHIER_FI2C_CYC);
+ writel(tmp / 2, priv->membase + UNIPHIER_FI2C_LCTL);
+ writel(tmp / 2, priv->membase + UNIPHIER_FI2C_SSUT);
+ writel(tmp / 16, priv->membase + UNIPHIER_FI2C_DSUT);
uniphier_fi2c_prepare_operation(priv);
-
- return 0;
}
static int uniphier_fi2c_probe(struct platform_device *pdev)
@@ -510,8 +487,9 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct uniphier_fi2c_priv *priv;
struct resource *regs;
- int irq;
- int ret;
+ u32 bus_speed;
+ unsigned long clk_rate;
+ int irq, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -528,6 +506,31 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
return irq;
}
+ if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
+ bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
+
+ if (!bus_speed || bus_speed > UNIPHIER_FI2C_MAX_SPEED) {
+ dev_err(dev, "invalid clock-frequency %d\n", bus_speed);
+ return -EINVAL;
+ }
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(priv->clk);
+ if (!clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
init_completion(&priv->comp);
priv->adap.owner = THIS_MODULE;
priv->adap.algo = &uniphier_fi2c_algo;
@@ -538,9 +541,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&priv->adap, priv);
platform_set_drvdata(pdev, priv);
- ret = uniphier_fi2c_clk_init(dev, priv);
- if (ret)
- goto err;
+ uniphier_fi2c_hw_init(priv, bus_speed, clk_rate);
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
pdev->name, priv);
@@ -550,11 +551,6 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
}
ret = i2c_add_adapter(&priv->adap);
- if (ret) {
- dev_err(dev, "failed to add I2C adapter\n");
- goto err;
- }
-
err:
if (ret)
clk_disable_unprepare(priv->clk);
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 475a5eb514e2..56e92af46ddc 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -316,50 +316,15 @@ static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
.unprepare_recovery = uniphier_i2c_unprepare_recovery,
};
-static int uniphier_i2c_clk_init(struct device *dev,
- struct uniphier_i2c_priv *priv)
+static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv,
+ u32 bus_speed, unsigned long clk_rate)
{
- struct device_node *np = dev->of_node;
- unsigned long clk_rate;
- u32 bus_speed;
- int ret;
-
- if (of_property_read_u32(np, "clock-frequency", &bus_speed))
- bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
-
- if (!bus_speed) {
- dev_err(dev, "clock-frequency should not be zero\n");
- return -EINVAL;
- }
-
- if (bus_speed > UNIPHIER_I2C_MAX_SPEED)
- bus_speed = UNIPHIER_I2C_MAX_SPEED;
-
- /* Get input clk rate through clk driver */
- priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "failed to get clock\n");
- return PTR_ERR(priv->clk);
- }
-
- ret = clk_prepare_enable(priv->clk);
- if (ret)
- return ret;
-
- clk_rate = clk_get_rate(priv->clk);
- if (!clk_rate) {
- dev_err(dev, "input clock rate should not be zero\n");
- return -EINVAL;
- }
-
uniphier_i2c_reset(priv, true);
writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed),
priv->membase + UNIPHIER_I2C_CLK);
uniphier_i2c_reset(priv, false);
-
- return 0;
}
static int uniphier_i2c_probe(struct platform_device *pdev)
@@ -367,8 +332,9 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct uniphier_i2c_priv *priv;
struct resource *regs;
- int irq;
- int ret;
+ u32 bus_speed;
+ unsigned long clk_rate;
+ int irq, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -385,6 +351,31 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
return irq;
}
+ if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
+ bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
+
+ if (!bus_speed || bus_speed > UNIPHIER_I2C_MAX_SPEED) {
+ dev_err(dev, "invalid clock-frequency %d\n", bus_speed);
+ return -EINVAL;
+ }
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(priv->clk);
+ if (!clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
init_completion(&priv->comp);
priv->adap.owner = THIS_MODULE;
priv->adap.algo = &uniphier_i2c_algo;
@@ -395,9 +386,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&priv->adap, priv);
platform_set_drvdata(pdev, priv);
- ret = uniphier_i2c_clk_init(dev, priv);
- if (ret)
- goto err;
+ uniphier_i2c_hw_init(priv, bus_speed, clk_rate);
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
priv);
@@ -407,11 +396,6 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
}
ret = i2c_add_adapter(&priv->adap);
- if (ret) {
- dev_err(dev, "failed to add I2C adapter\n");
- goto err;
- }
-
err:
if (ret)
clk_disable_unprepare(priv->clk);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index e1e3a85596c5..fbd0fd59f312 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -432,10 +432,8 @@ static int wmt_i2c_probe(struct platform_device *pdev)
}
err = i2c_add_adapter(adap);
- if (err) {
- dev_err(&pdev->dev, "failed to add adapter\n");
+ if (err)
return err;
- }
platform_set_drvdata(pdev, i2c_dev);
diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c
index 4233f5695352..263685c7a512 100644
--- a/drivers/i2c/busses/i2c-xgene-slimpro.c
+++ b/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -418,7 +418,6 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adapter, ctx);
rc = i2c_add_adapter(adapter);
if (rc) {
- dev_err(&pdev->dev, "Adapter registeration failed\n");
mbox_free_channel(ctx->mbox_chan);
return rc;
}
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 74f54f2f471f..66bce3b311a1 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -804,7 +804,6 @@ static int xiic_i2c_probe(struct platform_device *pdev)
/* add i2c adapter to i2c tree */
ret = i2c_add_adapter(&i2c->adap);
if (ret) {
- dev_err(&pdev->dev, "Failed to add adapter\n");
xiic_deinit(i2c);
goto err_clk_dis;
}
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
index 55a7bef1b2e1..2a972ed7aa0d 100644
--- a/drivers/i2c/busses/i2c-xlp9xx.c
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -400,10 +400,8 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&priv->adapter, priv);
err = i2c_add_adapter(&priv->adapter);
- if (err) {
- dev_err(&pdev->dev, "failed to add I2C adapter!\n");
+ if (err)
return err;
- }
platform_set_drvdata(pdev, priv);
dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
index 613c3a4f2c51..0968f59b6df5 100644
--- a/drivers/i2c/busses/i2c-xlr.c
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -432,10 +432,8 @@ static int xlr_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&priv->adap, priv);
ret = i2c_add_numbered_adapter(&priv->adap);
- if (ret < 0) {
- dev_err(&priv->adap.dev, "Failed to add i2c bus.\n");
+ if (ret < 0)
return ret;
- }
platform_set_drvdata(pdev, priv);
dev_info(&priv->adap.dev, "Added I2C Bus.\n");
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index da3a02ef4a31..98fffa3a09f7 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -88,7 +88,7 @@ void i2c_transfer_trace_unreg(void)
}
#if defined(CONFIG_ACPI)
-struct acpi_i2c_handler_data {
+struct i2c_acpi_handler_data {
struct acpi_connection_info info;
struct i2c_adapter *adapter;
};
@@ -103,15 +103,18 @@ struct gsb_buffer {
};
} __packed;
-struct acpi_i2c_lookup {
+struct i2c_acpi_lookup {
struct i2c_board_info *info;
acpi_handle adapter_handle;
acpi_handle device_handle;
+ acpi_handle search_handle;
+ u32 speed;
+ u32 min_speed;
};
-static int acpi_i2c_fill_info(struct acpi_resource *ares, void *data)
+static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
{
- struct acpi_i2c_lookup *lookup = data;
+ struct i2c_acpi_lookup *lookup = data;
struct i2c_board_info *info = lookup->info;
struct acpi_resource_i2c_serialbus *sb;
acpi_status status;
@@ -130,19 +133,18 @@ static int acpi_i2c_fill_info(struct acpi_resource *ares, void *data)
return 1;
info->addr = sb->slave_address;
+ lookup->speed = sb->connection_speed;
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
return 1;
}
-static int acpi_i2c_get_info(struct acpi_device *adev,
- struct i2c_board_info *info,
- acpi_handle *adapter_handle)
+static int i2c_acpi_do_lookup(struct acpi_device *adev,
+ struct i2c_acpi_lookup *lookup)
{
+ struct i2c_board_info *info = lookup->info;
struct list_head resource_list;
- struct resource_entry *entry;
- struct acpi_i2c_lookup lookup;
int ret;
if (acpi_bus_get_status(adev) || !adev->status.present ||
@@ -150,24 +152,58 @@ static int acpi_i2c_get_info(struct acpi_device *adev,
return -EINVAL;
memset(info, 0, sizeof(*info));
- info->fwnode = acpi_fwnode_handle(adev);
-
- memset(&lookup, 0, sizeof(lookup));
- lookup.device_handle = acpi_device_handle(adev);
- lookup.info = info;
+ lookup->device_handle = acpi_device_handle(adev);
/* Look up for I2cSerialBus resource */
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
- acpi_i2c_fill_info, &lookup);
+ i2c_acpi_fill_info, lookup);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0 || !info->addr)
return -EINVAL;
- *adapter_handle = lookup.adapter_handle;
+ return 0;
+}
+
+static int i2c_acpi_get_info(struct acpi_device *adev,
+ struct i2c_board_info *info,
+ struct i2c_adapter *adapter,
+ acpi_handle *adapter_handle)
+{
+ struct list_head resource_list;
+ struct resource_entry *entry;
+ struct i2c_acpi_lookup lookup;
+ int ret;
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.info = info;
+
+ ret = i2c_acpi_do_lookup(adev, &lookup);
+ if (ret)
+ return ret;
+
+ if (adapter) {
+ /* The adapter must match the one in I2cSerialBus() connector */
+ if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle)
+ return -ENODEV;
+ } else {
+ struct acpi_device *adapter_adev;
+
+ /* The adapter must be present */
+ if (acpi_bus_get_device(lookup.adapter_handle, &adapter_adev))
+ return -ENODEV;
+ if (acpi_bus_get_status(adapter_adev) ||
+ !adapter_adev->status.present)
+ return -ENODEV;
+ }
+
+ info->fwnode = acpi_fwnode_handle(adev);
+ if (adapter_handle)
+ *adapter_handle = lookup.adapter_handle;
/* Then fill IRQ number if any */
+ INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (ret < 0)
return -EINVAL;
@@ -186,7 +222,7 @@ static int acpi_i2c_get_info(struct acpi_device *adev,
return 0;
}
-static void acpi_i2c_register_device(struct i2c_adapter *adapter,
+static void i2c_acpi_register_device(struct i2c_adapter *adapter,
struct acpi_device *adev,
struct i2c_board_info *info)
{
@@ -201,39 +237,35 @@ static void acpi_i2c_register_device(struct i2c_adapter *adapter,
}
}
-static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
+static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level,
void *data, void **return_value)
{
struct i2c_adapter *adapter = data;
struct acpi_device *adev;
- acpi_handle adapter_handle;
struct i2c_board_info info;
if (acpi_bus_get_device(handle, &adev))
return AE_OK;
- if (acpi_i2c_get_info(adev, &info, &adapter_handle))
+ if (i2c_acpi_get_info(adev, &info, adapter, NULL))
return AE_OK;
- if (adapter_handle != ACPI_HANDLE(&adapter->dev))
- return AE_OK;
-
- acpi_i2c_register_device(adapter, adev, &info);
+ i2c_acpi_register_device(adapter, adev, &info);
return AE_OK;
}
-#define ACPI_I2C_MAX_SCAN_DEPTH 32
+#define I2C_ACPI_MAX_SCAN_DEPTH 32
/**
- * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
+ * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter
* @adap: pointer to adapter
*
* Enumerate all I2C slave devices behind this adapter by walking the ACPI
* namespace. When a device is found it will be added to the Linux device
* model and bound to the corresponding ACPI handle.
*/
-static void acpi_i2c_register_devices(struct i2c_adapter *adap)
+static void i2c_acpi_register_devices(struct i2c_adapter *adap)
{
acpi_status status;
@@ -241,14 +273,72 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap)
return;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_I2C_MAX_SCAN_DEPTH,
- acpi_i2c_add_device, NULL,
+ I2C_ACPI_MAX_SCAN_DEPTH,
+ i2c_acpi_add_device, NULL,
adap, NULL);
if (ACPI_FAILURE(status))
dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
}
-static int acpi_i2c_match_adapter(struct device *dev, void *data)
+static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct i2c_acpi_lookup *lookup = data;
+ struct acpi_device *adev;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+
+ if (i2c_acpi_do_lookup(adev, lookup))
+ return AE_OK;
+
+ if (lookup->search_handle != lookup->adapter_handle)
+ return AE_OK;
+
+ if (lookup->speed <= lookup->min_speed)
+ lookup->min_speed = lookup->speed;
+
+ return AE_OK;
+}
+
+/**
+ * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI
+ * @dev: The device owning the bus
+ *
+ * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves
+ * devices connected to this bus and use the speed of slowest device.
+ *
+ * Returns the speed in Hz or zero
+ */
+u32 i2c_acpi_find_bus_speed(struct device *dev)
+{
+ struct i2c_acpi_lookup lookup;
+ struct i2c_board_info dummy;
+ acpi_status status;
+
+ if (!has_acpi_companion(dev))
+ return 0;
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.search_handle = ACPI_HANDLE(dev);
+ lookup.min_speed = UINT_MAX;
+ lookup.info = &dummy;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ I2C_ACPI_MAX_SCAN_DEPTH,
+ i2c_acpi_lookup_speed, NULL,
+ &lookup, NULL);
+
+ if (ACPI_FAILURE(status)) {
+ dev_warn(dev, "unable to find I2C bus speed from ACPI\n");
+ return 0;
+ }
+
+ return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0;
+}
+EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
+
+static int i2c_acpi_match_adapter(struct device *dev, void *data)
{
struct i2c_adapter *adapter = i2c_verify_adapter(dev);
@@ -258,29 +348,29 @@ static int acpi_i2c_match_adapter(struct device *dev, void *data)
return ACPI_HANDLE(dev) == (acpi_handle)data;
}
-static int acpi_i2c_match_device(struct device *dev, void *data)
+static int i2c_acpi_match_device(struct device *dev, void *data)
{
return ACPI_COMPANION(dev) == data;
}
-static struct i2c_adapter *acpi_i2c_find_adapter_by_handle(acpi_handle handle)
+static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
{
struct device *dev;
dev = bus_find_device(&i2c_bus_type, NULL, handle,
- acpi_i2c_match_adapter);
+ i2c_acpi_match_adapter);
return dev ? i2c_verify_adapter(dev) : NULL;
}
-static struct i2c_client *acpi_i2c_find_client_by_adev(struct acpi_device *adev)
+static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
{
struct device *dev;
- dev = bus_find_device(&i2c_bus_type, NULL, adev, acpi_i2c_match_device);
+ dev = bus_find_device(&i2c_bus_type, NULL, adev, i2c_acpi_match_device);
return dev ? i2c_verify_client(dev) : NULL;
}
-static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value,
+static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
void *arg)
{
struct acpi_device *adev = arg;
@@ -291,20 +381,20 @@ static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value,
switch (value) {
case ACPI_RECONFIG_DEVICE_ADD:
- if (acpi_i2c_get_info(adev, &info, &adapter_handle))
+ if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle))
break;
- adapter = acpi_i2c_find_adapter_by_handle(adapter_handle);
+ adapter = i2c_acpi_find_adapter_by_handle(adapter_handle);
if (!adapter)
break;
- acpi_i2c_register_device(adapter, adev, &info);
+ i2c_acpi_register_device(adapter, adev, &info);
break;
case ACPI_RECONFIG_DEVICE_REMOVE:
if (!acpi_device_enumerated(adev))
break;
- client = acpi_i2c_find_client_by_adev(adev);
+ client = i2c_acpi_find_client_by_adev(adev);
if (!client)
break;
@@ -317,10 +407,10 @@ static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value,
}
static struct notifier_block i2c_acpi_notifier = {
- .notifier_call = acpi_i2c_notify,
+ .notifier_call = i2c_acpi_notify,
};
#else /* CONFIG_ACPI */
-static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
+static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
extern struct notifier_block i2c_acpi_notifier;
#endif /* CONFIG_ACPI */
@@ -386,12 +476,12 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
}
static acpi_status
-acpi_i2c_space_handler(u32 function, acpi_physical_address command,
+i2c_acpi_space_handler(u32 function, acpi_physical_address command,
u32 bits, u64 *value64,
void *handler_context, void *region_context)
{
struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
- struct acpi_i2c_handler_data *data = handler_context;
+ struct i2c_acpi_handler_data *data = handler_context;
struct acpi_connection_info *info = &data->info;
struct acpi_resource_i2c_serialbus *sb;
struct i2c_adapter *adapter = data->adapter;
@@ -510,10 +600,10 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
}
-static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
+static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter)
{
acpi_handle handle;
- struct acpi_i2c_handler_data *data;
+ struct i2c_acpi_handler_data *data;
acpi_status status;
if (!adapter->dev.parent)
@@ -524,7 +614,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
if (!handle)
return -ENODEV;
- data = kzalloc(sizeof(struct acpi_i2c_handler_data),
+ data = kzalloc(sizeof(struct i2c_acpi_handler_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -538,7 +628,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
status = acpi_install_address_space_handler(handle,
ACPI_ADR_SPACE_GSBUS,
- &acpi_i2c_space_handler,
+ &i2c_acpi_space_handler,
NULL,
data);
if (ACPI_FAILURE(status)) {
@@ -552,10 +642,10 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
return 0;
}
-static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
+static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter)
{
acpi_handle handle;
- struct acpi_i2c_handler_data *data;
+ struct i2c_acpi_handler_data *data;
acpi_status status;
if (!adapter->dev.parent)
@@ -568,7 +658,7 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
acpi_remove_address_space_handler(handle,
ACPI_ADR_SPACE_GSBUS,
- &acpi_i2c_space_handler);
+ &i2c_acpi_space_handler);
status = acpi_bus_get_private_data(handle, (void **)&data);
if (ACPI_SUCCESS(status))
@@ -577,10 +667,10 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
acpi_bus_detach_private_data(handle);
}
#else /* CONFIG_ACPI_I2C_OPREGION */
-static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
+static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter)
{ }
-static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
+static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter)
{ return 0; }
#endif /* CONFIG_ACPI_I2C_OPREGION */
@@ -853,7 +943,7 @@ static int i2c_device_probe(struct device *dev)
status = 0;
if (status)
- dev_warn(&client->dev, "failed to set up wakeup irq");
+ dev_warn(&client->dev, "failed to set up wakeup irq\n");
}
dev_dbg(dev, "probe\n");
@@ -1208,8 +1298,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
return client;
out_err:
- dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
- "(%d)\n", client->name, client->addr, status);
+ dev_err(&adap->dev,
+ "Failed to register i2c client %s at 0x%02x (%d)\n",
+ client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
@@ -1335,21 +1426,19 @@ static void i2c_adapter_dev_release(struct device *dev)
complete(&adap->dev_released);
}
-/*
- * This function is only needed for mutex_lock_nested, so it is never
- * called unless locking correctness checking is enabled. Thus we
- * make it inline to avoid a compiler warning. That's what gcc ends up
- * doing anyway.
- */
-static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
+unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
{
unsigned int depth = 0;
while ((adapter = i2c_parent_is_i2c_adapter(adapter)))
depth++;
+ WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES,
+ "adapter depth exceeds lockdep subclass limit\n");
+
return depth;
}
+EXPORT_SYMBOL_GPL(i2c_adapter_depth);
/*
* Let users instantiate I2C devices through sysfs. This can be used when
@@ -1678,8 +1767,8 @@ static int i2c_do_add_adapter(struct i2c_driver *driver,
if (driver->attach_adapter) {
dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
driver->driver.name);
- dev_warn(&adap->dev, "Please use another way to instantiate "
- "your i2c_client\n");
+ dev_warn(&adap->dev,
+ "Please use another way to instantiate your i2c_client\n");
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
@@ -1691,6 +1780,12 @@ static int __process_new_adapter(struct device_driver *d, void *data)
return i2c_do_add_adapter(to_i2c_driver(d), data);
}
+static const struct i2c_lock_operations i2c_adapter_lock_ops = {
+ .lock_bus = i2c_adapter_lock_bus,
+ .trylock_bus = i2c_adapter_trylock_bus,
+ .unlock_bus = i2c_adapter_unlock_bus,
+};
+
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = -EINVAL;
@@ -1710,11 +1805,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list;
}
- if (!adap->lock_bus) {
- adap->lock_bus = i2c_adapter_lock_bus;
- adap->trylock_bus = i2c_adapter_trylock_bus;
- adap->unlock_bus = i2c_adapter_unlock_bus;
- }
+ if (!adap->lock_ops)
+ adap->lock_ops = &i2c_adapter_lock_ops;
rt_mutex_init(&adap->bus_lock);
rt_mutex_init(&adap->mux_lock);
@@ -1752,8 +1844,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
/* create pre-declared device nodes */
of_i2c_register_devices(adap);
- acpi_i2c_register_devices(adap);
- acpi_i2c_install_space_handler(adap);
+ i2c_acpi_register_devices(adap);
+ i2c_acpi_install_space_handler(adap);
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
@@ -1925,7 +2017,7 @@ void i2c_del_adapter(struct i2c_adapter *adap)
return;
}
- acpi_i2c_remove_space_handler(adap);
+ i2c_acpi_remove_space_handler(adap);
/* Tell drivers about this removal */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap,
@@ -2451,15 +2543,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (adap->algo->master_xfer) {
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
- dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
- "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
- ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+ dev_dbg(&adap->dev,
+ "master_xfer[%d] %c, addr=0x%02x, len=%d%s\n",
+ ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W',
+ msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
if (in_atomic() || irqs_disabled()) {
- ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
+ ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
@@ -2619,9 +2712,9 @@ static int i2c_detect_address(struct i2c_client *temp_client,
/* Consistency check */
if (info.type[0] == '\0') {
- dev_err(&adapter->dev, "%s detection function provided "
- "no name for 0x%x\n", driver->driver.name,
- addr);
+ dev_err(&adapter->dev,
+ "%s detection function provided no name for 0x%x\n",
+ driver->driver.name, addr);
} else {
struct i2c_client *client;
@@ -2659,9 +2752,8 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
/* Warn that the adapter lost class based instantiation */
if (adapter->class == I2C_CLASS_DEPRECATED) {
dev_dbg(&adapter->dev,
- "This adapter dropped support for I2C classes and "
- "won't auto-detect %s devices anymore. If you need it, check "
- "'Documentation/i2c/instantiating-devices' for alternatives.\n",
+ "This adapter dropped support for I2C classes and won't auto-detect %s devices anymore. "
+ "If you need it, check 'Documentation/i2c/instantiating-devices' for alternatives.\n",
driver->driver.name);
return 0;
}
@@ -2677,8 +2769,9 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
temp_client->adapter = adapter;
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
- dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
- "addr 0x%02x\n", adap_id, address_list[i]);
+ dev_dbg(&adapter->dev,
+ "found normal entry for adapter %d, addr 0x%02x\n",
+ adap_id, address_list[i]);
temp_client->addr = address_list[i];
err = i2c_detect_address(temp_client, driver);
if (unlikely(err))
@@ -2710,15 +2803,16 @@ i2c_new_probed_device(struct i2c_adapter *adap,
for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
/* Check address validity */
if (i2c_check_7bit_addr_validity_strict(addr_list[i]) < 0) {
- dev_warn(&adap->dev, "Invalid 7-bit address "
- "0x%02x\n", addr_list[i]);
+ dev_warn(&adap->dev, "Invalid 7-bit address 0x%02x\n",
+ addr_list[i]);
continue;
}
/* Check address availability (7 bit, no need to encode flags) */
if (i2c_check_addr_busy(adap, addr_list[i])) {
- dev_dbg(&adap->dev, "Address 0x%02x already in "
- "use, not probing\n", addr_list[i]);
+ dev_dbg(&adap->dev,
+ "Address 0x%02x already in use, not probing\n",
+ addr_list[i]);
continue;
}
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 8eee98634cda..83768e85a919 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -159,7 +159,7 @@ static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
return 0; /* mux_lock not locked, failure */
if (!(flags & I2C_LOCK_ROOT_ADAPTER))
return 1; /* we only want mux_lock, success */
- if (parent->trylock_bus(parent, flags))
+ if (i2c_trylock_bus(parent, flags))
return 1; /* parent locked too, success */
rt_mutex_unlock(&parent->mux_lock);
return 0; /* parent not locked, failure */
@@ -193,7 +193,7 @@ static int i2c_parent_trylock_bus(struct i2c_adapter *adapter,
if (!rt_mutex_trylock(&parent->mux_lock))
return 0; /* mux_lock not locked, failure */
- if (parent->trylock_bus(parent, flags))
+ if (i2c_trylock_bus(parent, flags))
return 1; /* parent locked too, success */
rt_mutex_unlock(&parent->mux_lock);
return 0; /* parent not locked, failure */
@@ -255,6 +255,10 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
muxc->dev = dev;
if (flags & I2C_MUX_LOCKED)
muxc->mux_locked = true;
+ if (flags & I2C_MUX_ARBITRATOR)
+ muxc->arbitrator = true;
+ if (flags & I2C_MUX_GATE)
+ muxc->gate = true;
muxc->select = select;
muxc->deselect = deselect;
muxc->max_adapters = max_adapters;
@@ -263,6 +267,18 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
}
EXPORT_SYMBOL_GPL(i2c_mux_alloc);
+static const struct i2c_lock_operations i2c_mux_lock_ops = {
+ .lock_bus = i2c_mux_lock_bus,
+ .trylock_bus = i2c_mux_trylock_bus,
+ .unlock_bus = i2c_mux_unlock_bus,
+};
+
+static const struct i2c_lock_operations i2c_parent_lock_ops = {
+ .lock_bus = i2c_parent_lock_bus,
+ .trylock_bus = i2c_parent_trylock_bus,
+ .unlock_bus = i2c_parent_unlock_bus,
+};
+
int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
u32 force_nr, u32 chan_id,
unsigned int class)
@@ -312,15 +328,10 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
priv->adap.retries = parent->retries;
priv->adap.timeout = parent->timeout;
priv->adap.quirks = parent->quirks;
- if (muxc->mux_locked) {
- priv->adap.lock_bus = i2c_mux_lock_bus;
- priv->adap.trylock_bus = i2c_mux_trylock_bus;
- priv->adap.unlock_bus = i2c_mux_unlock_bus;
- } else {
- priv->adap.lock_bus = i2c_parent_lock_bus;
- priv->adap.trylock_bus = i2c_parent_trylock_bus;
- priv->adap.unlock_bus = i2c_parent_unlock_bus;
- }
+ if (muxc->mux_locked)
+ priv->adap.lock_ops = &i2c_mux_lock_ops;
+ else
+ priv->adap.lock_ops = &i2c_parent_lock_ops;
/* Sanity check on class */
if (i2c_mux_parent_classes(parent) & class)
@@ -335,18 +346,42 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
* nothing if !CONFIG_OF.
*/
if (muxc->dev->of_node) {
- struct device_node *child;
+ struct device_node *dev_node = muxc->dev->of_node;
+ struct device_node *mux_node, *child = NULL;
u32 reg;
- for_each_child_of_node(muxc->dev->of_node, child) {
- ret = of_property_read_u32(child, "reg", &reg);
- if (ret)
- continue;
- if (chan_id == reg) {
- priv->adap.dev.of_node = child;
- break;
+ if (muxc->arbitrator)
+ mux_node = of_get_child_by_name(dev_node, "i2c-arb");
+ else if (muxc->gate)
+ mux_node = of_get_child_by_name(dev_node, "i2c-gate");
+ else
+ mux_node = of_get_child_by_name(dev_node, "i2c-mux");
+
+ if (mux_node) {
+ /* A "reg" property indicates an old-style DT entry */
+ if (!of_property_read_u32(mux_node, "reg", &reg)) {
+ of_node_put(mux_node);
+ mux_node = NULL;
+ }
+ }
+
+ if (!mux_node)
+ mux_node = of_node_get(dev_node);
+ else if (muxc->arbitrator || muxc->gate)
+ child = of_node_get(mux_node);
+
+ if (!child) {
+ for_each_child_of_node(mux_node, child) {
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret)
+ continue;
+ if (chan_id == reg)
+ break;
}
}
+
+ priv->adap.dev.of_node = child;
+ of_node_put(mux_node);
}
/*
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index a90bbc4037dd..86fc2d4c081b 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -130,7 +130,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
return -EINVAL;
}
- muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0,
+ muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), I2C_MUX_ARBITRATOR,
i2c_arbitrator_select, i2c_arbitrator_deselect);
if (!muxc)
return -ENOMEM;
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 3cb8af635db5..4ea7e691afc7 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -85,6 +85,13 @@ static const struct i2c_device_id pca9541_id[] = {
MODULE_DEVICE_TABLE(i2c, pca9541_id);
+#ifdef CONFIG_OF
+static const struct of_device_id pca9541_of_match[] = {
+ { .compatible = "nxp,pca9541" },
+ {}
+};
+#endif
+
/*
* Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
* as they will try to lock the adapter a second time.
@@ -349,7 +356,8 @@ static int pca9541_probe(struct i2c_client *client,
force = 0;
if (pdata)
force = pdata->modes[0].adap_id;
- muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0,
+ muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data),
+ I2C_MUX_ARBITRATOR,
pca9541_select_chan, pca9541_release_chan);
if (!muxc)
return -ENOMEM;
@@ -382,6 +390,7 @@ static int pca9541_remove(struct i2c_client *client)
static struct i2c_driver pca9541_driver = {
.driver = {
.name = "pca9541",
+ .of_match_table = of_match_ptr(pca9541_of_match),
},
.probe = pca9541_probe,
.remove = pca9541_remove,
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 3278ebf1cc5c..1091346f2480 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -42,6 +42,7 @@
#include <linux/i2c/pca954x.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -58,14 +59,6 @@ enum pca_type {
pca_9548,
};
-struct pca954x {
- enum pca_type type;
-
- u8 last_chan; /* last register value */
- u8 deselect;
- struct i2c_client *client;
-};
-
struct chip_desc {
u8 nchans;
u8 enable; /* used for muxes only */
@@ -75,6 +68,14 @@ struct chip_desc {
} muxtype;
};
+struct pca954x {
+ const struct chip_desc *chip;
+
+ u8 last_chan; /* last register value */
+ u8 deselect;
+ struct i2c_client *client;
+};
+
/* Provide specs for the PCA954x types we know about */
static const struct chip_desc chips[] = {
[pca_9540] = {
@@ -119,6 +120,20 @@ static const struct i2c_device_id pca954x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca954x_id);
+#ifdef CONFIG_OF
+static const struct of_device_id pca954x_of_match[] = {
+ { .compatible = "nxp,pca9540", .data = &chips[pca_9540] },
+ { .compatible = "nxp,pca9542", .data = &chips[pca_9542] },
+ { .compatible = "nxp,pca9543", .data = &chips[pca_9543] },
+ { .compatible = "nxp,pca9544", .data = &chips[pca_9544] },
+ { .compatible = "nxp,pca9545", .data = &chips[pca_9545] },
+ { .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
+ { .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
+ { .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
+ {}
+};
+#endif
+
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
for this as they will try to lock adapter a second time */
static int pca954x_reg_write(struct i2c_adapter *adap,
@@ -151,7 +166,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
- const struct chip_desc *chip = &chips[data->type];
+ const struct chip_desc *chip = data->chip;
u8 regval;
int ret = 0;
@@ -197,6 +212,7 @@ static int pca954x_probe(struct i2c_client *client,
int num, force, class;
struct i2c_mux_core *muxc;
struct pca954x *data;
+ const struct of_device_id *match;
int ret;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
@@ -226,14 +242,19 @@ static int pca954x_probe(struct i2c_client *client,
return -ENODEV;
}
- data->type = id->driver_data;
+ match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev);
+ if (match)
+ data->chip = of_device_get_match_data(&client->dev);
+ else
+ data->chip = &chips[id->driver_data];
+
data->last_chan = 0; /* force the first selection */
idle_disconnect_dt = of_node &&
of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
/* Now create an adapter for each channel */
- for (num = 0; num < chips[data->type].nchans; num++) {
+ for (num = 0; num < data->chip->nchans; num++) {
bool idle_disconnect_pd = false;
force = 0; /* dynamic adap number */
@@ -263,7 +284,7 @@ static int pca954x_probe(struct i2c_client *client,
dev_info(&client->dev,
"registered %d multiplexed busses for I2C %s %s\n",
- num, chips[data->type].muxtype == pca954x_ismux
+ num, data->chip->muxtype == pca954x_ismux
? "mux" : "switch", client->name);
return 0;
@@ -299,6 +320,7 @@ static struct i2c_driver pca954x_driver = {
.driver = {
.name = "pca954x",
.pm = &pca954x_pm,
+ .of_match_table = of_match_ptr(pca954x_of_match),
},
.probe = pca954x_probe,
.remove = pca954x_remove,
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 67ec58f9ef99..4466a2f969d7 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -863,8 +863,8 @@ static struct cpuidle_state dnv_cstates[] = {
*
* Must be called under local_irq_disable().
*/
-static int intel_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static __cpuidle int intel_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
unsigned long ecx = 1; /* break on interrupt flag */
struct cpuidle_state *state = &drv->states[index];
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index e9b7dc037ff8..19a418a1b631 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -74,6 +74,7 @@ source "drivers/infiniband/hw/mlx5/Kconfig"
source "drivers/infiniband/hw/nes/Kconfig"
source "drivers/infiniband/hw/ocrdma/Kconfig"
source "drivers/infiniband/hw/usnic/Kconfig"
+source "drivers/infiniband/hw/hns/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 1374541a4528..b136d3acc5bd 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -800,7 +800,7 @@ static struct notifier_block nb = {
int addr_init(void)
{
- addr_wq = create_singlethread_workqueue("ib_addr");
+ addr_wq = alloc_workqueue("ib_addr", WQ_MEM_RECLAIM, 0);
if (!addr_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 5f65a78b27c9..36bf50ebb187 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -4369,7 +4369,7 @@ static int __init cma_init(void)
{
int ret;
- cma_wq = create_singlethread_workqueue("rdma_cm");
+ cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM);
if (!cma_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 357624f8b9d3..5495e22839a7 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -1160,7 +1160,7 @@ static int __init iw_cm_init(void)
if (ret)
pr_err("iw_cm: couldn't register netlink callbacks\n");
- iwcm_wq = create_singlethread_workqueue("iw_cm_wq");
+ iwcm_wq = alloc_ordered_workqueue("iw_cm_wq", WQ_MEM_RECLAIM);
if (!iwcm_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 2d49228f28b2..40cbd6bdb73b 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -3160,7 +3160,7 @@ static int ib_mad_port_open(struct ib_device *device,
goto error3;
}
- port_priv->pd = ib_alloc_pd(device);
+ port_priv->pd = ib_alloc_pd(device, 0);
if (IS_ERR(port_priv->pd)) {
dev_err(&device->dev, "Couldn't create ib_mad PD\n");
ret = PTR_ERR(port_priv->pd);
@@ -3177,7 +3177,7 @@ static int ib_mad_port_open(struct ib_device *device,
goto error7;
snprintf(name, sizeof name, "ib_mad%d", port_num);
- port_priv->wq = create_singlethread_workqueue(name);
+ port_priv->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
if (!port_priv->wq) {
ret = -ENOMEM;
goto error8;
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 51c79b2fb0b8..e51b739f6ea3 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -873,7 +873,7 @@ int mcast_init(void)
{
int ret;
- mcast_wq = create_singlethread_workqueue("ib_mcast");
+ mcast_wq = alloc_ordered_workqueue("ib_mcast", WQ_MEM_RECLAIM);
if (!mcast_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index b9bf7aa055e7..81b742ca1639 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -2015,7 +2015,7 @@ int ib_sa_init(void)
goto err2;
}
- ib_nl_wq = create_singlethread_workqueue("ib_nl_sa_wq");
+ ib_nl_wq = alloc_ordered_workqueue("ib_nl_sa_wq", WQ_MEM_RECLAIM);
if (!ib_nl_wq) {
ret = -ENOMEM;
goto err3;
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 15defefecb4f..c1fb545e8d78 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -1193,7 +1193,7 @@ static ssize_t set_node_desc(struct device *device,
if (!dev->modify_device)
return -EIO;
- memcpy(desc.node_desc, buf, min_t(int, count, 64));
+ memcpy(desc.node_desc, buf, min_t(int, count, IB_DEVICE_NODE_DESC_MAX));
ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
if (ret)
return ret;
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 2825ece91d3c..9520154f1d7c 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -1638,7 +1638,8 @@ static int ucma_open(struct inode *inode, struct file *filp)
if (!file)
return -ENOMEM;
- file->close_wq = create_singlethread_workqueue("ucma_close_id");
+ file->close_wq = alloc_ordered_workqueue("ucma_close_id",
+ WQ_MEM_RECLAIM);
if (!file->close_wq) {
kfree(file);
return -ENOMEM;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index f6647318138d..cb3f515a2285 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -571,7 +571,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
pd->device = ib_dev;
pd->uobject = uobj;
- pd->local_mr = NULL;
+ pd->__internal_mr = NULL;
atomic_set(&pd->usecnt, 0);
uobj->object = pd;
@@ -3078,51 +3078,102 @@ out_put:
return ret ? ret : in_len;
}
+static size_t kern_spec_filter_sz(struct ib_uverbs_flow_spec_hdr *spec)
+{
+ /* Returns user space filter size, includes padding */
+ return (spec->size - sizeof(struct ib_uverbs_flow_spec_hdr)) / 2;
+}
+
+static ssize_t spec_filter_size(void *kern_spec_filter, u16 kern_filter_size,
+ u16 ib_real_filter_sz)
+{
+ /*
+ * User space filter structures must be 64 bit aligned, otherwise this
+ * may pass, but we won't handle additional new attributes.
+ */
+
+ if (kern_filter_size > ib_real_filter_sz) {
+ if (memchr_inv(kern_spec_filter +
+ ib_real_filter_sz, 0,
+ kern_filter_size - ib_real_filter_sz))
+ return -EINVAL;
+ return ib_real_filter_sz;
+ }
+ return kern_filter_size;
+}
+
static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec,
union ib_flow_spec *ib_spec)
{
+ ssize_t actual_filter_sz;
+ ssize_t kern_filter_sz;
+ ssize_t ib_filter_sz;
+ void *kern_spec_mask;
+ void *kern_spec_val;
+
if (kern_spec->reserved)
return -EINVAL;
ib_spec->type = kern_spec->type;
+ kern_filter_sz = kern_spec_filter_sz(&kern_spec->hdr);
+ /* User flow spec size must be aligned to 4 bytes */
+ if (kern_filter_sz != ALIGN(kern_filter_sz, 4))
+ return -EINVAL;
+
+ kern_spec_val = (void *)kern_spec +
+ sizeof(struct ib_uverbs_flow_spec_hdr);
+ kern_spec_mask = kern_spec_val + kern_filter_sz;
+
switch (ib_spec->type) {
case IB_FLOW_SPEC_ETH:
- ib_spec->eth.size = sizeof(struct ib_flow_spec_eth);
- if (ib_spec->eth.size != kern_spec->eth.size)
+ ib_filter_sz = offsetof(struct ib_flow_eth_filter, real_sz);
+ actual_filter_sz = spec_filter_size(kern_spec_mask,
+ kern_filter_sz,
+ ib_filter_sz);
+ if (actual_filter_sz <= 0)
return -EINVAL;
- memcpy(&ib_spec->eth.val, &kern_spec->eth.val,
- sizeof(struct ib_flow_eth_filter));
- memcpy(&ib_spec->eth.mask, &kern_spec->eth.mask,
- sizeof(struct ib_flow_eth_filter));
+ ib_spec->size = sizeof(struct ib_flow_spec_eth);
+ memcpy(&ib_spec->eth.val, kern_spec_val, actual_filter_sz);
+ memcpy(&ib_spec->eth.mask, kern_spec_mask, actual_filter_sz);
break;
case IB_FLOW_SPEC_IPV4:
- ib_spec->ipv4.size = sizeof(struct ib_flow_spec_ipv4);
- if (ib_spec->ipv4.size != kern_spec->ipv4.size)
+ ib_filter_sz = offsetof(struct ib_flow_ipv4_filter, real_sz);
+ actual_filter_sz = spec_filter_size(kern_spec_mask,
+ kern_filter_sz,
+ ib_filter_sz);
+ if (actual_filter_sz <= 0)
return -EINVAL;
- memcpy(&ib_spec->ipv4.val, &kern_spec->ipv4.val,
- sizeof(struct ib_flow_ipv4_filter));
- memcpy(&ib_spec->ipv4.mask, &kern_spec->ipv4.mask,
- sizeof(struct ib_flow_ipv4_filter));
+ ib_spec->size = sizeof(struct ib_flow_spec_ipv4);
+ memcpy(&ib_spec->ipv4.val, kern_spec_val, actual_filter_sz);
+ memcpy(&ib_spec->ipv4.mask, kern_spec_mask, actual_filter_sz);
break;
case IB_FLOW_SPEC_IPV6:
- ib_spec->ipv6.size = sizeof(struct ib_flow_spec_ipv6);
- if (ib_spec->ipv6.size != kern_spec->ipv6.size)
+ ib_filter_sz = offsetof(struct ib_flow_ipv6_filter, real_sz);
+ actual_filter_sz = spec_filter_size(kern_spec_mask,
+ kern_filter_sz,
+ ib_filter_sz);
+ if (actual_filter_sz <= 0)
+ return -EINVAL;
+ ib_spec->size = sizeof(struct ib_flow_spec_ipv6);
+ memcpy(&ib_spec->ipv6.val, kern_spec_val, actual_filter_sz);
+ memcpy(&ib_spec->ipv6.mask, kern_spec_mask, actual_filter_sz);
+
+ if ((ntohl(ib_spec->ipv6.mask.flow_label)) >= BIT(20) ||
+ (ntohl(ib_spec->ipv6.val.flow_label)) >= BIT(20))
return -EINVAL;
- memcpy(&ib_spec->ipv6.val, &kern_spec->ipv6.val,
- sizeof(struct ib_flow_ipv6_filter));
- memcpy(&ib_spec->ipv6.mask, &kern_spec->ipv6.mask,
- sizeof(struct ib_flow_ipv6_filter));
break;
case IB_FLOW_SPEC_TCP:
case IB_FLOW_SPEC_UDP:
- ib_spec->tcp_udp.size = sizeof(struct ib_flow_spec_tcp_udp);
- if (ib_spec->tcp_udp.size != kern_spec->tcp_udp.size)
+ ib_filter_sz = offsetof(struct ib_flow_tcp_udp_filter, real_sz);
+ actual_filter_sz = spec_filter_size(kern_spec_mask,
+ kern_filter_sz,
+ ib_filter_sz);
+ if (actual_filter_sz <= 0)
return -EINVAL;
- memcpy(&ib_spec->tcp_udp.val, &kern_spec->tcp_udp.val,
- sizeof(struct ib_flow_tcp_udp_filter));
- memcpy(&ib_spec->tcp_udp.mask, &kern_spec->tcp_udp.mask,
- sizeof(struct ib_flow_tcp_udp_filter));
+ ib_spec->size = sizeof(struct ib_flow_spec_tcp_udp);
+ memcpy(&ib_spec->tcp_udp.val, kern_spec_val, actual_filter_sz);
+ memcpy(&ib_spec->tcp_udp.mask, kern_spec_mask, actual_filter_sz);
break;
default:
return -EINVAL;
@@ -3654,7 +3705,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
goto err_uobj;
}
- flow_attr = kmalloc(sizeof(*flow_attr) + cmd.flow_attr.size, GFP_KERNEL);
+ flow_attr = kzalloc(sizeof(*flow_attr) + cmd.flow_attr.num_of_specs *
+ sizeof(union ib_flow_spec), GFP_KERNEL);
if (!flow_attr) {
err = -ENOMEM;
goto err_put;
@@ -4173,6 +4225,23 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
resp.device_cap_flags_ex = attr.device_cap_flags;
resp.response_length += sizeof(resp.device_cap_flags_ex);
+
+ if (ucore->outlen < resp.response_length + sizeof(resp.rss_caps))
+ goto end;
+
+ resp.rss_caps.supported_qpts = attr.rss_caps.supported_qpts;
+ resp.rss_caps.max_rwq_indirection_tables =
+ attr.rss_caps.max_rwq_indirection_tables;
+ resp.rss_caps.max_rwq_indirection_table_size =
+ attr.rss_caps.max_rwq_indirection_table_size;
+
+ resp.response_length += sizeof(resp.rss_caps);
+
+ if (ucore->outlen < resp.response_length + sizeof(resp.max_wq_type_rq))
+ goto end;
+
+ resp.max_wq_type_rq = attr.max_wq_type_rq;
+ resp.response_length += sizeof(resp.max_wq_type_rq);
end:
err = ib_copy_to_udata(ucore, &resp, resp.response_length);
return err;
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index f2b776efab3a..83687646da68 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -227,9 +227,11 @@ EXPORT_SYMBOL(rdma_port_get_link_layer);
* Every PD has a local_dma_lkey which can be used as the lkey value for local
* memory operations.
*/
-struct ib_pd *ib_alloc_pd(struct ib_device *device)
+struct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags,
+ const char *caller)
{
struct ib_pd *pd;
+ int mr_access_flags = 0;
pd = device->alloc_pd(device, NULL, NULL);
if (IS_ERR(pd))
@@ -237,26 +239,46 @@ struct ib_pd *ib_alloc_pd(struct ib_device *device)
pd->device = device;
pd->uobject = NULL;
- pd->local_mr = NULL;
+ pd->__internal_mr = NULL;
atomic_set(&pd->usecnt, 0);
+ pd->flags = flags;
if (device->attrs.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)
pd->local_dma_lkey = device->local_dma_lkey;
- else {
+ else
+ mr_access_flags |= IB_ACCESS_LOCAL_WRITE;
+
+ if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) {
+ pr_warn("%s: enabling unsafe global rkey\n", caller);
+ mr_access_flags |= IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE;
+ }
+
+ if (mr_access_flags) {
struct ib_mr *mr;
- mr = ib_get_dma_mr(pd, IB_ACCESS_LOCAL_WRITE);
+ mr = pd->device->get_dma_mr(pd, mr_access_flags);
if (IS_ERR(mr)) {
ib_dealloc_pd(pd);
- return (struct ib_pd *)mr;
+ return ERR_CAST(mr);
}
- pd->local_mr = mr;
- pd->local_dma_lkey = pd->local_mr->lkey;
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = NULL;
+ mr->need_inval = false;
+
+ pd->__internal_mr = mr;
+
+ if (!(device->attrs.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY))
+ pd->local_dma_lkey = pd->__internal_mr->lkey;
+
+ if (flags & IB_PD_UNSAFE_GLOBAL_RKEY)
+ pd->unsafe_global_rkey = pd->__internal_mr->rkey;
}
+
return pd;
}
-EXPORT_SYMBOL(ib_alloc_pd);
+EXPORT_SYMBOL(__ib_alloc_pd);
/**
* ib_dealloc_pd - Deallocates a protection domain.
@@ -270,10 +292,10 @@ void ib_dealloc_pd(struct ib_pd *pd)
{
int ret;
- if (pd->local_mr) {
- ret = ib_dereg_mr(pd->local_mr);
+ if (pd->__internal_mr) {
+ ret = pd->device->dereg_mr(pd->__internal_mr);
WARN_ON(ret);
- pd->local_mr = NULL;
+ pd->__internal_mr = NULL;
}
/* uverbs manipulates usecnt with proper locking, while the kabi
@@ -821,7 +843,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
if (ret) {
pr_err("failed to init MR pool ret= %d\n", ret);
ib_destroy_qp(qp);
- qp = ERR_PTR(ret);
+ return ERR_PTR(ret);
}
}
@@ -1391,29 +1413,6 @@ EXPORT_SYMBOL(ib_resize_cq);
/* Memory regions */
-struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
-{
- struct ib_mr *mr;
- int err;
-
- err = ib_check_mr_access(mr_access_flags);
- if (err)
- return ERR_PTR(err);
-
- mr = pd->device->get_dma_mr(pd, mr_access_flags);
-
- if (!IS_ERR(mr)) {
- mr->device = pd->device;
- mr->pd = pd;
- mr->uobject = NULL;
- atomic_inc(&pd->usecnt);
- mr->need_inval = false;
- }
-
- return mr;
-}
-EXPORT_SYMBOL(ib_get_dma_mr);
-
int ib_dereg_mr(struct ib_mr *mr)
{
struct ib_pd *pd = mr->pd;
@@ -1812,13 +1811,13 @@ EXPORT_SYMBOL(ib_set_vf_guid);
*
* Constraints:
* - The first sg element is allowed to have an offset.
- * - Each sg element must be aligned to page_size (or physically
- * contiguous to the previous element). In case an sg element has a
- * non contiguous offset, the mapping prefix will not include it.
+ * - Each sg element must either be aligned to page_size or virtually
+ * contiguous to the previous element. In case an sg element has a
+ * non-contiguous offset, the mapping prefix will not include it.
* - The last sg element is allowed to have length less than page_size.
* - If sg_nents total byte length exceeds the mr max_num_sge * page_size
* then only max_num_sg entries will be mapped.
- * - If the MR was allocated with type IB_MR_TYPE_SG_GAPS_REG, non of these
+ * - If the MR was allocated with type IB_MR_TYPE_SG_GAPS, none of these
* constraints holds and the page_size argument is ignored.
*
* Returns the number of sg elements that were mapped to the memory region.
diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile
index c0c7cf8af3f4..21fe401ff178 100644
--- a/drivers/infiniband/hw/Makefile
+++ b/drivers/infiniband/hw/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_INFINIBAND_NES) += nes/
obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/
obj-$(CONFIG_INFINIBAND_USNIC) += usnic/
obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/
+obj-$(CONFIG_INFINIBAND_HNS) += hns/
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
index 8e77dc543dd1..b3e11329801d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.c
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -36,7 +36,7 @@
#include "cxgb3_offload.h"
#include "iwch_provider.h"
-#include "iwch_user.h"
+#include <rdma/cxgb3-abi.h>
#include "iwch.h"
#include "iwch_cm.h"
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 04bbf172abde..65ee64400deb 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -2258,7 +2258,7 @@ int __init iwch_cm_init(void)
{
skb_queue_head_init(&rxq);
- workq = create_singlethread_workqueue("iw_cxgb3");
+ workq = alloc_ordered_workqueue("iw_cxgb3", WQ_MEM_RECLAIM);
if (!workq)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 3edb80644b53..cba57bb53dba 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -58,7 +58,7 @@
#include "iwch.h"
#include "iwch_provider.h"
#include "iwch_cm.h"
-#include "iwch_user.h"
+#include <rdma/cxgb3-abi.h>
#include "common.h"
static struct ib_ah *iwch_ah_create(struct ib_pd *pd,
@@ -1396,6 +1396,7 @@ int iwch_register_device(struct iwch_dev *dev)
(1ull << IB_USER_VERBS_CMD_POST_SEND) |
(1ull << IB_USER_VERBS_CMD_POST_RECV);
dev->ibdev.node_type = RDMA_NODE_RNIC;
+ BUILD_BUG_ON(sizeof(IWCH_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC));
dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
dev->ibdev.num_comp_vectors = 1;
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 71c8867ef66b..f1510cc76d2d 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -4235,7 +4235,7 @@ int __init c4iw_cm_init(void)
spin_lock_init(&timeout_lock);
skb_queue_head_init(&rxq);
- workq = create_singlethread_workqueue("iw_cxgb4");
+ workq = alloc_ordered_workqueue("iw_cxgb4", WQ_MEM_RECLAIM);
if (!workq)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index ac926c942fee..867b8cf82be8 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -666,6 +666,18 @@ skip_cqe:
return ret;
}
+static void invalidate_mr(struct c4iw_dev *rhp, u32 rkey)
+{
+ struct c4iw_mr *mhp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rhp->lock, flags);
+ mhp = get_mhp(rhp, rkey >> 8);
+ if (mhp)
+ mhp->attr.state = 0;
+ spin_unlock_irqrestore(&rhp->lock, flags);
+}
+
/*
* Get one cq entry from c4iw and map it to openib.
*
@@ -721,6 +733,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
CQE_OPCODE(&cqe) == FW_RI_SEND_WITH_SE_INV) {
wc->ex.invalidate_rkey = CQE_WRID_STAG(&cqe);
wc->wc_flags |= IB_WC_WITH_INVALIDATE;
+ invalidate_mr(qhp->rhp, wc->ex.invalidate_rkey);
}
} else {
switch (CQE_OPCODE(&cqe)) {
@@ -746,6 +759,10 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
break;
case FW_RI_FAST_REGISTER:
wc->opcode = IB_WC_REG_MR;
+
+ /* Invalidate the MR if the fastreg failed */
+ if (CQE_STATUS(&cqe) != T4_ERR_SUCCESS)
+ invalidate_mr(qhp->rhp, CQE_WRID_FR_STAG(&cqe));
break;
default:
printk(KERN_ERR MOD "Unexpected opcode %d "
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index cdcf3eeb6f4a..7e7f79e55006 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -58,7 +58,7 @@
#include "cxgb4.h"
#include "cxgb4_uld.h"
#include "l2t.h"
-#include "user.h"
+#include <rdma/cxgb4-abi.h>
#define DRV_NAME "iw_cxgb4"
#define MOD DRV_NAME ":"
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 0b91b0f4df71..80e27749420a 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -695,7 +695,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,
mhp->attr.pdid = php->pdid;
mhp->attr.type = FW_RI_STAG_NSMR;
mhp->attr.stag = stag;
- mhp->attr.state = 1;
+ mhp->attr.state = 0;
mmid = (stag) >> 8;
mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) {
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index df127ce6b6ec..645e606a17c5 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -563,6 +563,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
(1ull << IB_USER_VERBS_CMD_POST_SEND) |
(1ull << IB_USER_VERBS_CMD_POST_RECV);
dev->ibdev.node_type = RDMA_NODE_RNIC;
+ BUILD_BUG_ON(sizeof(C4IW_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
memcpy(dev->ibdev.node_desc, C4IW_NODE_DESC, sizeof(C4IW_NODE_DESC));
dev->ibdev.phys_port_cnt = dev->rdev.lldi.nports;
dev->ibdev.num_comp_vectors = dev->rdev.lldi.nciq;
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 690435229be7..f57deba6717c 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -609,10 +609,42 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
return 0;
}
+static void build_tpte_memreg(struct fw_ri_fr_nsmr_tpte_wr *fr,
+ struct ib_reg_wr *wr, struct c4iw_mr *mhp,
+ u8 *len16)
+{
+ __be64 *p = (__be64 *)fr->pbl;
+
+ fr->r2 = cpu_to_be32(0);
+ fr->stag = cpu_to_be32(mhp->ibmr.rkey);
+
+ fr->tpte.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
+ FW_RI_TPTE_STAGKEY_V((mhp->ibmr.rkey & FW_RI_TPTE_STAGKEY_M)) |
+ FW_RI_TPTE_STAGSTATE_V(1) |
+ FW_RI_TPTE_STAGTYPE_V(FW_RI_STAG_NSMR) |
+ FW_RI_TPTE_PDID_V(mhp->attr.pdid));
+ fr->tpte.locread_to_qpid = cpu_to_be32(
+ FW_RI_TPTE_PERM_V(c4iw_ib_to_tpt_access(wr->access)) |
+ FW_RI_TPTE_ADDRTYPE_V(FW_RI_VA_BASED_TO) |
+ FW_RI_TPTE_PS_V(ilog2(wr->mr->page_size) - 12));
+ fr->tpte.nosnoop_pbladdr = cpu_to_be32(FW_RI_TPTE_PBLADDR_V(
+ PBL_OFF(&mhp->rhp->rdev, mhp->attr.pbl_addr)>>3));
+ fr->tpte.dca_mwbcnt_pstag = cpu_to_be32(0);
+ fr->tpte.len_hi = cpu_to_be32(0);
+ fr->tpte.len_lo = cpu_to_be32(mhp->ibmr.length);
+ fr->tpte.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32);
+ fr->tpte.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova & 0xffffffff);
+
+ p[0] = cpu_to_be64((u64)mhp->mpl[0]);
+ p[1] = cpu_to_be64((u64)mhp->mpl[1]);
+
+ *len16 = DIV_ROUND_UP(sizeof(*fr), 16);
+}
+
static int build_memreg(struct t4_sq *sq, union t4_wr *wqe,
- struct ib_reg_wr *wr, u8 *len16, bool dsgl_supported)
+ struct ib_reg_wr *wr, struct c4iw_mr *mhp, u8 *len16,
+ bool dsgl_supported)
{
- struct c4iw_mr *mhp = to_c4iw_mr(wr->mr);
struct fw_ri_immd *imdp;
__be64 *p;
int i;
@@ -674,9 +706,12 @@ static int build_memreg(struct t4_sq *sq, union t4_wr *wqe,
return 0;
}
-static int build_inv_stag(union t4_wr *wqe, struct ib_send_wr *wr,
- u8 *len16)
+static int build_inv_stag(struct c4iw_dev *dev, union t4_wr *wqe,
+ struct ib_send_wr *wr, u8 *len16)
{
+ struct c4iw_mr *mhp = get_mhp(dev, wr->ex.invalidate_rkey >> 8);
+
+ mhp->attr.state = 0;
wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
wqe->inv.r2 = 0;
*len16 = DIV_ROUND_UP(sizeof wqe->inv, 16);
@@ -816,18 +851,32 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
if (!qhp->wq.sq.oldest_read)
qhp->wq.sq.oldest_read = swsqe;
break;
- case IB_WR_REG_MR:
- fw_opcode = FW_RI_FR_NSMR_WR;
+ case IB_WR_REG_MR: {
+ struct c4iw_mr *mhp = to_c4iw_mr(reg_wr(wr)->mr);
+
swsqe->opcode = FW_RI_FAST_REGISTER;
- err = build_memreg(&qhp->wq.sq, wqe, reg_wr(wr), &len16,
- qhp->rhp->rdev.lldi.ulptx_memwrite_dsgl);
+ if (qhp->rhp->rdev.lldi.fr_nsmr_tpte_wr_support &&
+ !mhp->attr.state && mhp->mpl_len <= 2) {
+ fw_opcode = FW_RI_FR_NSMR_TPTE_WR;
+ build_tpte_memreg(&wqe->fr_tpte, reg_wr(wr),
+ mhp, &len16);
+ } else {
+ fw_opcode = FW_RI_FR_NSMR_WR;
+ err = build_memreg(&qhp->wq.sq, wqe, reg_wr(wr),
+ mhp, &len16,
+ qhp->rhp->rdev.lldi.ulptx_memwrite_dsgl);
+ if (err)
+ break;
+ }
+ mhp->attr.state = 1;
break;
+ }
case IB_WR_LOCAL_INV:
if (wr->send_flags & IB_SEND_FENCE)
fw_flags |= FW_RI_LOCAL_FENCE_FLAG;
fw_opcode = FW_RI_INV_LSTAG_WR;
swsqe->opcode = FW_RI_LOCAL_INV;
- err = build_inv_stag(wqe, wr, &len16);
+ err = build_inv_stag(qhp->rhp, wqe, wr, &len16);
break;
default:
PDBG("%s post of type=%d TBD!\n", __func__,
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index 02173f4315fa..862381aa83c8 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -95,6 +95,7 @@ union t4_wr {
struct fw_ri_rdma_read_wr read;
struct fw_ri_bind_mw_wr bind;
struct fw_ri_fr_nsmr_wr fr;
+ struct fw_ri_fr_nsmr_tpte_wr fr_tpte;
struct fw_ri_inv_lstag_wr inv;
struct t4_status_page status;
__be64 flits[T4_EQ_ENTRY_SIZE / sizeof(__be64) * T4_SQ_NUM_SLOTS];
@@ -170,7 +171,7 @@ struct t4_cqe {
__be32 msn;
} rcqe;
struct {
- u32 nada1;
+ u32 stag;
u16 nada2;
u16 cidx;
} scqe;
@@ -232,6 +233,7 @@ struct t4_cqe {
/* used for SQ completion processing */
#define CQE_WRID_SQ_IDX(x) ((x)->u.scqe.cidx)
+#define CQE_WRID_FR_STAG(x) (be32_to_cpu((x)->u.scqe.stag))
/* generic accessor macros */
#define CQE_WRID_HI(x) (be32_to_cpu((x)->u.gen.wrid_hi))
diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
index 1e26669793c3..010c709ba3bb 100644
--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
@@ -669,6 +669,18 @@ struct fw_ri_fr_nsmr_wr {
#define FW_RI_FR_NSMR_WR_DCACPU_G(x) \
(((x) >> FW_RI_FR_NSMR_WR_DCACPU_S) & FW_RI_FR_NSMR_WR_DCACPU_M)
+struct fw_ri_fr_nsmr_tpte_wr {
+ __u8 opcode;
+ __u8 flags;
+ __u16 wrid;
+ __u8 r1[3];
+ __u8 len16;
+ __u32 r2;
+ __u32 stag;
+ struct fw_ri_tpte tpte;
+ __u64 pbl[2];
+};
+
struct fw_ri_inv_lstag_wr {
__u8 opcode;
__u8 flags;
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index f2f6b5a78e0e..4b7a16ceb362 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -1441,7 +1441,8 @@ static int modify_device(struct ib_device *device,
}
if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC) {
- memcpy(device->node_desc, device_modify->node_desc, 64);
+ memcpy(device->node_desc, device_modify->node_desc,
+ IB_DEVICE_NODE_DESC_MAX);
for (i = 0; i < dd->num_pports; i++) {
struct hfi1_ibport *ibp = &dd->pport[i].ibport_data;
diff --git a/drivers/infiniband/hw/hns/Kconfig b/drivers/infiniband/hw/hns/Kconfig
new file mode 100644
index 000000000000..e1a6e055cd60
--- /dev/null
+++ b/drivers/infiniband/hw/hns/Kconfig
@@ -0,0 +1,10 @@
+config INFINIBAND_HNS
+ tristate "HNS RoCE Driver"
+ depends on NET_VENDOR_HISILICON
+ depends on ARM64 && HNS && HNS_DSAF && HNS_ENET
+ ---help---
+ This is a RoCE/RDMA driver for the Hisilicon RoCE engine. The engine
+ is used in Hisilicon Hi1610 and more further ICT SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hns-roce.
diff --git a/drivers/infiniband/hw/hns/Makefile b/drivers/infiniband/hw/hns/Makefile
new file mode 100644
index 000000000000..7e8ebd24dcae
--- /dev/null
+++ b/drivers/infiniband/hw/hns/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Hisilicon RoCE drivers.
+#
+
+obj-$(CONFIG_INFINIBAND_HNS) += hns-roce.o
+hns-roce-objs := hns_roce_main.o hns_roce_cmd.o hns_roce_eq.o hns_roce_pd.o \
+ hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \
+ hns_roce_cq.o hns_roce_alloc.o hns_roce_hw_v1.o
diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c
new file mode 100644
index 000000000000..24f79ee39fdf
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_ah.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include "hns_roce_device.h"
+
+#define HNS_ROCE_PORT_NUM_SHIFT 24
+#define HNS_ROCE_VLAN_SL_BIT_MASK 7
+#define HNS_ROCE_VLAN_SL_SHIFT 13
+
+struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *ah_attr)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibpd->device);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct ib_gid_attr gid_attr;
+ struct hns_roce_ah *ah;
+ u16 vlan_tag = 0xffff;
+ struct in6_addr in6;
+ union ib_gid sgid;
+ int ret;
+
+ ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
+ if (!ah)
+ return ERR_PTR(-ENOMEM);
+
+ /* Get mac address */
+ memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(ah_attr->grh.dgid.raw));
+ if (rdma_is_multicast_addr(&in6))
+ rdma_get_mcast_mac(&in6, ah->av.mac);
+ else
+ memcpy(ah->av.mac, ah_attr->dmac, sizeof(ah_attr->dmac));
+
+ /* Get source gid */
+ ret = ib_get_cached_gid(ibpd->device, ah_attr->port_num,
+ ah_attr->grh.sgid_index, &sgid, &gid_attr);
+ if (ret) {
+ dev_err(dev, "get sgid failed! ret = %d\n", ret);
+ kfree(ah);
+ return ERR_PTR(ret);
+ }
+
+ if (gid_attr.ndev) {
+ if (is_vlan_dev(gid_attr.ndev))
+ vlan_tag = vlan_dev_vlan_id(gid_attr.ndev);
+ dev_put(gid_attr.ndev);
+ }
+
+ if (vlan_tag < 0x1000)
+ vlan_tag |= (ah_attr->sl & HNS_ROCE_VLAN_SL_BIT_MASK) <<
+ HNS_ROCE_VLAN_SL_SHIFT;
+
+ ah->av.port_pd = cpu_to_be32(to_hr_pd(ibpd)->pdn | (ah_attr->port_num <<
+ HNS_ROCE_PORT_NUM_SHIFT));
+ ah->av.gid_index = ah_attr->grh.sgid_index;
+ ah->av.vlan = cpu_to_le16(vlan_tag);
+ dev_dbg(dev, "gid_index = 0x%x,vlan = 0x%x\n", ah->av.gid_index,
+ ah->av.vlan);
+
+ if (ah_attr->static_rate)
+ ah->av.stat_rate = IB_RATE_10_GBPS;
+
+ memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, HNS_ROCE_GID_SIZE);
+ ah->av.sl_tclass_flowlabel = cpu_to_le32(ah_attr->sl <<
+ HNS_ROCE_SL_SHIFT);
+
+ return &ah->ibah;
+}
+
+int hns_roce_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+ struct hns_roce_ah *ah = to_hr_ah(ibah);
+
+ memset(ah_attr, 0, sizeof(*ah_attr));
+
+ ah_attr->sl = le32_to_cpu(ah->av.sl_tclass_flowlabel) >>
+ HNS_ROCE_SL_SHIFT;
+ ah_attr->port_num = le32_to_cpu(ah->av.port_pd) >>
+ HNS_ROCE_PORT_NUM_SHIFT;
+ ah_attr->static_rate = ah->av.stat_rate;
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->grh.traffic_class = le32_to_cpu(ah->av.sl_tclass_flowlabel) >>
+ HNS_ROCE_TCLASS_SHIFT;
+ ah_attr->grh.flow_label = le32_to_cpu(ah->av.sl_tclass_flowlabel) &
+ HNS_ROCE_FLOW_LABLE_MASK;
+ ah_attr->grh.hop_limit = ah->av.hop_limit;
+ ah_attr->grh.sgid_index = ah->av.gid_index;
+ memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, HNS_ROCE_GID_SIZE);
+
+ return 0;
+}
+
+int hns_roce_destroy_ah(struct ib_ah *ah)
+{
+ kfree(to_hr_ah(ah));
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_alloc.c b/drivers/infiniband/hw/hns/hns_roce_alloc.c
new file mode 100644
index 000000000000..863a17a2de40
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include "hns_roce_device.h"
+
+int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj)
+{
+ int ret = 0;
+
+ spin_lock(&bitmap->lock);
+ *obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
+ if (*obj >= bitmap->max) {
+ bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
+ & bitmap->mask;
+ *obj = find_first_zero_bit(bitmap->table, bitmap->max);
+ }
+
+ if (*obj < bitmap->max) {
+ set_bit(*obj, bitmap->table);
+ bitmap->last = (*obj + 1);
+ if (bitmap->last == bitmap->max)
+ bitmap->last = 0;
+ *obj |= bitmap->top;
+ } else {
+ ret = -1;
+ }
+
+ spin_unlock(&bitmap->lock);
+
+ return ret;
+}
+
+void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj)
+{
+ hns_roce_bitmap_free_range(bitmap, obj, 1);
+}
+
+int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt,
+ int align, unsigned long *obj)
+{
+ int ret = 0;
+ int i;
+
+ if (likely(cnt == 1 && align == 1))
+ return hns_roce_bitmap_alloc(bitmap, obj);
+
+ spin_lock(&bitmap->lock);
+
+ *obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
+ bitmap->last, cnt, align - 1);
+ if (*obj >= bitmap->max) {
+ bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
+ & bitmap->mask;
+ *obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, 0,
+ cnt, align - 1);
+ }
+
+ if (*obj < bitmap->max) {
+ for (i = 0; i < cnt; i++)
+ set_bit(*obj + i, bitmap->table);
+
+ if (*obj == bitmap->last) {
+ bitmap->last = (*obj + cnt);
+ if (bitmap->last >= bitmap->max)
+ bitmap->last = 0;
+ }
+ *obj |= bitmap->top;
+ } else {
+ ret = -1;
+ }
+
+ spin_unlock(&bitmap->lock);
+
+ return ret;
+}
+
+void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap,
+ unsigned long obj, int cnt)
+{
+ int i;
+
+ obj &= bitmap->max + bitmap->reserved_top - 1;
+
+ spin_lock(&bitmap->lock);
+ for (i = 0; i < cnt; i++)
+ clear_bit(obj + i, bitmap->table);
+
+ bitmap->last = min(bitmap->last, obj);
+ bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
+ & bitmap->mask;
+ spin_unlock(&bitmap->lock);
+}
+
+int hns_roce_bitmap_init(struct hns_roce_bitmap *bitmap, u32 num, u32 mask,
+ u32 reserved_bot, u32 reserved_top)
+{
+ u32 i;
+
+ if (num != roundup_pow_of_two(num))
+ return -EINVAL;
+
+ bitmap->last = 0;
+ bitmap->top = 0;
+ bitmap->max = num - reserved_top;
+ bitmap->mask = mask;
+ bitmap->reserved_top = reserved_top;
+ spin_lock_init(&bitmap->lock);
+ bitmap->table = kcalloc(BITS_TO_LONGS(bitmap->max), sizeof(long),
+ GFP_KERNEL);
+ if (!bitmap->table)
+ return -ENOMEM;
+
+ for (i = 0; i < reserved_bot; ++i)
+ set_bit(i, bitmap->table);
+
+ return 0;
+}
+
+void hns_roce_bitmap_cleanup(struct hns_roce_bitmap *bitmap)
+{
+ kfree(bitmap->table);
+}
+
+void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
+ struct hns_roce_buf *buf)
+{
+ int i;
+ struct device *dev = &hr_dev->pdev->dev;
+ u32 bits_per_long = BITS_PER_LONG;
+
+ if (buf->nbufs == 1) {
+ dma_free_coherent(dev, size, buf->direct.buf, buf->direct.map);
+ } else {
+ if (bits_per_long == 64)
+ vunmap(buf->direct.buf);
+
+ for (i = 0; i < buf->nbufs; ++i)
+ if (buf->page_list[i].buf)
+ dma_free_coherent(&hr_dev->pdev->dev, PAGE_SIZE,
+ buf->page_list[i].buf,
+ buf->page_list[i].map);
+ kfree(buf->page_list);
+ }
+}
+
+int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
+ struct hns_roce_buf *buf)
+{
+ int i = 0;
+ dma_addr_t t;
+ struct page **pages;
+ struct device *dev = &hr_dev->pdev->dev;
+ u32 bits_per_long = BITS_PER_LONG;
+
+ /* SQ/RQ buf lease than one page, SQ + RQ = 8K */
+ if (size <= max_direct) {
+ buf->nbufs = 1;
+ /* Npages calculated by page_size */
+ buf->npages = 1 << get_order(size);
+ buf->page_shift = PAGE_SHIFT;
+ /* MTT PA must be recorded in 4k alignment, t is 4k aligned */
+ buf->direct.buf = dma_alloc_coherent(dev, size, &t, GFP_KERNEL);
+ if (!buf->direct.buf)
+ return -ENOMEM;
+
+ buf->direct.map = t;
+
+ while (t & ((1 << buf->page_shift) - 1)) {
+ --buf->page_shift;
+ buf->npages *= 2;
+ }
+
+ memset(buf->direct.buf, 0, size);
+ } else {
+ buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ buf->npages = buf->nbufs;
+ buf->page_shift = PAGE_SHIFT;
+ buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
+ GFP_KERNEL);
+
+ if (!buf->page_list)
+ return -ENOMEM;
+
+ for (i = 0; i < buf->nbufs; ++i) {
+ buf->page_list[i].buf = dma_alloc_coherent(dev,
+ PAGE_SIZE, &t,
+ GFP_KERNEL);
+
+ if (!buf->page_list[i].buf)
+ goto err_free;
+
+ buf->page_list[i].map = t;
+ memset(buf->page_list[i].buf, 0, PAGE_SIZE);
+ }
+ if (bits_per_long == 64) {
+ pages = kmalloc_array(buf->nbufs, sizeof(*pages),
+ GFP_KERNEL);
+ if (!pages)
+ goto err_free;
+
+ for (i = 0; i < buf->nbufs; ++i)
+ pages[i] = virt_to_page(buf->page_list[i].buf);
+
+ buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP,
+ PAGE_KERNEL);
+ kfree(pages);
+ if (!buf->direct.buf)
+ goto err_free;
+ }
+ }
+
+ return 0;
+
+err_free:
+ hns_roce_buf_free(hr_dev, size, buf);
+ return -ENOMEM;
+}
+
+void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_cleanup_qp_table(hr_dev);
+ hns_roce_cleanup_cq_table(hr_dev);
+ hns_roce_cleanup_mr_table(hr_dev);
+ hns_roce_cleanup_pd_table(hr_dev);
+ hns_roce_cleanup_uar_table(hr_dev);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.c b/drivers/infiniband/hw/hns/hns_roce_cmd.c
new file mode 100644
index 000000000000..2a0b6c05da5f
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_cmd.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/dmapool.h>
+#include <linux/platform_device.h>
+#include "hns_roce_common.h"
+#include "hns_roce_device.h"
+#include "hns_roce_cmd.h"
+
+#define CMD_POLL_TOKEN 0xffff
+#define CMD_MAX_NUM 32
+#define STATUS_MASK 0xff
+#define CMD_TOKEN_MASK 0x1f
+#define GO_BIT_TIMEOUT_MSECS 10000
+
+enum {
+ HCR_TOKEN_OFFSET = 0x14,
+ HCR_STATUS_OFFSET = 0x18,
+ HCR_GO_BIT = 15,
+};
+
+static int cmd_pending(struct hns_roce_dev *hr_dev)
+{
+ u32 status = readl(hr_dev->cmd.hcr + HCR_TOKEN_OFFSET);
+
+ return (!!(status & (1 << HCR_GO_BIT)));
+}
+
+/* this function should be serialized with "hcr_mutex" */
+static int __hns_roce_cmd_mbox_post_hw(struct hns_roce_dev *hr_dev,
+ u64 in_param, u64 out_param,
+ u32 in_modifier, u8 op_modifier, u16 op,
+ u16 token, int event)
+{
+ struct hns_roce_cmdq *cmd = &hr_dev->cmd;
+ struct device *dev = &hr_dev->pdev->dev;
+ u32 __iomem *hcr = (u32 *)cmd->hcr;
+ int ret = -EAGAIN;
+ unsigned long end;
+ u32 val = 0;
+
+ end = msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS) + jiffies;
+ while (cmd_pending(hr_dev)) {
+ if (time_after(jiffies, end)) {
+ dev_dbg(dev, "jiffies=%d end=%d\n", (int)jiffies,
+ (int)end);
+ goto out;
+ }
+ cond_resched();
+ }
+
+ roce_set_field(val, ROCEE_MB6_ROCEE_MB_CMD_M, ROCEE_MB6_ROCEE_MB_CMD_S,
+ op);
+ roce_set_field(val, ROCEE_MB6_ROCEE_MB_CMD_MDF_M,
+ ROCEE_MB6_ROCEE_MB_CMD_MDF_S, op_modifier);
+ roce_set_bit(val, ROCEE_MB6_ROCEE_MB_EVENT_S, event);
+ roce_set_bit(val, ROCEE_MB6_ROCEE_MB_HW_RUN_S, 1);
+ roce_set_field(val, ROCEE_MB6_ROCEE_MB_TOKEN_M,
+ ROCEE_MB6_ROCEE_MB_TOKEN_S, token);
+
+ __raw_writeq(cpu_to_le64(in_param), hcr + 0);
+ __raw_writeq(cpu_to_le64(out_param), hcr + 2);
+ __raw_writel(cpu_to_le32(in_modifier), hcr + 4);
+ /* Memory barrier */
+ wmb();
+
+ __raw_writel(cpu_to_le32(val), hcr + 5);
+
+ mmiowb();
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static int hns_roce_cmd_mbox_post_hw(struct hns_roce_dev *hr_dev, u64 in_param,
+ u64 out_param, u32 in_modifier,
+ u8 op_modifier, u16 op, u16 token,
+ int event)
+{
+ struct hns_roce_cmdq *cmd = &hr_dev->cmd;
+ int ret = -EAGAIN;
+
+ mutex_lock(&cmd->hcr_mutex);
+ ret = __hns_roce_cmd_mbox_post_hw(hr_dev, in_param, out_param,
+ in_modifier, op_modifier, op, token,
+ event);
+ mutex_unlock(&cmd->hcr_mutex);
+
+ return ret;
+}
+
+/* this should be called with "poll_sem" */
+static int __hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev, u64 in_param,
+ u64 out_param, unsigned long in_modifier,
+ u8 op_modifier, u16 op,
+ unsigned long timeout)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ u8 __iomem *hcr = hr_dev->cmd.hcr;
+ unsigned long end = 0;
+ u32 status = 0;
+ int ret;
+
+ ret = hns_roce_cmd_mbox_post_hw(hr_dev, in_param, out_param,
+ in_modifier, op_modifier, op,
+ CMD_POLL_TOKEN, 0);
+ if (ret) {
+ dev_err(dev, "[cmd_poll]hns_roce_cmd_mbox_post_hw failed\n");
+ goto out;
+ }
+
+ end = msecs_to_jiffies(timeout) + jiffies;
+ while (cmd_pending(hr_dev) && time_before(jiffies, end))
+ cond_resched();
+
+ if (cmd_pending(hr_dev)) {
+ dev_err(dev, "[cmd_poll]hw run cmd TIMEDOUT!\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ status = le32_to_cpu((__force __be32)
+ __raw_readl(hcr + HCR_STATUS_OFFSET));
+ if ((status & STATUS_MASK) != 0x1) {
+ dev_err(dev, "mailbox status 0x%x!\n", status);
+ ret = -EBUSY;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev, u64 in_param,
+ u64 out_param, unsigned long in_modifier,
+ u8 op_modifier, u16 op, unsigned long timeout)
+{
+ int ret;
+
+ down(&hr_dev->cmd.poll_sem);
+ ret = __hns_roce_cmd_mbox_poll(hr_dev, in_param, out_param, in_modifier,
+ op_modifier, op, timeout);
+ up(&hr_dev->cmd.poll_sem);
+
+ return ret;
+}
+
+void hns_roce_cmd_event(struct hns_roce_dev *hr_dev, u16 token, u8 status,
+ u64 out_param)
+{
+ struct hns_roce_cmd_context
+ *context = &hr_dev->cmd.context[token & hr_dev->cmd.token_mask];
+
+ if (token != context->token)
+ return;
+
+ context->result = (status == HNS_ROCE_CMD_SUCCESS) ? 0 : (-EIO);
+ context->out_param = out_param;
+ complete(&context->done);
+}
+
+/* this should be called with "use_events" */
+static int __hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev, u64 in_param,
+ u64 out_param, unsigned long in_modifier,
+ u8 op_modifier, u16 op,
+ unsigned long timeout)
+{
+ struct hns_roce_cmdq *cmd = &hr_dev->cmd;
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_cmd_context *context;
+ int ret = 0;
+
+ spin_lock(&cmd->context_lock);
+ WARN_ON(cmd->free_head < 0);
+ context = &cmd->context[cmd->free_head];
+ context->token += cmd->token_mask + 1;
+ cmd->free_head = context->next;
+ spin_unlock(&cmd->context_lock);
+
+ init_completion(&context->done);
+
+ ret = hns_roce_cmd_mbox_post_hw(hr_dev, in_param, out_param,
+ in_modifier, op_modifier, op,
+ context->token, 1);
+ if (ret)
+ goto out;
+
+ /*
+ * It is timeout when wait_for_completion_timeout return 0
+ * The return value is the time limit set in advance
+ * how many seconds showing
+ */
+ if (!wait_for_completion_timeout(&context->done,
+ msecs_to_jiffies(timeout))) {
+ dev_err(dev, "[cmd]wait_for_completion_timeout timeout\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = context->result;
+ if (ret) {
+ dev_err(dev, "[cmd]event mod cmd process error!err=%d\n", ret);
+ goto out;
+ }
+
+out:
+ spin_lock(&cmd->context_lock);
+ context->next = cmd->free_head;
+ cmd->free_head = context - cmd->context;
+ spin_unlock(&cmd->context_lock);
+
+ return ret;
+}
+
+static int hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev, u64 in_param,
+ u64 out_param, unsigned long in_modifier,
+ u8 op_modifier, u16 op, unsigned long timeout)
+{
+ int ret = 0;
+
+ down(&hr_dev->cmd.event_sem);
+ ret = __hns_roce_cmd_mbox_wait(hr_dev, in_param, out_param,
+ in_modifier, op_modifier, op, timeout);
+ up(&hr_dev->cmd.event_sem);
+
+ return ret;
+}
+
+int hns_roce_cmd_mbox(struct hns_roce_dev *hr_dev, u64 in_param, u64 out_param,
+ unsigned long in_modifier, u8 op_modifier, u16 op,
+ unsigned long timeout)
+{
+ if (hr_dev->cmd.use_events)
+ return hns_roce_cmd_mbox_wait(hr_dev, in_param, out_param,
+ in_modifier, op_modifier, op,
+ timeout);
+ else
+ return hns_roce_cmd_mbox_poll(hr_dev, in_param, out_param,
+ in_modifier, op_modifier, op,
+ timeout);
+}
+
+int hns_roce_cmd_init(struct hns_roce_dev *hr_dev)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+
+ mutex_init(&hr_dev->cmd.hcr_mutex);
+ sema_init(&hr_dev->cmd.poll_sem, 1);
+ hr_dev->cmd.use_events = 0;
+ hr_dev->cmd.toggle = 1;
+ hr_dev->cmd.max_cmds = CMD_MAX_NUM;
+ hr_dev->cmd.hcr = hr_dev->reg_base + ROCEE_MB1_REG;
+ hr_dev->cmd.pool = dma_pool_create("hns_roce_cmd", dev,
+ HNS_ROCE_MAILBOX_SIZE,
+ HNS_ROCE_MAILBOX_SIZE, 0);
+ if (!hr_dev->cmd.pool)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void hns_roce_cmd_cleanup(struct hns_roce_dev *hr_dev)
+{
+ dma_pool_destroy(hr_dev->cmd.pool);
+}
+
+int hns_roce_cmd_use_events(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_cmdq *hr_cmd = &hr_dev->cmd;
+ int i;
+
+ hr_cmd->context = kmalloc(hr_cmd->max_cmds *
+ sizeof(struct hns_roce_cmd_context),
+ GFP_KERNEL);
+ if (!hr_cmd->context)
+ return -ENOMEM;
+
+ for (i = 0; i < hr_cmd->max_cmds; ++i) {
+ hr_cmd->context[i].token = i;
+ hr_cmd->context[i].next = i + 1;
+ }
+
+ hr_cmd->context[hr_cmd->max_cmds - 1].next = -1;
+ hr_cmd->free_head = 0;
+
+ sema_init(&hr_cmd->event_sem, hr_cmd->max_cmds);
+ spin_lock_init(&hr_cmd->context_lock);
+
+ hr_cmd->token_mask = CMD_TOKEN_MASK;
+ hr_cmd->use_events = 1;
+
+ down(&hr_cmd->poll_sem);
+
+ return 0;
+}
+
+void hns_roce_cmd_use_polling(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_cmdq *hr_cmd = &hr_dev->cmd;
+ int i;
+
+ hr_cmd->use_events = 0;
+
+ for (i = 0; i < hr_cmd->max_cmds; ++i)
+ down(&hr_cmd->event_sem);
+
+ kfree(hr_cmd->context);
+ up(&hr_cmd->poll_sem);
+}
+
+struct hns_roce_cmd_mailbox
+ *hns_roce_alloc_cmd_mailbox(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_cmd_mailbox *mailbox;
+
+ mailbox = kmalloc(sizeof(*mailbox), GFP_KERNEL);
+ if (!mailbox)
+ return ERR_PTR(-ENOMEM);
+
+ mailbox->buf = dma_pool_alloc(hr_dev->cmd.pool, GFP_KERNEL,
+ &mailbox->dma);
+ if (!mailbox->buf) {
+ kfree(mailbox);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return mailbox;
+}
+
+void hns_roce_free_cmd_mailbox(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cmd_mailbox *mailbox)
+{
+ if (!mailbox)
+ return;
+
+ dma_pool_free(hr_dev->cmd.pool, mailbox->buf, mailbox->dma);
+ kfree(mailbox);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h
new file mode 100644
index 000000000000..e3997d312c55
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_CMD_H
+#define _HNS_ROCE_CMD_H
+
+#define HNS_ROCE_MAILBOX_SIZE 4096
+
+enum {
+ /* TPT commands */
+ HNS_ROCE_CMD_SW2HW_MPT = 0xd,
+ HNS_ROCE_CMD_HW2SW_MPT = 0xf,
+
+ /* CQ commands */
+ HNS_ROCE_CMD_SW2HW_CQ = 0x16,
+ HNS_ROCE_CMD_HW2SW_CQ = 0x17,
+
+ /* QP/EE commands */
+ HNS_ROCE_CMD_RST2INIT_QP = 0x19,
+ HNS_ROCE_CMD_INIT2RTR_QP = 0x1a,
+ HNS_ROCE_CMD_RTR2RTS_QP = 0x1b,
+ HNS_ROCE_CMD_RTS2RTS_QP = 0x1c,
+ HNS_ROCE_CMD_2ERR_QP = 0x1e,
+ HNS_ROCE_CMD_RTS2SQD_QP = 0x1f,
+ HNS_ROCE_CMD_SQD2SQD_QP = 0x38,
+ HNS_ROCE_CMD_SQD2RTS_QP = 0x20,
+ HNS_ROCE_CMD_2RST_QP = 0x21,
+ HNS_ROCE_CMD_QUERY_QP = 0x22,
+};
+
+enum {
+ HNS_ROCE_CMD_TIME_CLASS_A = 10000,
+ HNS_ROCE_CMD_TIME_CLASS_B = 10000,
+ HNS_ROCE_CMD_TIME_CLASS_C = 10000,
+};
+
+struct hns_roce_cmd_mailbox {
+ void *buf;
+ dma_addr_t dma;
+};
+
+int hns_roce_cmd_mbox(struct hns_roce_dev *hr_dev, u64 in_param, u64 out_param,
+ unsigned long in_modifier, u8 op_modifier, u16 op,
+ unsigned long timeout);
+
+struct hns_roce_cmd_mailbox
+ *hns_roce_alloc_cmd_mailbox(struct hns_roce_dev *hr_dev);
+void hns_roce_free_cmd_mailbox(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cmd_mailbox *mailbox);
+
+#endif /* _HNS_ROCE_CMD_H */
diff --git a/drivers/infiniband/hw/hns/hns_roce_common.h b/drivers/infiniband/hw/hns/hns_roce_common.h
new file mode 100644
index 000000000000..297016103aa7
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_common.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_COMMON_H
+#define _HNS_ROCE_COMMON_H
+
+#ifndef assert
+#define assert(cond)
+#endif
+
+#define roce_write(dev, reg, val) writel((val), (dev)->reg_base + (reg))
+#define roce_read(dev, reg) readl((dev)->reg_base + (reg))
+#define roce_raw_write(value, addr) \
+ __raw_writel((__force u32)cpu_to_le32(value), (addr))
+
+#define roce_get_field(origin, mask, shift) \
+ (((origin) & (mask)) >> (shift))
+
+#define roce_get_bit(origin, shift) \
+ roce_get_field((origin), (1ul << (shift)), (shift))
+
+#define roce_set_field(origin, mask, shift, val) \
+ do { \
+ (origin) &= (~(mask)); \
+ (origin) |= (((u32)(val) << (shift)) & (mask)); \
+ } while (0)
+
+#define roce_set_bit(origin, shift, val) \
+ roce_set_field((origin), (1ul << (shift)), (shift), (val))
+
+#define ROCEE_GLB_CFG_ROCEE_DB_SQ_MODE_S 3
+#define ROCEE_GLB_CFG_ROCEE_DB_OTH_MODE_S 4
+
+#define ROCEE_GLB_CFG_SQ_EXT_DB_MODE_S 5
+
+#define ROCEE_GLB_CFG_OTH_EXT_DB_MODE_S 6
+
+#define ROCEE_GLB_CFG_ROCEE_PORT_ST_S 10
+#define ROCEE_GLB_CFG_ROCEE_PORT_ST_M \
+ (((1UL << 6) - 1) << ROCEE_GLB_CFG_ROCEE_PORT_ST_S)
+
+#define ROCEE_GLB_CFG_TRP_RAQ_DROP_EN_S 16
+
+#define ROCEE_DMAE_USER_CFG1_ROCEE_STREAM_ID_TB_CFG_S 0
+#define ROCEE_DMAE_USER_CFG1_ROCEE_STREAM_ID_TB_CFG_M \
+ (((1UL << 24) - 1) << ROCEE_DMAE_USER_CFG1_ROCEE_STREAM_ID_TB_CFG_S)
+
+#define ROCEE_DMAE_USER_CFG1_ROCEE_CACHE_TB_CFG_S 24
+#define ROCEE_DMAE_USER_CFG1_ROCEE_CACHE_TB_CFG_M \
+ (((1UL << 4) - 1) << ROCEE_DMAE_USER_CFG1_ROCEE_CACHE_TB_CFG_S)
+
+#define ROCEE_DMAE_USER_CFG2_ROCEE_STREAM_ID_PKT_CFG_S 0
+#define ROCEE_DMAE_USER_CFG2_ROCEE_STREAM_ID_PKT_CFG_M \
+ (((1UL << 24) - 1) << ROCEE_DMAE_USER_CFG2_ROCEE_STREAM_ID_PKT_CFG_S)
+
+#define ROCEE_DMAE_USER_CFG2_ROCEE_CACHE_PKT_CFG_S 24
+#define ROCEE_DMAE_USER_CFG2_ROCEE_CACHE_PKT_CFG_M \
+ (((1UL << 4) - 1) << ROCEE_DMAE_USER_CFG2_ROCEE_CACHE_PKT_CFG_S)
+
+#define ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_S 0
+#define ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_M \
+ (((1UL << 16) - 1) << ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_S)
+
+#define ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_EMPTY_S 16
+#define ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_EMPTY_M \
+ (((1UL << 16) - 1) << ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_EMPTY_S)
+
+#define ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_S 0
+#define ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_M \
+ (((1UL << 16) - 1) << ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_S)
+
+#define ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_EMPTY_S 16
+#define ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_EMPTY_M \
+ (((1UL << 16) - 1) << ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_EMPTY_S)
+
+#define ROCEE_RAQ_WL_ROCEE_RAQ_WL_S 0
+#define ROCEE_RAQ_WL_ROCEE_RAQ_WL_M \
+ (((1UL << 8) - 1) << ROCEE_RAQ_WL_ROCEE_RAQ_WL_S)
+
+#define ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_POL_TIME_INTERVAL_S 0
+#define ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_POL_TIME_INTERVAL_M \
+ (((1UL << 15) - 1) << \
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_POL_TIME_INTERVAL_S)
+
+#define ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_CFG_S 16
+#define ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_CFG_M \
+ (((1UL << 4) - 1) << \
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_CFG_S)
+
+#define ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_EN_S 20
+
+#define ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_EXT_RAQ_MODE 21
+
+#define ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_SHIFT_S 0
+#define ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_SHIFT_M \
+ (((1UL << 5) - 1) << ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_SHIFT_S)
+
+#define ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_BA_H_S 5
+#define ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_BA_H_M \
+ (((1UL << 5) - 1) << ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_BA_H_S)
+
+#define ROCEE_EXT_DB_OTH_H_EXT_DB_OTH_SHIFT_S 0
+#define ROCEE_EXT_DB_OTH_H_EXT_DB_OTH_SHIFT_M \
+ (((1UL << 5) - 1) << ROCEE_EXT_DB_OTH_H_EXT_DB_OTH_SHIFT_S)
+
+#define ROCEE_EXT_DB_SQ_H_EXT_DB_OTH_BA_H_S 5
+#define ROCEE_EXT_DB_SQ_H_EXT_DB_OTH_BA_H_M \
+ (((1UL << 5) - 1) << ROCEE_EXT_DB_SQ_H_EXT_DB_OTH_BA_H_S)
+
+#define ROCEE_EXT_RAQ_H_EXT_RAQ_SHIFT_S 0
+#define ROCEE_EXT_RAQ_H_EXT_RAQ_SHIFT_M \
+ (((1UL << 5) - 1) << ROCEE_EXT_RAQ_H_EXT_RAQ_SHIFT_S)
+
+#define ROCEE_EXT_RAQ_H_EXT_RAQ_BA_H_S 8
+#define ROCEE_EXT_RAQ_H_EXT_RAQ_BA_H_M \
+ (((1UL << 5) - 1) << ROCEE_EXT_RAQ_H_EXT_RAQ_BA_H_S)
+
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S 0
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M \
+ (((1UL << 19) - 1) << ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S)
+
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_S 19
+
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S 20
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M \
+ (((1UL << 2) - 1) << ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S)
+
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S 22
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M \
+ (((1UL << 5) - 1) << ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S)
+
+#define ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S 31
+
+#define ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_S 0
+#define ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_M \
+ (((1UL << 3) - 1) << ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_S)
+
+#define ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S 0
+#define ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_M \
+ (((1UL << 15) - 1) << ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S)
+
+#define ROCEE_MB6_ROCEE_MB_CMD_S 0
+#define ROCEE_MB6_ROCEE_MB_CMD_M \
+ (((1UL << 8) - 1) << ROCEE_MB6_ROCEE_MB_CMD_S)
+
+#define ROCEE_MB6_ROCEE_MB_CMD_MDF_S 8
+#define ROCEE_MB6_ROCEE_MB_CMD_MDF_M \
+ (((1UL << 4) - 1) << ROCEE_MB6_ROCEE_MB_CMD_MDF_S)
+
+#define ROCEE_MB6_ROCEE_MB_EVENT_S 14
+
+#define ROCEE_MB6_ROCEE_MB_HW_RUN_S 15
+
+#define ROCEE_MB6_ROCEE_MB_TOKEN_S 16
+#define ROCEE_MB6_ROCEE_MB_TOKEN_M \
+ (((1UL << 16) - 1) << ROCEE_MB6_ROCEE_MB_TOKEN_S)
+
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_S 0
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_M \
+ (((1UL << 24) - 1) << ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_S)
+
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_S 24
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_M \
+ (((1UL << 4) - 1) << ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_S)
+
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_S 28
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_M \
+ (((1UL << 3) - 1) << ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_S)
+
+#define ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_HW_SYNS_S 31
+
+#define ROCEE_SMAC_H_ROCEE_SMAC_H_S 0
+#define ROCEE_SMAC_H_ROCEE_SMAC_H_M \
+ (((1UL << 16) - 1) << ROCEE_SMAC_H_ROCEE_SMAC_H_S)
+
+#define ROCEE_SMAC_H_ROCEE_PORT_MTU_S 16
+#define ROCEE_SMAC_H_ROCEE_PORT_MTU_M \
+ (((1UL << 4) - 1) << ROCEE_SMAC_H_ROCEE_PORT_MTU_S)
+
+#define ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_S 0
+#define ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_M \
+ (((1UL << 2) - 1) << ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_S)
+
+#define ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_AEQE_SHIFT_S 8
+#define ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_AEQE_SHIFT_M \
+ (((1UL << 4) - 1) << ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_AEQE_SHIFT_S)
+
+#define ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQ_ALM_OVF_INT_ST_S 17
+
+#define ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQ_BT_H_S 0
+#define ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQ_BT_H_M \
+ (((1UL << 5) - 1) << ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQ_BT_H_S)
+
+#define ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQE_CUR_IDX_S 16
+#define ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQE_CUR_IDX_M \
+ (((1UL << 16) - 1) << ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQE_CUR_IDX_S)
+
+#define ROCEE_CAEP_AEQE_CONS_IDX_CAEP_AEQE_CONS_IDX_S 0
+#define ROCEE_CAEP_AEQE_CONS_IDX_CAEP_AEQE_CONS_IDX_M \
+ (((1UL << 16) - 1) << ROCEE_CAEP_AEQE_CONS_IDX_CAEP_AEQE_CONS_IDX_S)
+
+#define ROCEE_CAEP_CEQC_SHIFT_CAEP_CEQ_ALM_OVF_INT_ST_S 16
+#define ROCEE_CAEP_CE_IRQ_MASK_CAEP_CEQ_ALM_OVF_MASK_S 1
+#define ROCEE_CAEP_CEQ_ALM_OVF_CAEP_CEQ_ALM_OVF_S 0
+
+#define ROCEE_CAEP_AE_MASK_CAEP_AEQ_ALM_OVF_MASK_S 0
+#define ROCEE_CAEP_AE_MASK_CAEP_AE_IRQ_MASK_S 1
+
+#define ROCEE_CAEP_AE_ST_CAEP_AEQ_ALM_OVF_S 0
+
+#define ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_S 0
+#define ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_M \
+ (((1UL << 28) - 1) << ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_S)
+
+#define ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S 0
+#define ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M \
+ (((1UL << 28) - 1) << ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S)
+
+#define ROCEE_SDB_INV_CNT_SDB_INV_CNT_S 0
+#define ROCEE_SDB_INV_CNT_SDB_INV_CNT_M \
+ (((1UL << 16) - 1) << ROCEE_SDB_INV_CNT_SDB_INV_CNT_S)
+
+/*************ROCEE_REG DEFINITION****************/
+#define ROCEE_VENDOR_ID_REG 0x0
+#define ROCEE_VENDOR_PART_ID_REG 0x4
+
+#define ROCEE_HW_VERSION_REG 0x8
+
+#define ROCEE_SYS_IMAGE_GUID_L_REG 0xC
+#define ROCEE_SYS_IMAGE_GUID_H_REG 0x10
+
+#define ROCEE_PORT_GID_L_0_REG 0x50
+#define ROCEE_PORT_GID_ML_0_REG 0x54
+#define ROCEE_PORT_GID_MH_0_REG 0x58
+#define ROCEE_PORT_GID_H_0_REG 0x5C
+
+#define ROCEE_BT_CMD_H_REG 0x204
+
+#define ROCEE_SMAC_L_0_REG 0x240
+#define ROCEE_SMAC_H_0_REG 0x244
+
+#define ROCEE_QP1C_CFG3_0_REG 0x27C
+
+#define ROCEE_CAEP_AEQE_CONS_IDX_REG 0x3AC
+#define ROCEE_CAEP_CEQC_CONS_IDX_0_REG 0x3BC
+
+#define ROCEE_ECC_UCERR_ALM1_REG 0xB38
+#define ROCEE_ECC_UCERR_ALM2_REG 0xB3C
+#define ROCEE_ECC_CERR_ALM1_REG 0xB44
+#define ROCEE_ECC_CERR_ALM2_REG 0xB48
+
+#define ROCEE_ACK_DELAY_REG 0x14
+#define ROCEE_GLB_CFG_REG 0x18
+
+#define ROCEE_DMAE_USER_CFG1_REG 0x40
+#define ROCEE_DMAE_USER_CFG2_REG 0x44
+
+#define ROCEE_DB_SQ_WL_REG 0x154
+#define ROCEE_DB_OTHERS_WL_REG 0x158
+#define ROCEE_RAQ_WL_REG 0x15C
+#define ROCEE_WRMS_POL_TIME_INTERVAL_REG 0x160
+#define ROCEE_EXT_DB_SQ_REG 0x164
+#define ROCEE_EXT_DB_SQ_H_REG 0x168
+#define ROCEE_EXT_DB_OTH_REG 0x16C
+
+#define ROCEE_EXT_DB_OTH_H_REG 0x170
+#define ROCEE_EXT_DB_SQ_WL_EMPTY_REG 0x174
+#define ROCEE_EXT_DB_SQ_WL_REG 0x178
+#define ROCEE_EXT_DB_OTHERS_WL_EMPTY_REG 0x17C
+#define ROCEE_EXT_DB_OTHERS_WL_REG 0x180
+#define ROCEE_EXT_RAQ_REG 0x184
+#define ROCEE_EXT_RAQ_H_REG 0x188
+
+#define ROCEE_CAEP_CE_INTERVAL_CFG_REG 0x190
+#define ROCEE_CAEP_CE_BURST_NUM_CFG_REG 0x194
+#define ROCEE_BT_CMD_L_REG 0x200
+
+#define ROCEE_MB1_REG 0x210
+#define ROCEE_DB_SQ_L_0_REG 0x230
+#define ROCEE_DB_OTHERS_L_0_REG 0x238
+#define ROCEE_QP1C_CFG0_0_REG 0x270
+
+#define ROCEE_CAEP_AEQC_AEQE_SHIFT_REG 0x3A0
+#define ROCEE_CAEP_CEQC_SHIFT_0_REG 0x3B0
+#define ROCEE_CAEP_CE_IRQ_MASK_0_REG 0x3C0
+#define ROCEE_CAEP_CEQ_ALM_OVF_0_REG 0x3C4
+#define ROCEE_CAEP_AE_MASK_REG 0x6C8
+#define ROCEE_CAEP_AE_ST_REG 0x6CC
+
+#define ROCEE_SDB_ISSUE_PTR_REG 0x758
+#define ROCEE_SDB_SEND_PTR_REG 0x75C
+#define ROCEE_SDB_INV_CNT_REG 0x9A4
+#define ROCEE_ECC_UCERR_ALM0_REG 0xB34
+#define ROCEE_ECC_CERR_ALM0_REG 0xB40
+
+#endif /* _HNS_ROCE_COMMON_H */
diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c
new file mode 100644
index 000000000000..875597b0e69c
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include <rdma/ib_umem.h>
+#include "hns_roce_device.h"
+#include "hns_roce_cmd.h"
+#include "hns_roce_hem.h"
+#include "hns_roce_user.h"
+#include "hns_roce_common.h"
+
+static void hns_roce_ib_cq_comp(struct hns_roce_cq *hr_cq)
+{
+ struct ib_cq *ibcq = &hr_cq->ib_cq;
+
+ ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
+
+static void hns_roce_ib_cq_event(struct hns_roce_cq *hr_cq,
+ enum hns_roce_event event_type)
+{
+ struct hns_roce_dev *hr_dev;
+ struct ib_event event;
+ struct ib_cq *ibcq;
+
+ ibcq = &hr_cq->ib_cq;
+ hr_dev = to_hr_dev(ibcq->device);
+
+ if (event_type != HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID &&
+ event_type != HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR &&
+ event_type != HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW) {
+ dev_err(&hr_dev->pdev->dev,
+ "hns_roce_ib: Unexpected event type 0x%x on CQ %06lx\n",
+ event_type, hr_cq->cqn);
+ return;
+ }
+
+ if (ibcq->event_handler) {
+ event.device = ibcq->device;
+ event.event = IB_EVENT_CQ_ERR;
+ event.element.cq = ibcq;
+ ibcq->event_handler(&event, ibcq->cq_context);
+ }
+}
+
+static int hns_roce_sw2hw_cq(struct hns_roce_dev *dev,
+ struct hns_roce_cmd_mailbox *mailbox,
+ unsigned long cq_num)
+{
+ return hns_roce_cmd_mbox(dev, mailbox->dma, 0, cq_num, 0,
+ HNS_ROCE_CMD_SW2HW_CQ, HNS_ROCE_CMD_TIME_CLASS_A);
+}
+
+static int hns_roce_cq_alloc(struct hns_roce_dev *hr_dev, int nent,
+ struct hns_roce_mtt *hr_mtt,
+ struct hns_roce_uar *hr_uar,
+ struct hns_roce_cq *hr_cq, int vector,
+ int collapsed)
+{
+ struct hns_roce_cmd_mailbox *mailbox = NULL;
+ struct hns_roce_cq_table *cq_table = NULL;
+ struct device *dev = &hr_dev->pdev->dev;
+ dma_addr_t dma_handle;
+ u64 *mtts = NULL;
+ int ret = 0;
+
+ cq_table = &hr_dev->cq_table;
+
+ /* Get the physical address of cq buf */
+ mtts = hns_roce_table_find(&hr_dev->mr_table.mtt_table,
+ hr_mtt->first_seg, &dma_handle);
+ if (!mtts) {
+ dev_err(dev, "CQ alloc.Failed to find cq buf addr.\n");
+ return -EINVAL;
+ }
+
+ if (vector >= hr_dev->caps.num_comp_vectors) {
+ dev_err(dev, "CQ alloc.Invalid vector.\n");
+ return -EINVAL;
+ }
+ hr_cq->vector = vector;
+
+ ret = hns_roce_bitmap_alloc(&cq_table->bitmap, &hr_cq->cqn);
+ if (ret == -1) {
+ dev_err(dev, "CQ alloc.Failed to alloc index.\n");
+ return -ENOMEM;
+ }
+
+ /* Get CQC memory HEM(Hardware Entry Memory) table */
+ ret = hns_roce_table_get(hr_dev, &cq_table->table, hr_cq->cqn);
+ if (ret) {
+ dev_err(dev, "CQ alloc.Failed to get context mem.\n");
+ goto err_out;
+ }
+
+ /* The cq insert radix tree */
+ spin_lock_irq(&cq_table->lock);
+ /* Radix_tree: The associated pointer and long integer key value like */
+ ret = radix_tree_insert(&cq_table->tree, hr_cq->cqn, hr_cq);
+ spin_unlock_irq(&cq_table->lock);
+ if (ret) {
+ dev_err(dev, "CQ alloc.Failed to radix_tree_insert.\n");
+ goto err_put;
+ }
+
+ /* Allocate mailbox memory */
+ mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
+ if (IS_ERR(mailbox)) {
+ ret = PTR_ERR(mailbox);
+ goto err_radix;
+ }
+
+ hr_dev->hw->write_cqc(hr_dev, hr_cq, mailbox->buf, mtts, dma_handle,
+ nent, vector);
+
+ /* Send mailbox to hw */
+ ret = hns_roce_sw2hw_cq(hr_dev, mailbox, hr_cq->cqn);
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+ if (ret) {
+ dev_err(dev, "CQ alloc.Failed to cmd mailbox.\n");
+ goto err_radix;
+ }
+
+ hr_cq->cons_index = 0;
+ hr_cq->uar = hr_uar;
+
+ return 0;
+
+err_radix:
+ spin_lock_irq(&cq_table->lock);
+ radix_tree_delete(&cq_table->tree, hr_cq->cqn);
+ spin_unlock_irq(&cq_table->lock);
+
+err_put:
+ hns_roce_table_put(hr_dev, &cq_table->table, hr_cq->cqn);
+
+err_out:
+ hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn);
+ return ret;
+}
+
+static int hns_roce_hw2sw_cq(struct hns_roce_dev *dev,
+ struct hns_roce_cmd_mailbox *mailbox,
+ unsigned long cq_num)
+{
+ return hns_roce_cmd_mbox(dev, 0, mailbox ? mailbox->dma : 0, cq_num,
+ mailbox ? 0 : 1, HNS_ROCE_CMD_HW2SW_CQ,
+ HNS_ROCE_CMD_TIME_CLASS_A);
+}
+
+static void hns_roce_free_cq(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cq *hr_cq)
+{
+ struct hns_roce_cq_table *cq_table = &hr_dev->cq_table;
+ struct device *dev = &hr_dev->pdev->dev;
+ int ret;
+
+ ret = hns_roce_hw2sw_cq(hr_dev, NULL, hr_cq->cqn);
+ if (ret)
+ dev_err(dev, "HW2SW_CQ failed (%d) for CQN %06lx\n", ret,
+ hr_cq->cqn);
+
+ /* Waiting interrupt process procedure carried out */
+ synchronize_irq(hr_dev->eq_table.eq[hr_cq->vector].irq);
+
+ spin_lock_irq(&cq_table->lock);
+ radix_tree_delete(&cq_table->tree, hr_cq->cqn);
+ spin_unlock_irq(&cq_table->lock);
+
+ hns_roce_table_put(hr_dev, &cq_table->table, hr_cq->cqn);
+ hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn);
+}
+
+static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev,
+ struct ib_ucontext *context,
+ struct hns_roce_cq_buf *buf,
+ struct ib_umem **umem, u64 buf_addr, int cqe)
+{
+ int ret;
+
+ *umem = ib_umem_get(context, buf_addr, cqe * hr_dev->caps.cq_entry_sz,
+ IB_ACCESS_LOCAL_WRITE, 1);
+ if (IS_ERR(*umem))
+ return PTR_ERR(*umem);
+
+ ret = hns_roce_mtt_init(hr_dev, ib_umem_page_count(*umem),
+ ilog2((unsigned int)(*umem)->page_size),
+ &buf->hr_mtt);
+ if (ret)
+ goto err_buf;
+
+ ret = hns_roce_ib_umem_write_mtt(hr_dev, &buf->hr_mtt, *umem);
+ if (ret)
+ goto err_mtt;
+
+ return 0;
+
+err_mtt:
+ hns_roce_mtt_cleanup(hr_dev, &buf->hr_mtt);
+
+err_buf:
+ ib_umem_release(*umem);
+ return ret;
+}
+
+static int hns_roce_ib_alloc_cq_buf(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cq_buf *buf, u32 nent)
+{
+ int ret;
+
+ ret = hns_roce_buf_alloc(hr_dev, nent * hr_dev->caps.cq_entry_sz,
+ PAGE_SIZE * 2, &buf->hr_buf);
+ if (ret)
+ goto out;
+
+ ret = hns_roce_mtt_init(hr_dev, buf->hr_buf.npages,
+ buf->hr_buf.page_shift, &buf->hr_mtt);
+ if (ret)
+ goto err_buf;
+
+ ret = hns_roce_buf_write_mtt(hr_dev, &buf->hr_mtt, &buf->hr_buf);
+ if (ret)
+ goto err_mtt;
+
+ return 0;
+
+err_mtt:
+ hns_roce_mtt_cleanup(hr_dev, &buf->hr_mtt);
+
+err_buf:
+ hns_roce_buf_free(hr_dev, nent * hr_dev->caps.cq_entry_sz,
+ &buf->hr_buf);
+out:
+ return ret;
+}
+
+static void hns_roce_ib_free_cq_buf(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cq_buf *buf, int cqe)
+{
+ hns_roce_buf_free(hr_dev, (cqe + 1) * hr_dev->caps.cq_entry_sz,
+ &buf->hr_buf);
+}
+
+struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_ib_create_cq ucmd;
+ struct hns_roce_cq *hr_cq = NULL;
+ struct hns_roce_uar *uar = NULL;
+ int vector = attr->comp_vector;
+ int cq_entries = attr->cqe;
+ int ret = 0;
+
+ if (cq_entries < 1 || cq_entries > hr_dev->caps.max_cqes) {
+ dev_err(dev, "Creat CQ failed. entries=%d, max=%d\n",
+ cq_entries, hr_dev->caps.max_cqes);
+ return ERR_PTR(-EINVAL);
+ }
+
+ hr_cq = kmalloc(sizeof(*hr_cq), GFP_KERNEL);
+ if (!hr_cq)
+ return ERR_PTR(-ENOMEM);
+
+ /* In v1 engine, parameter verification */
+ if (cq_entries < HNS_ROCE_MIN_CQE_NUM)
+ cq_entries = HNS_ROCE_MIN_CQE_NUM;
+
+ cq_entries = roundup_pow_of_two((unsigned int)cq_entries);
+ hr_cq->ib_cq.cqe = cq_entries - 1;
+ mutex_init(&hr_cq->resize_mutex);
+ spin_lock_init(&hr_cq->lock);
+ hr_cq->hr_resize_buf = NULL;
+ hr_cq->resize_umem = NULL;
+
+ if (context) {
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+ dev_err(dev, "Failed to copy_from_udata.\n");
+ ret = -EFAULT;
+ goto err_cq;
+ }
+
+ /* Get user space address, write it into mtt table */
+ ret = hns_roce_ib_get_cq_umem(hr_dev, context, &hr_cq->hr_buf,
+ &hr_cq->umem, ucmd.buf_addr,
+ cq_entries);
+ if (ret) {
+ dev_err(dev, "Failed to get_cq_umem.\n");
+ goto err_cq;
+ }
+
+ /* Get user space parameters */
+ uar = &to_hr_ucontext(context)->uar;
+ } else {
+ /* Init mmt table and write buff address to mtt table */
+ ret = hns_roce_ib_alloc_cq_buf(hr_dev, &hr_cq->hr_buf,
+ cq_entries);
+ if (ret) {
+ dev_err(dev, "Failed to alloc_cq_buf.\n");
+ goto err_cq;
+ }
+
+ uar = &hr_dev->priv_uar;
+ hr_cq->cq_db_l = hr_dev->reg_base + ROCEE_DB_OTHERS_L_0_REG +
+ 0x1000 * uar->index;
+ }
+
+ /* Allocate cq index, fill cq_context */
+ ret = hns_roce_cq_alloc(hr_dev, cq_entries, &hr_cq->hr_buf.hr_mtt,
+ uar, hr_cq, vector, 0);
+ if (ret) {
+ dev_err(dev, "Creat CQ .Failed to cq_alloc.\n");
+ goto err_mtt;
+ }
+
+ /* Get created cq handler and carry out event */
+ hr_cq->comp = hns_roce_ib_cq_comp;
+ hr_cq->event = hns_roce_ib_cq_event;
+ hr_cq->cq_depth = cq_entries;
+
+ if (context) {
+ if (ib_copy_to_udata(udata, &hr_cq->cqn, sizeof(u64))) {
+ ret = -EFAULT;
+ goto err_mtt;
+ }
+ }
+
+ return &hr_cq->ib_cq;
+
+err_mtt:
+ hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+ if (context)
+ ib_umem_release(hr_cq->umem);
+ else
+ hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf,
+ hr_cq->ib_cq.cqe);
+
+err_cq:
+ kfree(hr_cq);
+ return ERR_PTR(ret);
+}
+
+int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device);
+ struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq);
+
+ hns_roce_free_cq(hr_dev, hr_cq);
+ hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+
+ if (ib_cq->uobject)
+ ib_umem_release(hr_cq->umem);
+ else
+ /* Free the buff of stored cq */
+ hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf, ib_cq->cqe);
+
+ kfree(hr_cq);
+
+ return 0;
+}
+
+void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_cq *cq;
+
+ cq = radix_tree_lookup(&hr_dev->cq_table.tree,
+ cqn & (hr_dev->caps.num_cqs - 1));
+ if (!cq) {
+ dev_warn(dev, "Completion event for bogus CQ 0x%08x\n", cqn);
+ return;
+ }
+
+ cq->comp(cq);
+}
+
+void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type)
+{
+ struct hns_roce_cq_table *cq_table = &hr_dev->cq_table;
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_cq *cq;
+
+ cq = radix_tree_lookup(&cq_table->tree,
+ cqn & (hr_dev->caps.num_cqs - 1));
+ if (cq)
+ atomic_inc(&cq->refcount);
+
+ if (!cq) {
+ dev_warn(dev, "Async event for bogus CQ %08x\n", cqn);
+ return;
+ }
+
+ cq->event(cq, (enum hns_roce_event)event_type);
+
+ if (atomic_dec_and_test(&cq->refcount))
+ complete(&cq->free);
+}
+
+int hns_roce_init_cq_table(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_cq_table *cq_table = &hr_dev->cq_table;
+
+ spin_lock_init(&cq_table->lock);
+ INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC);
+
+ return hns_roce_bitmap_init(&cq_table->bitmap, hr_dev->caps.num_cqs,
+ hr_dev->caps.num_cqs - 1,
+ hr_dev->caps.reserved_cqs, 0);
+}
+
+void hns_roce_cleanup_cq_table(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_bitmap_cleanup(&hr_dev->cq_table.bitmap);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
new file mode 100644
index 000000000000..ea735800eb18
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_DEVICE_H
+#define _HNS_ROCE_DEVICE_H
+
+#include <rdma/ib_verbs.h>
+
+#define DRV_NAME "hns_roce"
+
+#define MAC_ADDR_OCTET_NUM 6
+#define HNS_ROCE_MAX_MSG_LEN 0x80000000
+
+#define HNS_ROCE_ALOGN_UP(a, b) ((((a) + (b) - 1) / (b)) * (b))
+
+#define HNS_ROCE_IB_MIN_SQ_STRIDE 6
+
+#define HNS_ROCE_BA_SIZE (32 * 4096)
+
+/* Hardware specification only for v1 engine */
+#define HNS_ROCE_MIN_CQE_NUM 0x40
+#define HNS_ROCE_MIN_WQE_NUM 0x20
+
+/* Hardware specification only for v1 engine */
+#define HNS_ROCE_MAX_INNER_MTPT_NUM 0x7
+#define HNS_ROCE_MAX_MTPT_PBL_NUM 0x100000
+
+#define HNS_ROCE_MAX_IRQ_NUM 34
+
+#define HNS_ROCE_COMP_VEC_NUM 32
+
+#define HNS_ROCE_AEQE_VEC_NUM 1
+#define HNS_ROCE_AEQE_OF_VEC_NUM 1
+
+/* 4G/4K = 1M */
+#define HNS_ROCE_SL_SHIFT 29
+#define HNS_ROCE_TCLASS_SHIFT 20
+#define HNS_ROCE_FLOW_LABLE_MASK 0xfffff
+
+#define HNS_ROCE_MAX_PORTS 6
+#define HNS_ROCE_MAX_GID_NUM 16
+#define HNS_ROCE_GID_SIZE 16
+
+#define MR_TYPE_MR 0x00
+#define MR_TYPE_DMA 0x03
+
+#define PKEY_ID 0xffff
+#define NODE_DESC_SIZE 64
+
+#define SERV_TYPE_RC 0
+#define SERV_TYPE_RD 1
+#define SERV_TYPE_UC 2
+#define SERV_TYPE_UD 3
+
+#define PAGES_SHIFT_8 8
+#define PAGES_SHIFT_16 16
+#define PAGES_SHIFT_24 24
+#define PAGES_SHIFT_32 32
+
+enum hns_roce_qp_state {
+ HNS_ROCE_QP_STATE_RST,
+ HNS_ROCE_QP_STATE_INIT,
+ HNS_ROCE_QP_STATE_RTR,
+ HNS_ROCE_QP_STATE_RTS,
+ HNS_ROCE_QP_STATE_SQD,
+ HNS_ROCE_QP_STATE_ERR,
+ HNS_ROCE_QP_NUM_STATE,
+};
+
+enum hns_roce_event {
+ HNS_ROCE_EVENT_TYPE_PATH_MIG = 0x01,
+ HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED = 0x02,
+ HNS_ROCE_EVENT_TYPE_COMM_EST = 0x03,
+ HNS_ROCE_EVENT_TYPE_SQ_DRAINED = 0x04,
+ HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR = 0x05,
+ HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR = 0x06,
+ HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR = 0x07,
+ HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH = 0x08,
+ HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH = 0x09,
+ HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR = 0x0a,
+ HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR = 0x0b,
+ HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW = 0x0c,
+ HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID = 0x0d,
+ HNS_ROCE_EVENT_TYPE_PORT_CHANGE = 0x0f,
+ /* 0x10 and 0x11 is unused in currently application case */
+ HNS_ROCE_EVENT_TYPE_DB_OVERFLOW = 0x12,
+ HNS_ROCE_EVENT_TYPE_MB = 0x13,
+ HNS_ROCE_EVENT_TYPE_CEQ_OVERFLOW = 0x14,
+};
+
+/* Local Work Queue Catastrophic Error,SUBTYPE 0x5 */
+enum {
+ HNS_ROCE_LWQCE_QPC_ERROR = 1,
+ HNS_ROCE_LWQCE_MTU_ERROR = 2,
+ HNS_ROCE_LWQCE_WQE_BA_ADDR_ERROR = 3,
+ HNS_ROCE_LWQCE_WQE_ADDR_ERROR = 4,
+ HNS_ROCE_LWQCE_SQ_WQE_SHIFT_ERROR = 5,
+ HNS_ROCE_LWQCE_SL_ERROR = 6,
+ HNS_ROCE_LWQCE_PORT_ERROR = 7,
+};
+
+/* Local Access Violation Work Queue Error,SUBTYPE 0x7 */
+enum {
+ HNS_ROCE_LAVWQE_R_KEY_VIOLATION = 1,
+ HNS_ROCE_LAVWQE_LENGTH_ERROR = 2,
+ HNS_ROCE_LAVWQE_VA_ERROR = 3,
+ HNS_ROCE_LAVWQE_PD_ERROR = 4,
+ HNS_ROCE_LAVWQE_RW_ACC_ERROR = 5,
+ HNS_ROCE_LAVWQE_KEY_STATE_ERROR = 6,
+ HNS_ROCE_LAVWQE_MR_OPERATION_ERROR = 7,
+};
+
+/* DOORBELL overflow subtype */
+enum {
+ HNS_ROCE_DB_SUBTYPE_SDB_OVF = 1,
+ HNS_ROCE_DB_SUBTYPE_SDB_ALM_OVF = 2,
+ HNS_ROCE_DB_SUBTYPE_ODB_OVF = 3,
+ HNS_ROCE_DB_SUBTYPE_ODB_ALM_OVF = 4,
+ HNS_ROCE_DB_SUBTYPE_SDB_ALM_EMP = 5,
+ HNS_ROCE_DB_SUBTYPE_ODB_ALM_EMP = 6,
+};
+
+enum {
+ /* RQ&SRQ related operations */
+ HNS_ROCE_OPCODE_SEND_DATA_RECEIVE = 0x06,
+ HNS_ROCE_OPCODE_RDMA_WITH_IMM_RECEIVE = 0x07,
+};
+
+#define HNS_ROCE_CMD_SUCCESS 1
+
+#define HNS_ROCE_PORT_DOWN 0
+#define HNS_ROCE_PORT_UP 1
+
+#define HNS_ROCE_MTT_ENTRY_PER_SEG 8
+
+#define PAGE_ADDR_SHIFT 12
+
+struct hns_roce_uar {
+ u64 pfn;
+ unsigned long index;
+};
+
+struct hns_roce_ucontext {
+ struct ib_ucontext ibucontext;
+ struct hns_roce_uar uar;
+};
+
+struct hns_roce_pd {
+ struct ib_pd ibpd;
+ unsigned long pdn;
+};
+
+struct hns_roce_bitmap {
+ /* Bitmap Traversal last a bit which is 1 */
+ unsigned long last;
+ unsigned long top;
+ unsigned long max;
+ unsigned long reserved_top;
+ unsigned long mask;
+ spinlock_t lock;
+ unsigned long *table;
+};
+
+/* Order bitmap length -- bit num compute formula: 1 << (max_order - order) */
+/* Order = 0: bitmap is biggest, order = max bitmap is least (only a bit) */
+/* Every bit repesent to a partner free/used status in bitmap */
+/*
+* Initial, bits of other bitmap are all 0 except that a bit of max_order is 1
+* Bit = 1 represent to idle and available; bit = 0: not available
+*/
+struct hns_roce_buddy {
+ /* Members point to every order level bitmap */
+ unsigned long **bits;
+ /* Represent to avail bits of the order level bitmap */
+ u32 *num_free;
+ int max_order;
+ spinlock_t lock;
+};
+
+/* For Hardware Entry Memory */
+struct hns_roce_hem_table {
+ /* HEM type: 0 = qpc, 1 = mtt, 2 = cqc, 3 = srq, 4 = other */
+ u32 type;
+ /* HEM array elment num */
+ unsigned long num_hem;
+ /* HEM entry record obj total num */
+ unsigned long num_obj;
+ /*Single obj size */
+ unsigned long obj_size;
+ int lowmem;
+ struct mutex mutex;
+ struct hns_roce_hem **hem;
+};
+
+struct hns_roce_mtt {
+ unsigned long first_seg;
+ int order;
+ int page_shift;
+};
+
+/* Only support 4K page size for mr register */
+#define MR_SIZE_4K 0
+
+struct hns_roce_mr {
+ struct ib_mr ibmr;
+ struct ib_umem *umem;
+ u64 iova; /* MR's virtual orignal addr */
+ u64 size; /* Address range of MR */
+ u32 key; /* Key of MR */
+ u32 pd; /* PD num of MR */
+ u32 access;/* Access permission of MR */
+ int enabled; /* MR's active status */
+ int type; /* MR's register type */
+ u64 *pbl_buf;/* MR's PBL space */
+ dma_addr_t pbl_dma_addr; /* MR's PBL space PA */
+};
+
+struct hns_roce_mr_table {
+ struct hns_roce_bitmap mtpt_bitmap;
+ struct hns_roce_buddy mtt_buddy;
+ struct hns_roce_hem_table mtt_table;
+ struct hns_roce_hem_table mtpt_table;
+};
+
+struct hns_roce_wq {
+ u64 *wrid; /* Work request ID */
+ spinlock_t lock;
+ int wqe_cnt; /* WQE num */
+ u32 max_post;
+ int max_gs;
+ int offset;
+ int wqe_shift;/* WQE size */
+ u32 head;
+ u32 tail;
+ void __iomem *db_reg_l;
+};
+
+struct hns_roce_buf_list {
+ void *buf;
+ dma_addr_t map;
+};
+
+struct hns_roce_buf {
+ struct hns_roce_buf_list direct;
+ struct hns_roce_buf_list *page_list;
+ int nbufs;
+ u32 npages;
+ int page_shift;
+};
+
+struct hns_roce_cq_buf {
+ struct hns_roce_buf hr_buf;
+ struct hns_roce_mtt hr_mtt;
+};
+
+struct hns_roce_cq_resize {
+ struct hns_roce_cq_buf hr_buf;
+ int cqe;
+};
+
+struct hns_roce_cq {
+ struct ib_cq ib_cq;
+ struct hns_roce_cq_buf hr_buf;
+ /* pointer to store information after resize*/
+ struct hns_roce_cq_resize *hr_resize_buf;
+ spinlock_t lock;
+ struct mutex resize_mutex;
+ struct ib_umem *umem;
+ struct ib_umem *resize_umem;
+ void (*comp)(struct hns_roce_cq *);
+ void (*event)(struct hns_roce_cq *, enum hns_roce_event);
+
+ struct hns_roce_uar *uar;
+ u32 cq_depth;
+ u32 cons_index;
+ void __iomem *cq_db_l;
+ void __iomem *tptr_addr;
+ unsigned long cqn;
+ u32 vector;
+ atomic_t refcount;
+ struct completion free;
+};
+
+struct hns_roce_srq {
+ struct ib_srq ibsrq;
+ int srqn;
+};
+
+struct hns_roce_uar_table {
+ struct hns_roce_bitmap bitmap;
+};
+
+struct hns_roce_qp_table {
+ struct hns_roce_bitmap bitmap;
+ spinlock_t lock;
+ struct hns_roce_hem_table qp_table;
+ struct hns_roce_hem_table irrl_table;
+};
+
+struct hns_roce_cq_table {
+ struct hns_roce_bitmap bitmap;
+ spinlock_t lock;
+ struct radix_tree_root tree;
+ struct hns_roce_hem_table table;
+};
+
+struct hns_roce_raq_table {
+ struct hns_roce_buf_list *e_raq_buf;
+};
+
+struct hns_roce_av {
+ __le32 port_pd;
+ u8 gid_index;
+ u8 stat_rate;
+ u8 hop_limit;
+ __le32 sl_tclass_flowlabel;
+ u8 dgid[HNS_ROCE_GID_SIZE];
+ u8 mac[6];
+ __le16 vlan;
+};
+
+struct hns_roce_ah {
+ struct ib_ah ibah;
+ struct hns_roce_av av;
+};
+
+struct hns_roce_cmd_context {
+ struct completion done;
+ int result;
+ int next;
+ u64 out_param;
+ u16 token;
+};
+
+struct hns_roce_cmdq {
+ struct dma_pool *pool;
+ u8 __iomem *hcr;
+ struct mutex hcr_mutex;
+ struct semaphore poll_sem;
+ /*
+ * Event mode: cmd register mutex protection,
+ * ensure to not exceed max_cmds and user use limit region
+ */
+ struct semaphore event_sem;
+ int max_cmds;
+ spinlock_t context_lock;
+ int free_head;
+ struct hns_roce_cmd_context *context;
+ /*
+ * Result of get integer part
+ * which max_comds compute according a power of 2
+ */
+ u16 token_mask;
+ /*
+ * Process whether use event mode, init default non-zero
+ * After the event queue of cmd event ready,
+ * can switch into event mode
+ * close device, switch into poll mode(non event mode)
+ */
+ u8 use_events;
+ u8 toggle;
+};
+
+struct hns_roce_dev;
+
+struct hns_roce_qp {
+ struct ib_qp ibqp;
+ struct hns_roce_buf hr_buf;
+ struct hns_roce_wq rq;
+ __le64 doorbell_qpn;
+ __le32 sq_signal_bits;
+ u32 sq_next_wqe;
+ int sq_max_wqes_per_wr;
+ int sq_spare_wqes;
+ struct hns_roce_wq sq;
+
+ struct ib_umem *umem;
+ struct hns_roce_mtt mtt;
+ u32 buff_size;
+ struct mutex mutex;
+ u8 port;
+ u8 sl;
+ u8 resp_depth;
+ u8 state;
+ u32 access_flags;
+ u32 pkey_index;
+ void (*event)(struct hns_roce_qp *,
+ enum hns_roce_event);
+ unsigned long qpn;
+
+ atomic_t refcount;
+ struct completion free;
+};
+
+struct hns_roce_sqp {
+ struct hns_roce_qp hr_qp;
+};
+
+struct hns_roce_ib_iboe {
+ spinlock_t lock;
+ struct net_device *netdevs[HNS_ROCE_MAX_PORTS];
+ struct notifier_block nb;
+ struct notifier_block nb_inet;
+ /* 16 GID is shared by 6 port in v1 engine. */
+ union ib_gid gid_table[HNS_ROCE_MAX_GID_NUM];
+ u8 phy_port[HNS_ROCE_MAX_PORTS];
+};
+
+struct hns_roce_eq {
+ struct hns_roce_dev *hr_dev;
+ void __iomem *doorbell;
+
+ int type_flag;/* Aeq:1 ceq:0 */
+ int eqn;
+ u32 entries;
+ int log_entries;
+ int eqe_size;
+ int irq;
+ int log_page_size;
+ int cons_index;
+ struct hns_roce_buf_list *buf_list;
+};
+
+struct hns_roce_eq_table {
+ struct hns_roce_eq *eq;
+ void __iomem **eqc_base;
+};
+
+struct hns_roce_caps {
+ u8 num_ports;
+ int gid_table_len[HNS_ROCE_MAX_PORTS];
+ int pkey_table_len[HNS_ROCE_MAX_PORTS];
+ int local_ca_ack_delay;
+ int num_uars;
+ u32 phy_num_uars;
+ u32 max_sq_sg; /* 2 */
+ u32 max_sq_inline; /* 32 */
+ u32 max_rq_sg; /* 2 */
+ int num_qps; /* 256k */
+ u32 max_wqes; /* 16k */
+ u32 max_sq_desc_sz; /* 64 */
+ u32 max_rq_desc_sz; /* 64 */
+ int max_qp_init_rdma;
+ int max_qp_dest_rdma;
+ int sqp_start;
+ int num_cqs;
+ int max_cqes;
+ int reserved_cqs;
+ int num_aeq_vectors; /* 1 */
+ int num_comp_vectors; /* 32 ceq */
+ int num_other_vectors;
+ int num_mtpts;
+ u32 num_mtt_segs;
+ int reserved_mrws;
+ int reserved_uars;
+ int num_pds;
+ int reserved_pds;
+ u32 mtt_entry_sz;
+ u32 cq_entry_sz;
+ u32 page_size_cap;
+ u32 reserved_lkey;
+ int mtpt_entry_sz;
+ int qpc_entry_sz;
+ int irrl_entry_sz;
+ int cqc_entry_sz;
+ int aeqe_depth;
+ int ceqe_depth[HNS_ROCE_COMP_VEC_NUM];
+ enum ib_mtu max_mtu;
+};
+
+struct hns_roce_hw {
+ int (*reset)(struct hns_roce_dev *hr_dev, bool enable);
+ void (*hw_profile)(struct hns_roce_dev *hr_dev);
+ int (*hw_init)(struct hns_roce_dev *hr_dev);
+ void (*hw_exit)(struct hns_roce_dev *hr_dev);
+ void (*set_gid)(struct hns_roce_dev *hr_dev, u8 port, int gid_index,
+ union ib_gid *gid);
+ void (*set_mac)(struct hns_roce_dev *hr_dev, u8 phy_port, u8 *addr);
+ void (*set_mtu)(struct hns_roce_dev *hr_dev, u8 phy_port,
+ enum ib_mtu mtu);
+ int (*write_mtpt)(void *mb_buf, struct hns_roce_mr *mr,
+ unsigned long mtpt_idx);
+ void (*write_cqc)(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts,
+ dma_addr_t dma_handle, int nent, u32 vector);
+ int (*query_qp)(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
+ int (*modify_qp)(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
+ int attr_mask, enum ib_qp_state cur_state,
+ enum ib_qp_state new_state);
+ int (*destroy_qp)(struct ib_qp *ibqp);
+ int (*post_send)(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr);
+ int (*post_recv)(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr);
+ int (*req_notify_cq)(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
+ int (*poll_cq)(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+ void *priv;
+};
+
+struct hns_roce_dev {
+ struct ib_device ib_dev;
+ struct platform_device *pdev;
+ struct hns_roce_uar priv_uar;
+ const char *irq_names[HNS_ROCE_MAX_IRQ_NUM];
+ spinlock_t sm_lock;
+ spinlock_t cq_db_lock;
+ spinlock_t bt_cmd_lock;
+ struct hns_roce_ib_iboe iboe;
+
+ int irq[HNS_ROCE_MAX_IRQ_NUM];
+ u8 __iomem *reg_base;
+ struct hns_roce_caps caps;
+ struct radix_tree_root qp_table_tree;
+
+ unsigned char dev_addr[HNS_ROCE_MAX_PORTS][MAC_ADDR_OCTET_NUM];
+ u64 sys_image_guid;
+ u32 vendor_id;
+ u32 vendor_part_id;
+ u32 hw_rev;
+ void __iomem *priv_addr;
+
+ struct hns_roce_cmdq cmd;
+ struct hns_roce_bitmap pd_bitmap;
+ struct hns_roce_uar_table uar_table;
+ struct hns_roce_mr_table mr_table;
+ struct hns_roce_cq_table cq_table;
+ struct hns_roce_qp_table qp_table;
+ struct hns_roce_eq_table eq_table;
+
+ int cmd_mod;
+ int loop_idc;
+ struct hns_roce_hw *hw;
+};
+
+static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev)
+{
+ return container_of(ib_dev, struct hns_roce_dev, ib_dev);
+}
+
+static inline struct hns_roce_ucontext
+ *to_hr_ucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct hns_roce_ucontext, ibucontext);
+}
+
+static inline struct hns_roce_pd *to_hr_pd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct hns_roce_pd, ibpd);
+}
+
+static inline struct hns_roce_ah *to_hr_ah(struct ib_ah *ibah)
+{
+ return container_of(ibah, struct hns_roce_ah, ibah);
+}
+
+static inline struct hns_roce_mr *to_hr_mr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct hns_roce_mr, ibmr);
+}
+
+static inline struct hns_roce_qp *to_hr_qp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct hns_roce_qp, ibqp);
+}
+
+static inline struct hns_roce_cq *to_hr_cq(struct ib_cq *ib_cq)
+{
+ return container_of(ib_cq, struct hns_roce_cq, ib_cq);
+}
+
+static inline struct hns_roce_srq *to_hr_srq(struct ib_srq *ibsrq)
+{
+ return container_of(ibsrq, struct hns_roce_srq, ibsrq);
+}
+
+static inline struct hns_roce_sqp *hr_to_hr_sqp(struct hns_roce_qp *hr_qp)
+{
+ return container_of(hr_qp, struct hns_roce_sqp, hr_qp);
+}
+
+static inline void hns_roce_write64_k(__be32 val[2], void __iomem *dest)
+{
+ __raw_writeq(*(u64 *) val, dest);
+}
+
+static inline struct hns_roce_qp
+ *__hns_roce_qp_lookup(struct hns_roce_dev *hr_dev, u32 qpn)
+{
+ return radix_tree_lookup(&hr_dev->qp_table_tree,
+ qpn & (hr_dev->caps.num_qps - 1));
+}
+
+static inline void *hns_roce_buf_offset(struct hns_roce_buf *buf, int offset)
+{
+ u32 bits_per_long_val = BITS_PER_LONG;
+
+ if (bits_per_long_val == 64 || buf->nbufs == 1)
+ return (char *)(buf->direct.buf) + offset;
+ else
+ return (char *)(buf->page_list[offset >> PAGE_SHIFT].buf) +
+ (offset & (PAGE_SIZE - 1));
+}
+
+int hns_roce_init_uar_table(struct hns_roce_dev *dev);
+int hns_roce_uar_alloc(struct hns_roce_dev *dev, struct hns_roce_uar *uar);
+void hns_roce_uar_free(struct hns_roce_dev *dev, struct hns_roce_uar *uar);
+void hns_roce_cleanup_uar_table(struct hns_roce_dev *dev);
+
+int hns_roce_cmd_init(struct hns_roce_dev *hr_dev);
+void hns_roce_cmd_cleanup(struct hns_roce_dev *hr_dev);
+void hns_roce_cmd_event(struct hns_roce_dev *hr_dev, u16 token, u8 status,
+ u64 out_param);
+int hns_roce_cmd_use_events(struct hns_roce_dev *hr_dev);
+void hns_roce_cmd_use_polling(struct hns_roce_dev *hr_dev);
+
+int hns_roce_mtt_init(struct hns_roce_dev *hr_dev, int npages, int page_shift,
+ struct hns_roce_mtt *mtt);
+void hns_roce_mtt_cleanup(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt);
+int hns_roce_buf_write_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt, struct hns_roce_buf *buf);
+
+int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev);
+int hns_roce_init_mr_table(struct hns_roce_dev *hr_dev);
+int hns_roce_init_eq_table(struct hns_roce_dev *hr_dev);
+int hns_roce_init_cq_table(struct hns_roce_dev *hr_dev);
+int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev);
+
+void hns_roce_cleanup_pd_table(struct hns_roce_dev *hr_dev);
+void hns_roce_cleanup_mr_table(struct hns_roce_dev *hr_dev);
+void hns_roce_cleanup_eq_table(struct hns_roce_dev *hr_dev);
+void hns_roce_cleanup_cq_table(struct hns_roce_dev *hr_dev);
+void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev);
+
+int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj);
+void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj);
+int hns_roce_bitmap_init(struct hns_roce_bitmap *bitmap, u32 num, u32 mask,
+ u32 reserved_bot, u32 resetrved_top);
+void hns_roce_bitmap_cleanup(struct hns_roce_bitmap *bitmap);
+void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev);
+int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt,
+ int align, unsigned long *obj);
+void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap,
+ unsigned long obj, int cnt);
+
+struct ib_ah *hns_roce_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+int hns_roce_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr);
+int hns_roce_destroy_ah(struct ib_ah *ah);
+
+struct ib_pd *hns_roce_alloc_pd(struct ib_device *ib_dev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+int hns_roce_dealloc_pd(struct ib_pd *pd);
+
+struct ib_mr *hns_roce_get_dma_mr(struct ib_pd *pd, int acc);
+struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt_addr, int access_flags,
+ struct ib_udata *udata);
+int hns_roce_dereg_mr(struct ib_mr *ibmr);
+
+void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
+ struct hns_roce_buf *buf);
+int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
+ struct hns_roce_buf *buf);
+
+int hns_roce_ib_umem_write_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt, struct ib_umem *umem);
+
+struct ib_qp *hns_roce_create_qp(struct ib_pd *ib_pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata);
+void *get_recv_wqe(struct hns_roce_qp *hr_qp, int n);
+void *get_send_wqe(struct hns_roce_qp *hr_qp, int n);
+bool hns_roce_wq_overflow(struct hns_roce_wq *hr_wq, int nreq,
+ struct ib_cq *ib_cq);
+enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state);
+void hns_roce_lock_cqs(struct hns_roce_cq *send_cq,
+ struct hns_roce_cq *recv_cq);
+void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq,
+ struct hns_roce_cq *recv_cq);
+void hns_roce_qp_remove(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
+void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
+void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
+ int cnt);
+__be32 send_ieth(struct ib_send_wr *wr);
+int to_hr_qp_type(int qp_type);
+
+struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq);
+
+void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn);
+void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type);
+void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type);
+int hns_get_gid_index(struct hns_roce_dev *hr_dev, u8 port, int gid_index);
+
+extern struct hns_roce_hw hns_roce_hw_v1;
+
+#endif /* _HNS_ROCE_DEVICE_H */
diff --git a/drivers/infiniband/hw/hns/hns_roce_eq.c b/drivers/infiniband/hw/hns/hns_roce_eq.c
new file mode 100644
index 000000000000..98af7fecf2f1
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_eq.c
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include "hns_roce_common.h"
+#include "hns_roce_device.h"
+#include "hns_roce_eq.h"
+
+static void eq_set_cons_index(struct hns_roce_eq *eq, int req_not)
+{
+ roce_raw_write((eq->cons_index & CONS_INDEX_MASK) |
+ (req_not << eq->log_entries), eq->doorbell);
+ /* Memory barrier */
+ mb();
+}
+
+static struct hns_roce_aeqe *get_aeqe(struct hns_roce_eq *eq, u32 entry)
+{
+ unsigned long off = (entry & (eq->entries - 1)) *
+ HNS_ROCE_AEQ_ENTRY_SIZE;
+
+ return (struct hns_roce_aeqe *)((u8 *)
+ (eq->buf_list[off / HNS_ROCE_BA_SIZE].buf) +
+ off % HNS_ROCE_BA_SIZE);
+}
+
+static struct hns_roce_aeqe *next_aeqe_sw(struct hns_roce_eq *eq)
+{
+ struct hns_roce_aeqe *aeqe = get_aeqe(eq, eq->cons_index);
+
+ return (roce_get_bit(aeqe->asyn, HNS_ROCE_AEQE_U32_4_OWNER_S) ^
+ !!(eq->cons_index & eq->entries)) ? aeqe : NULL;
+}
+
+static void hns_roce_wq_catas_err_handle(struct hns_roce_dev *hr_dev,
+ struct hns_roce_aeqe *aeqe, int qpn)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+
+ qpn = roce_get_field(aeqe->event.qp_event.qp,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S);
+ dev_warn(dev, "Local Work Queue Catastrophic Error.\n");
+ switch (roce_get_field(aeqe->asyn, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S)) {
+ case HNS_ROCE_LWQCE_QPC_ERROR:
+ dev_warn(dev, "QP %d, QPC error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_MTU_ERROR:
+ dev_warn(dev, "QP %d, MTU error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_WQE_BA_ADDR_ERROR:
+ dev_warn(dev, "QP %d, WQE BA addr error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_WQE_ADDR_ERROR:
+ dev_warn(dev, "QP %d, WQE addr error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_SQ_WQE_SHIFT_ERROR:
+ dev_warn(dev, "QP %d, WQE shift error\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_SL_ERROR:
+ dev_warn(dev, "QP %d, SL error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_PORT_ERROR:
+ dev_warn(dev, "QP %d, port error.\n", qpn);
+ break;
+ default:
+ break;
+ }
+
+ hns_roce_qp_event(hr_dev, roce_get_field(aeqe->event.qp_event.qp,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S),
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+}
+
+static void hns_roce_local_wq_access_err_handle(struct hns_roce_dev *hr_dev,
+ struct hns_roce_aeqe *aeqe,
+ int qpn)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+
+ qpn = roce_get_field(aeqe->event.qp_event.qp,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S);
+ dev_warn(dev, "Local Access Violation Work Queue Error.\n");
+ switch (roce_get_field(aeqe->asyn, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S)) {
+ case HNS_ROCE_LAVWQE_R_KEY_VIOLATION:
+ dev_warn(dev, "QP %d, R_key violation.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_LENGTH_ERROR:
+ dev_warn(dev, "QP %d, length error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_VA_ERROR:
+ dev_warn(dev, "QP %d, VA error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_PD_ERROR:
+ dev_err(dev, "QP %d, PD error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_RW_ACC_ERROR:
+ dev_warn(dev, "QP %d, rw acc error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_KEY_STATE_ERROR:
+ dev_warn(dev, "QP %d, key state error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_MR_OPERATION_ERROR:
+ dev_warn(dev, "QP %d, MR operation error.\n", qpn);
+ break;
+ default:
+ break;
+ }
+
+ hns_roce_qp_event(hr_dev, roce_get_field(aeqe->event.qp_event.qp,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S),
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+}
+
+static void hns_roce_db_overflow_handle(struct hns_roce_dev *hr_dev,
+ struct hns_roce_aeqe *aeqe)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+
+ switch (roce_get_field(aeqe->asyn, HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S)) {
+ case HNS_ROCE_DB_SUBTYPE_SDB_OVF:
+ dev_warn(dev, "SDB overflow.\n");
+ break;
+ case HNS_ROCE_DB_SUBTYPE_SDB_ALM_OVF:
+ dev_warn(dev, "SDB almost overflow.\n");
+ break;
+ case HNS_ROCE_DB_SUBTYPE_SDB_ALM_EMP:
+ dev_warn(dev, "SDB almost empty.\n");
+ break;
+ case HNS_ROCE_DB_SUBTYPE_ODB_OVF:
+ dev_warn(dev, "ODB overflow.\n");
+ break;
+ case HNS_ROCE_DB_SUBTYPE_ODB_ALM_OVF:
+ dev_warn(dev, "ODB almost overflow.\n");
+ break;
+ case HNS_ROCE_DB_SUBTYPE_ODB_ALM_EMP:
+ dev_warn(dev, "SDB almost empty.\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static int hns_roce_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_aeqe *aeqe;
+ int aeqes_found = 0;
+ int qpn = 0;
+
+ while ((aeqe = next_aeqe_sw(eq))) {
+ dev_dbg(dev, "aeqe = %p, aeqe->asyn.event_type = 0x%lx\n", aeqe,
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+ /* Memory barrier */
+ rmb();
+
+ switch (roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)) {
+ case HNS_ROCE_EVENT_TYPE_PATH_MIG:
+ dev_warn(dev, "PATH MIG not supported\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_COMM_EST:
+ dev_warn(dev, "COMMUNICATION established\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
+ dev_warn(dev, "SQ DRAINED not supported\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED:
+ dev_warn(dev, "PATH MIG failed\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
+ dev_warn(dev, "qpn = 0x%lx\n",
+ roce_get_field(aeqe->event.qp_event.qp,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S));
+ hns_roce_qp_event(hr_dev,
+ roce_get_field(aeqe->event.qp_event.qp,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M,
+ HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S),
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+ break;
+ case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
+ hns_roce_wq_catas_err_handle(hr_dev, aeqe, qpn);
+ break;
+ case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
+ hns_roce_local_wq_access_err_handle(hr_dev, aeqe, qpn);
+ break;
+ case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH:
+ case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR:
+ case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH:
+ dev_warn(dev, "SRQ not support!\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR:
+ dev_warn(dev, "CQ 0x%lx access err.\n",
+ roce_get_field(aeqe->event.cq_event.cq,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S));
+ hns_roce_cq_event(hr_dev,
+ le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)),
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+ break;
+ case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW:
+ dev_warn(dev, "CQ 0x%lx overflow\n",
+ roce_get_field(aeqe->event.cq_event.cq,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S));
+ hns_roce_cq_event(hr_dev,
+ le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)),
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+ break;
+ case HNS_ROCE_EVENT_TYPE_CQ_ID_INVALID:
+ dev_warn(dev, "CQ ID invalid.\n");
+ hns_roce_cq_event(hr_dev,
+ le32_to_cpu(roce_get_field(aeqe->event.cq_event.cq,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M,
+ HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)),
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
+ break;
+ case HNS_ROCE_EVENT_TYPE_PORT_CHANGE:
+ dev_warn(dev, "port change.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_MB:
+ hns_roce_cmd_event(hr_dev,
+ le16_to_cpu(aeqe->event.cmd.token),
+ aeqe->event.cmd.status,
+ le64_to_cpu(aeqe->event.cmd.out_param
+ ));
+ break;
+ case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW:
+ hns_roce_db_overflow_handle(hr_dev, aeqe);
+ break;
+ case HNS_ROCE_EVENT_TYPE_CEQ_OVERFLOW:
+ dev_warn(dev, "CEQ 0x%lx overflow.\n",
+ roce_get_field(aeqe->event.ce_event.ceqe,
+ HNS_ROCE_AEQE_EVENT_CE_EVENT_CEQE_CEQN_M,
+ HNS_ROCE_AEQE_EVENT_CE_EVENT_CEQE_CEQN_S));
+ break;
+ default:
+ dev_warn(dev, "Unhandled event 0x%lx on EQ %d at index %u\n",
+ roce_get_field(aeqe->asyn,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
+ HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S),
+ eq->eqn, eq->cons_index);
+ break;
+ };
+
+ eq->cons_index++;
+ aeqes_found = 1;
+
+ if (eq->cons_index > 2 * hr_dev->caps.aeqe_depth - 1) {
+ dev_warn(dev, "cons_index overflow, set back to zero\n"
+ );
+ eq->cons_index = 0;
+ }
+ }
+
+ eq_set_cons_index(eq, 0);
+
+ return aeqes_found;
+}
+
+static struct hns_roce_ceqe *get_ceqe(struct hns_roce_eq *eq, u32 entry)
+{
+ unsigned long off = (entry & (eq->entries - 1)) *
+ HNS_ROCE_CEQ_ENTRY_SIZE;
+
+ return (struct hns_roce_ceqe *)((u8 *)
+ (eq->buf_list[off / HNS_ROCE_BA_SIZE].buf) +
+ off % HNS_ROCE_BA_SIZE);
+}
+
+static struct hns_roce_ceqe *next_ceqe_sw(struct hns_roce_eq *eq)
+{
+ struct hns_roce_ceqe *ceqe = get_ceqe(eq, eq->cons_index);
+
+ return (!!(roce_get_bit(ceqe->ceqe.comp,
+ HNS_ROCE_CEQE_CEQE_COMP_OWNER_S))) ^
+ (!!(eq->cons_index & eq->entries)) ? ceqe : NULL;
+}
+
+static int hns_roce_ceq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq)
+{
+ struct hns_roce_ceqe *ceqe;
+ int ceqes_found = 0;
+ u32 cqn;
+
+ while ((ceqe = next_ceqe_sw(eq))) {
+ /* Memory barrier */
+ rmb();
+ cqn = roce_get_field(ceqe->ceqe.comp,
+ HNS_ROCE_CEQE_CEQE_COMP_CQN_M,
+ HNS_ROCE_CEQE_CEQE_COMP_CQN_S);
+ hns_roce_cq_completion(hr_dev, cqn);
+
+ ++eq->cons_index;
+ ceqes_found = 1;
+
+ if (eq->cons_index > 2 * hr_dev->caps.ceqe_depth[eq->eqn] - 1) {
+ dev_warn(&eq->hr_dev->pdev->dev,
+ "cons_index overflow, set back to zero\n");
+ eq->cons_index = 0;
+ }
+ }
+
+ eq_set_cons_index(eq, 0);
+
+ return ceqes_found;
+}
+
+static int hns_roce_aeq_ovf_int(struct hns_roce_dev *hr_dev,
+ struct hns_roce_eq *eq)
+{
+ struct device *dev = &eq->hr_dev->pdev->dev;
+ int eqovf_found = 0;
+ u32 caepaemask_val;
+ u32 cealmovf_val;
+ u32 caepaest_val;
+ u32 aeshift_val;
+ u32 ceshift_val;
+ u32 cemask_val;
+ int i = 0;
+
+ /**
+ * AEQ overflow ECC mult bit err CEQ overflow alarm
+ * must clear interrupt, mask irq, clear irq, cancel mask operation
+ */
+ aeshift_val = roce_read(hr_dev, ROCEE_CAEP_AEQC_AEQE_SHIFT_REG);
+
+ if (roce_get_bit(aeshift_val,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQ_ALM_OVF_INT_ST_S) == 1) {
+ dev_warn(dev, "AEQ overflow!\n");
+
+ /* Set mask */
+ caepaemask_val = roce_read(hr_dev, ROCEE_CAEP_AE_MASK_REG);
+ roce_set_bit(caepaemask_val,
+ ROCEE_CAEP_AE_MASK_CAEP_AEQ_ALM_OVF_MASK_S,
+ HNS_ROCE_INT_MASK_ENABLE);
+ roce_write(hr_dev, ROCEE_CAEP_AE_MASK_REG, caepaemask_val);
+
+ /* Clear int state(INT_WC : write 1 clear) */
+ caepaest_val = roce_read(hr_dev, ROCEE_CAEP_AE_ST_REG);
+ roce_set_bit(caepaest_val,
+ ROCEE_CAEP_AE_ST_CAEP_AEQ_ALM_OVF_S, 1);
+ roce_write(hr_dev, ROCEE_CAEP_AE_ST_REG, caepaest_val);
+
+ /* Clear mask */
+ caepaemask_val = roce_read(hr_dev, ROCEE_CAEP_AE_MASK_REG);
+ roce_set_bit(caepaemask_val,
+ ROCEE_CAEP_AE_MASK_CAEP_AEQ_ALM_OVF_MASK_S,
+ HNS_ROCE_INT_MASK_DISABLE);
+ roce_write(hr_dev, ROCEE_CAEP_AE_MASK_REG, caepaemask_val);
+ }
+
+ /* CEQ almost overflow */
+ for (i = 0; i < hr_dev->caps.num_comp_vectors; i++) {
+ ceshift_val = roce_read(hr_dev, ROCEE_CAEP_CEQC_SHIFT_0_REG +
+ i * CEQ_REG_OFFSET);
+
+ if (roce_get_bit(ceshift_val,
+ ROCEE_CAEP_CEQC_SHIFT_CAEP_CEQ_ALM_OVF_INT_ST_S) == 1) {
+ dev_warn(dev, "CEQ[%d] almost overflow!\n", i);
+ eqovf_found++;
+
+ /* Set mask */
+ cemask_val = roce_read(hr_dev,
+ ROCEE_CAEP_CE_IRQ_MASK_0_REG +
+ i * CEQ_REG_OFFSET);
+ roce_set_bit(cemask_val,
+ ROCEE_CAEP_CE_IRQ_MASK_CAEP_CEQ_ALM_OVF_MASK_S,
+ HNS_ROCE_INT_MASK_ENABLE);
+ roce_write(hr_dev, ROCEE_CAEP_CE_IRQ_MASK_0_REG +
+ i * CEQ_REG_OFFSET, cemask_val);
+
+ /* Clear int state(INT_WC : write 1 clear) */
+ cealmovf_val = roce_read(hr_dev,
+ ROCEE_CAEP_CEQ_ALM_OVF_0_REG +
+ i * CEQ_REG_OFFSET);
+ roce_set_bit(cealmovf_val,
+ ROCEE_CAEP_CEQ_ALM_OVF_CAEP_CEQ_ALM_OVF_S,
+ 1);
+ roce_write(hr_dev, ROCEE_CAEP_CEQ_ALM_OVF_0_REG +
+ i * CEQ_REG_OFFSET, cealmovf_val);
+
+ /* Clear mask */
+ cemask_val = roce_read(hr_dev,
+ ROCEE_CAEP_CE_IRQ_MASK_0_REG +
+ i * CEQ_REG_OFFSET);
+ roce_set_bit(cemask_val,
+ ROCEE_CAEP_CE_IRQ_MASK_CAEP_CEQ_ALM_OVF_MASK_S,
+ HNS_ROCE_INT_MASK_DISABLE);
+ roce_write(hr_dev, ROCEE_CAEP_CE_IRQ_MASK_0_REG +
+ i * CEQ_REG_OFFSET, cemask_val);
+ }
+ }
+
+ /* ECC multi-bit error alarm */
+ dev_warn(dev, "ECC UCERR ALARM: 0x%x, 0x%x, 0x%x\n",
+ roce_read(hr_dev, ROCEE_ECC_UCERR_ALM0_REG),
+ roce_read(hr_dev, ROCEE_ECC_UCERR_ALM1_REG),
+ roce_read(hr_dev, ROCEE_ECC_UCERR_ALM2_REG));
+
+ dev_warn(dev, "ECC CERR ALARM: 0x%x, 0x%x, 0x%x\n",
+ roce_read(hr_dev, ROCEE_ECC_CERR_ALM0_REG),
+ roce_read(hr_dev, ROCEE_ECC_CERR_ALM1_REG),
+ roce_read(hr_dev, ROCEE_ECC_CERR_ALM2_REG));
+
+ return eqovf_found;
+}
+
+static int hns_roce_eq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq)
+{
+ int eqes_found = 0;
+
+ if (likely(eq->type_flag == HNS_ROCE_CEQ))
+ /* CEQ irq routine, CEQ is pulse irq, not clear */
+ eqes_found = hns_roce_ceq_int(hr_dev, eq);
+ else if (likely(eq->type_flag == HNS_ROCE_AEQ))
+ /* AEQ irq routine, AEQ is pulse irq, not clear */
+ eqes_found = hns_roce_aeq_int(hr_dev, eq);
+ else
+ /* AEQ queue overflow irq */
+ eqes_found = hns_roce_aeq_ovf_int(hr_dev, eq);
+
+ return eqes_found;
+}
+
+static irqreturn_t hns_roce_msi_x_interrupt(int irq, void *eq_ptr)
+{
+ int int_work = 0;
+ struct hns_roce_eq *eq = eq_ptr;
+ struct hns_roce_dev *hr_dev = eq->hr_dev;
+
+ int_work = hns_roce_eq_int(hr_dev, eq);
+
+ return IRQ_RETVAL(int_work);
+}
+
+static void hns_roce_enable_eq(struct hns_roce_dev *hr_dev, int eq_num,
+ int enable_flag)
+{
+ void __iomem *eqc = hr_dev->eq_table.eqc_base[eq_num];
+ u32 val;
+
+ val = readl(eqc);
+
+ if (enable_flag)
+ roce_set_field(val,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_M,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_S,
+ HNS_ROCE_EQ_STAT_VALID);
+ else
+ roce_set_field(val,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_M,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_S,
+ HNS_ROCE_EQ_STAT_INVALID);
+ writel(val, eqc);
+}
+
+static int hns_roce_create_eq(struct hns_roce_dev *hr_dev,
+ struct hns_roce_eq *eq)
+{
+ void __iomem *eqc = hr_dev->eq_table.eqc_base[eq->eqn];
+ struct device *dev = &hr_dev->pdev->dev;
+ dma_addr_t tmp_dma_addr;
+ u32 eqconsindx_val = 0;
+ u32 eqcuridx_val = 0;
+ u32 eqshift_val = 0;
+ int num_bas = 0;
+ int ret;
+ int i;
+
+ num_bas = (PAGE_ALIGN(eq->entries * eq->eqe_size) +
+ HNS_ROCE_BA_SIZE - 1) / HNS_ROCE_BA_SIZE;
+
+ if ((eq->entries * eq->eqe_size) > HNS_ROCE_BA_SIZE) {
+ dev_err(dev, "[error]eq buf %d gt ba size(%d) need bas=%d\n",
+ (eq->entries * eq->eqe_size), HNS_ROCE_BA_SIZE,
+ num_bas);
+ return -EINVAL;
+ }
+
+ eq->buf_list = kcalloc(num_bas, sizeof(*eq->buf_list), GFP_KERNEL);
+ if (!eq->buf_list)
+ return -ENOMEM;
+
+ for (i = 0; i < num_bas; ++i) {
+ eq->buf_list[i].buf = dma_alloc_coherent(dev, HNS_ROCE_BA_SIZE,
+ &tmp_dma_addr,
+ GFP_KERNEL);
+ if (!eq->buf_list[i].buf) {
+ ret = -ENOMEM;
+ goto err_out_free_pages;
+ }
+
+ eq->buf_list[i].map = tmp_dma_addr;
+ memset(eq->buf_list[i].buf, 0, HNS_ROCE_BA_SIZE);
+ }
+ eq->cons_index = 0;
+ roce_set_field(eqshift_val,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_M,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_S,
+ HNS_ROCE_EQ_STAT_INVALID);
+ roce_set_field(eqshift_val,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_AEQE_SHIFT_M,
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_AEQE_SHIFT_S,
+ eq->log_entries);
+ writel(eqshift_val, eqc);
+
+ /* Configure eq extended address 12~44bit */
+ writel((u32)(eq->buf_list[0].map >> 12), (u8 *)eqc + 4);
+
+ /*
+ * Configure eq extended address 45~49 bit.
+ * 44 = 32 + 12, When evaluating addr to hardware, shift 12 because of
+ * using 4K page, and shift more 32 because of
+ * caculating the high 32 bit value evaluated to hardware.
+ */
+ roce_set_field(eqcuridx_val, ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQ_BT_H_M,
+ ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQ_BT_H_S,
+ eq->buf_list[0].map >> 44);
+ roce_set_field(eqcuridx_val,
+ ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQE_CUR_IDX_M,
+ ROCEE_CAEP_AEQE_CUR_IDX_CAEP_AEQE_CUR_IDX_S, 0);
+ writel(eqcuridx_val, (u8 *)eqc + 8);
+
+ /* Configure eq consumer index */
+ roce_set_field(eqconsindx_val,
+ ROCEE_CAEP_AEQE_CONS_IDX_CAEP_AEQE_CONS_IDX_M,
+ ROCEE_CAEP_AEQE_CONS_IDX_CAEP_AEQE_CONS_IDX_S, 0);
+ writel(eqconsindx_val, (u8 *)eqc + 0xc);
+
+ return 0;
+
+err_out_free_pages:
+ for (i = i - 1; i >= 0; i--)
+ dma_free_coherent(dev, HNS_ROCE_BA_SIZE, eq->buf_list[i].buf,
+ eq->buf_list[i].map);
+
+ kfree(eq->buf_list);
+ return ret;
+}
+
+static void hns_roce_free_eq(struct hns_roce_dev *hr_dev,
+ struct hns_roce_eq *eq)
+{
+ int i = 0;
+ int npages = (PAGE_ALIGN(eq->eqe_size * eq->entries) +
+ HNS_ROCE_BA_SIZE - 1) / HNS_ROCE_BA_SIZE;
+
+ if (!eq->buf_list)
+ return;
+
+ for (i = 0; i < npages; ++i)
+ dma_free_coherent(&hr_dev->pdev->dev, HNS_ROCE_BA_SIZE,
+ eq->buf_list[i].buf, eq->buf_list[i].map);
+
+ kfree(eq->buf_list);
+}
+
+static void hns_roce_int_mask_en(struct hns_roce_dev *hr_dev)
+{
+ int i = 0;
+ u32 aemask_val;
+ int masken = 0;
+
+ /* AEQ INT */
+ aemask_val = roce_read(hr_dev, ROCEE_CAEP_AE_MASK_REG);
+ roce_set_bit(aemask_val, ROCEE_CAEP_AE_MASK_CAEP_AEQ_ALM_OVF_MASK_S,
+ masken);
+ roce_set_bit(aemask_val, ROCEE_CAEP_AE_MASK_CAEP_AE_IRQ_MASK_S, masken);
+ roce_write(hr_dev, ROCEE_CAEP_AE_MASK_REG, aemask_val);
+
+ /* CEQ INT */
+ for (i = 0; i < hr_dev->caps.num_comp_vectors; i++) {
+ /* IRQ mask */
+ roce_write(hr_dev, ROCEE_CAEP_CE_IRQ_MASK_0_REG +
+ i * CEQ_REG_OFFSET, masken);
+ }
+}
+
+static void hns_roce_ce_int_default_cfg(struct hns_roce_dev *hr_dev)
+{
+ /* Configure ce int interval */
+ roce_write(hr_dev, ROCEE_CAEP_CE_INTERVAL_CFG_REG,
+ HNS_ROCE_CEQ_DEFAULT_INTERVAL);
+
+ /* Configure ce int burst num */
+ roce_write(hr_dev, ROCEE_CAEP_CE_BURST_NUM_CFG_REG,
+ HNS_ROCE_CEQ_DEFAULT_BURST_NUM);
+}
+
+int hns_roce_init_eq_table(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_eq_table *eq_table = &hr_dev->eq_table;
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_eq *eq = NULL;
+ int eq_num = 0;
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+
+ eq_num = hr_dev->caps.num_comp_vectors + hr_dev->caps.num_aeq_vectors;
+ eq_table->eq = kcalloc(eq_num, sizeof(*eq_table->eq), GFP_KERNEL);
+ if (!eq_table->eq)
+ return -ENOMEM;
+
+ eq_table->eqc_base = kcalloc(eq_num, sizeof(*eq_table->eqc_base),
+ GFP_KERNEL);
+ if (!eq_table->eqc_base) {
+ ret = -ENOMEM;
+ goto err_eqc_base_alloc_fail;
+ }
+
+ for (i = 0; i < eq_num; i++) {
+ eq = &eq_table->eq[i];
+ eq->hr_dev = hr_dev;
+ eq->eqn = i;
+ eq->irq = hr_dev->irq[i];
+ eq->log_page_size = PAGE_SHIFT;
+
+ if (i < hr_dev->caps.num_comp_vectors) {
+ /* CEQ */
+ eq_table->eqc_base[i] = hr_dev->reg_base +
+ ROCEE_CAEP_CEQC_SHIFT_0_REG +
+ HNS_ROCE_CEQC_REG_OFFSET * i;
+ eq->type_flag = HNS_ROCE_CEQ;
+ eq->doorbell = hr_dev->reg_base +
+ ROCEE_CAEP_CEQC_CONS_IDX_0_REG +
+ HNS_ROCE_CEQC_REG_OFFSET * i;
+ eq->entries = hr_dev->caps.ceqe_depth[i];
+ eq->log_entries = ilog2(eq->entries);
+ eq->eqe_size = sizeof(struct hns_roce_ceqe);
+ } else {
+ /* AEQ */
+ eq_table->eqc_base[i] = hr_dev->reg_base +
+ ROCEE_CAEP_AEQC_AEQE_SHIFT_REG;
+ eq->type_flag = HNS_ROCE_AEQ;
+ eq->doorbell = hr_dev->reg_base +
+ ROCEE_CAEP_AEQE_CONS_IDX_REG;
+ eq->entries = hr_dev->caps.aeqe_depth;
+ eq->log_entries = ilog2(eq->entries);
+ eq->eqe_size = sizeof(struct hns_roce_aeqe);
+ }
+ }
+
+ /* Disable irq */
+ hns_roce_int_mask_en(hr_dev);
+
+ /* Configure CE irq interval and burst num */
+ hns_roce_ce_int_default_cfg(hr_dev);
+
+ for (i = 0; i < eq_num; i++) {
+ ret = hns_roce_create_eq(hr_dev, &eq_table->eq[i]);
+ if (ret) {
+ dev_err(dev, "eq create failed\n");
+ goto err_create_eq_fail;
+ }
+ }
+
+ for (j = 0; j < eq_num; j++) {
+ ret = request_irq(eq_table->eq[j].irq, hns_roce_msi_x_interrupt,
+ 0, hr_dev->irq_names[j], eq_table->eq + j);
+ if (ret) {
+ dev_err(dev, "request irq error!\n");
+ goto err_request_irq_fail;
+ }
+ }
+
+ for (i = 0; i < eq_num; i++)
+ hns_roce_enable_eq(hr_dev, i, EQ_ENABLE);
+
+ return 0;
+
+err_request_irq_fail:
+ for (j = j - 1; j >= 0; j--)
+ free_irq(eq_table->eq[j].irq, eq_table->eq + j);
+
+err_create_eq_fail:
+ for (i = i - 1; i >= 0; i--)
+ hns_roce_free_eq(hr_dev, &eq_table->eq[i]);
+
+ kfree(eq_table->eqc_base);
+
+err_eqc_base_alloc_fail:
+ kfree(eq_table->eq);
+
+ return ret;
+}
+
+void hns_roce_cleanup_eq_table(struct hns_roce_dev *hr_dev)
+{
+ int i;
+ int eq_num;
+ struct hns_roce_eq_table *eq_table = &hr_dev->eq_table;
+
+ eq_num = hr_dev->caps.num_comp_vectors + hr_dev->caps.num_aeq_vectors;
+ for (i = 0; i < eq_num; i++) {
+ /* Disable EQ */
+ hns_roce_enable_eq(hr_dev, i, EQ_DISABLE);
+
+ free_irq(eq_table->eq[i].irq, eq_table->eq + i);
+
+ hns_roce_free_eq(hr_dev, &eq_table->eq[i]);
+ }
+
+ kfree(eq_table->eqc_base);
+ kfree(eq_table->eq);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_eq.h b/drivers/infiniband/hw/hns/hns_roce_eq.h
new file mode 100644
index 000000000000..fe4388191a3c
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_eq.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_EQ_H
+#define _HNS_ROCE_EQ_H
+
+#define HNS_ROCE_CEQ 1
+#define HNS_ROCE_AEQ 2
+
+#define HNS_ROCE_CEQ_ENTRY_SIZE 0x4
+#define HNS_ROCE_AEQ_ENTRY_SIZE 0x10
+#define HNS_ROCE_CEQC_REG_OFFSET 0x18
+
+#define HNS_ROCE_CEQ_DEFAULT_INTERVAL 0x10
+#define HNS_ROCE_CEQ_DEFAULT_BURST_NUM 0x10
+
+#define HNS_ROCE_INT_MASK_DISABLE 0
+#define HNS_ROCE_INT_MASK_ENABLE 1
+
+#define EQ_ENABLE 1
+#define EQ_DISABLE 0
+#define CONS_INDEX_MASK 0xffff
+
+#define CEQ_REG_OFFSET 0x18
+
+enum {
+ HNS_ROCE_EQ_STAT_INVALID = 0,
+ HNS_ROCE_EQ_STAT_VALID = 2,
+};
+
+struct hns_roce_aeqe {
+ u32 asyn;
+ union {
+ struct {
+ u32 qp;
+ u32 rsv0;
+ u32 rsv1;
+ } qp_event;
+
+ struct {
+ u32 cq;
+ u32 rsv0;
+ u32 rsv1;
+ } cq_event;
+
+ struct {
+ u32 port;
+ u32 rsv0;
+ u32 rsv1;
+ } port_event;
+
+ struct {
+ u32 ceqe;
+ u32 rsv0;
+ u32 rsv1;
+ } ce_event;
+
+ struct {
+ __le64 out_param;
+ __le16 token;
+ u8 status;
+ u8 rsv0;
+ } __packed cmd;
+ } event;
+};
+
+#define HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S 16
+#define HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M \
+ (((1UL << 8) - 1) << HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S)
+
+#define HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S 24
+#define HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_M \
+ (((1UL << 7) - 1) << HNS_ROCE_AEQE_U32_4_EVENT_SUB_TYPE_S)
+
+#define HNS_ROCE_AEQE_U32_4_OWNER_S 31
+
+#define HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S 0
+#define HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_M \
+ (((1UL << 24) - 1) << HNS_ROCE_AEQE_EVENT_QP_EVENT_QP_QPN_S)
+
+#define HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S 0
+#define HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_M \
+ (((1UL << 16) - 1) << HNS_ROCE_AEQE_EVENT_CQ_EVENT_CQ_CQN_S)
+
+#define HNS_ROCE_AEQE_EVENT_CE_EVENT_CEQE_CEQN_S 0
+#define HNS_ROCE_AEQE_EVENT_CE_EVENT_CEQE_CEQN_M \
+ (((1UL << 5) - 1) << HNS_ROCE_AEQE_EVENT_CE_EVENT_CEQE_CEQN_S)
+
+struct hns_roce_ceqe {
+ union {
+ int comp;
+ } ceqe;
+};
+
+#define HNS_ROCE_CEQE_CEQE_COMP_OWNER_S 0
+
+#define HNS_ROCE_CEQE_CEQE_COMP_CQN_S 16
+#define HNS_ROCE_CEQE_CEQE_COMP_CQN_M \
+ (((1UL << 16) - 1) << HNS_ROCE_CEQE_CEQE_COMP_CQN_S)
+
+#endif /* _HNS_ROCE_EQ_H */
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c
new file mode 100644
index 000000000000..d53d64362389
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include "hns_roce_device.h"
+#include "hns_roce_hem.h"
+#include "hns_roce_common.h"
+
+#define HW_SYNC_TIMEOUT_MSECS 500
+#define HW_SYNC_SLEEP_TIME_INTERVAL 20
+
+#define HNS_ROCE_HEM_ALLOC_SIZE (1 << 17)
+#define HNS_ROCE_TABLE_CHUNK_SIZE (1 << 17)
+
+#define DMA_ADDR_T_SHIFT 12
+#define BT_CMD_SYNC_SHIFT 31
+#define BT_BA_SHIFT 32
+
+struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev, int npages,
+ gfp_t gfp_mask)
+{
+ struct hns_roce_hem_chunk *chunk = NULL;
+ struct hns_roce_hem *hem;
+ struct scatterlist *mem;
+ int order;
+ void *buf;
+
+ WARN_ON(gfp_mask & __GFP_HIGHMEM);
+
+ hem = kmalloc(sizeof(*hem),
+ gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
+ if (!hem)
+ return NULL;
+
+ hem->refcount = 0;
+ INIT_LIST_HEAD(&hem->chunk_list);
+
+ order = get_order(HNS_ROCE_HEM_ALLOC_SIZE);
+
+ while (npages > 0) {
+ if (!chunk) {
+ chunk = kmalloc(sizeof(*chunk),
+ gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
+ if (!chunk)
+ goto fail;
+
+ sg_init_table(chunk->mem, HNS_ROCE_HEM_CHUNK_LEN);
+ chunk->npages = 0;
+ chunk->nsg = 0;
+ list_add_tail(&chunk->list, &hem->chunk_list);
+ }
+
+ while (1 << order > npages)
+ --order;
+
+ /*
+ * Alloc memory one time. If failed, don't alloc small block
+ * memory, directly return fail.
+ */
+ mem = &chunk->mem[chunk->npages];
+ buf = dma_alloc_coherent(&hr_dev->pdev->dev, PAGE_SIZE << order,
+ &sg_dma_address(mem), gfp_mask);
+ if (!buf)
+ goto fail;
+
+ sg_set_buf(mem, buf, PAGE_SIZE << order);
+ WARN_ON(mem->offset);
+ sg_dma_len(mem) = PAGE_SIZE << order;
+
+ ++chunk->npages;
+ ++chunk->nsg;
+ npages -= 1 << order;
+ }
+
+ return hem;
+
+fail:
+ hns_roce_free_hem(hr_dev, hem);
+ return NULL;
+}
+
+void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem)
+{
+ struct hns_roce_hem_chunk *chunk, *tmp;
+ int i;
+
+ if (!hem)
+ return;
+
+ list_for_each_entry_safe(chunk, tmp, &hem->chunk_list, list) {
+ for (i = 0; i < chunk->npages; ++i)
+ dma_free_coherent(&hr_dev->pdev->dev,
+ chunk->mem[i].length,
+ lowmem_page_address(sg_page(&chunk->mem[i])),
+ sg_dma_address(&chunk->mem[i]));
+ kfree(chunk);
+ }
+
+ kfree(hem);
+}
+
+static int hns_roce_set_hem(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, unsigned long obj)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ spinlock_t *lock = &hr_dev->bt_cmd_lock;
+ unsigned long end = 0;
+ unsigned long flags;
+ struct hns_roce_hem_iter iter;
+ void __iomem *bt_cmd;
+ u32 bt_cmd_h_val = 0;
+ u32 bt_cmd_val[2];
+ u32 bt_cmd_l = 0;
+ u64 bt_ba = 0;
+ int ret = 0;
+
+ /* Find the HEM(Hardware Entry Memory) entry */
+ unsigned long i = (obj & (table->num_obj - 1)) /
+ (HNS_ROCE_TABLE_CHUNK_SIZE / table->obj_size);
+
+ switch (table->type) {
+ case HEM_TYPE_QPC:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_QPC);
+ break;
+ case HEM_TYPE_MTPT:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S,
+ HEM_TYPE_MTPT);
+ break;
+ case HEM_TYPE_CQC:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_CQC);
+ break;
+ case HEM_TYPE_SRQC:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S,
+ HEM_TYPE_SRQC);
+ break;
+ default:
+ return ret;
+ }
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj);
+ roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0);
+ roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1);
+
+ /* Currently iter only a chunk */
+ for (hns_roce_hem_first(table->hem[i], &iter);
+ !hns_roce_hem_last(&iter); hns_roce_hem_next(&iter)) {
+ bt_ba = hns_roce_hem_addr(&iter) >> DMA_ADDR_T_SHIFT;
+
+ spin_lock_irqsave(lock, flags);
+
+ bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG;
+
+ end = msecs_to_jiffies(HW_SYNC_TIMEOUT_MSECS) + jiffies;
+ while (1) {
+ if (readl(bt_cmd) >> BT_CMD_SYNC_SHIFT) {
+ if (!(time_before(jiffies, end))) {
+ dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n");
+ spin_unlock_irqrestore(lock, flags);
+ return -EBUSY;
+ }
+ } else {
+ break;
+ }
+ msleep(HW_SYNC_SLEEP_TIME_INTERVAL);
+ }
+
+ bt_cmd_l = (u32)bt_ba;
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S,
+ bt_ba >> BT_BA_SHIFT);
+
+ bt_cmd_val[0] = bt_cmd_l;
+ bt_cmd_val[1] = bt_cmd_h_val;
+ hns_roce_write64_k(bt_cmd_val,
+ hr_dev->reg_base + ROCEE_BT_CMD_L_REG);
+ spin_unlock_irqrestore(lock, flags);
+ }
+
+ return ret;
+}
+
+static int hns_roce_clear_hem(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table,
+ unsigned long obj)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ unsigned long end = 0;
+ unsigned long flags;
+ void __iomem *bt_cmd;
+ uint32_t bt_cmd_val[2];
+ u32 bt_cmd_h_val = 0;
+ int ret = 0;
+
+ switch (table->type) {
+ case HEM_TYPE_QPC:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_QPC);
+ break;
+ case HEM_TYPE_MTPT:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S,
+ HEM_TYPE_MTPT);
+ break;
+ case HEM_TYPE_CQC:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_CQC);
+ break;
+ case HEM_TYPE_SRQC:
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S,
+ HEM_TYPE_SRQC);
+ break;
+ default:
+ return ret;
+ }
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj);
+ roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0);
+ roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1);
+ roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S, 0);
+
+ spin_lock_irqsave(&hr_dev->bt_cmd_lock, flags);
+
+ bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG;
+
+ end = msecs_to_jiffies(HW_SYNC_TIMEOUT_MSECS) + jiffies;
+ while (1) {
+ if (readl(bt_cmd) >> BT_CMD_SYNC_SHIFT) {
+ if (!(time_before(jiffies, end))) {
+ dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n");
+ spin_unlock_irqrestore(&hr_dev->bt_cmd_lock,
+ flags);
+ return -EBUSY;
+ }
+ } else {
+ break;
+ }
+ msleep(HW_SYNC_SLEEP_TIME_INTERVAL);
+ }
+
+ bt_cmd_val[0] = 0;
+ bt_cmd_val[1] = bt_cmd_h_val;
+ hns_roce_write64_k(bt_cmd_val, hr_dev->reg_base + ROCEE_BT_CMD_L_REG);
+ spin_unlock_irqrestore(&hr_dev->bt_cmd_lock, flags);
+
+ return ret;
+}
+
+int hns_roce_table_get(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, unsigned long obj)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ int ret = 0;
+ unsigned long i;
+
+ i = (obj & (table->num_obj - 1)) / (HNS_ROCE_TABLE_CHUNK_SIZE /
+ table->obj_size);
+
+ mutex_lock(&table->mutex);
+
+ if (table->hem[i]) {
+ ++table->hem[i]->refcount;
+ goto out;
+ }
+
+ table->hem[i] = hns_roce_alloc_hem(hr_dev,
+ HNS_ROCE_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
+ (table->lowmem ? GFP_KERNEL :
+ GFP_HIGHUSER) | __GFP_NOWARN);
+ if (!table->hem[i]) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Set HEM base address(128K/page, pa) to Hardware */
+ if (hns_roce_set_hem(hr_dev, table, obj)) {
+ ret = -ENODEV;
+ dev_err(dev, "set HEM base address to HW failed.\n");
+ goto out;
+ }
+
+ ++table->hem[i]->refcount;
+out:
+ mutex_unlock(&table->mutex);
+ return ret;
+}
+
+void hns_roce_table_put(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, unsigned long obj)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ unsigned long i;
+
+ i = (obj & (table->num_obj - 1)) /
+ (HNS_ROCE_TABLE_CHUNK_SIZE / table->obj_size);
+
+ mutex_lock(&table->mutex);
+
+ if (--table->hem[i]->refcount == 0) {
+ /* Clear HEM base address */
+ if (hns_roce_clear_hem(hr_dev, table, obj))
+ dev_warn(dev, "Clear HEM base address failed.\n");
+
+ hns_roce_free_hem(hr_dev, table->hem[i]);
+ table->hem[i] = NULL;
+ }
+
+ mutex_unlock(&table->mutex);
+}
+
+void *hns_roce_table_find(struct hns_roce_hem_table *table, unsigned long obj,
+ dma_addr_t *dma_handle)
+{
+ struct hns_roce_hem_chunk *chunk;
+ unsigned long idx;
+ int i;
+ int offset, dma_offset;
+ struct hns_roce_hem *hem;
+ struct page *page = NULL;
+
+ if (!table->lowmem)
+ return NULL;
+
+ mutex_lock(&table->mutex);
+ idx = (obj & (table->num_obj - 1)) * table->obj_size;
+ hem = table->hem[idx / HNS_ROCE_TABLE_CHUNK_SIZE];
+ dma_offset = offset = idx % HNS_ROCE_TABLE_CHUNK_SIZE;
+
+ if (!hem)
+ goto out;
+
+ list_for_each_entry(chunk, &hem->chunk_list, list) {
+ for (i = 0; i < chunk->npages; ++i) {
+ if (dma_handle && dma_offset >= 0) {
+ if (sg_dma_len(&chunk->mem[i]) >
+ (u32)dma_offset)
+ *dma_handle = sg_dma_address(
+ &chunk->mem[i]) + dma_offset;
+ dma_offset -= sg_dma_len(&chunk->mem[i]);
+ }
+
+ if (chunk->mem[i].length > (u32)offset) {
+ page = sg_page(&chunk->mem[i]);
+ goto out;
+ }
+ offset -= chunk->mem[i].length;
+ }
+ }
+
+out:
+ mutex_unlock(&table->mutex);
+ return page ? lowmem_page_address(page) + offset : NULL;
+}
+
+int hns_roce_table_get_range(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table,
+ unsigned long start, unsigned long end)
+{
+ unsigned long inc = HNS_ROCE_TABLE_CHUNK_SIZE / table->obj_size;
+ unsigned long i = 0;
+ int ret = 0;
+
+ /* Allocate MTT entry memory according to chunk(128K) */
+ for (i = start; i <= end; i += inc) {
+ ret = hns_roce_table_get(hr_dev, table, i);
+ if (ret)
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ while (i > start) {
+ i -= inc;
+ hns_roce_table_put(hr_dev, table, i);
+ }
+ return ret;
+}
+
+void hns_roce_table_put_range(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table,
+ unsigned long start, unsigned long end)
+{
+ unsigned long i;
+
+ for (i = start; i <= end;
+ i += HNS_ROCE_TABLE_CHUNK_SIZE / table->obj_size)
+ hns_roce_table_put(hr_dev, table, i);
+}
+
+int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, u32 type,
+ unsigned long obj_size, unsigned long nobj,
+ int use_lowmem)
+{
+ unsigned long obj_per_chunk;
+ unsigned long num_hem;
+
+ obj_per_chunk = HNS_ROCE_TABLE_CHUNK_SIZE / obj_size;
+ num_hem = (nobj + obj_per_chunk - 1) / obj_per_chunk;
+
+ table->hem = kcalloc(num_hem, sizeof(*table->hem), GFP_KERNEL);
+ if (!table->hem)
+ return -ENOMEM;
+
+ table->type = type;
+ table->num_hem = num_hem;
+ table->num_obj = nobj;
+ table->obj_size = obj_size;
+ table->lowmem = use_lowmem;
+ mutex_init(&table->mutex);
+
+ return 0;
+}
+
+void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ unsigned long i;
+
+ for (i = 0; i < table->num_hem; ++i)
+ if (table->hem[i]) {
+ if (hns_roce_clear_hem(hr_dev, table,
+ i * HNS_ROCE_TABLE_CHUNK_SIZE / table->obj_size))
+ dev_err(dev, "Clear HEM base address failed.\n");
+
+ hns_roce_free_hem(hr_dev, table->hem[i]);
+ }
+
+ kfree(table->hem);
+}
+
+void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->cq_table.table);
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.irrl_table);
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.qp_table);
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table);
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtt_table);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.h b/drivers/infiniband/hw/hns/hns_roce_hem.h
new file mode 100644
index 000000000000..ad6617588fba
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_HEM_H
+#define _HNS_ROCE_HEM_H
+
+enum {
+ /* MAP HEM(Hardware Entry Memory) */
+ HEM_TYPE_QPC = 0,
+ HEM_TYPE_MTPT,
+ HEM_TYPE_CQC,
+ HEM_TYPE_SRQC,
+
+ /* UNMAP HEM */
+ HEM_TYPE_MTT,
+ HEM_TYPE_IRRL,
+};
+
+#define HNS_ROCE_HEM_CHUNK_LEN \
+ ((256 - sizeof(struct list_head) - 2 * sizeof(int)) / \
+ (sizeof(struct scatterlist)))
+
+enum {
+ HNS_ROCE_HEM_PAGE_SHIFT = 12,
+ HNS_ROCE_HEM_PAGE_SIZE = 1 << HNS_ROCE_HEM_PAGE_SHIFT,
+};
+
+struct hns_roce_hem_chunk {
+ struct list_head list;
+ int npages;
+ int nsg;
+ struct scatterlist mem[HNS_ROCE_HEM_CHUNK_LEN];
+};
+
+struct hns_roce_hem {
+ struct list_head chunk_list;
+ int refcount;
+};
+
+struct hns_roce_hem_iter {
+ struct hns_roce_hem *hem;
+ struct hns_roce_hem_chunk *chunk;
+ int page_idx;
+};
+
+void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem);
+int hns_roce_table_get(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, unsigned long obj);
+void hns_roce_table_put(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, unsigned long obj);
+void *hns_roce_table_find(struct hns_roce_hem_table *table, unsigned long obj,
+ dma_addr_t *dma_handle);
+int hns_roce_table_get_range(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table,
+ unsigned long start, unsigned long end);
+void hns_roce_table_put_range(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table,
+ unsigned long start, unsigned long end);
+int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, u32 type,
+ unsigned long obj_size, unsigned long nobj,
+ int use_lowmem);
+void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table);
+void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev);
+
+static inline void hns_roce_hem_first(struct hns_roce_hem *hem,
+ struct hns_roce_hem_iter *iter)
+{
+ iter->hem = hem;
+ iter->chunk = list_empty(&hem->chunk_list) ? NULL :
+ list_entry(hem->chunk_list.next,
+ struct hns_roce_hem_chunk, list);
+ iter->page_idx = 0;
+}
+
+static inline int hns_roce_hem_last(struct hns_roce_hem_iter *iter)
+{
+ return !iter->chunk;
+}
+
+static inline void hns_roce_hem_next(struct hns_roce_hem_iter *iter)
+{
+ if (++iter->page_idx >= iter->chunk->nsg) {
+ if (iter->chunk->list.next == &iter->hem->chunk_list) {
+ iter->chunk = NULL;
+ return;
+ }
+
+ iter->chunk = list_entry(iter->chunk->list.next,
+ struct hns_roce_hem_chunk, list);
+ iter->page_idx = 0;
+ }
+}
+
+static inline dma_addr_t hns_roce_hem_addr(struct hns_roce_hem_iter *iter)
+{
+ return sg_dma_address(&iter->chunk->mem[iter->page_idx]);
+}
+
+#endif /*_HNS_ROCE_HEM_H*/
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
new file mode 100644
index 000000000000..399f5dedaf2d
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -0,0 +1,2800 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <rdma/ib_umem.h>
+#include "hns_roce_common.h"
+#include "hns_roce_device.h"
+#include "hns_roce_cmd.h"
+#include "hns_roce_hem.h"
+#include "hns_roce_hw_v1.h"
+
+static void set_data_seg(struct hns_roce_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+ dseg->lkey = cpu_to_le32(sg->lkey);
+ dseg->addr = cpu_to_le64(sg->addr);
+ dseg->len = cpu_to_le32(sg->length);
+}
+
+static void set_raddr_seg(struct hns_roce_wqe_raddr_seg *rseg, u64 remote_addr,
+ u32 rkey)
+{
+ rseg->raddr = cpu_to_le64(remote_addr);
+ rseg->rkey = cpu_to_le32(rkey);
+ rseg->len = 0;
+}
+
+int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct hns_roce_ah *ah = to_hr_ah(ud_wr(wr)->ah);
+ struct hns_roce_ud_send_wqe *ud_sq_wqe = NULL;
+ struct hns_roce_wqe_ctrl_seg *ctrl = NULL;
+ struct hns_roce_wqe_data_seg *dseg = NULL;
+ struct hns_roce_qp *qp = to_hr_qp(ibqp);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_sq_db sq_db;
+ int ps_opcode = 0, i = 0;
+ unsigned long flags = 0;
+ void *wqe = NULL;
+ u32 doorbell[2];
+ int nreq = 0;
+ u32 ind = 0;
+ int ret = 0;
+
+ spin_lock_irqsave(&qp->sq.lock, flags);
+
+ ind = qp->sq_next_wqe;
+ for (nreq = 0; wr; ++nreq, wr = wr->next) {
+ if (hns_roce_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
+ ret = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ if (unlikely(wr->num_sge > qp->sq.max_gs)) {
+ dev_err(dev, "num_sge=%d > qp->sq.max_gs=%d\n",
+ wr->num_sge, qp->sq.max_gs);
+ ret = -EINVAL;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1));
+ qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] =
+ wr->wr_id;
+
+ /* Corresponding to the RC and RD type wqe process separately */
+ if (ibqp->qp_type == IB_QPT_GSI) {
+ ud_sq_wqe = wqe;
+ roce_set_field(ud_sq_wqe->dmac_h,
+ UD_SEND_WQE_U32_4_DMAC_0_M,
+ UD_SEND_WQE_U32_4_DMAC_0_S,
+ ah->av.mac[0]);
+ roce_set_field(ud_sq_wqe->dmac_h,
+ UD_SEND_WQE_U32_4_DMAC_1_M,
+ UD_SEND_WQE_U32_4_DMAC_1_S,
+ ah->av.mac[1]);
+ roce_set_field(ud_sq_wqe->dmac_h,
+ UD_SEND_WQE_U32_4_DMAC_2_M,
+ UD_SEND_WQE_U32_4_DMAC_2_S,
+ ah->av.mac[2]);
+ roce_set_field(ud_sq_wqe->dmac_h,
+ UD_SEND_WQE_U32_4_DMAC_3_M,
+ UD_SEND_WQE_U32_4_DMAC_3_S,
+ ah->av.mac[3]);
+
+ roce_set_field(ud_sq_wqe->u32_8,
+ UD_SEND_WQE_U32_8_DMAC_4_M,
+ UD_SEND_WQE_U32_8_DMAC_4_S,
+ ah->av.mac[4]);
+ roce_set_field(ud_sq_wqe->u32_8,
+ UD_SEND_WQE_U32_8_DMAC_5_M,
+ UD_SEND_WQE_U32_8_DMAC_5_S,
+ ah->av.mac[5]);
+ roce_set_field(ud_sq_wqe->u32_8,
+ UD_SEND_WQE_U32_8_OPERATION_TYPE_M,
+ UD_SEND_WQE_U32_8_OPERATION_TYPE_S,
+ HNS_ROCE_WQE_OPCODE_SEND);
+ roce_set_field(ud_sq_wqe->u32_8,
+ UD_SEND_WQE_U32_8_NUMBER_OF_DATA_SEG_M,
+ UD_SEND_WQE_U32_8_NUMBER_OF_DATA_SEG_S,
+ 2);
+ roce_set_bit(ud_sq_wqe->u32_8,
+ UD_SEND_WQE_U32_8_SEND_GL_ROUTING_HDR_FLAG_S,
+ 1);
+
+ ud_sq_wqe->u32_8 |= (wr->send_flags & IB_SEND_SIGNALED ?
+ cpu_to_le32(HNS_ROCE_WQE_CQ_NOTIFY) : 0) |
+ (wr->send_flags & IB_SEND_SOLICITED ?
+ cpu_to_le32(HNS_ROCE_WQE_SE) : 0) |
+ ((wr->opcode == IB_WR_SEND_WITH_IMM) ?
+ cpu_to_le32(HNS_ROCE_WQE_IMM) : 0);
+
+ roce_set_field(ud_sq_wqe->u32_16,
+ UD_SEND_WQE_U32_16_DEST_QP_M,
+ UD_SEND_WQE_U32_16_DEST_QP_S,
+ ud_wr(wr)->remote_qpn);
+ roce_set_field(ud_sq_wqe->u32_16,
+ UD_SEND_WQE_U32_16_MAX_STATIC_RATE_M,
+ UD_SEND_WQE_U32_16_MAX_STATIC_RATE_S,
+ ah->av.stat_rate);
+
+ roce_set_field(ud_sq_wqe->u32_36,
+ UD_SEND_WQE_U32_36_FLOW_LABEL_M,
+ UD_SEND_WQE_U32_36_FLOW_LABEL_S, 0);
+ roce_set_field(ud_sq_wqe->u32_36,
+ UD_SEND_WQE_U32_36_PRIORITY_M,
+ UD_SEND_WQE_U32_36_PRIORITY_S,
+ ah->av.sl_tclass_flowlabel >>
+ HNS_ROCE_SL_SHIFT);
+ roce_set_field(ud_sq_wqe->u32_36,
+ UD_SEND_WQE_U32_36_SGID_INDEX_M,
+ UD_SEND_WQE_U32_36_SGID_INDEX_S,
+ hns_get_gid_index(hr_dev, qp->port,
+ ah->av.gid_index));
+
+ roce_set_field(ud_sq_wqe->u32_40,
+ UD_SEND_WQE_U32_40_HOP_LIMIT_M,
+ UD_SEND_WQE_U32_40_HOP_LIMIT_S,
+ ah->av.hop_limit);
+ roce_set_field(ud_sq_wqe->u32_40,
+ UD_SEND_WQE_U32_40_TRAFFIC_CLASS_M,
+ UD_SEND_WQE_U32_40_TRAFFIC_CLASS_S, 0);
+
+ memcpy(&ud_sq_wqe->dgid[0], &ah->av.dgid[0], GID_LEN);
+
+ ud_sq_wqe->va0_l = (u32)wr->sg_list[0].addr;
+ ud_sq_wqe->va0_h = (wr->sg_list[0].addr) >> 32;
+ ud_sq_wqe->l_key0 = wr->sg_list[0].lkey;
+
+ ud_sq_wqe->va1_l = (u32)wr->sg_list[1].addr;
+ ud_sq_wqe->va1_h = (wr->sg_list[1].addr) >> 32;
+ ud_sq_wqe->l_key1 = wr->sg_list[1].lkey;
+ ind++;
+ } else if (ibqp->qp_type == IB_QPT_RC) {
+ ctrl = wqe;
+ memset(ctrl, 0, sizeof(struct hns_roce_wqe_ctrl_seg));
+ for (i = 0; i < wr->num_sge; i++)
+ ctrl->msg_length += wr->sg_list[i].length;
+
+ ctrl->sgl_pa_h = 0;
+ ctrl->flag = 0;
+ ctrl->imm_data = send_ieth(wr);
+
+ /*Ctrl field, ctrl set type: sig, solic, imm, fence */
+ /* SO wait for conforming application scenarios */
+ ctrl->flag |= (wr->send_flags & IB_SEND_SIGNALED ?
+ cpu_to_le32(HNS_ROCE_WQE_CQ_NOTIFY) : 0) |
+ (wr->send_flags & IB_SEND_SOLICITED ?
+ cpu_to_le32(HNS_ROCE_WQE_SE) : 0) |
+ ((wr->opcode == IB_WR_SEND_WITH_IMM ||
+ wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) ?
+ cpu_to_le32(HNS_ROCE_WQE_IMM) : 0) |
+ (wr->send_flags & IB_SEND_FENCE ?
+ (cpu_to_le32(HNS_ROCE_WQE_FENCE)) : 0);
+
+ wqe = (struct hns_roce_wqe_ctrl_seg *)wqe +
+ sizeof(struct hns_roce_wqe_ctrl_seg);
+
+ switch (wr->opcode) {
+ case IB_WR_RDMA_READ:
+ ps_opcode = HNS_ROCE_WQE_OPCODE_RDMA_READ;
+ set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
+ atomic_wr(wr)->rkey);
+ break;
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ ps_opcode = HNS_ROCE_WQE_OPCODE_RDMA_WRITE;
+ set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
+ atomic_wr(wr)->rkey);
+ break;
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_INV:
+ case IB_WR_SEND_WITH_IMM:
+ ps_opcode = HNS_ROCE_WQE_OPCODE_SEND;
+ break;
+ case IB_WR_LOCAL_INV:
+ break;
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+ case IB_WR_LSO:
+ default:
+ ps_opcode = HNS_ROCE_WQE_OPCODE_MASK;
+ break;
+ }
+ ctrl->flag |= cpu_to_le32(ps_opcode);
+ wqe = (struct hns_roce_wqe_raddr_seg *)wqe +
+ sizeof(struct hns_roce_wqe_raddr_seg);
+
+ dseg = wqe;
+ if (wr->send_flags & IB_SEND_INLINE && wr->num_sge) {
+ if (ctrl->msg_length >
+ hr_dev->caps.max_sq_inline) {
+ ret = -EINVAL;
+ *bad_wr = wr;
+ dev_err(dev, "inline len(1-%d)=%d, illegal",
+ ctrl->msg_length,
+ hr_dev->caps.max_sq_inline);
+ goto out;
+ }
+ for (i = 0; i < wr->num_sge; i++) {
+ memcpy(wqe, ((void *) (uintptr_t)
+ wr->sg_list[i].addr),
+ wr->sg_list[i].length);
+ wqe = (struct hns_roce_wqe_raddr_seg *)
+ wqe + wr->sg_list[i].length;
+ }
+ ctrl->flag |= HNS_ROCE_WQE_INLINE;
+ } else {
+ /*sqe num is two */
+ for (i = 0; i < wr->num_sge; i++)
+ set_data_seg(dseg + i, wr->sg_list + i);
+
+ ctrl->flag |= cpu_to_le32(wr->num_sge <<
+ HNS_ROCE_WQE_SGE_NUM_BIT);
+ }
+ ind++;
+ } else {
+ dev_dbg(dev, "unSupported QP type\n");
+ break;
+ }
+ }
+
+out:
+ /* Set DB return */
+ if (likely(nreq)) {
+ qp->sq.head += nreq;
+ /* Memory barrier */
+ wmb();
+
+ sq_db.u32_4 = 0;
+ sq_db.u32_8 = 0;
+ roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_SQ_HEAD_M,
+ SQ_DOORBELL_U32_4_SQ_HEAD_S,
+ (qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1)));
+ roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_PORT_M,
+ SQ_DOORBELL_U32_4_PORT_S, qp->port);
+ roce_set_field(sq_db.u32_8, SQ_DOORBELL_U32_8_QPN_M,
+ SQ_DOORBELL_U32_8_QPN_S, qp->doorbell_qpn);
+ roce_set_bit(sq_db.u32_8, SQ_DOORBELL_HW_SYNC_S, 1);
+
+ doorbell[0] = sq_db.u32_4;
+ doorbell[1] = sq_db.u32_8;
+
+ hns_roce_write64_k(doorbell, qp->sq.db_reg_l);
+ qp->sq_next_wqe = ind;
+ }
+
+ spin_unlock_irqrestore(&qp->sq.lock, flags);
+
+ return ret;
+}
+
+int hns_roce_v1_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ int ret = 0;
+ int nreq = 0;
+ int ind = 0;
+ int i = 0;
+ u32 reg_val = 0;
+ unsigned long flags = 0;
+ struct hns_roce_rq_wqe_ctrl *ctrl = NULL;
+ struct hns_roce_wqe_data_seg *scat = NULL;
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_rq_db rq_db;
+ uint32_t doorbell[2] = {0};
+
+ spin_lock_irqsave(&hr_qp->rq.lock, flags);
+ ind = hr_qp->rq.head & (hr_qp->rq.wqe_cnt - 1);
+
+ for (nreq = 0; wr; ++nreq, wr = wr->next) {
+ if (hns_roce_wq_overflow(&hr_qp->rq, nreq,
+ hr_qp->ibqp.recv_cq)) {
+ ret = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ if (unlikely(wr->num_sge > hr_qp->rq.max_gs)) {
+ dev_err(dev, "rq:num_sge=%d > qp->sq.max_gs=%d\n",
+ wr->num_sge, hr_qp->rq.max_gs);
+ ret = -EINVAL;
+ *bad_wr = wr;
+ goto out;
+ }
+
+ ctrl = get_recv_wqe(hr_qp, ind);
+
+ roce_set_field(ctrl->rwqe_byte_12,
+ RQ_WQE_CTRL_RWQE_BYTE_12_RWQE_SGE_NUM_M,
+ RQ_WQE_CTRL_RWQE_BYTE_12_RWQE_SGE_NUM_S,
+ wr->num_sge);
+
+ scat = (struct hns_roce_wqe_data_seg *)(ctrl + 1);
+
+ for (i = 0; i < wr->num_sge; i++)
+ set_data_seg(scat + i, wr->sg_list + i);
+
+ hr_qp->rq.wrid[ind] = wr->wr_id;
+
+ ind = (ind + 1) & (hr_qp->rq.wqe_cnt - 1);
+ }
+
+out:
+ if (likely(nreq)) {
+ hr_qp->rq.head += nreq;
+ /* Memory barrier */
+ wmb();
+
+ if (ibqp->qp_type == IB_QPT_GSI) {
+ /* SW update GSI rq header */
+ reg_val = roce_read(to_hr_dev(ibqp->device),
+ ROCEE_QP1C_CFG3_0_REG +
+ QP1C_CFGN_OFFSET * hr_qp->port);
+ roce_set_field(reg_val,
+ ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_M,
+ ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S,
+ hr_qp->rq.head);
+ roce_write(to_hr_dev(ibqp->device),
+ ROCEE_QP1C_CFG3_0_REG +
+ QP1C_CFGN_OFFSET * hr_qp->port, reg_val);
+ } else {
+ rq_db.u32_4 = 0;
+ rq_db.u32_8 = 0;
+
+ roce_set_field(rq_db.u32_4, RQ_DOORBELL_U32_4_RQ_HEAD_M,
+ RQ_DOORBELL_U32_4_RQ_HEAD_S,
+ hr_qp->rq.head);
+ roce_set_field(rq_db.u32_8, RQ_DOORBELL_U32_8_QPN_M,
+ RQ_DOORBELL_U32_8_QPN_S, hr_qp->qpn);
+ roce_set_field(rq_db.u32_8, RQ_DOORBELL_U32_8_CMD_M,
+ RQ_DOORBELL_U32_8_CMD_S, 1);
+ roce_set_bit(rq_db.u32_8, RQ_DOORBELL_U32_8_HW_SYNC_S,
+ 1);
+
+ doorbell[0] = rq_db.u32_4;
+ doorbell[1] = rq_db.u32_8;
+
+ hns_roce_write64_k(doorbell, hr_qp->rq.db_reg_l);
+ }
+ }
+ spin_unlock_irqrestore(&hr_qp->rq.lock, flags);
+
+ return ret;
+}
+
+static void hns_roce_set_db_event_mode(struct hns_roce_dev *hr_dev,
+ int sdb_mode, int odb_mode)
+{
+ u32 val;
+
+ val = roce_read(hr_dev, ROCEE_GLB_CFG_REG);
+ roce_set_bit(val, ROCEE_GLB_CFG_ROCEE_DB_SQ_MODE_S, sdb_mode);
+ roce_set_bit(val, ROCEE_GLB_CFG_ROCEE_DB_OTH_MODE_S, odb_mode);
+ roce_write(hr_dev, ROCEE_GLB_CFG_REG, val);
+}
+
+static void hns_roce_set_db_ext_mode(struct hns_roce_dev *hr_dev, u32 sdb_mode,
+ u32 odb_mode)
+{
+ u32 val;
+
+ /* Configure SDB/ODB extend mode */
+ val = roce_read(hr_dev, ROCEE_GLB_CFG_REG);
+ roce_set_bit(val, ROCEE_GLB_CFG_SQ_EXT_DB_MODE_S, sdb_mode);
+ roce_set_bit(val, ROCEE_GLB_CFG_OTH_EXT_DB_MODE_S, odb_mode);
+ roce_write(hr_dev, ROCEE_GLB_CFG_REG, val);
+}
+
+static void hns_roce_set_sdb(struct hns_roce_dev *hr_dev, u32 sdb_alept,
+ u32 sdb_alful)
+{
+ u32 val;
+
+ /* Configure SDB */
+ val = roce_read(hr_dev, ROCEE_DB_SQ_WL_REG);
+ roce_set_field(val, ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_M,
+ ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_S, sdb_alful);
+ roce_set_field(val, ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_EMPTY_M,
+ ROCEE_DB_SQ_WL_ROCEE_DB_SQ_WL_EMPTY_S, sdb_alept);
+ roce_write(hr_dev, ROCEE_DB_SQ_WL_REG, val);
+}
+
+static void hns_roce_set_odb(struct hns_roce_dev *hr_dev, u32 odb_alept,
+ u32 odb_alful)
+{
+ u32 val;
+
+ /* Configure ODB */
+ val = roce_read(hr_dev, ROCEE_DB_OTHERS_WL_REG);
+ roce_set_field(val, ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_M,
+ ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_S, odb_alful);
+ roce_set_field(val, ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_EMPTY_M,
+ ROCEE_DB_OTHERS_WL_ROCEE_DB_OTH_WL_EMPTY_S, odb_alept);
+ roce_write(hr_dev, ROCEE_DB_OTHERS_WL_REG, val);
+}
+
+static void hns_roce_set_sdb_ext(struct hns_roce_dev *hr_dev, u32 ext_sdb_alept,
+ u32 ext_sdb_alful)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_db_table *db;
+ dma_addr_t sdb_dma_addr;
+ u32 val;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ db = &priv->db_table;
+
+ /* Configure extend SDB threshold */
+ roce_write(hr_dev, ROCEE_EXT_DB_SQ_WL_EMPTY_REG, ext_sdb_alept);
+ roce_write(hr_dev, ROCEE_EXT_DB_SQ_WL_REG, ext_sdb_alful);
+
+ /* Configure extend SDB base addr */
+ sdb_dma_addr = db->ext_db->sdb_buf_list->map;
+ roce_write(hr_dev, ROCEE_EXT_DB_SQ_REG, (u32)(sdb_dma_addr >> 12));
+
+ /* Configure extend SDB depth */
+ val = roce_read(hr_dev, ROCEE_EXT_DB_SQ_H_REG);
+ roce_set_field(val, ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_SHIFT_M,
+ ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_SHIFT_S,
+ db->ext_db->esdb_dep);
+ /*
+ * 44 = 32 + 12, When evaluating addr to hardware, shift 12 because of
+ * using 4K page, and shift more 32 because of
+ * caculating the high 32 bit value evaluated to hardware.
+ */
+ roce_set_field(val, ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_BA_H_M,
+ ROCEE_EXT_DB_SQ_H_EXT_DB_SQ_BA_H_S, sdb_dma_addr >> 44);
+ roce_write(hr_dev, ROCEE_EXT_DB_SQ_H_REG, val);
+
+ dev_dbg(dev, "ext SDB depth: 0x%x\n", db->ext_db->esdb_dep);
+ dev_dbg(dev, "ext SDB threshold: epmty: 0x%x, ful: 0x%x\n",
+ ext_sdb_alept, ext_sdb_alful);
+}
+
+static void hns_roce_set_odb_ext(struct hns_roce_dev *hr_dev, u32 ext_odb_alept,
+ u32 ext_odb_alful)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_db_table *db;
+ dma_addr_t odb_dma_addr;
+ u32 val;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ db = &priv->db_table;
+
+ /* Configure extend ODB threshold */
+ roce_write(hr_dev, ROCEE_EXT_DB_OTHERS_WL_EMPTY_REG, ext_odb_alept);
+ roce_write(hr_dev, ROCEE_EXT_DB_OTHERS_WL_REG, ext_odb_alful);
+
+ /* Configure extend ODB base addr */
+ odb_dma_addr = db->ext_db->odb_buf_list->map;
+ roce_write(hr_dev, ROCEE_EXT_DB_OTH_REG, (u32)(odb_dma_addr >> 12));
+
+ /* Configure extend ODB depth */
+ val = roce_read(hr_dev, ROCEE_EXT_DB_OTH_H_REG);
+ roce_set_field(val, ROCEE_EXT_DB_OTH_H_EXT_DB_OTH_SHIFT_M,
+ ROCEE_EXT_DB_OTH_H_EXT_DB_OTH_SHIFT_S,
+ db->ext_db->eodb_dep);
+ roce_set_field(val, ROCEE_EXT_DB_SQ_H_EXT_DB_OTH_BA_H_M,
+ ROCEE_EXT_DB_SQ_H_EXT_DB_OTH_BA_H_S,
+ db->ext_db->eodb_dep);
+ roce_write(hr_dev, ROCEE_EXT_DB_OTH_H_REG, val);
+
+ dev_dbg(dev, "ext ODB depth: 0x%x\n", db->ext_db->eodb_dep);
+ dev_dbg(dev, "ext ODB threshold: empty: 0x%x, ful: 0x%x\n",
+ ext_odb_alept, ext_odb_alful);
+}
+
+static int hns_roce_db_ext_init(struct hns_roce_dev *hr_dev, u32 sdb_ext_mod,
+ u32 odb_ext_mod)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_db_table *db;
+ dma_addr_t sdb_dma_addr;
+ dma_addr_t odb_dma_addr;
+ int ret = 0;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ db = &priv->db_table;
+
+ db->ext_db = kmalloc(sizeof(*db->ext_db), GFP_KERNEL);
+ if (!db->ext_db)
+ return -ENOMEM;
+
+ if (sdb_ext_mod) {
+ db->ext_db->sdb_buf_list = kmalloc(
+ sizeof(*db->ext_db->sdb_buf_list), GFP_KERNEL);
+ if (!db->ext_db->sdb_buf_list) {
+ ret = -ENOMEM;
+ goto ext_sdb_buf_fail_out;
+ }
+
+ db->ext_db->sdb_buf_list->buf = dma_alloc_coherent(dev,
+ HNS_ROCE_V1_EXT_SDB_SIZE,
+ &sdb_dma_addr, GFP_KERNEL);
+ if (!db->ext_db->sdb_buf_list->buf) {
+ ret = -ENOMEM;
+ goto alloc_sq_db_buf_fail;
+ }
+ db->ext_db->sdb_buf_list->map = sdb_dma_addr;
+
+ db->ext_db->esdb_dep = ilog2(HNS_ROCE_V1_EXT_SDB_DEPTH);
+ hns_roce_set_sdb_ext(hr_dev, HNS_ROCE_V1_EXT_SDB_ALEPT,
+ HNS_ROCE_V1_EXT_SDB_ALFUL);
+ } else
+ hns_roce_set_sdb(hr_dev, HNS_ROCE_V1_SDB_ALEPT,
+ HNS_ROCE_V1_SDB_ALFUL);
+
+ if (odb_ext_mod) {
+ db->ext_db->odb_buf_list = kmalloc(
+ sizeof(*db->ext_db->odb_buf_list), GFP_KERNEL);
+ if (!db->ext_db->odb_buf_list) {
+ ret = -ENOMEM;
+ goto ext_odb_buf_fail_out;
+ }
+
+ db->ext_db->odb_buf_list->buf = dma_alloc_coherent(dev,
+ HNS_ROCE_V1_EXT_ODB_SIZE,
+ &odb_dma_addr, GFP_KERNEL);
+ if (!db->ext_db->odb_buf_list->buf) {
+ ret = -ENOMEM;
+ goto alloc_otr_db_buf_fail;
+ }
+ db->ext_db->odb_buf_list->map = odb_dma_addr;
+
+ db->ext_db->eodb_dep = ilog2(HNS_ROCE_V1_EXT_ODB_DEPTH);
+ hns_roce_set_odb_ext(hr_dev, HNS_ROCE_V1_EXT_ODB_ALEPT,
+ HNS_ROCE_V1_EXT_ODB_ALFUL);
+ } else
+ hns_roce_set_odb(hr_dev, HNS_ROCE_V1_ODB_ALEPT,
+ HNS_ROCE_V1_ODB_ALFUL);
+
+ hns_roce_set_db_ext_mode(hr_dev, sdb_ext_mod, odb_ext_mod);
+
+ return 0;
+
+alloc_otr_db_buf_fail:
+ kfree(db->ext_db->odb_buf_list);
+
+ext_odb_buf_fail_out:
+ if (sdb_ext_mod) {
+ dma_free_coherent(dev, HNS_ROCE_V1_EXT_SDB_SIZE,
+ db->ext_db->sdb_buf_list->buf,
+ db->ext_db->sdb_buf_list->map);
+ }
+
+alloc_sq_db_buf_fail:
+ if (sdb_ext_mod)
+ kfree(db->ext_db->sdb_buf_list);
+
+ext_sdb_buf_fail_out:
+ kfree(db->ext_db);
+ return ret;
+}
+
+static int hns_roce_db_init(struct hns_roce_dev *hr_dev)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_db_table *db;
+ u32 sdb_ext_mod;
+ u32 odb_ext_mod;
+ u32 sdb_evt_mod;
+ u32 odb_evt_mod;
+ int ret = 0;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ db = &priv->db_table;
+
+ memset(db, 0, sizeof(*db));
+
+ /* Default DB mode */
+ sdb_ext_mod = HNS_ROCE_SDB_EXTEND_MODE;
+ odb_ext_mod = HNS_ROCE_ODB_EXTEND_MODE;
+ sdb_evt_mod = HNS_ROCE_SDB_NORMAL_MODE;
+ odb_evt_mod = HNS_ROCE_ODB_POLL_MODE;
+
+ db->sdb_ext_mod = sdb_ext_mod;
+ db->odb_ext_mod = odb_ext_mod;
+
+ /* Init extend DB */
+ ret = hns_roce_db_ext_init(hr_dev, sdb_ext_mod, odb_ext_mod);
+ if (ret) {
+ dev_err(dev, "Failed in extend DB configuration.\n");
+ return ret;
+ }
+
+ hns_roce_set_db_event_mode(hr_dev, sdb_evt_mod, odb_evt_mod);
+
+ return 0;
+}
+
+static void hns_roce_db_free(struct hns_roce_dev *hr_dev)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_db_table *db;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ db = &priv->db_table;
+
+ if (db->sdb_ext_mod) {
+ dma_free_coherent(dev, HNS_ROCE_V1_EXT_SDB_SIZE,
+ db->ext_db->sdb_buf_list->buf,
+ db->ext_db->sdb_buf_list->map);
+ kfree(db->ext_db->sdb_buf_list);
+ }
+
+ if (db->odb_ext_mod) {
+ dma_free_coherent(dev, HNS_ROCE_V1_EXT_ODB_SIZE,
+ db->ext_db->odb_buf_list->buf,
+ db->ext_db->odb_buf_list->map);
+ kfree(db->ext_db->odb_buf_list);
+ }
+
+ kfree(db->ext_db);
+}
+
+static int hns_roce_raq_init(struct hns_roce_dev *hr_dev)
+{
+ int ret;
+ int raq_shift = 0;
+ dma_addr_t addr;
+ u32 val;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_raq_table *raq;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ raq = &priv->raq_table;
+
+ raq->e_raq_buf = kzalloc(sizeof(*(raq->e_raq_buf)), GFP_KERNEL);
+ if (!raq->e_raq_buf)
+ return -ENOMEM;
+
+ raq->e_raq_buf->buf = dma_alloc_coherent(dev, HNS_ROCE_V1_RAQ_SIZE,
+ &addr, GFP_KERNEL);
+ if (!raq->e_raq_buf->buf) {
+ ret = -ENOMEM;
+ goto err_dma_alloc_raq;
+ }
+ raq->e_raq_buf->map = addr;
+
+ /* Configure raq extended address. 48bit 4K align*/
+ roce_write(hr_dev, ROCEE_EXT_RAQ_REG, raq->e_raq_buf->map >> 12);
+
+ /* Configure raq_shift */
+ raq_shift = ilog2(HNS_ROCE_V1_RAQ_SIZE / HNS_ROCE_V1_RAQ_ENTRY);
+ val = roce_read(hr_dev, ROCEE_EXT_RAQ_H_REG);
+ roce_set_field(val, ROCEE_EXT_RAQ_H_EXT_RAQ_SHIFT_M,
+ ROCEE_EXT_RAQ_H_EXT_RAQ_SHIFT_S, raq_shift);
+ /*
+ * 44 = 32 + 12, When evaluating addr to hardware, shift 12 because of
+ * using 4K page, and shift more 32 because of
+ * caculating the high 32 bit value evaluated to hardware.
+ */
+ roce_set_field(val, ROCEE_EXT_RAQ_H_EXT_RAQ_BA_H_M,
+ ROCEE_EXT_RAQ_H_EXT_RAQ_BA_H_S,
+ raq->e_raq_buf->map >> 44);
+ roce_write(hr_dev, ROCEE_EXT_RAQ_H_REG, val);
+ dev_dbg(dev, "Configure raq_shift 0x%x.\n", val);
+
+ /* Configure raq threshold */
+ val = roce_read(hr_dev, ROCEE_RAQ_WL_REG);
+ roce_set_field(val, ROCEE_RAQ_WL_ROCEE_RAQ_WL_M,
+ ROCEE_RAQ_WL_ROCEE_RAQ_WL_S,
+ HNS_ROCE_V1_EXT_RAQ_WF);
+ roce_write(hr_dev, ROCEE_RAQ_WL_REG, val);
+ dev_dbg(dev, "Configure raq_wl 0x%x.\n", val);
+
+ /* Enable extend raq */
+ val = roce_read(hr_dev, ROCEE_WRMS_POL_TIME_INTERVAL_REG);
+ roce_set_field(val,
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_POL_TIME_INTERVAL_M,
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_POL_TIME_INTERVAL_S,
+ POL_TIME_INTERVAL_VAL);
+ roce_set_bit(val, ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_EXT_RAQ_MODE, 1);
+ roce_set_field(val,
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_CFG_M,
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_CFG_S,
+ 2);
+ roce_set_bit(val,
+ ROCEE_WRMS_POL_TIME_INTERVAL_WRMS_RAQ_TIMEOUT_CHK_EN_S, 1);
+ roce_write(hr_dev, ROCEE_WRMS_POL_TIME_INTERVAL_REG, val);
+ dev_dbg(dev, "Configure WrmsPolTimeInterval 0x%x.\n", val);
+
+ /* Enable raq drop */
+ val = roce_read(hr_dev, ROCEE_GLB_CFG_REG);
+ roce_set_bit(val, ROCEE_GLB_CFG_TRP_RAQ_DROP_EN_S, 1);
+ roce_write(hr_dev, ROCEE_GLB_CFG_REG, val);
+ dev_dbg(dev, "Configure GlbCfg = 0x%x.\n", val);
+
+ return 0;
+
+err_dma_alloc_raq:
+ kfree(raq->e_raq_buf);
+ return ret;
+}
+
+static void hns_roce_raq_free(struct hns_roce_dev *hr_dev)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_v1_priv *priv;
+ struct hns_roce_raq_table *raq;
+
+ priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv;
+ raq = &priv->raq_table;
+
+ dma_free_coherent(dev, HNS_ROCE_V1_RAQ_SIZE, raq->e_raq_buf->buf,
+ raq->e_raq_buf->map);
+ kfree(raq->e_raq_buf);
+}
+
+static void hns_roce_port_enable(struct hns_roce_dev *hr_dev, int enable_flag)
+{
+ u32 val;
+
+ if (enable_flag) {
+ val = roce_read(hr_dev, ROCEE_GLB_CFG_REG);
+ /* Open all ports */
+ roce_set_field(val, ROCEE_GLB_CFG_ROCEE_PORT_ST_M,
+ ROCEE_GLB_CFG_ROCEE_PORT_ST_S,
+ ALL_PORT_VAL_OPEN);
+ roce_write(hr_dev, ROCEE_GLB_CFG_REG, val);
+ } else {
+ val = roce_read(hr_dev, ROCEE_GLB_CFG_REG);
+ /* Close all ports */
+ roce_set_field(val, ROCEE_GLB_CFG_ROCEE_PORT_ST_M,
+ ROCEE_GLB_CFG_ROCEE_PORT_ST_S, 0x0);
+ roce_write(hr_dev, ROCEE_GLB_CFG_REG, val);
+ }
+}
+
+/**
+ * hns_roce_v1_reset - reset RoCE
+ * @hr_dev: RoCE device struct pointer
+ * @enable: true -- drop reset, false -- reset
+ * return 0 - success , negative --fail
+ */
+int hns_roce_v1_reset(struct hns_roce_dev *hr_dev, bool dereset)
+{
+ struct device_node *dsaf_node;
+ struct device *dev = &hr_dev->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ /* check if this is DT/ACPI case */
+ if (dev_of_node(dev)) {
+ dsaf_node = of_parse_phandle(np, "dsaf-handle", 0);
+ if (!dsaf_node) {
+ dev_err(dev, "could not find dsaf-handle\n");
+ return -EINVAL;
+ }
+ fwnode = &dsaf_node->fwnode;
+ } else if (is_acpi_device_node(dev->fwnode)) {
+ struct acpi_reference_args args;
+
+ ret = acpi_node_get_property_reference(dev->fwnode,
+ "dsaf-handle", 0, &args);
+ if (ret) {
+ dev_err(dev, "could not find dsaf-handle\n");
+ return ret;
+ }
+ fwnode = acpi_fwnode_handle(args.adev);
+ } else {
+ dev_err(dev, "cannot read data from DT or ACPI\n");
+ return -ENXIO;
+ }
+
+ ret = hns_dsaf_roce_reset(fwnode, false);
+ if (ret)
+ return ret;
+
+ if (dereset) {
+ msleep(SLEEP_TIME_INTERVAL);
+ ret = hns_dsaf_roce_reset(fwnode, true);
+ }
+
+ return ret;
+}
+
+void hns_roce_v1_profile(struct hns_roce_dev *hr_dev)
+{
+ int i = 0;
+ struct hns_roce_caps *caps = &hr_dev->caps;
+
+ hr_dev->vendor_id = le32_to_cpu(roce_read(hr_dev, ROCEE_VENDOR_ID_REG));
+ hr_dev->vendor_part_id = le32_to_cpu(roce_read(hr_dev,
+ ROCEE_VENDOR_PART_ID_REG));
+ hr_dev->hw_rev = le32_to_cpu(roce_read(hr_dev, ROCEE_HW_VERSION_REG));
+
+ hr_dev->sys_image_guid = le32_to_cpu(roce_read(hr_dev,
+ ROCEE_SYS_IMAGE_GUID_L_REG)) |
+ ((u64)le32_to_cpu(roce_read(hr_dev,
+ ROCEE_SYS_IMAGE_GUID_H_REG)) << 32);
+
+ caps->num_qps = HNS_ROCE_V1_MAX_QP_NUM;
+ caps->max_wqes = HNS_ROCE_V1_MAX_WQE_NUM;
+ caps->num_cqs = HNS_ROCE_V1_MAX_CQ_NUM;
+ caps->max_cqes = HNS_ROCE_V1_MAX_CQE_NUM;
+ caps->max_sq_sg = HNS_ROCE_V1_SG_NUM;
+ caps->max_rq_sg = HNS_ROCE_V1_SG_NUM;
+ caps->max_sq_inline = HNS_ROCE_V1_INLINE_SIZE;
+ caps->num_uars = HNS_ROCE_V1_UAR_NUM;
+ caps->phy_num_uars = HNS_ROCE_V1_PHY_UAR_NUM;
+ caps->num_aeq_vectors = HNS_ROCE_AEQE_VEC_NUM;
+ caps->num_comp_vectors = HNS_ROCE_COMP_VEC_NUM;
+ caps->num_other_vectors = HNS_ROCE_AEQE_OF_VEC_NUM;
+ caps->num_mtpts = HNS_ROCE_V1_MAX_MTPT_NUM;
+ caps->num_mtt_segs = HNS_ROCE_V1_MAX_MTT_SEGS;
+ caps->num_pds = HNS_ROCE_V1_MAX_PD_NUM;
+ caps->max_qp_init_rdma = HNS_ROCE_V1_MAX_QP_INIT_RDMA;
+ caps->max_qp_dest_rdma = HNS_ROCE_V1_MAX_QP_DEST_RDMA;
+ caps->max_sq_desc_sz = HNS_ROCE_V1_MAX_SQ_DESC_SZ;
+ caps->max_rq_desc_sz = HNS_ROCE_V1_MAX_RQ_DESC_SZ;
+ caps->qpc_entry_sz = HNS_ROCE_V1_QPC_ENTRY_SIZE;
+ caps->irrl_entry_sz = HNS_ROCE_V1_IRRL_ENTRY_SIZE;
+ caps->cqc_entry_sz = HNS_ROCE_V1_CQC_ENTRY_SIZE;
+ caps->mtpt_entry_sz = HNS_ROCE_V1_MTPT_ENTRY_SIZE;
+ caps->mtt_entry_sz = HNS_ROCE_V1_MTT_ENTRY_SIZE;
+ caps->cq_entry_sz = HNS_ROCE_V1_CQE_ENTRY_SIZE;
+ caps->page_size_cap = HNS_ROCE_V1_PAGE_SIZE_SUPPORT;
+ caps->sqp_start = 0;
+ caps->reserved_lkey = 0;
+ caps->reserved_pds = 0;
+ caps->reserved_mrws = 1;
+ caps->reserved_uars = 0;
+ caps->reserved_cqs = 0;
+
+ for (i = 0; i < caps->num_ports; i++)
+ caps->pkey_table_len[i] = 1;
+
+ for (i = 0; i < caps->num_ports; i++) {
+ /* Six ports shared 16 GID in v1 engine */
+ if (i >= (HNS_ROCE_V1_GID_NUM % caps->num_ports))
+ caps->gid_table_len[i] = HNS_ROCE_V1_GID_NUM /
+ caps->num_ports;
+ else
+ caps->gid_table_len[i] = HNS_ROCE_V1_GID_NUM /
+ caps->num_ports + 1;
+ }
+
+ for (i = 0; i < caps->num_comp_vectors; i++)
+ caps->ceqe_depth[i] = HNS_ROCE_V1_NUM_COMP_EQE;
+
+ caps->aeqe_depth = HNS_ROCE_V1_NUM_ASYNC_EQE;
+ caps->local_ca_ack_delay = le32_to_cpu(roce_read(hr_dev,
+ ROCEE_ACK_DELAY_REG));
+ caps->max_mtu = IB_MTU_2048;
+}
+
+int hns_roce_v1_init(struct hns_roce_dev *hr_dev)
+{
+ int ret;
+ u32 val;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ /* DMAE user config */
+ val = roce_read(hr_dev, ROCEE_DMAE_USER_CFG1_REG);
+ roce_set_field(val, ROCEE_DMAE_USER_CFG1_ROCEE_CACHE_TB_CFG_M,
+ ROCEE_DMAE_USER_CFG1_ROCEE_CACHE_TB_CFG_S, 0xf);
+ roce_set_field(val, ROCEE_DMAE_USER_CFG1_ROCEE_STREAM_ID_TB_CFG_M,
+ ROCEE_DMAE_USER_CFG1_ROCEE_STREAM_ID_TB_CFG_S,
+ 1 << PAGES_SHIFT_16);
+ roce_write(hr_dev, ROCEE_DMAE_USER_CFG1_REG, val);
+
+ val = roce_read(hr_dev, ROCEE_DMAE_USER_CFG2_REG);
+ roce_set_field(val, ROCEE_DMAE_USER_CFG2_ROCEE_CACHE_PKT_CFG_M,
+ ROCEE_DMAE_USER_CFG2_ROCEE_CACHE_PKT_CFG_S, 0xf);
+ roce_set_field(val, ROCEE_DMAE_USER_CFG2_ROCEE_STREAM_ID_PKT_CFG_M,
+ ROCEE_DMAE_USER_CFG2_ROCEE_STREAM_ID_PKT_CFG_S,
+ 1 << PAGES_SHIFT_16);
+
+ ret = hns_roce_db_init(hr_dev);
+ if (ret) {
+ dev_err(dev, "doorbell init failed!\n");
+ return ret;
+ }
+
+ ret = hns_roce_raq_init(hr_dev);
+ if (ret) {
+ dev_err(dev, "raq init failed!\n");
+ goto error_failed_raq_init;
+ }
+
+ hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_UP);
+
+ return 0;
+
+error_failed_raq_init:
+ hns_roce_db_free(hr_dev);
+ return ret;
+}
+
+void hns_roce_v1_exit(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN);
+ hns_roce_raq_free(hr_dev);
+ hns_roce_db_free(hr_dev);
+}
+
+void hns_roce_v1_set_gid(struct hns_roce_dev *hr_dev, u8 port, int gid_index,
+ union ib_gid *gid)
+{
+ u32 *p = NULL;
+ u8 gid_idx = 0;
+
+ gid_idx = hns_get_gid_index(hr_dev, port, gid_index);
+
+ p = (u32 *)&gid->raw[0];
+ roce_raw_write(*p, hr_dev->reg_base + ROCEE_PORT_GID_L_0_REG +
+ (HNS_ROCE_V1_GID_NUM * gid_idx));
+
+ p = (u32 *)&gid->raw[4];
+ roce_raw_write(*p, hr_dev->reg_base + ROCEE_PORT_GID_ML_0_REG +
+ (HNS_ROCE_V1_GID_NUM * gid_idx));
+
+ p = (u32 *)&gid->raw[8];
+ roce_raw_write(*p, hr_dev->reg_base + ROCEE_PORT_GID_MH_0_REG +
+ (HNS_ROCE_V1_GID_NUM * gid_idx));
+
+ p = (u32 *)&gid->raw[0xc];
+ roce_raw_write(*p, hr_dev->reg_base + ROCEE_PORT_GID_H_0_REG +
+ (HNS_ROCE_V1_GID_NUM * gid_idx));
+}
+
+void hns_roce_v1_set_mac(struct hns_roce_dev *hr_dev, u8 phy_port, u8 *addr)
+{
+ u32 reg_smac_l;
+ u16 reg_smac_h;
+ u16 *p_h;
+ u32 *p;
+ u32 val;
+
+ p = (u32 *)(&addr[0]);
+ reg_smac_l = *p;
+ roce_raw_write(reg_smac_l, hr_dev->reg_base + ROCEE_SMAC_L_0_REG +
+ PHY_PORT_OFFSET * phy_port);
+
+ val = roce_read(hr_dev,
+ ROCEE_SMAC_H_0_REG + phy_port * PHY_PORT_OFFSET);
+ p_h = (u16 *)(&addr[4]);
+ reg_smac_h = *p_h;
+ roce_set_field(val, ROCEE_SMAC_H_ROCEE_SMAC_H_M,
+ ROCEE_SMAC_H_ROCEE_SMAC_H_S, reg_smac_h);
+ roce_write(hr_dev, ROCEE_SMAC_H_0_REG + phy_port * PHY_PORT_OFFSET,
+ val);
+}
+
+void hns_roce_v1_set_mtu(struct hns_roce_dev *hr_dev, u8 phy_port,
+ enum ib_mtu mtu)
+{
+ u32 val;
+
+ val = roce_read(hr_dev,
+ ROCEE_SMAC_H_0_REG + phy_port * PHY_PORT_OFFSET);
+ roce_set_field(val, ROCEE_SMAC_H_ROCEE_PORT_MTU_M,
+ ROCEE_SMAC_H_ROCEE_PORT_MTU_S, mtu);
+ roce_write(hr_dev, ROCEE_SMAC_H_0_REG + phy_port * PHY_PORT_OFFSET,
+ val);
+}
+
+int hns_roce_v1_write_mtpt(void *mb_buf, struct hns_roce_mr *mr,
+ unsigned long mtpt_idx)
+{
+ struct hns_roce_v1_mpt_entry *mpt_entry;
+ struct scatterlist *sg;
+ u64 *pages;
+ int entry;
+ int i;
+
+ /* MPT filled into mailbox buf */
+ mpt_entry = (struct hns_roce_v1_mpt_entry *)mb_buf;
+ memset(mpt_entry, 0, sizeof(*mpt_entry));
+
+ roce_set_field(mpt_entry->mpt_byte_4, MPT_BYTE_4_KEY_STATE_M,
+ MPT_BYTE_4_KEY_STATE_S, KEY_VALID);
+ roce_set_field(mpt_entry->mpt_byte_4, MPT_BYTE_4_KEY_M,
+ MPT_BYTE_4_KEY_S, mr->key);
+ roce_set_field(mpt_entry->mpt_byte_4, MPT_BYTE_4_PAGE_SIZE_M,
+ MPT_BYTE_4_PAGE_SIZE_S, MR_SIZE_4K);
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_MW_TYPE_S, 0);
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_MW_BIND_ENABLE_S,
+ (mr->access & IB_ACCESS_MW_BIND ? 1 : 0));
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_OWN_S, 0);
+ roce_set_field(mpt_entry->mpt_byte_4, MPT_BYTE_4_MEMORY_LOCATION_TYPE_M,
+ MPT_BYTE_4_MEMORY_LOCATION_TYPE_S, mr->type);
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_REMOTE_ATOMIC_S, 0);
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_LOCAL_WRITE_S,
+ (mr->access & IB_ACCESS_LOCAL_WRITE ? 1 : 0));
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_REMOTE_WRITE_S,
+ (mr->access & IB_ACCESS_REMOTE_WRITE ? 1 : 0));
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_REMOTE_READ_S,
+ (mr->access & IB_ACCESS_REMOTE_READ ? 1 : 0));
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_REMOTE_INVAL_ENABLE_S,
+ 0);
+ roce_set_bit(mpt_entry->mpt_byte_4, MPT_BYTE_4_ADDRESS_TYPE_S, 0);
+
+ roce_set_field(mpt_entry->mpt_byte_12, MPT_BYTE_12_PBL_ADDR_H_M,
+ MPT_BYTE_12_PBL_ADDR_H_S, 0);
+ roce_set_field(mpt_entry->mpt_byte_12, MPT_BYTE_12_MW_BIND_COUNTER_M,
+ MPT_BYTE_12_MW_BIND_COUNTER_S, 0);
+
+ mpt_entry->virt_addr_l = (u32)mr->iova;
+ mpt_entry->virt_addr_h = (u32)(mr->iova >> 32);
+ mpt_entry->length = (u32)mr->size;
+
+ roce_set_field(mpt_entry->mpt_byte_28, MPT_BYTE_28_PD_M,
+ MPT_BYTE_28_PD_S, mr->pd);
+ roce_set_field(mpt_entry->mpt_byte_28, MPT_BYTE_28_L_KEY_IDX_L_M,
+ MPT_BYTE_28_L_KEY_IDX_L_S, mtpt_idx);
+ roce_set_field(mpt_entry->mpt_byte_64, MPT_BYTE_64_L_KEY_IDX_H_M,
+ MPT_BYTE_64_L_KEY_IDX_H_S, mtpt_idx >> MTPT_IDX_SHIFT);
+
+ /* DMA momery regsiter */
+ if (mr->type == MR_TYPE_DMA)
+ return 0;
+
+ pages = (u64 *) __get_free_page(GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_sg(mr->umem->sg_head.sgl, sg, mr->umem->nmap, entry) {
+ pages[i] = ((u64)sg_dma_address(sg)) >> 12;
+
+ /* Directly record to MTPT table firstly 7 entry */
+ if (i >= HNS_ROCE_MAX_INNER_MTPT_NUM)
+ break;
+ i++;
+ }
+
+ /* Register user mr */
+ for (i = 0; i < HNS_ROCE_MAX_INNER_MTPT_NUM; i++) {
+ switch (i) {
+ case 0:
+ mpt_entry->pa0_l = cpu_to_le32((u32)(pages[i]));
+ roce_set_field(mpt_entry->mpt_byte_36,
+ MPT_BYTE_36_PA0_H_M,
+ MPT_BYTE_36_PA0_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_32)));
+ break;
+ case 1:
+ roce_set_field(mpt_entry->mpt_byte_36,
+ MPT_BYTE_36_PA1_L_M,
+ MPT_BYTE_36_PA1_L_S,
+ cpu_to_le32((u32)(pages[i])));
+ roce_set_field(mpt_entry->mpt_byte_40,
+ MPT_BYTE_40_PA1_H_M,
+ MPT_BYTE_40_PA1_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_24)));
+ break;
+ case 2:
+ roce_set_field(mpt_entry->mpt_byte_40,
+ MPT_BYTE_40_PA2_L_M,
+ MPT_BYTE_40_PA2_L_S,
+ cpu_to_le32((u32)(pages[i])));
+ roce_set_field(mpt_entry->mpt_byte_44,
+ MPT_BYTE_44_PA2_H_M,
+ MPT_BYTE_44_PA2_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_16)));
+ break;
+ case 3:
+ roce_set_field(mpt_entry->mpt_byte_44,
+ MPT_BYTE_44_PA3_L_M,
+ MPT_BYTE_44_PA3_L_S,
+ cpu_to_le32((u32)(pages[i])));
+ roce_set_field(mpt_entry->mpt_byte_48,
+ MPT_BYTE_48_PA3_H_M,
+ MPT_BYTE_48_PA3_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_8)));
+ break;
+ case 4:
+ mpt_entry->pa4_l = cpu_to_le32((u32)(pages[i]));
+ roce_set_field(mpt_entry->mpt_byte_56,
+ MPT_BYTE_56_PA4_H_M,
+ MPT_BYTE_56_PA4_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_32)));
+ break;
+ case 5:
+ roce_set_field(mpt_entry->mpt_byte_56,
+ MPT_BYTE_56_PA5_L_M,
+ MPT_BYTE_56_PA5_L_S,
+ cpu_to_le32((u32)(pages[i])));
+ roce_set_field(mpt_entry->mpt_byte_60,
+ MPT_BYTE_60_PA5_H_M,
+ MPT_BYTE_60_PA5_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_24)));
+ break;
+ case 6:
+ roce_set_field(mpt_entry->mpt_byte_60,
+ MPT_BYTE_60_PA6_L_M,
+ MPT_BYTE_60_PA6_L_S,
+ cpu_to_le32((u32)(pages[i])));
+ roce_set_field(mpt_entry->mpt_byte_64,
+ MPT_BYTE_64_PA6_H_M,
+ MPT_BYTE_64_PA6_H_S,
+ cpu_to_le32((u32)(pages[i] >> PAGES_SHIFT_16)));
+ break;
+ default:
+ break;
+ }
+ }
+
+ free_page((unsigned long) pages);
+
+ mpt_entry->pbl_addr_l = (u32)(mr->pbl_dma_addr);
+
+ roce_set_field(mpt_entry->mpt_byte_12, MPT_BYTE_12_PBL_ADDR_H_M,
+ MPT_BYTE_12_PBL_ADDR_H_S,
+ ((u32)(mr->pbl_dma_addr >> 32)));
+
+ return 0;
+}
+
+static void *get_cqe(struct hns_roce_cq *hr_cq, int n)
+{
+ return hns_roce_buf_offset(&hr_cq->hr_buf.hr_buf,
+ n * HNS_ROCE_V1_CQE_ENTRY_SIZE);
+}
+
+static void *get_sw_cqe(struct hns_roce_cq *hr_cq, int n)
+{
+ struct hns_roce_cqe *hr_cqe = get_cqe(hr_cq, n & hr_cq->ib_cq.cqe);
+
+ /* Get cqe when Owner bit is Conversely with the MSB of cons_idx */
+ return (roce_get_bit(hr_cqe->cqe_byte_4, CQE_BYTE_4_OWNER_S) ^
+ !!(n & (hr_cq->ib_cq.cqe + 1))) ? hr_cqe : NULL;
+}
+
+static struct hns_roce_cqe *next_cqe_sw(struct hns_roce_cq *hr_cq)
+{
+ return get_sw_cqe(hr_cq, hr_cq->cons_index);
+}
+
+void hns_roce_v1_cq_set_ci(struct hns_roce_cq *hr_cq, u32 cons_index,
+ spinlock_t *doorbell_lock)
+
+{
+ u32 doorbell[2];
+
+ doorbell[0] = cons_index & ((hr_cq->cq_depth << 1) - 1);
+ roce_set_bit(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_HW_SYNS_S, 1);
+ roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_M,
+ ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_S, 3);
+ roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_M,
+ ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_S, 0);
+ roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_M,
+ ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_S, hr_cq->cqn);
+
+ hns_roce_write64_k(doorbell, hr_cq->cq_db_l);
+}
+
+static void __hns_roce_v1_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn,
+ struct hns_roce_srq *srq)
+{
+ struct hns_roce_cqe *cqe, *dest;
+ u32 prod_index;
+ int nfreed = 0;
+ u8 owner_bit;
+
+ for (prod_index = hr_cq->cons_index; get_sw_cqe(hr_cq, prod_index);
+ ++prod_index) {
+ if (prod_index == hr_cq->cons_index + hr_cq->ib_cq.cqe)
+ break;
+ }
+
+ /*
+ * Now backwards through the CQ, removing CQ entries
+ * that match our QP by overwriting them with next entries.
+ */
+ while ((int) --prod_index - (int) hr_cq->cons_index >= 0) {
+ cqe = get_cqe(hr_cq, prod_index & hr_cq->ib_cq.cqe);
+ if ((roce_get_field(cqe->cqe_byte_16, CQE_BYTE_16_LOCAL_QPN_M,
+ CQE_BYTE_16_LOCAL_QPN_S) &
+ HNS_ROCE_CQE_QPN_MASK) == qpn) {
+ /* In v1 engine, not support SRQ */
+ ++nfreed;
+ } else if (nfreed) {
+ dest = get_cqe(hr_cq, (prod_index + nfreed) &
+ hr_cq->ib_cq.cqe);
+ owner_bit = roce_get_bit(dest->cqe_byte_4,
+ CQE_BYTE_4_OWNER_S);
+ memcpy(dest, cqe, sizeof(*cqe));
+ roce_set_bit(dest->cqe_byte_4, CQE_BYTE_4_OWNER_S,
+ owner_bit);
+ }
+ }
+
+ if (nfreed) {
+ hr_cq->cons_index += nfreed;
+ /*
+ * Make sure update of buffer contents is done before
+ * updating consumer index.
+ */
+ wmb();
+
+ hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index,
+ &to_hr_dev(hr_cq->ib_cq.device)->cq_db_lock);
+ }
+}
+
+static void hns_roce_v1_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn,
+ struct hns_roce_srq *srq)
+{
+ spin_lock_irq(&hr_cq->lock);
+ __hns_roce_v1_cq_clean(hr_cq, qpn, srq);
+ spin_unlock_irq(&hr_cq->lock);
+}
+
+void hns_roce_v1_write_cqc(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts,
+ dma_addr_t dma_handle, int nent, u32 vector)
+{
+ struct hns_roce_cq_context *cq_context = NULL;
+ void __iomem *tptr_addr;
+
+ cq_context = mb_buf;
+ memset(cq_context, 0, sizeof(*cq_context));
+
+ tptr_addr = 0;
+ hr_dev->priv_addr = tptr_addr;
+ hr_cq->tptr_addr = tptr_addr;
+
+ /* Register cq_context members */
+ roce_set_field(cq_context->cqc_byte_4,
+ CQ_CONTEXT_CQC_BYTE_4_CQC_STATE_M,
+ CQ_CONTEXT_CQC_BYTE_4_CQC_STATE_S, CQ_STATE_VALID);
+ roce_set_field(cq_context->cqc_byte_4, CQ_CONTEXT_CQC_BYTE_4_CQN_M,
+ CQ_CONTEXT_CQC_BYTE_4_CQN_S, hr_cq->cqn);
+ cq_context->cqc_byte_4 = cpu_to_le32(cq_context->cqc_byte_4);
+
+ cq_context->cq_bt_l = (u32)dma_handle;
+ cq_context->cq_bt_l = cpu_to_le32(cq_context->cq_bt_l);
+
+ roce_set_field(cq_context->cqc_byte_12,
+ CQ_CONTEXT_CQC_BYTE_12_CQ_BT_H_M,
+ CQ_CONTEXT_CQC_BYTE_12_CQ_BT_H_S,
+ ((u64)dma_handle >> 32));
+ roce_set_field(cq_context->cqc_byte_12,
+ CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_M,
+ CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_S,
+ ilog2((unsigned int)nent));
+ roce_set_field(cq_context->cqc_byte_12, CQ_CONTEXT_CQC_BYTE_12_CEQN_M,
+ CQ_CONTEXT_CQC_BYTE_12_CEQN_S, vector);
+ cq_context->cqc_byte_12 = cpu_to_le32(cq_context->cqc_byte_12);
+
+ cq_context->cur_cqe_ba0_l = (u32)(mtts[0]);
+ cq_context->cur_cqe_ba0_l = cpu_to_le32(cq_context->cur_cqe_ba0_l);
+
+ roce_set_field(cq_context->cqc_byte_20,
+ CQ_CONTEXT_CQC_BYTE_20_CUR_CQE_BA0_H_M,
+ CQ_CONTEXT_CQC_BYTE_20_CUR_CQE_BA0_H_S,
+ cpu_to_le32((mtts[0]) >> 32));
+ /* Dedicated hardware, directly set 0 */
+ roce_set_field(cq_context->cqc_byte_20,
+ CQ_CONTEXT_CQC_BYTE_20_CQ_CUR_INDEX_M,
+ CQ_CONTEXT_CQC_BYTE_20_CQ_CUR_INDEX_S, 0);
+ /**
+ * 44 = 32 + 12, When evaluating addr to hardware, shift 12 because of
+ * using 4K page, and shift more 32 because of
+ * caculating the high 32 bit value evaluated to hardware.
+ */
+ roce_set_field(cq_context->cqc_byte_20,
+ CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_M,
+ CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_S,
+ (u64)tptr_addr >> 44);
+ cq_context->cqc_byte_20 = cpu_to_le32(cq_context->cqc_byte_20);
+
+ cq_context->cqe_tptr_addr_l = (u32)((u64)tptr_addr >> 12);
+
+ roce_set_field(cq_context->cqc_byte_32,
+ CQ_CONTEXT_CQC_BYTE_32_CUR_CQE_BA1_H_M,
+ CQ_CONTEXT_CQC_BYTE_32_CUR_CQE_BA1_H_S, 0);
+ roce_set_bit(cq_context->cqc_byte_32,
+ CQ_CONTEXT_CQC_BYTE_32_SE_FLAG_S, 0);
+ roce_set_bit(cq_context->cqc_byte_32,
+ CQ_CONTEXT_CQC_BYTE_32_CE_FLAG_S, 0);
+ roce_set_bit(cq_context->cqc_byte_32,
+ CQ_CONTEXT_CQC_BYTE_32_NOTIFICATION_FLAG_S, 0);
+ roce_set_bit(cq_context->cqc_byte_32,
+ CQ_CQNTEXT_CQC_BYTE_32_TYPE_OF_COMPLETION_NOTIFICATION_S,
+ 0);
+ /*The initial value of cq's ci is 0 */
+ roce_set_field(cq_context->cqc_byte_32,
+ CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_M,
+ CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_S, 0);
+ cq_context->cqc_byte_32 = cpu_to_le32(cq_context->cqc_byte_32);
+}
+
+int hns_roce_v1_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+ struct hns_roce_cq *hr_cq = to_hr_cq(ibcq);
+ u32 notification_flag;
+ u32 doorbell[2];
+ int ret = 0;
+
+ notification_flag = (flags & IB_CQ_SOLICITED_MASK) ==
+ IB_CQ_SOLICITED ? CQ_DB_REQ_NOT : CQ_DB_REQ_NOT_SOL;
+ /*
+ * flags = 0; Notification Flag = 1, next
+ * flags = 1; Notification Flag = 0, solocited
+ */
+ doorbell[0] = hr_cq->cons_index & ((hr_cq->cq_depth << 1) - 1);
+ roce_set_bit(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_HW_SYNS_S, 1);
+ roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_M,
+ ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_S, 3);
+ roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_M,
+ ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_MDF_S, 1);
+ roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_M,
+ ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_INP_H_S,
+ hr_cq->cqn | notification_flag);
+
+ hns_roce_write64_k(doorbell, hr_cq->cq_db_l);
+
+ return ret;
+}
+
+static int hns_roce_v1_poll_one(struct hns_roce_cq *hr_cq,
+ struct hns_roce_qp **cur_qp, struct ib_wc *wc)
+{
+ int qpn;
+ int is_send;
+ u16 wqe_ctr;
+ u32 status;
+ u32 opcode;
+ struct hns_roce_cqe *cqe;
+ struct hns_roce_qp *hr_qp;
+ struct hns_roce_wq *wq;
+ struct hns_roce_wqe_ctrl_seg *sq_wqe;
+ struct hns_roce_dev *hr_dev = to_hr_dev(hr_cq->ib_cq.device);
+ struct device *dev = &hr_dev->pdev->dev;
+
+ /* Find cqe according consumer index */
+ cqe = next_cqe_sw(hr_cq);
+ if (!cqe)
+ return -EAGAIN;
+
+ ++hr_cq->cons_index;
+ /* Memory barrier */
+ rmb();
+ /* 0->SQ, 1->RQ */
+ is_send = !(roce_get_bit(cqe->cqe_byte_4, CQE_BYTE_4_SQ_RQ_FLAG_S));
+
+ /* Local_qpn in UD cqe is always 1, so it needs to compute new qpn */
+ if (roce_get_field(cqe->cqe_byte_16, CQE_BYTE_16_LOCAL_QPN_M,
+ CQE_BYTE_16_LOCAL_QPN_S) <= 1) {
+ qpn = roce_get_field(cqe->cqe_byte_20, CQE_BYTE_20_PORT_NUM_M,
+ CQE_BYTE_20_PORT_NUM_S) +
+ roce_get_field(cqe->cqe_byte_16, CQE_BYTE_16_LOCAL_QPN_M,
+ CQE_BYTE_16_LOCAL_QPN_S) *
+ HNS_ROCE_MAX_PORTS;
+ } else {
+ qpn = roce_get_field(cqe->cqe_byte_16, CQE_BYTE_16_LOCAL_QPN_M,
+ CQE_BYTE_16_LOCAL_QPN_S);
+ }
+
+ if (!*cur_qp || (qpn & HNS_ROCE_CQE_QPN_MASK) != (*cur_qp)->qpn) {
+ hr_qp = __hns_roce_qp_lookup(hr_dev, qpn);
+ if (unlikely(!hr_qp)) {
+ dev_err(dev, "CQ %06lx with entry for unknown QPN %06x\n",
+ hr_cq->cqn, (qpn & HNS_ROCE_CQE_QPN_MASK));
+ return -EINVAL;
+ }
+
+ *cur_qp = hr_qp;
+ }
+
+ wc->qp = &(*cur_qp)->ibqp;
+ wc->vendor_err = 0;
+
+ status = roce_get_field(cqe->cqe_byte_4,
+ CQE_BYTE_4_STATUS_OF_THE_OPERATION_M,
+ CQE_BYTE_4_STATUS_OF_THE_OPERATION_S) &
+ HNS_ROCE_CQE_STATUS_MASK;
+ switch (status) {
+ case HNS_ROCE_CQE_SUCCESS:
+ wc->status = IB_WC_SUCCESS;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_LOCAL_LENGTH_ERR:
+ wc->status = IB_WC_LOC_LEN_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_LOCAL_QP_OP_ERR:
+ wc->status = IB_WC_LOC_QP_OP_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_LOCAL_PROT_ERR:
+ wc->status = IB_WC_LOC_PROT_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_WR_FLUSH_ERR:
+ wc->status = IB_WC_WR_FLUSH_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_MEM_MANAGE_OPERATE_ERR:
+ wc->status = IB_WC_MW_BIND_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_BAD_RESP_ERR:
+ wc->status = IB_WC_BAD_RESP_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_LOCAL_ACCESS_ERR:
+ wc->status = IB_WC_LOC_ACCESS_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR:
+ wc->status = IB_WC_REM_INV_REQ_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_REMOTE_ACCESS_ERR:
+ wc->status = IB_WC_REM_ACCESS_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_REMOTE_OP_ERR:
+ wc->status = IB_WC_REM_OP_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR:
+ wc->status = IB_WC_RETRY_EXC_ERR;
+ break;
+ case HNS_ROCE_CQE_SYNDROME_RNR_RETRY_EXC_ERR:
+ wc->status = IB_WC_RNR_RETRY_EXC_ERR;
+ break;
+ default:
+ wc->status = IB_WC_GENERAL_ERR;
+ break;
+ }
+
+ /* CQE status error, directly return */
+ if (wc->status != IB_WC_SUCCESS)
+ return 0;
+
+ if (is_send) {
+ /* SQ conrespond to CQE */
+ sq_wqe = get_send_wqe(*cur_qp, roce_get_field(cqe->cqe_byte_4,
+ CQE_BYTE_4_WQE_INDEX_M,
+ CQE_BYTE_4_WQE_INDEX_S));
+ switch (sq_wqe->flag & HNS_ROCE_WQE_OPCODE_MASK) {
+ case HNS_ROCE_WQE_OPCODE_SEND:
+ wc->opcode = IB_WC_SEND;
+ break;
+ case HNS_ROCE_WQE_OPCODE_RDMA_READ:
+ wc->opcode = IB_WC_RDMA_READ;
+ wc->byte_len = le32_to_cpu(cqe->byte_cnt);
+ break;
+ case HNS_ROCE_WQE_OPCODE_RDMA_WRITE:
+ wc->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case HNS_ROCE_WQE_OPCODE_LOCAL_INV:
+ wc->opcode = IB_WC_LOCAL_INV;
+ break;
+ case HNS_ROCE_WQE_OPCODE_UD_SEND:
+ wc->opcode = IB_WC_SEND;
+ break;
+ default:
+ wc->status = IB_WC_GENERAL_ERR;
+ break;
+ }
+ wc->wc_flags = (sq_wqe->flag & HNS_ROCE_WQE_IMM ?
+ IB_WC_WITH_IMM : 0);
+
+ wq = &(*cur_qp)->sq;
+ if ((*cur_qp)->sq_signal_bits) {
+ /*
+ * If sg_signal_bit is 1,
+ * firstly tail pointer updated to wqe
+ * which current cqe correspond to
+ */
+ wqe_ctr = (u16)roce_get_field(cqe->cqe_byte_4,
+ CQE_BYTE_4_WQE_INDEX_M,
+ CQE_BYTE_4_WQE_INDEX_S);
+ wq->tail += (wqe_ctr - (u16)wq->tail) &
+ (wq->wqe_cnt - 1);
+ }
+ wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+ ++wq->tail;
+ } else {
+ /* RQ conrespond to CQE */
+ wc->byte_len = le32_to_cpu(cqe->byte_cnt);
+ opcode = roce_get_field(cqe->cqe_byte_4,
+ CQE_BYTE_4_OPERATION_TYPE_M,
+ CQE_BYTE_4_OPERATION_TYPE_S) &
+ HNS_ROCE_CQE_OPCODE_MASK;
+ switch (opcode) {
+ case HNS_ROCE_OPCODE_RDMA_WITH_IMM_RECEIVE:
+ wc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ wc->wc_flags = IB_WC_WITH_IMM;
+ wc->ex.imm_data = le32_to_cpu(cqe->immediate_data);
+ break;
+ case HNS_ROCE_OPCODE_SEND_DATA_RECEIVE:
+ if (roce_get_bit(cqe->cqe_byte_4,
+ CQE_BYTE_4_IMM_INDICATOR_S)) {
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = IB_WC_WITH_IMM;
+ wc->ex.imm_data = le32_to_cpu(
+ cqe->immediate_data);
+ } else {
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = 0;
+ }
+ break;
+ default:
+ wc->status = IB_WC_GENERAL_ERR;
+ break;
+ }
+
+ /* Update tail pointer, record wr_id */
+ wq = &(*cur_qp)->rq;
+ wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+ ++wq->tail;
+ wc->sl = (u8)roce_get_field(cqe->cqe_byte_20, CQE_BYTE_20_SL_M,
+ CQE_BYTE_20_SL_S);
+ wc->src_qp = (u8)roce_get_field(cqe->cqe_byte_20,
+ CQE_BYTE_20_REMOTE_QPN_M,
+ CQE_BYTE_20_REMOTE_QPN_S);
+ wc->wc_flags |= (roce_get_bit(cqe->cqe_byte_20,
+ CQE_BYTE_20_GRH_PRESENT_S) ?
+ IB_WC_GRH : 0);
+ wc->pkey_index = (u16)roce_get_field(cqe->cqe_byte_28,
+ CQE_BYTE_28_P_KEY_IDX_M,
+ CQE_BYTE_28_P_KEY_IDX_S);
+ }
+
+ return 0;
+}
+
+int hns_roce_v1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+ struct hns_roce_cq *hr_cq = to_hr_cq(ibcq);
+ struct hns_roce_qp *cur_qp = NULL;
+ unsigned long flags;
+ int npolled;
+ int ret = 0;
+
+ spin_lock_irqsave(&hr_cq->lock, flags);
+
+ for (npolled = 0; npolled < num_entries; ++npolled) {
+ ret = hns_roce_v1_poll_one(hr_cq, &cur_qp, wc + npolled);
+ if (ret)
+ break;
+ }
+
+ if (npolled) {
+ hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index,
+ &to_hr_dev(ibcq->device)->cq_db_lock);
+ }
+
+ spin_unlock_irqrestore(&hr_cq->lock, flags);
+
+ if (ret == 0 || ret == -EAGAIN)
+ return npolled;
+ else
+ return ret;
+}
+
+static int hns_roce_v1_qp_modify(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt,
+ enum hns_roce_qp_state cur_state,
+ enum hns_roce_qp_state new_state,
+ struct hns_roce_qp_context *context,
+ struct hns_roce_qp *hr_qp)
+{
+ static const u16
+ op[HNS_ROCE_QP_NUM_STATE][HNS_ROCE_QP_NUM_STATE] = {
+ [HNS_ROCE_QP_STATE_RST] = {
+ [HNS_ROCE_QP_STATE_RST] = HNS_ROCE_CMD_2RST_QP,
+ [HNS_ROCE_QP_STATE_ERR] = HNS_ROCE_CMD_2ERR_QP,
+ [HNS_ROCE_QP_STATE_INIT] = HNS_ROCE_CMD_RST2INIT_QP,
+ },
+ [HNS_ROCE_QP_STATE_INIT] = {
+ [HNS_ROCE_QP_STATE_RST] = HNS_ROCE_CMD_2RST_QP,
+ [HNS_ROCE_QP_STATE_ERR] = HNS_ROCE_CMD_2ERR_QP,
+ /* Note: In v1 engine, HW doesn't support RST2INIT.
+ * We use RST2INIT cmd instead of INIT2INIT.
+ */
+ [HNS_ROCE_QP_STATE_INIT] = HNS_ROCE_CMD_RST2INIT_QP,
+ [HNS_ROCE_QP_STATE_RTR] = HNS_ROCE_CMD_INIT2RTR_QP,
+ },
+ [HNS_ROCE_QP_STATE_RTR] = {
+ [HNS_ROCE_QP_STATE_RST] = HNS_ROCE_CMD_2RST_QP,
+ [HNS_ROCE_QP_STATE_ERR] = HNS_ROCE_CMD_2ERR_QP,
+ [HNS_ROCE_QP_STATE_RTS] = HNS_ROCE_CMD_RTR2RTS_QP,
+ },
+ [HNS_ROCE_QP_STATE_RTS] = {
+ [HNS_ROCE_QP_STATE_RST] = HNS_ROCE_CMD_2RST_QP,
+ [HNS_ROCE_QP_STATE_ERR] = HNS_ROCE_CMD_2ERR_QP,
+ [HNS_ROCE_QP_STATE_RTS] = HNS_ROCE_CMD_RTS2RTS_QP,
+ [HNS_ROCE_QP_STATE_SQD] = HNS_ROCE_CMD_RTS2SQD_QP,
+ },
+ [HNS_ROCE_QP_STATE_SQD] = {
+ [HNS_ROCE_QP_STATE_RST] = HNS_ROCE_CMD_2RST_QP,
+ [HNS_ROCE_QP_STATE_ERR] = HNS_ROCE_CMD_2ERR_QP,
+ [HNS_ROCE_QP_STATE_RTS] = HNS_ROCE_CMD_SQD2RTS_QP,
+ [HNS_ROCE_QP_STATE_SQD] = HNS_ROCE_CMD_SQD2SQD_QP,
+ },
+ [HNS_ROCE_QP_STATE_ERR] = {
+ [HNS_ROCE_QP_STATE_RST] = HNS_ROCE_CMD_2RST_QP,
+ [HNS_ROCE_QP_STATE_ERR] = HNS_ROCE_CMD_2ERR_QP,
+ }
+ };
+
+ struct hns_roce_cmd_mailbox *mailbox;
+ struct device *dev = &hr_dev->pdev->dev;
+ int ret = 0;
+
+ if (cur_state >= HNS_ROCE_QP_NUM_STATE ||
+ new_state >= HNS_ROCE_QP_NUM_STATE ||
+ !op[cur_state][new_state]) {
+ dev_err(dev, "[modify_qp]not support state %d to %d\n",
+ cur_state, new_state);
+ return -EINVAL;
+ }
+
+ if (op[cur_state][new_state] == HNS_ROCE_CMD_2RST_QP)
+ return hns_roce_cmd_mbox(hr_dev, 0, 0, hr_qp->qpn, 2,
+ HNS_ROCE_CMD_2RST_QP,
+ HNS_ROCE_CMD_TIME_CLASS_A);
+
+ if (op[cur_state][new_state] == HNS_ROCE_CMD_2ERR_QP)
+ return hns_roce_cmd_mbox(hr_dev, 0, 0, hr_qp->qpn, 2,
+ HNS_ROCE_CMD_2ERR_QP,
+ HNS_ROCE_CMD_TIME_CLASS_A);
+
+ mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ memcpy(mailbox->buf, context, sizeof(*context));
+
+ ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, hr_qp->qpn, 0,
+ op[cur_state][new_state],
+ HNS_ROCE_CMD_TIME_CLASS_C);
+
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+ return ret;
+}
+
+static int hns_roce_v1_m_sqp(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
+ int attr_mask, enum ib_qp_state cur_state,
+ enum ib_qp_state new_state)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+ struct hns_roce_sqp_context *context;
+ struct device *dev = &hr_dev->pdev->dev;
+ dma_addr_t dma_handle = 0;
+ int rq_pa_start;
+ u32 reg_val;
+ u64 *mtts;
+ u32 *addr;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return -ENOMEM;
+
+ /* Search QP buf's MTTs */
+ mtts = hns_roce_table_find(&hr_dev->mr_table.mtt_table,
+ hr_qp->mtt.first_seg, &dma_handle);
+ if (!mtts) {
+ dev_err(dev, "qp buf pa find failed\n");
+ goto out;
+ }
+
+ if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
+ roce_set_field(context->qp1c_bytes_4,
+ QP1C_BYTES_4_SQ_WQE_SHIFT_M,
+ QP1C_BYTES_4_SQ_WQE_SHIFT_S,
+ ilog2((unsigned int)hr_qp->sq.wqe_cnt));
+ roce_set_field(context->qp1c_bytes_4,
+ QP1C_BYTES_4_RQ_WQE_SHIFT_M,
+ QP1C_BYTES_4_RQ_WQE_SHIFT_S,
+ ilog2((unsigned int)hr_qp->rq.wqe_cnt));
+ roce_set_field(context->qp1c_bytes_4, QP1C_BYTES_4_PD_M,
+ QP1C_BYTES_4_PD_S, to_hr_pd(ibqp->pd)->pdn);
+
+ context->sq_rq_bt_l = (u32)(dma_handle);
+ roce_set_field(context->qp1c_bytes_12,
+ QP1C_BYTES_12_SQ_RQ_BT_H_M,
+ QP1C_BYTES_12_SQ_RQ_BT_H_S,
+ ((u32)(dma_handle >> 32)));
+
+ roce_set_field(context->qp1c_bytes_16, QP1C_BYTES_16_RQ_HEAD_M,
+ QP1C_BYTES_16_RQ_HEAD_S, hr_qp->rq.head);
+ roce_set_field(context->qp1c_bytes_16, QP1C_BYTES_16_PORT_NUM_M,
+ QP1C_BYTES_16_PORT_NUM_S, hr_qp->port);
+ roce_set_bit(context->qp1c_bytes_16,
+ QP1C_BYTES_16_SIGNALING_TYPE_S,
+ hr_qp->sq_signal_bits);
+ roce_set_bit(context->qp1c_bytes_16,
+ QP1C_BYTES_16_LOCAL_ENABLE_E2E_CREDIT_S,
+ hr_qp->sq_signal_bits);
+ roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_RQ_BA_FLG_S,
+ 1);
+ roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_SQ_BA_FLG_S,
+ 1);
+ roce_set_bit(context->qp1c_bytes_16, QP1C_BYTES_16_QP1_ERR_S,
+ 0);
+
+ roce_set_field(context->qp1c_bytes_20, QP1C_BYTES_20_SQ_HEAD_M,
+ QP1C_BYTES_20_SQ_HEAD_S, hr_qp->sq.head);
+ roce_set_field(context->qp1c_bytes_20, QP1C_BYTES_20_PKEY_IDX_M,
+ QP1C_BYTES_20_PKEY_IDX_S, attr->pkey_index);
+
+ rq_pa_start = (u32)hr_qp->rq.offset / PAGE_SIZE;
+ context->cur_rq_wqe_ba_l = (u32)(mtts[rq_pa_start]);
+
+ roce_set_field(context->qp1c_bytes_28,
+ QP1C_BYTES_28_CUR_RQ_WQE_BA_H_M,
+ QP1C_BYTES_28_CUR_RQ_WQE_BA_H_S,
+ (mtts[rq_pa_start]) >> 32);
+ roce_set_field(context->qp1c_bytes_28,
+ QP1C_BYTES_28_RQ_CUR_IDX_M,
+ QP1C_BYTES_28_RQ_CUR_IDX_S, 0);
+
+ roce_set_field(context->qp1c_bytes_32,
+ QP1C_BYTES_32_RX_CQ_NUM_M,
+ QP1C_BYTES_32_RX_CQ_NUM_S,
+ to_hr_cq(ibqp->recv_cq)->cqn);
+ roce_set_field(context->qp1c_bytes_32,
+ QP1C_BYTES_32_TX_CQ_NUM_M,
+ QP1C_BYTES_32_TX_CQ_NUM_S,
+ to_hr_cq(ibqp->send_cq)->cqn);
+
+ context->cur_sq_wqe_ba_l = (u32)mtts[0];
+
+ roce_set_field(context->qp1c_bytes_40,
+ QP1C_BYTES_40_CUR_SQ_WQE_BA_H_M,
+ QP1C_BYTES_40_CUR_SQ_WQE_BA_H_S,
+ (mtts[0]) >> 32);
+ roce_set_field(context->qp1c_bytes_40,
+ QP1C_BYTES_40_SQ_CUR_IDX_M,
+ QP1C_BYTES_40_SQ_CUR_IDX_S, 0);
+
+ /* Copy context to QP1C register */
+ addr = (u32 *)(hr_dev->reg_base + ROCEE_QP1C_CFG0_0_REG +
+ hr_qp->port * sizeof(*context));
+
+ writel(context->qp1c_bytes_4, addr);
+ writel(context->sq_rq_bt_l, addr + 1);
+ writel(context->qp1c_bytes_12, addr + 2);
+ writel(context->qp1c_bytes_16, addr + 3);
+ writel(context->qp1c_bytes_20, addr + 4);
+ writel(context->cur_rq_wqe_ba_l, addr + 5);
+ writel(context->qp1c_bytes_28, addr + 6);
+ writel(context->qp1c_bytes_32, addr + 7);
+ writel(context->cur_sq_wqe_ba_l, addr + 8);
+ }
+
+ /* Modify QP1C status */
+ reg_val = roce_read(hr_dev, ROCEE_QP1C_CFG0_0_REG +
+ hr_qp->port * sizeof(*context));
+ roce_set_field(reg_val, ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_M,
+ ROCEE_QP1C_CFG0_0_ROCEE_QP1C_QP_ST_S, new_state);
+ roce_write(hr_dev, ROCEE_QP1C_CFG0_0_REG +
+ hr_qp->port * sizeof(*context), reg_val);
+
+ hr_qp->state = new_state;
+ if (new_state == IB_QPS_RESET) {
+ hns_roce_v1_cq_clean(to_hr_cq(ibqp->recv_cq), hr_qp->qpn,
+ ibqp->srq ? to_hr_srq(ibqp->srq) : NULL);
+ if (ibqp->send_cq != ibqp->recv_cq)
+ hns_roce_v1_cq_clean(to_hr_cq(ibqp->send_cq),
+ hr_qp->qpn, NULL);
+
+ hr_qp->rq.head = 0;
+ hr_qp->rq.tail = 0;
+ hr_qp->sq.head = 0;
+ hr_qp->sq.tail = 0;
+ hr_qp->sq_next_wqe = 0;
+ }
+
+ kfree(context);
+ return 0;
+
+out:
+ kfree(context);
+ return -EINVAL;
+}
+
+static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
+ int attr_mask, enum ib_qp_state cur_state,
+ enum ib_qp_state new_state)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_qp_context *context;
+ struct hns_roce_rq_db rq_db;
+ dma_addr_t dma_handle_2 = 0;
+ dma_addr_t dma_handle = 0;
+ uint32_t doorbell[2] = {0};
+ int rq_pa_start = 0;
+ u32 reg_val = 0;
+ u64 *mtts_2 = NULL;
+ int ret = -EINVAL;
+ u64 *mtts = NULL;
+ int port;
+ u8 *dmac;
+ u8 *smac;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return -ENOMEM;
+
+ /* Search qp buf's mtts */
+ mtts = hns_roce_table_find(&hr_dev->mr_table.mtt_table,
+ hr_qp->mtt.first_seg, &dma_handle);
+ if (mtts == NULL) {
+ dev_err(dev, "qp buf pa find failed\n");
+ goto out;
+ }
+
+ /* Search IRRL's mtts */
+ mtts_2 = hns_roce_table_find(&hr_dev->qp_table.irrl_table, hr_qp->qpn,
+ &dma_handle_2);
+ if (mtts_2 == NULL) {
+ dev_err(dev, "qp irrl_table find failed\n");
+ goto out;
+ }
+
+ /*
+ *Reset to init
+ * Mandatory param:
+ * IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS
+ * Optional param: NA
+ */
+ if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_M,
+ QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_S,
+ to_hr_qp_type(hr_qp->ibqp.qp_type));
+
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_ENABLE_FPMR_S, 0);
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_READ_ENABLE_S,
+ !!(attr->qp_access_flags & IB_ACCESS_REMOTE_READ));
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_WRITE_ENABLE_S,
+ !!(attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
+ );
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_ATOMIC_OPERATION_ENABLE_S,
+ !!(attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)
+ );
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMAR_USE_S, 1);
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_M,
+ QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_S,
+ ilog2((unsigned int)hr_qp->sq.wqe_cnt));
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_M,
+ QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_S,
+ ilog2((unsigned int)hr_qp->rq.wqe_cnt));
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_PD_M,
+ QP_CONTEXT_QPC_BYTES_4_PD_S,
+ to_hr_pd(ibqp->pd)->pdn);
+ hr_qp->access_flags = attr->qp_access_flags;
+ roce_set_field(context->qpc_bytes_8,
+ QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_M,
+ QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_S,
+ to_hr_cq(ibqp->send_cq)->cqn);
+ roce_set_field(context->qpc_bytes_8,
+ QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_M,
+ QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_S,
+ to_hr_cq(ibqp->recv_cq)->cqn);
+
+ if (ibqp->srq)
+ roce_set_field(context->qpc_bytes_12,
+ QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_M,
+ QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_S,
+ to_hr_srq(ibqp->srq)->srqn);
+
+ roce_set_field(context->qpc_bytes_12,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S,
+ attr->pkey_index);
+ hr_qp->pkey_index = attr->pkey_index;
+ roce_set_field(context->qpc_bytes_16,
+ QP_CONTEXT_QPC_BYTES_16_QP_NUM_M,
+ QP_CONTEXT_QPC_BYTES_16_QP_NUM_S, hr_qp->qpn);
+
+ } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) {
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_M,
+ QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_S,
+ to_hr_qp_type(hr_qp->ibqp.qp_type));
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_ENABLE_FPMR_S, 0);
+ if (attr_mask & IB_QP_ACCESS_FLAGS) {
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_READ_ENABLE_S,
+ !!(attr->qp_access_flags &
+ IB_ACCESS_REMOTE_READ));
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_WRITE_ENABLE_S,
+ !!(attr->qp_access_flags &
+ IB_ACCESS_REMOTE_WRITE));
+ } else {
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_READ_ENABLE_S,
+ !!(hr_qp->access_flags &
+ IB_ACCESS_REMOTE_READ));
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_WRITE_ENABLE_S,
+ !!(hr_qp->access_flags &
+ IB_ACCESS_REMOTE_WRITE));
+ }
+
+ roce_set_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMAR_USE_S, 1);
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_M,
+ QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_S,
+ ilog2((unsigned int)hr_qp->sq.wqe_cnt));
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_M,
+ QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_S,
+ ilog2((unsigned int)hr_qp->rq.wqe_cnt));
+ roce_set_field(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTES_4_PD_M,
+ QP_CONTEXT_QPC_BYTES_4_PD_S,
+ to_hr_pd(ibqp->pd)->pdn);
+
+ roce_set_field(context->qpc_bytes_8,
+ QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_M,
+ QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_S,
+ to_hr_cq(ibqp->send_cq)->cqn);
+ roce_set_field(context->qpc_bytes_8,
+ QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_M,
+ QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_S,
+ to_hr_cq(ibqp->recv_cq)->cqn);
+
+ if (ibqp->srq)
+ roce_set_field(context->qpc_bytes_12,
+ QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_M,
+ QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_S,
+ to_hr_srq(ibqp->srq)->srqn);
+ if (attr_mask & IB_QP_PKEY_INDEX)
+ roce_set_field(context->qpc_bytes_12,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S,
+ attr->pkey_index);
+ else
+ roce_set_field(context->qpc_bytes_12,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S,
+ hr_qp->pkey_index);
+
+ roce_set_field(context->qpc_bytes_16,
+ QP_CONTEXT_QPC_BYTES_16_QP_NUM_M,
+ QP_CONTEXT_QPC_BYTES_16_QP_NUM_S, hr_qp->qpn);
+ } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
+ if ((attr_mask & IB_QP_ALT_PATH) ||
+ (attr_mask & IB_QP_ACCESS_FLAGS) ||
+ (attr_mask & IB_QP_PKEY_INDEX) ||
+ (attr_mask & IB_QP_QKEY)) {
+ dev_err(dev, "INIT2RTR attr_mask error\n");
+ goto out;
+ }
+
+ dmac = (u8 *)attr->ah_attr.dmac;
+
+ context->sq_rq_bt_l = (u32)(dma_handle);
+ roce_set_field(context->qpc_bytes_24,
+ QP_CONTEXT_QPC_BYTES_24_SQ_RQ_BT_H_M,
+ QP_CONTEXT_QPC_BYTES_24_SQ_RQ_BT_H_S,
+ ((u32)(dma_handle >> 32)));
+ roce_set_bit(context->qpc_bytes_24,
+ QP_CONTEXT_QPC_BYTE_24_REMOTE_ENABLE_E2E_CREDITS_S,
+ 1);
+ roce_set_field(context->qpc_bytes_24,
+ QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_M,
+ QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_S,
+ attr->min_rnr_timer);
+ context->irrl_ba_l = (u32)(dma_handle_2);
+ roce_set_field(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTES_32_IRRL_BA_H_M,
+ QP_CONTEXT_QPC_BYTES_32_IRRL_BA_H_S,
+ ((u32)(dma_handle_2 >> 32)) &
+ QP_CONTEXT_QPC_BYTES_32_IRRL_BA_H_M);
+ roce_set_field(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTES_32_MIG_STATE_M,
+ QP_CONTEXT_QPC_BYTES_32_MIG_STATE_S, 0);
+ roce_set_bit(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTE_32_LOCAL_ENABLE_E2E_CREDITS_S,
+ 1);
+ roce_set_bit(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTE_32_SIGNALING_TYPE_S,
+ hr_qp->sq_signal_bits);
+
+ for (port = 0; port < hr_dev->caps.num_ports; port++) {
+ smac = (u8 *)hr_dev->dev_addr[port];
+ dev_dbg(dev, "smac: %2x: %2x: %2x: %2x: %2x: %2x\n",
+ smac[0], smac[1], smac[2], smac[3], smac[4],
+ smac[5]);
+ if ((dmac[0] == smac[0]) && (dmac[1] == smac[1]) &&
+ (dmac[2] == smac[2]) && (dmac[3] == smac[3]) &&
+ (dmac[4] == smac[4]) && (dmac[5] == smac[5])) {
+ roce_set_bit(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTE_32_LOOPBACK_INDICATOR_S,
+ 1);
+ break;
+ }
+ }
+
+ if (hr_dev->loop_idc == 0x1)
+ roce_set_bit(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTE_32_LOOPBACK_INDICATOR_S, 1);
+
+ roce_set_bit(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTE_32_GLOBAL_HEADER_S,
+ attr->ah_attr.ah_flags);
+ roce_set_field(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_M,
+ QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_S,
+ ilog2((unsigned int)attr->max_dest_rd_atomic));
+
+ roce_set_field(context->qpc_bytes_36,
+ QP_CONTEXT_QPC_BYTES_36_DEST_QP_M,
+ QP_CONTEXT_QPC_BYTES_36_DEST_QP_S,
+ attr->dest_qp_num);
+
+ /* Configure GID index */
+ roce_set_field(context->qpc_bytes_36,
+ QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_S,
+ hns_get_gid_index(hr_dev,
+ attr->ah_attr.port_num - 1,
+ attr->ah_attr.grh.sgid_index));
+
+ memcpy(&(context->dmac_l), dmac, 4);
+
+ roce_set_field(context->qpc_bytes_44,
+ QP_CONTEXT_QPC_BYTES_44_DMAC_H_M,
+ QP_CONTEXT_QPC_BYTES_44_DMAC_H_S,
+ *((u16 *)(&dmac[4])));
+ roce_set_field(context->qpc_bytes_44,
+ QP_CONTEXT_QPC_BYTES_44_MAXIMUM_STATIC_RATE_M,
+ QP_CONTEXT_QPC_BYTES_44_MAXIMUM_STATIC_RATE_S,
+ attr->ah_attr.static_rate);
+ roce_set_field(context->qpc_bytes_44,
+ QP_CONTEXT_QPC_BYTES_44_HOPLMT_M,
+ QP_CONTEXT_QPC_BYTES_44_HOPLMT_S,
+ attr->ah_attr.grh.hop_limit);
+
+ roce_set_field(context->qpc_bytes_48,
+ QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_M,
+ QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_S,
+ attr->ah_attr.grh.flow_label);
+ roce_set_field(context->qpc_bytes_48,
+ QP_CONTEXT_QPC_BYTES_48_TCLASS_M,
+ QP_CONTEXT_QPC_BYTES_48_TCLASS_S,
+ attr->ah_attr.grh.traffic_class);
+ roce_set_field(context->qpc_bytes_48,
+ QP_CONTEXT_QPC_BYTES_48_MTU_M,
+ QP_CONTEXT_QPC_BYTES_48_MTU_S, attr->path_mtu);
+
+ memcpy(context->dgid, attr->ah_attr.grh.dgid.raw,
+ sizeof(attr->ah_attr.grh.dgid.raw));
+
+ dev_dbg(dev, "dmac:%x :%lx\n", context->dmac_l,
+ roce_get_field(context->qpc_bytes_44,
+ QP_CONTEXT_QPC_BYTES_44_DMAC_H_M,
+ QP_CONTEXT_QPC_BYTES_44_DMAC_H_S));
+
+ roce_set_field(context->qpc_bytes_68,
+ QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_M,
+ QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_S, 0);
+ roce_set_field(context->qpc_bytes_68,
+ QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_S, 0);
+
+ rq_pa_start = (u32)hr_qp->rq.offset / PAGE_SIZE;
+ context->cur_rq_wqe_ba_l = (u32)(mtts[rq_pa_start]);
+
+ roce_set_field(context->qpc_bytes_76,
+ QP_CONTEXT_QPC_BYTES_76_CUR_RQ_WQE_BA_H_M,
+ QP_CONTEXT_QPC_BYTES_76_CUR_RQ_WQE_BA_H_S,
+ mtts[rq_pa_start] >> 32);
+ roce_set_field(context->qpc_bytes_76,
+ QP_CONTEXT_QPC_BYTES_76_RX_REQ_MSN_M,
+ QP_CONTEXT_QPC_BYTES_76_RX_REQ_MSN_S, 0);
+
+ context->rx_rnr_time = 0;
+
+ roce_set_field(context->qpc_bytes_84,
+ QP_CONTEXT_QPC_BYTES_84_LAST_ACK_PSN_M,
+ QP_CONTEXT_QPC_BYTES_84_LAST_ACK_PSN_S,
+ attr->rq_psn - 1);
+ roce_set_field(context->qpc_bytes_84,
+ QP_CONTEXT_QPC_BYTES_84_TRRL_HEAD_M,
+ QP_CONTEXT_QPC_BYTES_84_TRRL_HEAD_S, 0);
+
+ roce_set_field(context->qpc_bytes_88,
+ QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_M,
+ QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_S,
+ attr->rq_psn);
+ roce_set_bit(context->qpc_bytes_88,
+ QP_CONTEXT_QPC_BYTES_88_RX_REQ_PSN_ERR_FLAG_S, 0);
+ roce_set_bit(context->qpc_bytes_88,
+ QP_CONTEXT_QPC_BYTES_88_RX_LAST_OPCODE_FLG_S, 0);
+ roce_set_field(context->qpc_bytes_88,
+ QP_CONTEXT_QPC_BYTES_88_RQ_REQ_LAST_OPERATION_TYPE_M,
+ QP_CONTEXT_QPC_BYTES_88_RQ_REQ_LAST_OPERATION_TYPE_S,
+ 0);
+ roce_set_field(context->qpc_bytes_88,
+ QP_CONTEXT_QPC_BYTES_88_RQ_REQ_RDMA_WR_FLAG_M,
+ QP_CONTEXT_QPC_BYTES_88_RQ_REQ_RDMA_WR_FLAG_S,
+ 0);
+
+ context->dma_length = 0;
+ context->r_key = 0;
+ context->va_l = 0;
+ context->va_h = 0;
+
+ roce_set_field(context->qpc_bytes_108,
+ QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_M,
+ QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_S, 0);
+ roce_set_bit(context->qpc_bytes_108,
+ QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_FLG_S, 0);
+ roce_set_bit(context->qpc_bytes_108,
+ QP_CONTEXT_QPC_BYTES_108_TRRL_TDB_PSN_FLG_S, 0);
+
+ roce_set_field(context->qpc_bytes_112,
+ QP_CONTEXT_QPC_BYTES_112_TRRL_TDB_PSN_M,
+ QP_CONTEXT_QPC_BYTES_112_TRRL_TDB_PSN_S, 0);
+ roce_set_field(context->qpc_bytes_112,
+ QP_CONTEXT_QPC_BYTES_112_TRRL_TAIL_M,
+ QP_CONTEXT_QPC_BYTES_112_TRRL_TAIL_S, 0);
+
+ /* For chip resp ack */
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M,
+ QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S,
+ hr_qp->port);
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_SL_M,
+ QP_CONTEXT_QPC_BYTES_156_SL_S, attr->ah_attr.sl);
+ hr_qp->sl = attr->ah_attr.sl;
+ } else if (cur_state == IB_QPS_RTR &&
+ new_state == IB_QPS_RTS) {
+ /* If exist optional param, return error */
+ if ((attr_mask & IB_QP_ALT_PATH) ||
+ (attr_mask & IB_QP_ACCESS_FLAGS) ||
+ (attr_mask & IB_QP_QKEY) ||
+ (attr_mask & IB_QP_PATH_MIG_STATE) ||
+ (attr_mask & IB_QP_CUR_STATE) ||
+ (attr_mask & IB_QP_MIN_RNR_TIMER)) {
+ dev_err(dev, "RTR2RTS attr_mask error\n");
+ goto out;
+ }
+
+ context->rx_cur_sq_wqe_ba_l = (u32)(mtts[0]);
+
+ roce_set_field(context->qpc_bytes_120,
+ QP_CONTEXT_QPC_BYTES_120_RX_CUR_SQ_WQE_BA_H_M,
+ QP_CONTEXT_QPC_BYTES_120_RX_CUR_SQ_WQE_BA_H_S,
+ (mtts[0]) >> 32);
+
+ roce_set_field(context->qpc_bytes_124,
+ QP_CONTEXT_QPC_BYTES_124_RX_ACK_MSN_M,
+ QP_CONTEXT_QPC_BYTES_124_RX_ACK_MSN_S, 0);
+ roce_set_field(context->qpc_bytes_124,
+ QP_CONTEXT_QPC_BYTES_124_IRRL_MSG_IDX_M,
+ QP_CONTEXT_QPC_BYTES_124_IRRL_MSG_IDX_S, 0);
+
+ roce_set_field(context->qpc_bytes_128,
+ QP_CONTEXT_QPC_BYTES_128_RX_ACK_EPSN_M,
+ QP_CONTEXT_QPC_BYTES_128_RX_ACK_EPSN_S,
+ attr->sq_psn);
+ roce_set_bit(context->qpc_bytes_128,
+ QP_CONTEXT_QPC_BYTES_128_RX_ACK_PSN_ERR_FLG_S, 0);
+ roce_set_field(context->qpc_bytes_128,
+ QP_CONTEXT_QPC_BYTES_128_ACK_LAST_OPERATION_TYPE_M,
+ QP_CONTEXT_QPC_BYTES_128_ACK_LAST_OPERATION_TYPE_S,
+ 0);
+ roce_set_bit(context->qpc_bytes_128,
+ QP_CONTEXT_QPC_BYTES_128_IRRL_PSN_VLD_FLG_S, 0);
+
+ roce_set_field(context->qpc_bytes_132,
+ QP_CONTEXT_QPC_BYTES_132_IRRL_PSN_M,
+ QP_CONTEXT_QPC_BYTES_132_IRRL_PSN_S, 0);
+ roce_set_field(context->qpc_bytes_132,
+ QP_CONTEXT_QPC_BYTES_132_IRRL_TAIL_M,
+ QP_CONTEXT_QPC_BYTES_132_IRRL_TAIL_S, 0);
+
+ roce_set_field(context->qpc_bytes_136,
+ QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_PSN_M,
+ QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_PSN_S,
+ attr->sq_psn);
+ roce_set_field(context->qpc_bytes_136,
+ QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_FPKT_PSN_L_M,
+ QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_FPKT_PSN_L_S,
+ attr->sq_psn);
+
+ roce_set_field(context->qpc_bytes_140,
+ QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_FPKT_PSN_H_M,
+ QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_FPKT_PSN_H_S,
+ (attr->sq_psn >> SQ_PSN_SHIFT));
+ roce_set_field(context->qpc_bytes_140,
+ QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_MSN_M,
+ QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_MSN_S, 0);
+ roce_set_bit(context->qpc_bytes_140,
+ QP_CONTEXT_QPC_BYTES_140_RNR_RETRY_FLG_S, 0);
+
+ roce_set_field(context->qpc_bytes_144,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_M,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_S,
+ attr->qp_state);
+
+ roce_set_field(context->qpc_bytes_148,
+ QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_M,
+ QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_S, 0);
+ roce_set_field(context->qpc_bytes_148,
+ QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_M,
+ QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_S, 0);
+ roce_set_field(context->qpc_bytes_148,
+ QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_M,
+ QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_S, 0);
+ roce_set_field(context->qpc_bytes_148,
+ QP_CONTEXT_QPC_BYTES_148_LSN_M,
+ QP_CONTEXT_QPC_BYTES_148_LSN_S, 0x100);
+
+ context->rnr_retry = 0;
+
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_M,
+ QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_S,
+ attr->retry_cnt);
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_M,
+ QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S,
+ attr->timeout);
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_M,
+ QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_S,
+ attr->rnr_retry);
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M,
+ QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S,
+ hr_qp->port);
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_SL_M,
+ QP_CONTEXT_QPC_BYTES_156_SL_S, attr->ah_attr.sl);
+ hr_qp->sl = attr->ah_attr.sl;
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_M,
+ QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_S,
+ ilog2((unsigned int)attr->max_rd_atomic));
+ roce_set_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_ACK_REQ_IND_M,
+ QP_CONTEXT_QPC_BYTES_156_ACK_REQ_IND_S, 0);
+ context->pkt_use_len = 0;
+
+ roce_set_field(context->qpc_bytes_164,
+ QP_CONTEXT_QPC_BYTES_164_SQ_PSN_M,
+ QP_CONTEXT_QPC_BYTES_164_SQ_PSN_S, attr->sq_psn);
+ roce_set_field(context->qpc_bytes_164,
+ QP_CONTEXT_QPC_BYTES_164_IRRL_HEAD_M,
+ QP_CONTEXT_QPC_BYTES_164_IRRL_HEAD_S, 0);
+
+ roce_set_field(context->qpc_bytes_168,
+ QP_CONTEXT_QPC_BYTES_168_RETRY_SQ_PSN_M,
+ QP_CONTEXT_QPC_BYTES_168_RETRY_SQ_PSN_S,
+ attr->sq_psn);
+ roce_set_field(context->qpc_bytes_168,
+ QP_CONTEXT_QPC_BYTES_168_SGE_USE_FLA_M,
+ QP_CONTEXT_QPC_BYTES_168_SGE_USE_FLA_S, 0);
+ roce_set_field(context->qpc_bytes_168,
+ QP_CONTEXT_QPC_BYTES_168_DB_TYPE_M,
+ QP_CONTEXT_QPC_BYTES_168_DB_TYPE_S, 0);
+ roce_set_bit(context->qpc_bytes_168,
+ QP_CONTEXT_QPC_BYTES_168_MSG_LP_IND_S, 0);
+ roce_set_bit(context->qpc_bytes_168,
+ QP_CONTEXT_QPC_BYTES_168_CSDB_LP_IND_S, 0);
+ roce_set_bit(context->qpc_bytes_168,
+ QP_CONTEXT_QPC_BYTES_168_QP_ERR_FLG_S, 0);
+ context->sge_use_len = 0;
+
+ roce_set_field(context->qpc_bytes_176,
+ QP_CONTEXT_QPC_BYTES_176_DB_CUR_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_176_DB_CUR_INDEX_S, 0);
+ roce_set_field(context->qpc_bytes_176,
+ QP_CONTEXT_QPC_BYTES_176_RETRY_DB_CUR_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_176_RETRY_DB_CUR_INDEX_S,
+ 0);
+ roce_set_field(context->qpc_bytes_180,
+ QP_CONTEXT_QPC_BYTES_180_SQ_CUR_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_180_SQ_CUR_INDEX_S, 0);
+ roce_set_field(context->qpc_bytes_180,
+ QP_CONTEXT_QPC_BYTES_180_SQ_HEAD_M,
+ QP_CONTEXT_QPC_BYTES_180_SQ_HEAD_S, 0);
+
+ context->tx_cur_sq_wqe_ba_l = (u32)(mtts[0]);
+
+ roce_set_field(context->qpc_bytes_188,
+ QP_CONTEXT_QPC_BYTES_188_TX_CUR_SQ_WQE_BA_H_M,
+ QP_CONTEXT_QPC_BYTES_188_TX_CUR_SQ_WQE_BA_H_S,
+ (mtts[0]) >> 32);
+ roce_set_bit(context->qpc_bytes_188,
+ QP_CONTEXT_QPC_BYTES_188_PKT_RETRY_FLG_S, 0);
+ roce_set_field(context->qpc_bytes_188,
+ QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_S,
+ 0);
+ } else if ((cur_state == IB_QPS_INIT && new_state == IB_QPS_RESET) ||
+ (cur_state == IB_QPS_INIT && new_state == IB_QPS_ERR) ||
+ (cur_state == IB_QPS_RTR && new_state == IB_QPS_RESET) ||
+ (cur_state == IB_QPS_RTR && new_state == IB_QPS_ERR) ||
+ (cur_state == IB_QPS_RTS && new_state == IB_QPS_RESET) ||
+ (cur_state == IB_QPS_RTS && new_state == IB_QPS_ERR) ||
+ (cur_state == IB_QPS_ERR && new_state == IB_QPS_RESET) ||
+ (cur_state == IB_QPS_ERR && new_state == IB_QPS_ERR)) {
+ roce_set_field(context->qpc_bytes_144,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_M,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_S,
+ attr->qp_state);
+
+ } else {
+ dev_err(dev, "not support this modify\n");
+ goto out;
+ }
+
+ /* Every status migrate must change state */
+ roce_set_field(context->qpc_bytes_144,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_M,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_S, attr->qp_state);
+
+ /* SW pass context to HW */
+ ret = hns_roce_v1_qp_modify(hr_dev, &hr_qp->mtt,
+ to_hns_roce_state(cur_state),
+ to_hns_roce_state(new_state), context,
+ hr_qp);
+ if (ret) {
+ dev_err(dev, "hns_roce_qp_modify failed\n");
+ goto out;
+ }
+
+ /*
+ * Use rst2init to instead of init2init with drv,
+ * need to hw to flash RQ HEAD by DB again
+ */
+ if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) {
+ /* Memory barrier */
+ wmb();
+ if (hr_qp->ibqp.qp_type == IB_QPT_GSI) {
+ /* SW update GSI rq header */
+ reg_val = roce_read(hr_dev, ROCEE_QP1C_CFG3_0_REG +
+ QP1C_CFGN_OFFSET * hr_qp->port);
+ roce_set_field(reg_val,
+ ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_M,
+ ROCEE_QP1C_CFG3_0_ROCEE_QP1C_RQ_HEAD_S,
+ hr_qp->rq.head);
+ roce_write(hr_dev, ROCEE_QP1C_CFG3_0_REG +
+ QP1C_CFGN_OFFSET * hr_qp->port, reg_val);
+ } else {
+ rq_db.u32_4 = 0;
+ rq_db.u32_8 = 0;
+
+ roce_set_field(rq_db.u32_4, RQ_DOORBELL_U32_4_RQ_HEAD_M,
+ RQ_DOORBELL_U32_4_RQ_HEAD_S,
+ hr_qp->rq.head);
+ roce_set_field(rq_db.u32_8, RQ_DOORBELL_U32_8_QPN_M,
+ RQ_DOORBELL_U32_8_QPN_S, hr_qp->qpn);
+ roce_set_field(rq_db.u32_8, RQ_DOORBELL_U32_8_CMD_M,
+ RQ_DOORBELL_U32_8_CMD_S, 1);
+ roce_set_bit(rq_db.u32_8, RQ_DOORBELL_U32_8_HW_SYNC_S,
+ 1);
+
+ doorbell[0] = rq_db.u32_4;
+ doorbell[1] = rq_db.u32_8;
+
+ hns_roce_write64_k(doorbell, hr_qp->rq.db_reg_l);
+ }
+ }
+
+ hr_qp->state = new_state;
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+ hr_qp->resp_depth = attr->max_dest_rd_atomic;
+ if (attr_mask & IB_QP_PORT)
+ hr_qp->port = (attr->port_num - 1);
+
+ if (new_state == IB_QPS_RESET && !ibqp->uobject) {
+ hns_roce_v1_cq_clean(to_hr_cq(ibqp->recv_cq), hr_qp->qpn,
+ ibqp->srq ? to_hr_srq(ibqp->srq) : NULL);
+ if (ibqp->send_cq != ibqp->recv_cq)
+ hns_roce_v1_cq_clean(to_hr_cq(ibqp->send_cq),
+ hr_qp->qpn, NULL);
+
+ hr_qp->rq.head = 0;
+ hr_qp->rq.tail = 0;
+ hr_qp->sq.head = 0;
+ hr_qp->sq.tail = 0;
+ hr_qp->sq_next_wqe = 0;
+ }
+out:
+ kfree(context);
+ return ret;
+}
+
+int hns_roce_v1_modify_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
+ int attr_mask, enum ib_qp_state cur_state,
+ enum ib_qp_state new_state)
+{
+
+ if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI)
+ return hns_roce_v1_m_sqp(ibqp, attr, attr_mask, cur_state,
+ new_state);
+ else
+ return hns_roce_v1_m_qp(ibqp, attr, attr_mask, cur_state,
+ new_state);
+}
+
+static enum ib_qp_state to_ib_qp_state(enum hns_roce_qp_state state)
+{
+ switch (state) {
+ case HNS_ROCE_QP_STATE_RST:
+ return IB_QPS_RESET;
+ case HNS_ROCE_QP_STATE_INIT:
+ return IB_QPS_INIT;
+ case HNS_ROCE_QP_STATE_RTR:
+ return IB_QPS_RTR;
+ case HNS_ROCE_QP_STATE_RTS:
+ return IB_QPS_RTS;
+ case HNS_ROCE_QP_STATE_SQD:
+ return IB_QPS_SQD;
+ case HNS_ROCE_QP_STATE_ERR:
+ return IB_QPS_ERR;
+ default:
+ return IB_QPS_ERR;
+ }
+}
+
+static int hns_roce_v1_query_qpc(struct hns_roce_dev *hr_dev,
+ struct hns_roce_qp *hr_qp,
+ struct hns_roce_qp_context *hr_context)
+{
+ struct hns_roce_cmd_mailbox *mailbox;
+ int ret;
+
+ mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, hr_qp->qpn, 0,
+ HNS_ROCE_CMD_QUERY_QP,
+ HNS_ROCE_CMD_TIME_CLASS_A);
+ if (!ret)
+ memcpy(hr_context, mailbox->buf, sizeof(*hr_context));
+ else
+ dev_err(&hr_dev->pdev->dev, "QUERY QP cmd process error\n");
+
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+
+ return ret;
+}
+
+int hns_roce_v1_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_qp_context *context;
+ int tmp_qp_state = 0;
+ int ret = 0;
+ int state;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return -ENOMEM;
+
+ memset(qp_attr, 0, sizeof(*qp_attr));
+ memset(qp_init_attr, 0, sizeof(*qp_init_attr));
+
+ mutex_lock(&hr_qp->mutex);
+
+ if (hr_qp->state == IB_QPS_RESET) {
+ qp_attr->qp_state = IB_QPS_RESET;
+ goto done;
+ }
+
+ ret = hns_roce_v1_query_qpc(hr_dev, hr_qp, context);
+ if (ret) {
+ dev_err(dev, "query qpc error\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ state = roce_get_field(context->qpc_bytes_144,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_M,
+ QP_CONTEXT_QPC_BYTES_144_QP_STATE_S);
+ tmp_qp_state = (int)to_ib_qp_state((enum hns_roce_qp_state)state);
+ if (tmp_qp_state == -1) {
+ dev_err(dev, "to_ib_qp_state error\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ hr_qp->state = (u8)tmp_qp_state;
+ qp_attr->qp_state = (enum ib_qp_state)hr_qp->state;
+ qp_attr->path_mtu = (enum ib_mtu)roce_get_field(context->qpc_bytes_48,
+ QP_CONTEXT_QPC_BYTES_48_MTU_M,
+ QP_CONTEXT_QPC_BYTES_48_MTU_S);
+ qp_attr->path_mig_state = IB_MIG_ARMED;
+ if (hr_qp->ibqp.qp_type == IB_QPT_UD)
+ qp_attr->qkey = QKEY_VAL;
+
+ qp_attr->rq_psn = roce_get_field(context->qpc_bytes_88,
+ QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_M,
+ QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_S);
+ qp_attr->sq_psn = (u32)roce_get_field(context->qpc_bytes_164,
+ QP_CONTEXT_QPC_BYTES_164_SQ_PSN_M,
+ QP_CONTEXT_QPC_BYTES_164_SQ_PSN_S);
+ qp_attr->dest_qp_num = (u8)roce_get_field(context->qpc_bytes_36,
+ QP_CONTEXT_QPC_BYTES_36_DEST_QP_M,
+ QP_CONTEXT_QPC_BYTES_36_DEST_QP_S);
+ qp_attr->qp_access_flags = ((roce_get_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_READ_ENABLE_S)) << 2) |
+ ((roce_get_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_RDMA_WRITE_ENABLE_S)) << 1) |
+ ((roce_get_bit(context->qpc_bytes_4,
+ QP_CONTEXT_QPC_BYTE_4_ATOMIC_OPERATION_ENABLE_S)) << 3);
+
+ if (hr_qp->ibqp.qp_type == IB_QPT_RC ||
+ hr_qp->ibqp.qp_type == IB_QPT_UC) {
+ qp_attr->ah_attr.sl = roce_get_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_SL_M,
+ QP_CONTEXT_QPC_BYTES_156_SL_S);
+ qp_attr->ah_attr.grh.flow_label = roce_get_field(
+ context->qpc_bytes_48,
+ QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_M,
+ QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_S);
+ qp_attr->ah_attr.grh.sgid_index = roce_get_field(
+ context->qpc_bytes_36,
+ QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_S);
+ qp_attr->ah_attr.grh.hop_limit = roce_get_field(
+ context->qpc_bytes_44,
+ QP_CONTEXT_QPC_BYTES_44_HOPLMT_M,
+ QP_CONTEXT_QPC_BYTES_44_HOPLMT_S);
+ qp_attr->ah_attr.grh.traffic_class = roce_get_field(
+ context->qpc_bytes_48,
+ QP_CONTEXT_QPC_BYTES_48_TCLASS_M,
+ QP_CONTEXT_QPC_BYTES_48_TCLASS_S);
+
+ memcpy(qp_attr->ah_attr.grh.dgid.raw, context->dgid,
+ sizeof(qp_attr->ah_attr.grh.dgid.raw));
+ }
+
+ qp_attr->pkey_index = roce_get_field(context->qpc_bytes_12,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_M,
+ QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S);
+ qp_attr->port_num = (u8)roce_get_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M,
+ QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S) + 1;
+ qp_attr->sq_draining = 0;
+ qp_attr->max_rd_atomic = roce_get_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_M,
+ QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_S);
+ qp_attr->max_dest_rd_atomic = roce_get_field(context->qpc_bytes_32,
+ QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_M,
+ QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_S);
+ qp_attr->min_rnr_timer = (u8)(roce_get_field(context->qpc_bytes_24,
+ QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_M,
+ QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_S));
+ qp_attr->timeout = (u8)(roce_get_field(context->qpc_bytes_156,
+ QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_M,
+ QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S));
+ qp_attr->retry_cnt = roce_get_field(context->qpc_bytes_148,
+ QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_M,
+ QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_S);
+ qp_attr->rnr_retry = context->rnr_retry;
+
+done:
+ qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->cap.max_recv_wr = hr_qp->rq.wqe_cnt;
+ qp_attr->cap.max_recv_sge = hr_qp->rq.max_gs;
+
+ if (!ibqp->uobject) {
+ qp_attr->cap.max_send_wr = hr_qp->sq.wqe_cnt;
+ qp_attr->cap.max_send_sge = hr_qp->sq.max_gs;
+ } else {
+ qp_attr->cap.max_send_wr = 0;
+ qp_attr->cap.max_send_sge = 0;
+ }
+
+ qp_init_attr->cap = qp_attr->cap;
+
+out:
+ mutex_unlock(&hr_qp->mutex);
+ kfree(context);
+ return ret;
+}
+
+static void hns_roce_v1_destroy_qp_common(struct hns_roce_dev *hr_dev,
+ struct hns_roce_qp *hr_qp,
+ int is_user)
+{
+ u32 sdbinvcnt;
+ unsigned long end = 0;
+ u32 sdbinvcnt_val;
+ u32 sdbsendptr_val;
+ u32 sdbisusepr_val;
+ struct hns_roce_cq *send_cq, *recv_cq;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ if (hr_qp->ibqp.qp_type == IB_QPT_RC) {
+ if (hr_qp->state != IB_QPS_RESET) {
+ /*
+ * Set qp to ERR,
+ * waiting for hw complete processing all dbs
+ */
+ if (hns_roce_v1_qp_modify(hr_dev, NULL,
+ to_hns_roce_state(
+ (enum ib_qp_state)hr_qp->state),
+ HNS_ROCE_QP_STATE_ERR, NULL,
+ hr_qp))
+ dev_err(dev, "modify QP %06lx to ERR failed.\n",
+ hr_qp->qpn);
+
+ /* Record issued doorbell */
+ sdbisusepr_val = roce_read(hr_dev,
+ ROCEE_SDB_ISSUE_PTR_REG);
+ /*
+ * Query db process status,
+ * until hw process completely
+ */
+ end = msecs_to_jiffies(
+ HNS_ROCE_QP_DESTROY_TIMEOUT_MSECS) + jiffies;
+ do {
+ sdbsendptr_val = roce_read(hr_dev,
+ ROCEE_SDB_SEND_PTR_REG);
+ if (!time_before(jiffies, end)) {
+ dev_err(dev, "destroy qp(0x%lx) timeout!!!",
+ hr_qp->qpn);
+ break;
+ }
+ } while ((short)(roce_get_field(sdbsendptr_val,
+ ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M,
+ ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) -
+ roce_get_field(sdbisusepr_val,
+ ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_M,
+ ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_S)
+ ) < 0);
+
+ /* Get list pointer */
+ sdbinvcnt = roce_read(hr_dev, ROCEE_SDB_INV_CNT_REG);
+
+ /* Query db's list status, until hw reversal */
+ do {
+ sdbinvcnt_val = roce_read(hr_dev,
+ ROCEE_SDB_INV_CNT_REG);
+ if (!time_before(jiffies, end)) {
+ dev_err(dev, "destroy qp(0x%lx) timeout!!!",
+ hr_qp->qpn);
+ dev_err(dev, "SdbInvCnt = 0x%x\n",
+ sdbinvcnt_val);
+ break;
+ }
+ } while ((short)(roce_get_field(sdbinvcnt_val,
+ ROCEE_SDB_INV_CNT_SDB_INV_CNT_M,
+ ROCEE_SDB_INV_CNT_SDB_INV_CNT_S) -
+ (sdbinvcnt + SDB_INV_CNT_OFFSET)) < 0);
+
+ /* Modify qp to reset before destroying qp */
+ if (hns_roce_v1_qp_modify(hr_dev, NULL,
+ to_hns_roce_state(
+ (enum ib_qp_state)hr_qp->state),
+ HNS_ROCE_QP_STATE_RST, NULL, hr_qp))
+ dev_err(dev, "modify QP %06lx to RESET failed.\n",
+ hr_qp->qpn);
+ }
+ }
+
+ send_cq = to_hr_cq(hr_qp->ibqp.send_cq);
+ recv_cq = to_hr_cq(hr_qp->ibqp.recv_cq);
+
+ hns_roce_lock_cqs(send_cq, recv_cq);
+
+ if (!is_user) {
+ __hns_roce_v1_cq_clean(recv_cq, hr_qp->qpn, hr_qp->ibqp.srq ?
+ to_hr_srq(hr_qp->ibqp.srq) : NULL);
+ if (send_cq != recv_cq)
+ __hns_roce_v1_cq_clean(send_cq, hr_qp->qpn, NULL);
+ }
+
+ hns_roce_qp_remove(hr_dev, hr_qp);
+
+ hns_roce_unlock_cqs(send_cq, recv_cq);
+
+ hns_roce_qp_free(hr_dev, hr_qp);
+
+ /* Not special_QP, free their QPN */
+ if ((hr_qp->ibqp.qp_type == IB_QPT_RC) ||
+ (hr_qp->ibqp.qp_type == IB_QPT_UC) ||
+ (hr_qp->ibqp.qp_type == IB_QPT_UD))
+ hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1);
+
+ hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
+
+ if (is_user) {
+ ib_umem_release(hr_qp->umem);
+ } else {
+ kfree(hr_qp->sq.wrid);
+ kfree(hr_qp->rq.wrid);
+ hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
+ }
+}
+
+int hns_roce_v1_destroy_qp(struct ib_qp *ibqp)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+
+ hns_roce_v1_destroy_qp_common(hr_dev, hr_qp, !!ibqp->pd->uobject);
+
+ if (hr_qp->ibqp.qp_type == IB_QPT_GSI)
+ kfree(hr_to_hr_sqp(hr_qp));
+ else
+ kfree(hr_qp);
+
+ return 0;
+}
+
+struct hns_roce_v1_priv hr_v1_priv;
+
+struct hns_roce_hw hns_roce_hw_v1 = {
+ .reset = hns_roce_v1_reset,
+ .hw_profile = hns_roce_v1_profile,
+ .hw_init = hns_roce_v1_init,
+ .hw_exit = hns_roce_v1_exit,
+ .set_gid = hns_roce_v1_set_gid,
+ .set_mac = hns_roce_v1_set_mac,
+ .set_mtu = hns_roce_v1_set_mtu,
+ .write_mtpt = hns_roce_v1_write_mtpt,
+ .write_cqc = hns_roce_v1_write_cqc,
+ .modify_qp = hns_roce_v1_modify_qp,
+ .query_qp = hns_roce_v1_query_qp,
+ .destroy_qp = hns_roce_v1_destroy_qp,
+ .post_send = hns_roce_v1_post_send,
+ .post_recv = hns_roce_v1_post_recv,
+ .req_notify_cq = hns_roce_v1_req_notify_cq,
+ .poll_cq = hns_roce_v1_poll_cq,
+ .priv = &hr_v1_priv,
+};
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h
new file mode 100644
index 000000000000..316b592b1636
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h
@@ -0,0 +1,981 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_HW_V1_H
+#define _HNS_ROCE_HW_V1_H
+
+#define CQ_STATE_VALID 2
+
+#define HNS_ROCE_V1_MAX_PD_NUM 0x8000
+#define HNS_ROCE_V1_MAX_CQ_NUM 0x10000
+#define HNS_ROCE_V1_MAX_CQE_NUM 0x8000
+
+#define HNS_ROCE_V1_MAX_QP_NUM 0x40000
+#define HNS_ROCE_V1_MAX_WQE_NUM 0x4000
+
+#define HNS_ROCE_V1_MAX_MTPT_NUM 0x80000
+
+#define HNS_ROCE_V1_MAX_MTT_SEGS 0x100000
+
+#define HNS_ROCE_V1_MAX_QP_INIT_RDMA 128
+#define HNS_ROCE_V1_MAX_QP_DEST_RDMA 128
+
+#define HNS_ROCE_V1_MAX_SQ_DESC_SZ 64
+#define HNS_ROCE_V1_MAX_RQ_DESC_SZ 64
+#define HNS_ROCE_V1_SG_NUM 2
+#define HNS_ROCE_V1_INLINE_SIZE 32
+
+#define HNS_ROCE_V1_UAR_NUM 256
+#define HNS_ROCE_V1_PHY_UAR_NUM 8
+
+#define HNS_ROCE_V1_GID_NUM 16
+
+#define HNS_ROCE_V1_NUM_COMP_EQE 0x8000
+#define HNS_ROCE_V1_NUM_ASYNC_EQE 0x400
+
+#define HNS_ROCE_V1_QPC_ENTRY_SIZE 256
+#define HNS_ROCE_V1_IRRL_ENTRY_SIZE 8
+#define HNS_ROCE_V1_CQC_ENTRY_SIZE 64
+#define HNS_ROCE_V1_MTPT_ENTRY_SIZE 64
+#define HNS_ROCE_V1_MTT_ENTRY_SIZE 64
+
+#define HNS_ROCE_V1_CQE_ENTRY_SIZE 32
+#define HNS_ROCE_V1_PAGE_SIZE_SUPPORT 0xFFFFF000
+
+#define HNS_ROCE_V1_EXT_RAQ_WF 8
+#define HNS_ROCE_V1_RAQ_ENTRY 64
+#define HNS_ROCE_V1_RAQ_DEPTH 32768
+#define HNS_ROCE_V1_RAQ_SIZE (HNS_ROCE_V1_RAQ_ENTRY * HNS_ROCE_V1_RAQ_DEPTH)
+
+#define HNS_ROCE_V1_SDB_DEPTH 0x400
+#define HNS_ROCE_V1_ODB_DEPTH 0x400
+
+#define HNS_ROCE_V1_DB_RSVD 0x80
+
+#define HNS_ROCE_V1_SDB_ALEPT HNS_ROCE_V1_DB_RSVD
+#define HNS_ROCE_V1_SDB_ALFUL (HNS_ROCE_V1_SDB_DEPTH - HNS_ROCE_V1_DB_RSVD)
+#define HNS_ROCE_V1_ODB_ALEPT HNS_ROCE_V1_DB_RSVD
+#define HNS_ROCE_V1_ODB_ALFUL (HNS_ROCE_V1_ODB_DEPTH - HNS_ROCE_V1_DB_RSVD)
+
+#define HNS_ROCE_V1_EXT_SDB_DEPTH 0x4000
+#define HNS_ROCE_V1_EXT_ODB_DEPTH 0x4000
+#define HNS_ROCE_V1_EXT_SDB_ENTRY 16
+#define HNS_ROCE_V1_EXT_ODB_ENTRY 16
+#define HNS_ROCE_V1_EXT_SDB_SIZE \
+ (HNS_ROCE_V1_EXT_SDB_DEPTH * HNS_ROCE_V1_EXT_SDB_ENTRY)
+#define HNS_ROCE_V1_EXT_ODB_SIZE \
+ (HNS_ROCE_V1_EXT_ODB_DEPTH * HNS_ROCE_V1_EXT_ODB_ENTRY)
+
+#define HNS_ROCE_V1_EXT_SDB_ALEPT HNS_ROCE_V1_DB_RSVD
+#define HNS_ROCE_V1_EXT_SDB_ALFUL \
+ (HNS_ROCE_V1_EXT_SDB_DEPTH - HNS_ROCE_V1_DB_RSVD)
+#define HNS_ROCE_V1_EXT_ODB_ALEPT HNS_ROCE_V1_DB_RSVD
+#define HNS_ROCE_V1_EXT_ODB_ALFUL \
+ (HNS_ROCE_V1_EXT_ODB_DEPTH - HNS_ROCE_V1_DB_RSVD)
+
+#define HNS_ROCE_ODB_POLL_MODE 0
+
+#define HNS_ROCE_SDB_NORMAL_MODE 0
+#define HNS_ROCE_SDB_EXTEND_MODE 1
+
+#define HNS_ROCE_ODB_EXTEND_MODE 1
+
+#define KEY_VALID 0x02
+
+#define HNS_ROCE_CQE_QPN_MASK 0x3ffff
+#define HNS_ROCE_CQE_STATUS_MASK 0x1f
+#define HNS_ROCE_CQE_OPCODE_MASK 0xf
+
+#define HNS_ROCE_CQE_SUCCESS 0x00
+#define HNS_ROCE_CQE_SYNDROME_LOCAL_LENGTH_ERR 0x01
+#define HNS_ROCE_CQE_SYNDROME_LOCAL_QP_OP_ERR 0x02
+#define HNS_ROCE_CQE_SYNDROME_LOCAL_PROT_ERR 0x03
+#define HNS_ROCE_CQE_SYNDROME_WR_FLUSH_ERR 0x04
+#define HNS_ROCE_CQE_SYNDROME_MEM_MANAGE_OPERATE_ERR 0x05
+#define HNS_ROCE_CQE_SYNDROME_BAD_RESP_ERR 0x06
+#define HNS_ROCE_CQE_SYNDROME_LOCAL_ACCESS_ERR 0x07
+#define HNS_ROCE_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR 0x08
+#define HNS_ROCE_CQE_SYNDROME_REMOTE_ACCESS_ERR 0x09
+#define HNS_ROCE_CQE_SYNDROME_REMOTE_OP_ERR 0x0a
+#define HNS_ROCE_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR 0x0b
+#define HNS_ROCE_CQE_SYNDROME_RNR_RETRY_EXC_ERR 0x0c
+
+#define QP1C_CFGN_OFFSET 0x28
+#define PHY_PORT_OFFSET 0x8
+#define MTPT_IDX_SHIFT 16
+#define ALL_PORT_VAL_OPEN 0x3f
+#define POL_TIME_INTERVAL_VAL 0x80
+#define SLEEP_TIME_INTERVAL 20
+#define SQ_PSN_SHIFT 8
+#define QKEY_VAL 0x80010000
+#define SDB_INV_CNT_OFFSET 8
+
+struct hns_roce_cq_context {
+ u32 cqc_byte_4;
+ u32 cq_bt_l;
+ u32 cqc_byte_12;
+ u32 cur_cqe_ba0_l;
+ u32 cqc_byte_20;
+ u32 cqe_tptr_addr_l;
+ u32 cur_cqe_ba1_l;
+ u32 cqc_byte_32;
+};
+
+#define CQ_CONTEXT_CQC_BYTE_4_CQC_STATE_S 0
+#define CQ_CONTEXT_CQC_BYTE_4_CQC_STATE_M \
+ (((1UL << 2) - 1) << CQ_CONTEXT_CQC_BYTE_4_CQC_STATE_S)
+
+#define CQ_CONTEXT_CQC_BYTE_4_CQN_S 16
+#define CQ_CONTEXT_CQC_BYTE_4_CQN_M \
+ (((1UL << 16) - 1) << CQ_CONTEXT_CQC_BYTE_4_CQN_S)
+
+#define CQ_CONTEXT_CQC_BYTE_12_CQ_BT_H_S 0
+#define CQ_CONTEXT_CQC_BYTE_12_CQ_BT_H_M \
+ (((1UL << 17) - 1) << CQ_CONTEXT_CQC_BYTE_12_CQ_BT_H_S)
+
+#define CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_S 20
+#define CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_M \
+ (((1UL << 4) - 1) << CQ_CONTEXT_CQC_BYTE_12_CQ_CQE_SHIFT_S)
+
+#define CQ_CONTEXT_CQC_BYTE_12_CEQN_S 24
+#define CQ_CONTEXT_CQC_BYTE_12_CEQN_M \
+ (((1UL << 5) - 1) << CQ_CONTEXT_CQC_BYTE_12_CEQN_S)
+
+#define CQ_CONTEXT_CQC_BYTE_20_CUR_CQE_BA0_H_S 0
+#define CQ_CONTEXT_CQC_BYTE_20_CUR_CQE_BA0_H_M \
+ (((1UL << 5) - 1) << CQ_CONTEXT_CQC_BYTE_20_CUR_CQE_BA0_H_S)
+
+#define CQ_CONTEXT_CQC_BYTE_20_CQ_CUR_INDEX_S 16
+#define CQ_CONTEXT_CQC_BYTE_20_CQ_CUR_INDEX_M \
+ (((1UL << 16) - 1) << CQ_CONTEXT_CQC_BYTE_20_CQ_CUR_INDEX_S)
+
+#define CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_S 8
+#define CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_M \
+ (((1UL << 5) - 1) << CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_S)
+
+#define CQ_CONTEXT_CQC_BYTE_32_CUR_CQE_BA1_H_S 0
+#define CQ_CONTEXT_CQC_BYTE_32_CUR_CQE_BA1_H_M \
+ (((1UL << 5) - 1) << CQ_CONTEXT_CQC_BYTE_32_CUR_CQE_BA1_H_S)
+
+#define CQ_CONTEXT_CQC_BYTE_32_SE_FLAG_S 9
+
+#define CQ_CONTEXT_CQC_BYTE_32_CE_FLAG_S 8
+#define CQ_CONTEXT_CQC_BYTE_32_NOTIFICATION_FLAG_S 14
+#define CQ_CQNTEXT_CQC_BYTE_32_TYPE_OF_COMPLETION_NOTIFICATION_S 15
+
+#define CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_S 16
+#define CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_M \
+ (((1UL << 16) - 1) << CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_S)
+
+struct hns_roce_cqe {
+ u32 cqe_byte_4;
+ union {
+ u32 r_key;
+ u32 immediate_data;
+ };
+ u32 byte_cnt;
+ u32 cqe_byte_16;
+ u32 cqe_byte_20;
+ u32 s_mac_l;
+ u32 cqe_byte_28;
+ u32 reserved;
+};
+
+#define CQE_BYTE_4_OWNER_S 7
+#define CQE_BYTE_4_SQ_RQ_FLAG_S 14
+
+#define CQE_BYTE_4_STATUS_OF_THE_OPERATION_S 8
+#define CQE_BYTE_4_STATUS_OF_THE_OPERATION_M \
+ (((1UL << 5) - 1) << CQE_BYTE_4_STATUS_OF_THE_OPERATION_S)
+
+#define CQE_BYTE_4_WQE_INDEX_S 16
+#define CQE_BYTE_4_WQE_INDEX_M (((1UL << 14) - 1) << CQE_BYTE_4_WQE_INDEX_S)
+
+#define CQE_BYTE_4_OPERATION_TYPE_S 0
+#define CQE_BYTE_4_OPERATION_TYPE_M \
+ (((1UL << 4) - 1) << CQE_BYTE_4_OPERATION_TYPE_S)
+
+#define CQE_BYTE_4_IMM_INDICATOR_S 15
+
+#define CQE_BYTE_16_LOCAL_QPN_S 0
+#define CQE_BYTE_16_LOCAL_QPN_M (((1UL << 24) - 1) << CQE_BYTE_16_LOCAL_QPN_S)
+
+#define CQE_BYTE_20_PORT_NUM_S 26
+#define CQE_BYTE_20_PORT_NUM_M (((1UL << 3) - 1) << CQE_BYTE_20_PORT_NUM_S)
+
+#define CQE_BYTE_20_SL_S 24
+#define CQE_BYTE_20_SL_M (((1UL << 2) - 1) << CQE_BYTE_20_SL_S)
+
+#define CQE_BYTE_20_REMOTE_QPN_S 0
+#define CQE_BYTE_20_REMOTE_QPN_M \
+ (((1UL << 24) - 1) << CQE_BYTE_20_REMOTE_QPN_S)
+
+#define CQE_BYTE_20_GRH_PRESENT_S 29
+
+#define CQE_BYTE_28_P_KEY_IDX_S 16
+#define CQE_BYTE_28_P_KEY_IDX_M (((1UL << 16) - 1) << CQE_BYTE_28_P_KEY_IDX_S)
+
+#define CQ_DB_REQ_NOT_SOL 0
+#define CQ_DB_REQ_NOT (1 << 16)
+
+struct hns_roce_v1_mpt_entry {
+ u32 mpt_byte_4;
+ u32 pbl_addr_l;
+ u32 mpt_byte_12;
+ u32 virt_addr_l;
+ u32 virt_addr_h;
+ u32 length;
+ u32 mpt_byte_28;
+ u32 pa0_l;
+ u32 mpt_byte_36;
+ u32 mpt_byte_40;
+ u32 mpt_byte_44;
+ u32 mpt_byte_48;
+ u32 pa4_l;
+ u32 mpt_byte_56;
+ u32 mpt_byte_60;
+ u32 mpt_byte_64;
+};
+
+#define MPT_BYTE_4_KEY_STATE_S 0
+#define MPT_BYTE_4_KEY_STATE_M (((1UL << 2) - 1) << MPT_BYTE_4_KEY_STATE_S)
+
+#define MPT_BYTE_4_KEY_S 8
+#define MPT_BYTE_4_KEY_M (((1UL << 8) - 1) << MPT_BYTE_4_KEY_S)
+
+#define MPT_BYTE_4_PAGE_SIZE_S 16
+#define MPT_BYTE_4_PAGE_SIZE_M (((1UL << 2) - 1) << MPT_BYTE_4_PAGE_SIZE_S)
+
+#define MPT_BYTE_4_MW_TYPE_S 20
+
+#define MPT_BYTE_4_MW_BIND_ENABLE_S 21
+
+#define MPT_BYTE_4_OWN_S 22
+
+#define MPT_BYTE_4_MEMORY_LOCATION_TYPE_S 24
+#define MPT_BYTE_4_MEMORY_LOCATION_TYPE_M \
+ (((1UL << 2) - 1) << MPT_BYTE_4_MEMORY_LOCATION_TYPE_S)
+
+#define MPT_BYTE_4_REMOTE_ATOMIC_S 26
+#define MPT_BYTE_4_LOCAL_WRITE_S 27
+#define MPT_BYTE_4_REMOTE_WRITE_S 28
+#define MPT_BYTE_4_REMOTE_READ_S 29
+#define MPT_BYTE_4_REMOTE_INVAL_ENABLE_S 30
+#define MPT_BYTE_4_ADDRESS_TYPE_S 31
+
+#define MPT_BYTE_12_PBL_ADDR_H_S 0
+#define MPT_BYTE_12_PBL_ADDR_H_M \
+ (((1UL << 17) - 1) << MPT_BYTE_12_PBL_ADDR_H_S)
+
+#define MPT_BYTE_12_MW_BIND_COUNTER_S 17
+#define MPT_BYTE_12_MW_BIND_COUNTER_M \
+ (((1UL << 15) - 1) << MPT_BYTE_12_MW_BIND_COUNTER_S)
+
+#define MPT_BYTE_28_PD_S 0
+#define MPT_BYTE_28_PD_M (((1UL << 16) - 1) << MPT_BYTE_28_PD_S)
+
+#define MPT_BYTE_28_L_KEY_IDX_L_S 16
+#define MPT_BYTE_28_L_KEY_IDX_L_M \
+ (((1UL << 16) - 1) << MPT_BYTE_28_L_KEY_IDX_L_S)
+
+#define MPT_BYTE_36_PA0_H_S 0
+#define MPT_BYTE_36_PA0_H_M (((1UL << 5) - 1) << MPT_BYTE_36_PA0_H_S)
+
+#define MPT_BYTE_36_PA1_L_S 8
+#define MPT_BYTE_36_PA1_L_M (((1UL << 24) - 1) << MPT_BYTE_36_PA1_L_S)
+
+#define MPT_BYTE_40_PA1_H_S 0
+#define MPT_BYTE_40_PA1_H_M (((1UL << 13) - 1) << MPT_BYTE_40_PA1_H_S)
+
+#define MPT_BYTE_40_PA2_L_S 16
+#define MPT_BYTE_40_PA2_L_M (((1UL << 16) - 1) << MPT_BYTE_40_PA2_L_S)
+
+#define MPT_BYTE_44_PA2_H_S 0
+#define MPT_BYTE_44_PA2_H_M (((1UL << 21) - 1) << MPT_BYTE_44_PA2_H_S)
+
+#define MPT_BYTE_44_PA3_L_S 24
+#define MPT_BYTE_44_PA3_L_M (((1UL << 8) - 1) << MPT_BYTE_44_PA3_L_S)
+
+#define MPT_BYTE_48_PA3_H_S 0
+#define MPT_BYTE_48_PA3_H_M (((1UL << 29) - 1) << MPT_BYTE_48_PA3_H_S)
+
+#define MPT_BYTE_56_PA4_H_S 0
+#define MPT_BYTE_56_PA4_H_M (((1UL << 5) - 1) << MPT_BYTE_56_PA4_H_S)
+
+#define MPT_BYTE_56_PA5_L_S 8
+#define MPT_BYTE_56_PA5_L_M (((1UL << 24) - 1) << MPT_BYTE_56_PA5_L_S)
+
+#define MPT_BYTE_60_PA5_H_S 0
+#define MPT_BYTE_60_PA5_H_M (((1UL << 13) - 1) << MPT_BYTE_60_PA5_H_S)
+
+#define MPT_BYTE_60_PA6_L_S 16
+#define MPT_BYTE_60_PA6_L_M (((1UL << 16) - 1) << MPT_BYTE_60_PA6_L_S)
+
+#define MPT_BYTE_64_PA6_H_S 0
+#define MPT_BYTE_64_PA6_H_M (((1UL << 21) - 1) << MPT_BYTE_64_PA6_H_S)
+
+#define MPT_BYTE_64_L_KEY_IDX_H_S 24
+#define MPT_BYTE_64_L_KEY_IDX_H_M \
+ (((1UL << 8) - 1) << MPT_BYTE_64_L_KEY_IDX_H_S)
+
+struct hns_roce_wqe_ctrl_seg {
+ __be32 sgl_pa_h;
+ __be32 flag;
+ __be32 imm_data;
+ __be32 msg_length;
+};
+
+struct hns_roce_wqe_data_seg {
+ __be64 addr;
+ __be32 lkey;
+ __be32 len;
+};
+
+struct hns_roce_wqe_raddr_seg {
+ __be32 rkey;
+ __be32 len;/* reserved */
+ __be64 raddr;
+};
+
+struct hns_roce_rq_wqe_ctrl {
+
+ u32 rwqe_byte_4;
+ u32 rocee_sgl_ba_l;
+ u32 rwqe_byte_12;
+ u32 reserved[5];
+};
+
+#define RQ_WQE_CTRL_RWQE_BYTE_12_RWQE_SGE_NUM_S 16
+#define RQ_WQE_CTRL_RWQE_BYTE_12_RWQE_SGE_NUM_M \
+ (((1UL << 6) - 1) << RQ_WQE_CTRL_RWQE_BYTE_12_RWQE_SGE_NUM_S)
+
+#define HNS_ROCE_QP_DESTROY_TIMEOUT_MSECS 10000
+
+#define GID_LEN 16
+
+struct hns_roce_ud_send_wqe {
+ u32 dmac_h;
+ u32 u32_8;
+ u32 immediate_data;
+
+ u32 u32_16;
+ union {
+ unsigned char dgid[GID_LEN];
+ struct {
+ u32 u32_20;
+ u32 u32_24;
+ u32 u32_28;
+ u32 u32_32;
+ };
+ };
+
+ u32 u32_36;
+ u32 u32_40;
+
+ u32 va0_l;
+ u32 va0_h;
+ u32 l_key0;
+
+ u32 va1_l;
+ u32 va1_h;
+ u32 l_key1;
+};
+
+#define UD_SEND_WQE_U32_4_DMAC_0_S 0
+#define UD_SEND_WQE_U32_4_DMAC_0_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_4_DMAC_0_S)
+
+#define UD_SEND_WQE_U32_4_DMAC_1_S 8
+#define UD_SEND_WQE_U32_4_DMAC_1_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_4_DMAC_1_S)
+
+#define UD_SEND_WQE_U32_4_DMAC_2_S 16
+#define UD_SEND_WQE_U32_4_DMAC_2_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_4_DMAC_2_S)
+
+#define UD_SEND_WQE_U32_4_DMAC_3_S 24
+#define UD_SEND_WQE_U32_4_DMAC_3_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_4_DMAC_3_S)
+
+#define UD_SEND_WQE_U32_8_DMAC_4_S 0
+#define UD_SEND_WQE_U32_8_DMAC_4_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_8_DMAC_4_S)
+
+#define UD_SEND_WQE_U32_8_DMAC_5_S 8
+#define UD_SEND_WQE_U32_8_DMAC_5_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_8_DMAC_5_S)
+
+#define UD_SEND_WQE_U32_8_OPERATION_TYPE_S 16
+#define UD_SEND_WQE_U32_8_OPERATION_TYPE_M \
+ (((1UL << 4) - 1) << UD_SEND_WQE_U32_8_OPERATION_TYPE_S)
+
+#define UD_SEND_WQE_U32_8_NUMBER_OF_DATA_SEG_S 24
+#define UD_SEND_WQE_U32_8_NUMBER_OF_DATA_SEG_M \
+ (((1UL << 6) - 1) << UD_SEND_WQE_U32_8_NUMBER_OF_DATA_SEG_S)
+
+#define UD_SEND_WQE_U32_8_SEND_GL_ROUTING_HDR_FLAG_S 31
+
+#define UD_SEND_WQE_U32_16_DEST_QP_S 0
+#define UD_SEND_WQE_U32_16_DEST_QP_M \
+ (((1UL << 24) - 1) << UD_SEND_WQE_U32_16_DEST_QP_S)
+
+#define UD_SEND_WQE_U32_16_MAX_STATIC_RATE_S 24
+#define UD_SEND_WQE_U32_16_MAX_STATIC_RATE_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_16_MAX_STATIC_RATE_S)
+
+#define UD_SEND_WQE_U32_36_FLOW_LABEL_S 0
+#define UD_SEND_WQE_U32_36_FLOW_LABEL_M \
+ (((1UL << 20) - 1) << UD_SEND_WQE_U32_36_FLOW_LABEL_S)
+
+#define UD_SEND_WQE_U32_36_PRIORITY_S 20
+#define UD_SEND_WQE_U32_36_PRIORITY_M \
+ (((1UL << 4) - 1) << UD_SEND_WQE_U32_36_PRIORITY_S)
+
+#define UD_SEND_WQE_U32_36_SGID_INDEX_S 24
+#define UD_SEND_WQE_U32_36_SGID_INDEX_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_36_SGID_INDEX_S)
+
+#define UD_SEND_WQE_U32_40_HOP_LIMIT_S 0
+#define UD_SEND_WQE_U32_40_HOP_LIMIT_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_40_HOP_LIMIT_S)
+
+#define UD_SEND_WQE_U32_40_TRAFFIC_CLASS_S 8
+#define UD_SEND_WQE_U32_40_TRAFFIC_CLASS_M \
+ (((1UL << 8) - 1) << UD_SEND_WQE_U32_40_TRAFFIC_CLASS_S)
+
+struct hns_roce_sqp_context {
+ u32 qp1c_bytes_4;
+ u32 sq_rq_bt_l;
+ u32 qp1c_bytes_12;
+ u32 qp1c_bytes_16;
+ u32 qp1c_bytes_20;
+ u32 qp1c_bytes_28;
+ u32 cur_rq_wqe_ba_l;
+ u32 qp1c_bytes_32;
+ u32 cur_sq_wqe_ba_l;
+ u32 qp1c_bytes_40;
+};
+
+#define QP1C_BYTES_4_SQ_WQE_SHIFT_S 8
+#define QP1C_BYTES_4_SQ_WQE_SHIFT_M \
+ (((1UL << 4) - 1) << QP1C_BYTES_4_SQ_WQE_SHIFT_S)
+
+#define QP1C_BYTES_4_RQ_WQE_SHIFT_S 12
+#define QP1C_BYTES_4_RQ_WQE_SHIFT_M \
+ (((1UL << 4) - 1) << QP1C_BYTES_4_RQ_WQE_SHIFT_S)
+
+#define QP1C_BYTES_4_PD_S 16
+#define QP1C_BYTES_4_PD_M (((1UL << 16) - 1) << QP1C_BYTES_4_PD_S)
+
+#define QP1C_BYTES_12_SQ_RQ_BT_H_S 0
+#define QP1C_BYTES_12_SQ_RQ_BT_H_M \
+ (((1UL << 17) - 1) << QP1C_BYTES_12_SQ_RQ_BT_H_S)
+
+#define QP1C_BYTES_16_RQ_HEAD_S 0
+#define QP1C_BYTES_16_RQ_HEAD_M (((1UL << 15) - 1) << QP1C_BYTES_16_RQ_HEAD_S)
+
+#define QP1C_BYTES_16_PORT_NUM_S 16
+#define QP1C_BYTES_16_PORT_NUM_M \
+ (((1UL << 3) - 1) << QP1C_BYTES_16_PORT_NUM_S)
+
+#define QP1C_BYTES_16_SIGNALING_TYPE_S 27
+#define QP1C_BYTES_16_LOCAL_ENABLE_E2E_CREDIT_S 28
+#define QP1C_BYTES_16_RQ_BA_FLG_S 29
+#define QP1C_BYTES_16_SQ_BA_FLG_S 30
+#define QP1C_BYTES_16_QP1_ERR_S 31
+
+#define QP1C_BYTES_20_SQ_HEAD_S 0
+#define QP1C_BYTES_20_SQ_HEAD_M (((1UL << 15) - 1) << QP1C_BYTES_20_SQ_HEAD_S)
+
+#define QP1C_BYTES_20_PKEY_IDX_S 16
+#define QP1C_BYTES_20_PKEY_IDX_M \
+ (((1UL << 16) - 1) << QP1C_BYTES_20_PKEY_IDX_S)
+
+#define QP1C_BYTES_28_CUR_RQ_WQE_BA_H_S 0
+#define QP1C_BYTES_28_CUR_RQ_WQE_BA_H_M \
+ (((1UL << 5) - 1) << QP1C_BYTES_28_CUR_RQ_WQE_BA_H_S)
+
+#define QP1C_BYTES_28_RQ_CUR_IDX_S 16
+#define QP1C_BYTES_28_RQ_CUR_IDX_M \
+ (((1UL << 15) - 1) << QP1C_BYTES_28_RQ_CUR_IDX_S)
+
+#define QP1C_BYTES_32_TX_CQ_NUM_S 0
+#define QP1C_BYTES_32_TX_CQ_NUM_M \
+ (((1UL << 16) - 1) << QP1C_BYTES_32_TX_CQ_NUM_S)
+
+#define QP1C_BYTES_32_RX_CQ_NUM_S 16
+#define QP1C_BYTES_32_RX_CQ_NUM_M \
+ (((1UL << 16) - 1) << QP1C_BYTES_32_RX_CQ_NUM_S)
+
+#define QP1C_BYTES_40_CUR_SQ_WQE_BA_H_S 0
+#define QP1C_BYTES_40_CUR_SQ_WQE_BA_H_M \
+ (((1UL << 5) - 1) << QP1C_BYTES_40_CUR_SQ_WQE_BA_H_S)
+
+#define QP1C_BYTES_40_SQ_CUR_IDX_S 16
+#define QP1C_BYTES_40_SQ_CUR_IDX_M \
+ (((1UL << 15) - 1) << QP1C_BYTES_40_SQ_CUR_IDX_S)
+
+#define HNS_ROCE_WQE_INLINE (1UL<<31)
+#define HNS_ROCE_WQE_SE (1UL<<30)
+
+#define HNS_ROCE_WQE_SGE_NUM_BIT 24
+#define HNS_ROCE_WQE_IMM (1UL<<23)
+#define HNS_ROCE_WQE_FENCE (1UL<<21)
+#define HNS_ROCE_WQE_CQ_NOTIFY (1UL<<20)
+
+#define HNS_ROCE_WQE_OPCODE_SEND (0<<16)
+#define HNS_ROCE_WQE_OPCODE_RDMA_READ (1<<16)
+#define HNS_ROCE_WQE_OPCODE_RDMA_WRITE (2<<16)
+#define HNS_ROCE_WQE_OPCODE_LOCAL_INV (4<<16)
+#define HNS_ROCE_WQE_OPCODE_UD_SEND (7<<16)
+#define HNS_ROCE_WQE_OPCODE_MASK (15<<16)
+
+struct hns_roce_qp_context {
+ u32 qpc_bytes_4;
+ u32 qpc_bytes_8;
+ u32 qpc_bytes_12;
+ u32 qpc_bytes_16;
+ u32 sq_rq_bt_l;
+ u32 qpc_bytes_24;
+ u32 irrl_ba_l;
+ u32 qpc_bytes_32;
+ u32 qpc_bytes_36;
+ u32 dmac_l;
+ u32 qpc_bytes_44;
+ u32 qpc_bytes_48;
+ u8 dgid[16];
+ u32 qpc_bytes_68;
+ u32 cur_rq_wqe_ba_l;
+ u32 qpc_bytes_76;
+ u32 rx_rnr_time;
+ u32 qpc_bytes_84;
+ u32 qpc_bytes_88;
+ union {
+ u32 rx_sge_len;
+ u32 dma_length;
+ };
+ union {
+ u32 rx_sge_num;
+ u32 rx_send_pktn;
+ u32 r_key;
+ };
+ u32 va_l;
+ u32 va_h;
+ u32 qpc_bytes_108;
+ u32 qpc_bytes_112;
+ u32 rx_cur_sq_wqe_ba_l;
+ u32 qpc_bytes_120;
+ u32 qpc_bytes_124;
+ u32 qpc_bytes_128;
+ u32 qpc_bytes_132;
+ u32 qpc_bytes_136;
+ u32 qpc_bytes_140;
+ u32 qpc_bytes_144;
+ u32 qpc_bytes_148;
+ union {
+ u32 rnr_retry;
+ u32 ack_time;
+ };
+ u32 qpc_bytes_156;
+ u32 pkt_use_len;
+ u32 qpc_bytes_164;
+ u32 qpc_bytes_168;
+ union {
+ u32 sge_use_len;
+ u32 pa_use_len;
+ };
+ u32 qpc_bytes_176;
+ u32 qpc_bytes_180;
+ u32 tx_cur_sq_wqe_ba_l;
+ u32 qpc_bytes_188;
+ u32 rvd21;
+};
+
+#define QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_S 0
+#define QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_S)
+
+#define QP_CONTEXT_QPC_BYTE_4_ENABLE_FPMR_S 3
+#define QP_CONTEXT_QPC_BYTE_4_RDMA_READ_ENABLE_S 4
+#define QP_CONTEXT_QPC_BYTE_4_RDMA_WRITE_ENABLE_S 5
+#define QP_CONTEXT_QPC_BYTE_4_ATOMIC_OPERATION_ENABLE_S 6
+#define QP_CONTEXT_QPC_BYTE_4_RDMAR_USE_S 7
+
+#define QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_S 8
+#define QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_M \
+ (((1UL << 4) - 1) << QP_CONTEXT_QPC_BYTES_4_SQ_WQE_SHIFT_S)
+
+#define QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_S 12
+#define QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_M \
+ (((1UL << 4) - 1) << QP_CONTEXT_QPC_BYTES_4_RQ_WQE_SHIFT_S)
+
+#define QP_CONTEXT_QPC_BYTES_4_PD_S 16
+#define QP_CONTEXT_QPC_BYTES_4_PD_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_4_PD_S)
+
+#define QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_S 0
+#define QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_8_TX_COMPLETION_S)
+
+#define QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_S 16
+#define QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_8_RX_COMPLETION_S)
+
+#define QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_S 0
+#define QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_12_SRQ_NUMBER_S)
+
+#define QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S 16
+#define QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S)
+
+#define QP_CONTEXT_QPC_BYTES_16_QP_NUM_S 0
+#define QP_CONTEXT_QPC_BYTES_16_QP_NUM_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_16_QP_NUM_S)
+
+#define QP_CONTEXT_QPC_BYTES_24_SQ_RQ_BT_H_S 0
+#define QP_CONTEXT_QPC_BYTES_24_SQ_RQ_BT_H_M \
+ (((1UL << 17) - 1) << QP_CONTEXT_QPC_BYTES_24_SQ_RQ_BT_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_S 18
+#define QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_M \
+ (((1UL << 5) - 1) << QP_CONTEXT_QPC_BYTES_24_MINIMUM_RNR_NAK_TIMER_S)
+
+#define QP_CONTEXT_QPC_BYTE_24_REMOTE_ENABLE_E2E_CREDITS_S 23
+
+#define QP_CONTEXT_QPC_BYTES_32_IRRL_BA_H_S 0
+#define QP_CONTEXT_QPC_BYTES_32_IRRL_BA_H_M \
+ (((1UL << 17) - 1) << QP_CONTEXT_QPC_BYTES_32_IRRL_BA_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_32_MIG_STATE_S 18
+#define QP_CONTEXT_QPC_BYTES_32_MIG_STATE_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_32_MIG_STATE_S)
+
+#define QP_CONTEXT_QPC_BYTE_32_LOCAL_ENABLE_E2E_CREDITS_S 20
+#define QP_CONTEXT_QPC_BYTE_32_SIGNALING_TYPE_S 21
+#define QP_CONTEXT_QPC_BYTE_32_LOOPBACK_INDICATOR_S 22
+#define QP_CONTEXT_QPC_BYTE_32_GLOBAL_HEADER_S 23
+
+#define QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_S 24
+#define QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_32_RESPONDER_RESOURCES_S)
+
+#define QP_CONTEXT_QPC_BYTES_36_DEST_QP_S 0
+#define QP_CONTEXT_QPC_BYTES_36_DEST_QP_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_36_DEST_QP_S)
+
+#define QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_S 24
+#define QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_36_SGID_INDEX_S)
+
+#define QP_CONTEXT_QPC_BYTES_44_DMAC_H_S 0
+#define QP_CONTEXT_QPC_BYTES_44_DMAC_H_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_44_DMAC_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_44_MAXIMUM_STATIC_RATE_S 16
+#define QP_CONTEXT_QPC_BYTES_44_MAXIMUM_STATIC_RATE_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_44_MAXIMUM_STATIC_RATE_S)
+
+#define QP_CONTEXT_QPC_BYTES_44_HOPLMT_S 24
+#define QP_CONTEXT_QPC_BYTES_44_HOPLMT_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_44_HOPLMT_S)
+
+#define QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_S 0
+#define QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_M \
+ (((1UL << 20) - 1) << QP_CONTEXT_QPC_BYTES_48_FLOWLABEL_S)
+
+#define QP_CONTEXT_QPC_BYTES_48_TCLASS_S 20
+#define QP_CONTEXT_QPC_BYTES_48_TCLASS_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_48_TCLASS_S)
+
+#define QP_CONTEXT_QPC_BYTES_48_MTU_S 28
+#define QP_CONTEXT_QPC_BYTES_48_MTU_M \
+ (((1UL << 4) - 1) << QP_CONTEXT_QPC_BYTES_48_MTU_S)
+
+#define QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_S 0
+#define QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_68_RQ_HEAD_S)
+
+#define QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_S 16
+#define QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_68_RQ_CUR_INDEX_S)
+
+#define QP_CONTEXT_QPC_BYTES_76_CUR_RQ_WQE_BA_H_S 0
+#define QP_CONTEXT_QPC_BYTES_76_CUR_RQ_WQE_BA_H_M \
+ (((1UL << 5) - 1) << QP_CONTEXT_QPC_BYTES_76_CUR_RQ_WQE_BA_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_76_RX_REQ_MSN_S 8
+#define QP_CONTEXT_QPC_BYTES_76_RX_REQ_MSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_76_RX_REQ_MSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_84_LAST_ACK_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_84_LAST_ACK_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_84_LAST_ACK_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_84_TRRL_HEAD_S 24
+#define QP_CONTEXT_QPC_BYTES_84_TRRL_HEAD_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_84_TRRL_HEAD_S)
+
+#define QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_S 0
+#define QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_88_RX_REQ_EPSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_88_RX_REQ_PSN_ERR_FLAG_S 24
+#define QP_CONTEXT_QPC_BYTES_88_RX_LAST_OPCODE_FLG_S 25
+
+#define QP_CONTEXT_QPC_BYTES_88_RQ_REQ_LAST_OPERATION_TYPE_S 26
+#define QP_CONTEXT_QPC_BYTES_88_RQ_REQ_LAST_OPERATION_TYPE_M \
+ (((1UL << 2) - 1) << \
+ QP_CONTEXT_QPC_BYTES_88_RQ_REQ_LAST_OPERATION_TYPE_S)
+
+#define QP_CONTEXT_QPC_BYTES_88_RQ_REQ_RDMA_WR_FLAG_S 29
+#define QP_CONTEXT_QPC_BYTES_88_RQ_REQ_RDMA_WR_FLAG_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_88_RQ_REQ_RDMA_WR_FLAG_S)
+
+#define QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_108_TRRL_SDB_PSN_FLG_S 24
+#define QP_CONTEXT_QPC_BYTES_108_TRRL_TDB_PSN_FLG_S 25
+
+#define QP_CONTEXT_QPC_BYTES_112_TRRL_TDB_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_112_TRRL_TDB_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_112_TRRL_TDB_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_112_TRRL_TAIL_S 24
+#define QP_CONTEXT_QPC_BYTES_112_TRRL_TAIL_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_112_TRRL_TAIL_S)
+
+#define QP_CONTEXT_QPC_BYTES_120_RX_CUR_SQ_WQE_BA_H_S 0
+#define QP_CONTEXT_QPC_BYTES_120_RX_CUR_SQ_WQE_BA_H_M \
+ (((1UL << 5) - 1) << QP_CONTEXT_QPC_BYTES_120_RX_CUR_SQ_WQE_BA_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_124_RX_ACK_MSN_S 0
+#define QP_CONTEXT_QPC_BYTES_124_RX_ACK_MSN_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_124_RX_ACK_MSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_124_IRRL_MSG_IDX_S 16
+#define QP_CONTEXT_QPC_BYTES_124_IRRL_MSG_IDX_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_124_IRRL_MSG_IDX_S)
+
+#define QP_CONTEXT_QPC_BYTES_128_RX_ACK_EPSN_S 0
+#define QP_CONTEXT_QPC_BYTES_128_RX_ACK_EPSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_128_RX_ACK_EPSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_128_RX_ACK_PSN_ERR_FLG_S 24
+
+#define QP_CONTEXT_QPC_BYTES_128_ACK_LAST_OPERATION_TYPE_S 25
+#define QP_CONTEXT_QPC_BYTES_128_ACK_LAST_OPERATION_TYPE_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_128_ACK_LAST_OPERATION_TYPE_S)
+
+#define QP_CONTEXT_QPC_BYTES_128_IRRL_PSN_VLD_FLG_S 27
+
+#define QP_CONTEXT_QPC_BYTES_132_IRRL_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_132_IRRL_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_132_IRRL_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_132_IRRL_TAIL_S 24
+#define QP_CONTEXT_QPC_BYTES_132_IRRL_TAIL_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_132_IRRL_TAIL_S)
+
+#define QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_FPKT_PSN_L_S 24
+#define QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_FPKT_PSN_L_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_136_RETRY_MSG_FPKT_PSN_L_S)
+
+#define QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_FPKT_PSN_H_S 0
+#define QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_FPKT_PSN_H_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_FPKT_PSN_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_MSN_S 16
+#define QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_MSN_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_140_RETRY_MSG_MSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_140_RNR_RETRY_FLG_S 31
+
+#define QP_CONTEXT_QPC_BYTES_144_QP_STATE_S 0
+#define QP_CONTEXT_QPC_BYTES_144_QP_STATE_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_144_QP_STATE_S)
+
+#define QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_S 0
+#define QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_148_CHECK_FLAG_S)
+
+#define QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_S 2
+#define QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_148_RETRY_COUNT_S)
+
+#define QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_S 5
+#define QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_148_RNR_RETRY_COUNT_S)
+
+#define QP_CONTEXT_QPC_BYTES_148_LSN_S 8
+#define QP_CONTEXT_QPC_BYTES_148_LSN_M \
+ (((1UL << 16) - 1) << QP_CONTEXT_QPC_BYTES_148_LSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_S 0
+#define QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_156_RETRY_COUNT_INIT_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S 3
+#define QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_M \
+ (((1UL << 5) - 1) << QP_CONTEXT_QPC_BYTES_156_ACK_TIMEOUT_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_S 8
+#define QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_156_RNR_RETRY_COUNT_INIT_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S 11
+#define QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M \
+ (((1UL << 3) - 1) << QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_SL_S 14
+#define QP_CONTEXT_QPC_BYTES_156_SL_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_156_SL_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_S 16
+#define QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_S)
+
+#define QP_CONTEXT_QPC_BYTES_156_ACK_REQ_IND_S 24
+#define QP_CONTEXT_QPC_BYTES_156_ACK_REQ_IND_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_156_ACK_REQ_IND_S)
+
+#define QP_CONTEXT_QPC_BYTES_164_SQ_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_164_SQ_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_164_SQ_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_164_IRRL_HEAD_S 24
+#define QP_CONTEXT_QPC_BYTES_164_IRRL_HEAD_M \
+ (((1UL << 8) - 1) << QP_CONTEXT_QPC_BYTES_164_IRRL_HEAD_S)
+
+#define QP_CONTEXT_QPC_BYTES_168_RETRY_SQ_PSN_S 0
+#define QP_CONTEXT_QPC_BYTES_168_RETRY_SQ_PSN_M \
+ (((1UL << 24) - 1) << QP_CONTEXT_QPC_BYTES_168_RETRY_SQ_PSN_S)
+
+#define QP_CONTEXT_QPC_BYTES_168_SGE_USE_FLA_S 24
+#define QP_CONTEXT_QPC_BYTES_168_SGE_USE_FLA_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_168_SGE_USE_FLA_S)
+
+#define QP_CONTEXT_QPC_BYTES_168_DB_TYPE_S 26
+#define QP_CONTEXT_QPC_BYTES_168_DB_TYPE_M \
+ (((1UL << 2) - 1) << QP_CONTEXT_QPC_BYTES_168_DB_TYPE_S)
+
+#define QP_CONTEXT_QPC_BYTES_168_MSG_LP_IND_S 28
+#define QP_CONTEXT_QPC_BYTES_168_CSDB_LP_IND_S 29
+#define QP_CONTEXT_QPC_BYTES_168_QP_ERR_FLG_S 30
+
+#define QP_CONTEXT_QPC_BYTES_176_DB_CUR_INDEX_S 0
+#define QP_CONTEXT_QPC_BYTES_176_DB_CUR_INDEX_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_176_DB_CUR_INDEX_S)
+
+#define QP_CONTEXT_QPC_BYTES_176_RETRY_DB_CUR_INDEX_S 16
+#define QP_CONTEXT_QPC_BYTES_176_RETRY_DB_CUR_INDEX_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_176_RETRY_DB_CUR_INDEX_S)
+
+#define QP_CONTEXT_QPC_BYTES_180_SQ_HEAD_S 0
+#define QP_CONTEXT_QPC_BYTES_180_SQ_HEAD_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_180_SQ_HEAD_S)
+
+#define QP_CONTEXT_QPC_BYTES_180_SQ_CUR_INDEX_S 16
+#define QP_CONTEXT_QPC_BYTES_180_SQ_CUR_INDEX_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_180_SQ_CUR_INDEX_S)
+
+#define QP_CONTEXT_QPC_BYTES_188_TX_CUR_SQ_WQE_BA_H_S 0
+#define QP_CONTEXT_QPC_BYTES_188_TX_CUR_SQ_WQE_BA_H_M \
+ (((1UL << 5) - 1) << QP_CONTEXT_QPC_BYTES_188_TX_CUR_SQ_WQE_BA_H_S)
+
+#define QP_CONTEXT_QPC_BYTES_188_PKT_RETRY_FLG_S 8
+
+#define QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_S 16
+#define QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_M \
+ (((1UL << 15) - 1) << QP_CONTEXT_QPC_BYTES_188_TX_RETRY_CUR_INDEX_S)
+
+struct hns_roce_rq_db {
+ u32 u32_4;
+ u32 u32_8;
+};
+
+#define RQ_DOORBELL_U32_4_RQ_HEAD_S 0
+#define RQ_DOORBELL_U32_4_RQ_HEAD_M \
+ (((1UL << 15) - 1) << RQ_DOORBELL_U32_4_RQ_HEAD_S)
+
+#define RQ_DOORBELL_U32_8_QPN_S 0
+#define RQ_DOORBELL_U32_8_QPN_M (((1UL << 24) - 1) << RQ_DOORBELL_U32_8_QPN_S)
+
+#define RQ_DOORBELL_U32_8_CMD_S 28
+#define RQ_DOORBELL_U32_8_CMD_M (((1UL << 3) - 1) << RQ_DOORBELL_U32_8_CMD_S)
+
+#define RQ_DOORBELL_U32_8_HW_SYNC_S 31
+
+struct hns_roce_sq_db {
+ u32 u32_4;
+ u32 u32_8;
+};
+
+#define SQ_DOORBELL_U32_4_SQ_HEAD_S 0
+#define SQ_DOORBELL_U32_4_SQ_HEAD_M \
+ (((1UL << 15) - 1) << SQ_DOORBELL_U32_4_SQ_HEAD_S)
+
+#define SQ_DOORBELL_U32_4_PORT_S 18
+#define SQ_DOORBELL_U32_4_PORT_M (((1UL << 3) - 1) << SQ_DOORBELL_U32_4_PORT_S)
+
+#define SQ_DOORBELL_U32_8_QPN_S 0
+#define SQ_DOORBELL_U32_8_QPN_M (((1UL << 24) - 1) << SQ_DOORBELL_U32_8_QPN_S)
+
+#define SQ_DOORBELL_HW_SYNC_S 31
+
+struct hns_roce_ext_db {
+ int esdb_dep;
+ int eodb_dep;
+ struct hns_roce_buf_list *sdb_buf_list;
+ struct hns_roce_buf_list *odb_buf_list;
+};
+
+struct hns_roce_db_table {
+ int sdb_ext_mod;
+ int odb_ext_mod;
+ struct hns_roce_ext_db *ext_db;
+};
+
+struct hns_roce_v1_priv {
+ struct hns_roce_db_table db_table;
+ struct hns_roce_raq_table raq_table;
+};
+
+int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset);
+
+#endif
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
new file mode 100644
index 000000000000..f64f0dde9a88
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -0,0 +1,1142 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/acpi.h>
+#include <linux/of_platform.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_user_verbs.h>
+#include "hns_roce_common.h"
+#include "hns_roce_device.h"
+#include "hns_roce_user.h"
+#include "hns_roce_hem.h"
+
+/**
+ * hns_roce_addrconf_ifid_eui48 - Get default gid.
+ * @eui: eui.
+ * @vlan_id: gid
+ * @dev: net device
+ * Description:
+ * MAC convert to GID
+ * gid[0..7] = fe80 0000 0000 0000
+ * gid[8] = mac[0] ^ 2
+ * gid[9] = mac[1]
+ * gid[10] = mac[2]
+ * gid[11] = ff (VLAN ID high byte (4 MS bits))
+ * gid[12] = fe (VLAN ID low byte)
+ * gid[13] = mac[3]
+ * gid[14] = mac[4]
+ * gid[15] = mac[5]
+ */
+static void hns_roce_addrconf_ifid_eui48(u8 *eui, u16 vlan_id,
+ struct net_device *dev)
+{
+ memcpy(eui, dev->dev_addr, 3);
+ memcpy(eui + 5, dev->dev_addr + 3, 3);
+ if (vlan_id < 0x1000) {
+ eui[3] = vlan_id >> 8;
+ eui[4] = vlan_id & 0xff;
+ } else {
+ eui[3] = 0xff;
+ eui[4] = 0xfe;
+ }
+ eui[0] ^= 2;
+}
+
+static void hns_roce_make_default_gid(struct net_device *dev, union ib_gid *gid)
+{
+ memset(gid, 0, sizeof(*gid));
+ gid->raw[0] = 0xFE;
+ gid->raw[1] = 0x80;
+ hns_roce_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev);
+}
+
+/**
+ * hns_get_gid_index - Get gid index.
+ * @hr_dev: pointer to structure hns_roce_dev.
+ * @port: port, value range: 0 ~ MAX
+ * @gid_index: gid_index, value range: 0 ~ MAX
+ * Description:
+ * N ports shared gids, allocation method as follow:
+ * GID[0][0], GID[1][0],.....GID[N - 1][0],
+ * GID[0][0], GID[1][0],.....GID[N - 1][0],
+ * And so on
+ */
+int hns_get_gid_index(struct hns_roce_dev *hr_dev, u8 port, int gid_index)
+{
+ return gid_index * hr_dev->caps.num_ports + port;
+}
+
+static int hns_roce_set_gid(struct hns_roce_dev *hr_dev, u8 port, int gid_index,
+ union ib_gid *gid)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ u8 gid_idx = 0;
+
+ if (gid_index >= hr_dev->caps.gid_table_len[port]) {
+ dev_err(dev, "gid_index %d illegal, port %d gid range: 0~%d\n",
+ gid_index, port, hr_dev->caps.gid_table_len[port] - 1);
+ return -EINVAL;
+ }
+
+ gid_idx = hns_get_gid_index(hr_dev, port, gid_index);
+
+ if (!memcmp(gid, &hr_dev->iboe.gid_table[gid_idx], sizeof(*gid)))
+ return -EINVAL;
+
+ memcpy(&hr_dev->iboe.gid_table[gid_idx], gid, sizeof(*gid));
+
+ hr_dev->hw->set_gid(hr_dev, port, gid_index, gid);
+
+ return 0;
+}
+
+static void hns_roce_set_mac(struct hns_roce_dev *hr_dev, u8 port, u8 *addr)
+{
+ u8 phy_port;
+ u32 i = 0;
+
+ if (!memcmp(hr_dev->dev_addr[port], addr, MAC_ADDR_OCTET_NUM))
+ return;
+
+ for (i = 0; i < MAC_ADDR_OCTET_NUM; i++)
+ hr_dev->dev_addr[port][i] = addr[i];
+
+ phy_port = hr_dev->iboe.phy_port[port];
+ hr_dev->hw->set_mac(hr_dev, phy_port, addr);
+}
+
+static void hns_roce_set_mtu(struct hns_roce_dev *hr_dev, u8 port, int mtu)
+{
+ u8 phy_port = hr_dev->iboe.phy_port[port];
+ enum ib_mtu tmp;
+
+ tmp = iboe_get_mtu(mtu);
+ if (!tmp)
+ tmp = IB_MTU_256;
+
+ hr_dev->hw->set_mtu(hr_dev, phy_port, tmp);
+}
+
+static void hns_roce_update_gids(struct hns_roce_dev *hr_dev, int port)
+{
+ struct ib_event event;
+
+ /* Refresh gid in ib_cache */
+ event.device = &hr_dev->ib_dev;
+ event.element.port_num = port + 1;
+ event.event = IB_EVENT_GID_CHANGE;
+ ib_dispatch_event(&event);
+}
+
+static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port,
+ unsigned long event)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct net_device *netdev;
+ unsigned long flags;
+ union ib_gid gid;
+ int ret = 0;
+
+ netdev = hr_dev->iboe.netdevs[port];
+ if (!netdev) {
+ dev_err(dev, "port(%d) can't find netdev\n", port);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&hr_dev->iboe.lock, flags);
+
+ switch (event) {
+ case NETDEV_UP:
+ case NETDEV_CHANGE:
+ case NETDEV_REGISTER:
+ case NETDEV_CHANGEADDR:
+ hns_roce_set_mac(hr_dev, port, netdev->dev_addr);
+ hns_roce_make_default_gid(netdev, &gid);
+ ret = hns_roce_set_gid(hr_dev, port, 0, &gid);
+ if (!ret)
+ hns_roce_update_gids(hr_dev, port);
+ break;
+ case NETDEV_DOWN:
+ /*
+ * In v1 engine, only support all ports closed together.
+ */
+ break;
+ default:
+ dev_dbg(dev, "NETDEV event = 0x%x!\n", (u32)(event));
+ break;
+ }
+
+ spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
+ return ret;
+}
+
+static int hns_roce_netdev_event(struct notifier_block *self,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct hns_roce_ib_iboe *iboe = NULL;
+ struct hns_roce_dev *hr_dev = NULL;
+ u8 port = 0;
+ int ret = 0;
+
+ hr_dev = container_of(self, struct hns_roce_dev, iboe.nb);
+ iboe = &hr_dev->iboe;
+
+ for (port = 0; port < hr_dev->caps.num_ports; port++) {
+ if (dev == iboe->netdevs[port]) {
+ ret = handle_en_event(hr_dev, port, event);
+ if (ret)
+ return NOTIFY_DONE;
+ break;
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static void hns_roce_addr_event(int event, struct net_device *event_netdev,
+ struct hns_roce_dev *hr_dev, union ib_gid *gid)
+{
+ struct hns_roce_ib_iboe *iboe = NULL;
+ int gid_table_len = 0;
+ unsigned long flags;
+ union ib_gid zgid;
+ u8 gid_idx = 0;
+ u8 port = 0;
+ int i = 0;
+ int free;
+ struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ?
+ rdma_vlan_dev_real_dev(event_netdev) :
+ event_netdev;
+
+ if (event != NETDEV_UP && event != NETDEV_DOWN)
+ return;
+
+ iboe = &hr_dev->iboe;
+ while (port < hr_dev->caps.num_ports) {
+ if (real_dev == iboe->netdevs[port])
+ break;
+ port++;
+ }
+
+ if (port >= hr_dev->caps.num_ports) {
+ dev_dbg(&hr_dev->pdev->dev, "can't find netdev\n");
+ return;
+ }
+
+ memset(zgid.raw, 0, sizeof(zgid.raw));
+ free = -1;
+ gid_table_len = hr_dev->caps.gid_table_len[port];
+
+ spin_lock_irqsave(&hr_dev->iboe.lock, flags);
+
+ for (i = 0; i < gid_table_len; i++) {
+ gid_idx = hns_get_gid_index(hr_dev, port, i);
+ if (!memcmp(gid->raw, iboe->gid_table[gid_idx].raw,
+ sizeof(gid->raw)))
+ break;
+ if (free < 0 && !memcmp(zgid.raw,
+ iboe->gid_table[gid_idx].raw, sizeof(zgid.raw)))
+ free = i;
+ }
+
+ if (i >= gid_table_len) {
+ if (free < 0) {
+ spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
+ dev_dbg(&hr_dev->pdev->dev,
+ "gid_index overflow, port(%d)\n", port);
+ return;
+ }
+ if (!hns_roce_set_gid(hr_dev, port, free, gid))
+ hns_roce_update_gids(hr_dev, port);
+ } else if (event == NETDEV_DOWN) {
+ if (!hns_roce_set_gid(hr_dev, port, i, &zgid))
+ hns_roce_update_gids(hr_dev, port);
+ }
+
+ spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
+}
+
+static int hns_roce_inet_event(struct notifier_block *self, unsigned long event,
+ void *ptr)
+{
+ struct in_ifaddr *ifa = ptr;
+ struct hns_roce_dev *hr_dev;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ union ib_gid gid;
+
+ ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid);
+
+ hr_dev = container_of(self, struct hns_roce_dev, iboe.nb_inet);
+
+ hns_roce_addr_event(event, dev, hr_dev, &gid);
+
+ return NOTIFY_DONE;
+}
+
+static int hns_roce_setup_mtu_gids(struct hns_roce_dev *hr_dev)
+{
+ struct in_ifaddr *ifa_list = NULL;
+ union ib_gid gid = {{0} };
+ u32 ipaddr = 0;
+ int index = 0;
+ int ret = 0;
+ u8 i = 0;
+
+ for (i = 0; i < hr_dev->caps.num_ports; i++) {
+ hns_roce_set_mtu(hr_dev, i,
+ ib_mtu_enum_to_int(hr_dev->caps.max_mtu));
+ hns_roce_set_mac(hr_dev, i, hr_dev->iboe.netdevs[i]->dev_addr);
+
+ if (hr_dev->iboe.netdevs[i]->ip_ptr) {
+ ifa_list = hr_dev->iboe.netdevs[i]->ip_ptr->ifa_list;
+ index = 1;
+ while (ifa_list) {
+ ipaddr = ifa_list->ifa_address;
+ ipv6_addr_set_v4mapped(ipaddr,
+ (struct in6_addr *)&gid);
+ ret = hns_roce_set_gid(hr_dev, i, index, &gid);
+ if (ret)
+ break;
+ index++;
+ ifa_list = ifa_list->ifa_next;
+ }
+ hns_roce_update_gids(hr_dev, i);
+ }
+ }
+
+ return ret;
+}
+
+static int hns_roce_query_device(struct ib_device *ib_dev,
+ struct ib_device_attr *props,
+ struct ib_udata *uhw)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+
+ memset(props, 0, sizeof(*props));
+
+ props->sys_image_guid = hr_dev->sys_image_guid;
+ props->max_mr_size = (u64)(~(0ULL));
+ props->page_size_cap = hr_dev->caps.page_size_cap;
+ props->vendor_id = hr_dev->vendor_id;
+ props->vendor_part_id = hr_dev->vendor_part_id;
+ props->hw_ver = hr_dev->hw_rev;
+ props->max_qp = hr_dev->caps.num_qps;
+ props->max_qp_wr = hr_dev->caps.max_wqes;
+ props->device_cap_flags = IB_DEVICE_PORT_ACTIVE_EVENT |
+ IB_DEVICE_RC_RNR_NAK_GEN |
+ IB_DEVICE_LOCAL_DMA_LKEY;
+ props->max_sge = hr_dev->caps.max_sq_sg;
+ props->max_sge_rd = 1;
+ props->max_cq = hr_dev->caps.num_cqs;
+ props->max_cqe = hr_dev->caps.max_cqes;
+ props->max_mr = hr_dev->caps.num_mtpts;
+ props->max_pd = hr_dev->caps.num_pds;
+ props->max_qp_rd_atom = hr_dev->caps.max_qp_dest_rdma;
+ props->max_qp_init_rd_atom = hr_dev->caps.max_qp_init_rdma;
+ props->atomic_cap = IB_ATOMIC_NONE;
+ props->max_pkeys = 1;
+ props->local_ca_ack_delay = hr_dev->caps.local_ca_ack_delay;
+
+ return 0;
+}
+
+static int hns_roce_query_port(struct ib_device *ib_dev, u8 port_num,
+ struct ib_port_attr *props)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct net_device *net_dev;
+ unsigned long flags;
+ enum ib_mtu mtu;
+ u8 port;
+
+ assert(port_num > 0);
+ port = port_num - 1;
+
+ memset(props, 0, sizeof(*props));
+
+ props->max_mtu = hr_dev->caps.max_mtu;
+ props->gid_tbl_len = hr_dev->caps.gid_table_len[port];
+ props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
+ IB_PORT_VENDOR_CLASS_SUP |
+ IB_PORT_BOOT_MGMT_SUP;
+ props->max_msg_sz = HNS_ROCE_MAX_MSG_LEN;
+ props->pkey_tbl_len = 1;
+ props->active_width = IB_WIDTH_4X;
+ props->active_speed = 1;
+
+ spin_lock_irqsave(&hr_dev->iboe.lock, flags);
+
+ net_dev = hr_dev->iboe.netdevs[port];
+ if (!net_dev) {
+ spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
+ dev_err(dev, "find netdev %d failed!\r\n", port);
+ return -EINVAL;
+ }
+
+ mtu = iboe_get_mtu(net_dev->mtu);
+ props->active_mtu = mtu ? min(props->max_mtu, mtu) : IB_MTU_256;
+ props->state = (netif_running(net_dev) && netif_carrier_ok(net_dev)) ?
+ IB_PORT_ACTIVE : IB_PORT_DOWN;
+ props->phys_state = (props->state == IB_PORT_ACTIVE) ? 5 : 3;
+
+ spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
+
+ return 0;
+}
+
+static enum rdma_link_layer hns_roce_get_link_layer(struct ib_device *device,
+ u8 port_num)
+{
+ return IB_LINK_LAYER_ETHERNET;
+}
+
+static int hns_roce_query_gid(struct ib_device *ib_dev, u8 port_num, int index,
+ union ib_gid *gid)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+ struct device *dev = &hr_dev->pdev->dev;
+ u8 gid_idx = 0;
+ u8 port;
+
+ if (port_num < 1 || port_num > hr_dev->caps.num_ports ||
+ index >= hr_dev->caps.gid_table_len[port_num - 1]) {
+ dev_err(dev,
+ "port_num %d index %d illegal! correct range: port_num 1~%d index 0~%d!\n",
+ port_num, index, hr_dev->caps.num_ports,
+ hr_dev->caps.gid_table_len[port_num - 1] - 1);
+ return -EINVAL;
+ }
+
+ port = port_num - 1;
+ gid_idx = hns_get_gid_index(hr_dev, port, index);
+ if (gid_idx >= HNS_ROCE_MAX_GID_NUM) {
+ dev_err(dev, "port_num %d index %d illegal! total gid num %d!\n",
+ port_num, index, HNS_ROCE_MAX_GID_NUM);
+ return -EINVAL;
+ }
+
+ memcpy(gid->raw, hr_dev->iboe.gid_table[gid_idx].raw,
+ HNS_ROCE_GID_SIZE);
+
+ return 0;
+}
+
+static int hns_roce_query_pkey(struct ib_device *ib_dev, u8 port, u16 index,
+ u16 *pkey)
+{
+ *pkey = PKEY_ID;
+
+ return 0;
+}
+
+static int hns_roce_modify_device(struct ib_device *ib_dev, int mask,
+ struct ib_device_modify *props)
+{
+ unsigned long flags;
+
+ if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+ return -EOPNOTSUPP;
+
+ if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+ spin_lock_irqsave(&to_hr_dev(ib_dev)->sm_lock, flags);
+ memcpy(ib_dev->node_desc, props->node_desc, NODE_DESC_SIZE);
+ spin_unlock_irqrestore(&to_hr_dev(ib_dev)->sm_lock, flags);
+ }
+
+ return 0;
+}
+
+static int hns_roce_modify_port(struct ib_device *ib_dev, u8 port_num, int mask,
+ struct ib_port_modify *props)
+{
+ return 0;
+}
+
+static struct ib_ucontext *hns_roce_alloc_ucontext(struct ib_device *ib_dev,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct hns_roce_ucontext *context;
+ struct hns_roce_ib_alloc_ucontext_resp resp;
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+
+ resp.qp_tab_size = hr_dev->caps.num_qps;
+
+ context = kmalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ ret = hns_roce_uar_alloc(hr_dev, &context->uar);
+ if (ret)
+ goto error_fail_uar_alloc;
+
+ ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
+ if (ret)
+ goto error_fail_copy_to_udata;
+
+ return &context->ibucontext;
+
+error_fail_copy_to_udata:
+ hns_roce_uar_free(hr_dev, &context->uar);
+
+error_fail_uar_alloc:
+ kfree(context);
+
+ return ERR_PTR(ret);
+}
+
+static int hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext)
+{
+ struct hns_roce_ucontext *context = to_hr_ucontext(ibcontext);
+
+ hns_roce_uar_free(to_hr_dev(ibcontext->device), &context->uar);
+ kfree(context);
+
+ return 0;
+}
+
+static int hns_roce_mmap(struct ib_ucontext *context,
+ struct vm_area_struct *vma)
+{
+ if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0)
+ return -EINVAL;
+
+ if (vma->vm_pgoff == 0) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (io_remap_pfn_range(vma, vma->vm_start,
+ to_hr_ucontext(context)->uar.pfn,
+ PAGE_SIZE, vma->vm_page_prot))
+ return -EAGAIN;
+
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hns_roce_port_immutable(struct ib_device *ib_dev, u8 port_num,
+ struct ib_port_immutable *immutable)
+{
+ struct ib_port_attr attr;
+ int ret;
+
+ ret = hns_roce_query_port(ib_dev, port_num, &attr);
+ if (ret)
+ return ret;
+
+ immutable->pkey_tbl_len = attr.pkey_tbl_len;
+ immutable->gid_tbl_len = attr.gid_tbl_len;
+
+ immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE;
+ immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+
+ return 0;
+}
+
+static void hns_roce_unregister_device(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_ib_iboe *iboe = &hr_dev->iboe;
+
+ unregister_inetaddr_notifier(&iboe->nb_inet);
+ unregister_netdevice_notifier(&iboe->nb);
+ ib_unregister_device(&hr_dev->ib_dev);
+}
+
+static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
+{
+ int ret;
+ struct hns_roce_ib_iboe *iboe = NULL;
+ struct ib_device *ib_dev = NULL;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ iboe = &hr_dev->iboe;
+
+ ib_dev = &hr_dev->ib_dev;
+ strlcpy(ib_dev->name, "hisi_%d", IB_DEVICE_NAME_MAX);
+
+ ib_dev->owner = THIS_MODULE;
+ ib_dev->node_type = RDMA_NODE_IB_CA;
+ ib_dev->dma_device = dev;
+
+ ib_dev->phys_port_cnt = hr_dev->caps.num_ports;
+ ib_dev->local_dma_lkey = hr_dev->caps.reserved_lkey;
+ ib_dev->num_comp_vectors = hr_dev->caps.num_comp_vectors;
+ ib_dev->uverbs_abi_ver = 1;
+ ib_dev->uverbs_cmd_mask =
+ (1ULL << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ULL << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ULL << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ULL << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ULL << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ULL << IB_USER_VERBS_CMD_REG_MR) |
+ (1ULL << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ULL << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ULL << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ULL << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ULL << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ULL << IB_USER_VERBS_CMD_QUERY_QP) |
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_QP);
+
+ /* HCA||device||port */
+ ib_dev->modify_device = hns_roce_modify_device;
+ ib_dev->query_device = hns_roce_query_device;
+ ib_dev->query_port = hns_roce_query_port;
+ ib_dev->modify_port = hns_roce_modify_port;
+ ib_dev->get_link_layer = hns_roce_get_link_layer;
+ ib_dev->query_gid = hns_roce_query_gid;
+ ib_dev->query_pkey = hns_roce_query_pkey;
+ ib_dev->alloc_ucontext = hns_roce_alloc_ucontext;
+ ib_dev->dealloc_ucontext = hns_roce_dealloc_ucontext;
+ ib_dev->mmap = hns_roce_mmap;
+
+ /* PD */
+ ib_dev->alloc_pd = hns_roce_alloc_pd;
+ ib_dev->dealloc_pd = hns_roce_dealloc_pd;
+
+ /* AH */
+ ib_dev->create_ah = hns_roce_create_ah;
+ ib_dev->query_ah = hns_roce_query_ah;
+ ib_dev->destroy_ah = hns_roce_destroy_ah;
+
+ /* QP */
+ ib_dev->create_qp = hns_roce_create_qp;
+ ib_dev->modify_qp = hns_roce_modify_qp;
+ ib_dev->query_qp = hr_dev->hw->query_qp;
+ ib_dev->destroy_qp = hr_dev->hw->destroy_qp;
+ ib_dev->post_send = hr_dev->hw->post_send;
+ ib_dev->post_recv = hr_dev->hw->post_recv;
+
+ /* CQ */
+ ib_dev->create_cq = hns_roce_ib_create_cq;
+ ib_dev->destroy_cq = hns_roce_ib_destroy_cq;
+ ib_dev->req_notify_cq = hr_dev->hw->req_notify_cq;
+ ib_dev->poll_cq = hr_dev->hw->poll_cq;
+
+ /* MR */
+ ib_dev->get_dma_mr = hns_roce_get_dma_mr;
+ ib_dev->reg_user_mr = hns_roce_reg_user_mr;
+ ib_dev->dereg_mr = hns_roce_dereg_mr;
+
+ /* OTHERS */
+ ib_dev->get_port_immutable = hns_roce_port_immutable;
+
+ ret = ib_register_device(ib_dev, NULL);
+ if (ret) {
+ dev_err(dev, "ib_register_device failed!\n");
+ return ret;
+ }
+
+ ret = hns_roce_setup_mtu_gids(hr_dev);
+ if (ret) {
+ dev_err(dev, "roce_setup_mtu_gids failed!\n");
+ goto error_failed_setup_mtu_gids;
+ }
+
+ spin_lock_init(&iboe->lock);
+
+ iboe->nb.notifier_call = hns_roce_netdev_event;
+ ret = register_netdevice_notifier(&iboe->nb);
+ if (ret) {
+ dev_err(dev, "register_netdevice_notifier failed!\n");
+ goto error_failed_setup_mtu_gids;
+ }
+
+ iboe->nb_inet.notifier_call = hns_roce_inet_event;
+ ret = register_inetaddr_notifier(&iboe->nb_inet);
+ if (ret) {
+ dev_err(dev, "register inet addr notifier failed!\n");
+ goto error_failed_register_inetaddr_notifier;
+ }
+
+ return 0;
+
+error_failed_register_inetaddr_notifier:
+ unregister_netdevice_notifier(&iboe->nb);
+
+error_failed_setup_mtu_gids:
+ ib_unregister_device(ib_dev);
+
+ return ret;
+}
+
+static const struct of_device_id hns_roce_of_match[] = {
+ { .compatible = "hisilicon,hns-roce-v1", .data = &hns_roce_hw_v1, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hns_roce_of_match);
+
+static const struct acpi_device_id hns_roce_acpi_match[] = {
+ { "HISI00D1", (kernel_ulong_t)&hns_roce_hw_v1 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match);
+
+static int hns_roce_node_match(struct device *dev, void *fwnode)
+{
+ return dev->fwnode == fwnode;
+}
+
+static struct
+platform_device *hns_roce_find_pdev(struct fwnode_handle *fwnode)
+{
+ struct device *dev;
+
+ /* get the 'device'corresponding to matching 'fwnode' */
+ dev = bus_find_device(&platform_bus_type, NULL,
+ fwnode, hns_roce_node_match);
+ /* get the platform device */
+ return dev ? to_platform_device(dev) : NULL;
+}
+
+static int hns_roce_get_cfg(struct hns_roce_dev *hr_dev)
+{
+ int i;
+ int ret;
+ u8 phy_port;
+ int port_cnt = 0;
+ struct device *dev = &hr_dev->pdev->dev;
+ struct device_node *net_node;
+ struct net_device *netdev = NULL;
+ struct platform_device *pdev = NULL;
+ struct resource *res;
+
+ /* check if we are compatible with the underlying SoC */
+ if (dev_of_node(dev)) {
+ const struct of_device_id *of_id;
+
+ of_id = of_match_node(hns_roce_of_match, dev->of_node);
+ if (!of_id) {
+ dev_err(dev, "device is not compatible!\n");
+ return -ENXIO;
+ }
+ hr_dev->hw = (struct hns_roce_hw *)of_id->data;
+ if (!hr_dev->hw) {
+ dev_err(dev, "couldn't get H/W specific DT data!\n");
+ return -ENXIO;
+ }
+ } else if (is_acpi_device_node(dev->fwnode)) {
+ const struct acpi_device_id *acpi_id;
+
+ acpi_id = acpi_match_device(hns_roce_acpi_match, dev);
+ if (!acpi_id) {
+ dev_err(dev, "device is not compatible!\n");
+ return -ENXIO;
+ }
+ hr_dev->hw = (struct hns_roce_hw *) acpi_id->driver_data;
+ if (!hr_dev->hw) {
+ dev_err(dev, "couldn't get H/W specific ACPI data!\n");
+ return -ENXIO;
+ }
+ } else {
+ dev_err(dev, "can't read compatibility data from DT or ACPI\n");
+ return -ENXIO;
+ }
+
+ /* get the mapped register base address */
+ res = platform_get_resource(hr_dev->pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "memory resource not found!\n");
+ return -EINVAL;
+ }
+ hr_dev->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hr_dev->reg_base))
+ return PTR_ERR(hr_dev->reg_base);
+
+ /* get the RoCE associated ethernet ports or netdevices */
+ for (i = 0; i < HNS_ROCE_MAX_PORTS; i++) {
+ if (dev_of_node(dev)) {
+ net_node = of_parse_phandle(dev->of_node, "eth-handle",
+ i);
+ if (!net_node)
+ continue;
+ pdev = of_find_device_by_node(net_node);
+ } else if (is_acpi_device_node(dev->fwnode)) {
+ struct acpi_reference_args args;
+ struct fwnode_handle *fwnode;
+
+ ret = acpi_node_get_property_reference(dev->fwnode,
+ "eth-handle",
+ i, &args);
+ if (ret)
+ continue;
+ fwnode = acpi_fwnode_handle(args.adev);
+ pdev = hns_roce_find_pdev(fwnode);
+ } else {
+ dev_err(dev, "cannot read data from DT or ACPI\n");
+ return -ENXIO;
+ }
+
+ if (pdev) {
+ netdev = platform_get_drvdata(pdev);
+ phy_port = (u8)i;
+ if (netdev) {
+ hr_dev->iboe.netdevs[port_cnt] = netdev;
+ hr_dev->iboe.phy_port[port_cnt] = phy_port;
+ } else {
+ dev_err(dev, "no netdev found with pdev %s\n",
+ pdev->name);
+ return -ENODEV;
+ }
+ port_cnt++;
+ }
+ }
+
+ if (port_cnt == 0) {
+ dev_err(dev, "unable to get eth-handle for available ports!\n");
+ return -EINVAL;
+ }
+
+ hr_dev->caps.num_ports = port_cnt;
+
+ /* cmd issue mode: 0 is poll, 1 is event */
+ hr_dev->cmd_mod = 1;
+ hr_dev->loop_idc = 0;
+
+ /* read the interrupt names from the DT or ACPI */
+ ret = device_property_read_string_array(dev, "interrupt-names",
+ hr_dev->irq_names,
+ HNS_ROCE_MAX_IRQ_NUM);
+ if (ret < 0) {
+ dev_err(dev, "couldn't get interrupt names from DT or ACPI!\n");
+ return ret;
+ }
+
+ /* fetch the interrupt numbers */
+ for (i = 0; i < HNS_ROCE_MAX_IRQ_NUM; i++) {
+ hr_dev->irq[i] = platform_get_irq(hr_dev->pdev, i);
+ if (hr_dev->irq[i] <= 0) {
+ dev_err(dev, "platform get of irq[=%d] failed!\n", i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int hns_roce_init_hem(struct hns_roce_dev *hr_dev)
+{
+ int ret;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ ret = hns_roce_init_hem_table(hr_dev, &hr_dev->mr_table.mtt_table,
+ HEM_TYPE_MTT, hr_dev->caps.mtt_entry_sz,
+ hr_dev->caps.num_mtt_segs, 1);
+ if (ret) {
+ dev_err(dev, "Failed to init MTT context memory, aborting.\n");
+ return ret;
+ }
+
+ ret = hns_roce_init_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table,
+ HEM_TYPE_MTPT, hr_dev->caps.mtpt_entry_sz,
+ hr_dev->caps.num_mtpts, 1);
+ if (ret) {
+ dev_err(dev, "Failed to init MTPT context memory, aborting.\n");
+ goto err_unmap_mtt;
+ }
+
+ ret = hns_roce_init_hem_table(hr_dev, &hr_dev->qp_table.qp_table,
+ HEM_TYPE_QPC, hr_dev->caps.qpc_entry_sz,
+ hr_dev->caps.num_qps, 1);
+ if (ret) {
+ dev_err(dev, "Failed to init QP context memory, aborting.\n");
+ goto err_unmap_dmpt;
+ }
+
+ ret = hns_roce_init_hem_table(hr_dev, &hr_dev->qp_table.irrl_table,
+ HEM_TYPE_IRRL,
+ hr_dev->caps.irrl_entry_sz *
+ hr_dev->caps.max_qp_init_rdma,
+ hr_dev->caps.num_qps, 1);
+ if (ret) {
+ dev_err(dev, "Failed to init irrl_table memory, aborting.\n");
+ goto err_unmap_qp;
+ }
+
+ ret = hns_roce_init_hem_table(hr_dev, &hr_dev->cq_table.table,
+ HEM_TYPE_CQC, hr_dev->caps.cqc_entry_sz,
+ hr_dev->caps.num_cqs, 1);
+ if (ret) {
+ dev_err(dev, "Failed to init CQ context memory, aborting.\n");
+ goto err_unmap_irrl;
+ }
+
+ return 0;
+
+err_unmap_irrl:
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.irrl_table);
+
+err_unmap_qp:
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.qp_table);
+
+err_unmap_dmpt:
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table);
+
+err_unmap_mtt:
+ hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtt_table);
+
+ return ret;
+}
+
+/**
+* hns_roce_setup_hca - setup host channel adapter
+* @hr_dev: pointer to hns roce device
+* Return : int
+*/
+static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)
+{
+ int ret;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ spin_lock_init(&hr_dev->sm_lock);
+ spin_lock_init(&hr_dev->cq_db_lock);
+ spin_lock_init(&hr_dev->bt_cmd_lock);
+
+ ret = hns_roce_init_uar_table(hr_dev);
+ if (ret) {
+ dev_err(dev, "Failed to initialize uar table. aborting\n");
+ return ret;
+ }
+
+ ret = hns_roce_uar_alloc(hr_dev, &hr_dev->priv_uar);
+ if (ret) {
+ dev_err(dev, "Failed to allocate priv_uar.\n");
+ goto err_uar_table_free;
+ }
+
+ ret = hns_roce_init_pd_table(hr_dev);
+ if (ret) {
+ dev_err(dev, "Failed to init protected domain table.\n");
+ goto err_uar_alloc_free;
+ }
+
+ ret = hns_roce_init_mr_table(hr_dev);
+ if (ret) {
+ dev_err(dev, "Failed to init memory region table.\n");
+ goto err_pd_table_free;
+ }
+
+ ret = hns_roce_init_cq_table(hr_dev);
+ if (ret) {
+ dev_err(dev, "Failed to init completion queue table.\n");
+ goto err_mr_table_free;
+ }
+
+ ret = hns_roce_init_qp_table(hr_dev);
+ if (ret) {
+ dev_err(dev, "Failed to init queue pair table.\n");
+ goto err_cq_table_free;
+ }
+
+ return 0;
+
+err_cq_table_free:
+ hns_roce_cleanup_cq_table(hr_dev);
+
+err_mr_table_free:
+ hns_roce_cleanup_mr_table(hr_dev);
+
+err_pd_table_free:
+ hns_roce_cleanup_pd_table(hr_dev);
+
+err_uar_alloc_free:
+ hns_roce_uar_free(hr_dev, &hr_dev->priv_uar);
+
+err_uar_table_free:
+ hns_roce_cleanup_uar_table(hr_dev);
+ return ret;
+}
+
+/**
+* hns_roce_probe - RoCE driver entrance
+* @pdev: pointer to platform device
+* Return : int
+*
+*/
+static int hns_roce_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct hns_roce_dev *hr_dev;
+ struct device *dev = &pdev->dev;
+
+ hr_dev = (struct hns_roce_dev *)ib_alloc_device(sizeof(*hr_dev));
+ if (!hr_dev)
+ return -ENOMEM;
+
+ memset((u8 *)hr_dev + sizeof(struct ib_device), 0,
+ sizeof(struct hns_roce_dev) - sizeof(struct ib_device));
+
+ hr_dev->pdev = pdev;
+ platform_set_drvdata(pdev, hr_dev);
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64ULL)) &&
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32ULL))) {
+ dev_err(dev, "Not usable DMA addressing mode\n");
+ ret = -EIO;
+ goto error_failed_get_cfg;
+ }
+
+ ret = hns_roce_get_cfg(hr_dev);
+ if (ret) {
+ dev_err(dev, "Get Configuration failed!\n");
+ goto error_failed_get_cfg;
+ }
+
+ ret = hr_dev->hw->reset(hr_dev, true);
+ if (ret) {
+ dev_err(dev, "Reset RoCE engine failed!\n");
+ goto error_failed_get_cfg;
+ }
+
+ hr_dev->hw->hw_profile(hr_dev);
+
+ ret = hns_roce_cmd_init(hr_dev);
+ if (ret) {
+ dev_err(dev, "cmd init failed!\n");
+ goto error_failed_cmd_init;
+ }
+
+ ret = hns_roce_init_eq_table(hr_dev);
+ if (ret) {
+ dev_err(dev, "eq init failed!\n");
+ goto error_failed_eq_table;
+ }
+
+ if (hr_dev->cmd_mod) {
+ ret = hns_roce_cmd_use_events(hr_dev);
+ if (ret) {
+ dev_err(dev, "Switch to event-driven cmd failed!\n");
+ goto error_failed_use_event;
+ }
+ }
+
+ ret = hns_roce_init_hem(hr_dev);
+ if (ret) {
+ dev_err(dev, "init HEM(Hardware Entry Memory) failed!\n");
+ goto error_failed_init_hem;
+ }
+
+ ret = hns_roce_setup_hca(hr_dev);
+ if (ret) {
+ dev_err(dev, "setup hca failed!\n");
+ goto error_failed_setup_hca;
+ }
+
+ ret = hr_dev->hw->hw_init(hr_dev);
+ if (ret) {
+ dev_err(dev, "hw_init failed!\n");
+ goto error_failed_engine_init;
+ }
+
+ ret = hns_roce_register_device(hr_dev);
+ if (ret)
+ goto error_failed_register_device;
+
+ return 0;
+
+error_failed_register_device:
+ hr_dev->hw->hw_exit(hr_dev);
+
+error_failed_engine_init:
+ hns_roce_cleanup_bitmap(hr_dev);
+
+error_failed_setup_hca:
+ hns_roce_cleanup_hem(hr_dev);
+
+error_failed_init_hem:
+ if (hr_dev->cmd_mod)
+ hns_roce_cmd_use_polling(hr_dev);
+
+error_failed_use_event:
+ hns_roce_cleanup_eq_table(hr_dev);
+
+error_failed_eq_table:
+ hns_roce_cmd_cleanup(hr_dev);
+
+error_failed_cmd_init:
+ ret = hr_dev->hw->reset(hr_dev, false);
+ if (ret)
+ dev_err(&hr_dev->pdev->dev, "roce_engine reset fail\n");
+
+error_failed_get_cfg:
+ ib_dealloc_device(&hr_dev->ib_dev);
+
+ return ret;
+}
+
+/**
+* hns_roce_remove - remove RoCE device
+* @pdev: pointer to platform device
+*/
+static int hns_roce_remove(struct platform_device *pdev)
+{
+ struct hns_roce_dev *hr_dev = platform_get_drvdata(pdev);
+
+ hns_roce_unregister_device(hr_dev);
+ hr_dev->hw->hw_exit(hr_dev);
+ hns_roce_cleanup_bitmap(hr_dev);
+ hns_roce_cleanup_hem(hr_dev);
+
+ if (hr_dev->cmd_mod)
+ hns_roce_cmd_use_polling(hr_dev);
+
+ hns_roce_cleanup_eq_table(hr_dev);
+ hns_roce_cmd_cleanup(hr_dev);
+ hr_dev->hw->reset(hr_dev, false);
+
+ ib_dealloc_device(&hr_dev->ib_dev);
+
+ return 0;
+}
+
+static struct platform_driver hns_roce_driver = {
+ .probe = hns_roce_probe,
+ .remove = hns_roce_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = hns_roce_of_match,
+ .acpi_match_table = ACPI_PTR(hns_roce_acpi_match),
+ },
+};
+
+module_platform_driver(hns_roce_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Wei Hu <xavier.huwei@huawei.com>");
+MODULE_AUTHOR("Nenglong Zhao <zhaonenglong@hisilicon.com>");
+MODULE_AUTHOR("Lijun Ou <oulijun@huawei.com>");
+MODULE_DESCRIPTION("HNS RoCE Driver");
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
new file mode 100644
index 000000000000..59f5e2be046b
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include <rdma/ib_umem.h>
+#include "hns_roce_device.h"
+#include "hns_roce_cmd.h"
+#include "hns_roce_hem.h"
+
+static u32 hw_index_to_key(unsigned long ind)
+{
+ return (u32)(ind >> 24) | (ind << 8);
+}
+
+static unsigned long key_to_hw_index(u32 key)
+{
+ return (key << 24) | (key >> 8);
+}
+
+static int hns_roce_sw2hw_mpt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cmd_mailbox *mailbox,
+ unsigned long mpt_index)
+{
+ return hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, mpt_index, 0,
+ HNS_ROCE_CMD_SW2HW_MPT,
+ HNS_ROCE_CMD_TIME_CLASS_B);
+}
+
+static int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_cmd_mailbox *mailbox,
+ unsigned long mpt_index)
+{
+ return hns_roce_cmd_mbox(hr_dev, 0, mailbox ? mailbox->dma : 0,
+ mpt_index, !mailbox, HNS_ROCE_CMD_HW2SW_MPT,
+ HNS_ROCE_CMD_TIME_CLASS_B);
+}
+
+static int hns_roce_buddy_alloc(struct hns_roce_buddy *buddy, int order,
+ unsigned long *seg)
+{
+ int o;
+ u32 m;
+
+ spin_lock(&buddy->lock);
+
+ for (o = order; o <= buddy->max_order; ++o) {
+ if (buddy->num_free[o]) {
+ m = 1 << (buddy->max_order - o);
+ *seg = find_first_bit(buddy->bits[o], m);
+ if (*seg < m)
+ goto found;
+ }
+ }
+ spin_unlock(&buddy->lock);
+ return -1;
+
+ found:
+ clear_bit(*seg, buddy->bits[o]);
+ --buddy->num_free[o];
+
+ while (o > order) {
+ --o;
+ *seg <<= 1;
+ set_bit(*seg ^ 1, buddy->bits[o]);
+ ++buddy->num_free[o];
+ }
+
+ spin_unlock(&buddy->lock);
+
+ *seg <<= order;
+ return 0;
+}
+
+static void hns_roce_buddy_free(struct hns_roce_buddy *buddy, unsigned long seg,
+ int order)
+{
+ seg >>= order;
+
+ spin_lock(&buddy->lock);
+
+ while (test_bit(seg ^ 1, buddy->bits[order])) {
+ clear_bit(seg ^ 1, buddy->bits[order]);
+ --buddy->num_free[order];
+ seg >>= 1;
+ ++order;
+ }
+
+ set_bit(seg, buddy->bits[order]);
+ ++buddy->num_free[order];
+
+ spin_unlock(&buddy->lock);
+}
+
+static int hns_roce_buddy_init(struct hns_roce_buddy *buddy, int max_order)
+{
+ int i, s;
+
+ buddy->max_order = max_order;
+ spin_lock_init(&buddy->lock);
+
+ buddy->bits = kzalloc((buddy->max_order + 1) * sizeof(long *),
+ GFP_KERNEL);
+ buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof(int *),
+ GFP_KERNEL);
+ if (!buddy->bits || !buddy->num_free)
+ goto err_out;
+
+ for (i = 0; i <= buddy->max_order; ++i) {
+ s = BITS_TO_LONGS(1 << (buddy->max_order - i));
+ buddy->bits[i] = kmalloc_array(s, sizeof(long), GFP_KERNEL);
+ if (!buddy->bits[i])
+ goto err_out_free;
+
+ bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i));
+ }
+
+ set_bit(0, buddy->bits[buddy->max_order]);
+ buddy->num_free[buddy->max_order] = 1;
+
+ return 0;
+
+err_out_free:
+ for (i = 0; i <= buddy->max_order; ++i)
+ kfree(buddy->bits[i]);
+
+err_out:
+ kfree(buddy->bits);
+ kfree(buddy->num_free);
+ return -ENOMEM;
+}
+
+static void hns_roce_buddy_cleanup(struct hns_roce_buddy *buddy)
+{
+ int i;
+
+ for (i = 0; i <= buddy->max_order; ++i)
+ kfree(buddy->bits[i]);
+
+ kfree(buddy->bits);
+ kfree(buddy->num_free);
+}
+
+static int hns_roce_alloc_mtt_range(struct hns_roce_dev *hr_dev, int order,
+ unsigned long *seg)
+{
+ struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+ int ret = 0;
+
+ ret = hns_roce_buddy_alloc(&mr_table->mtt_buddy, order, seg);
+ if (ret == -1)
+ return -1;
+
+ if (hns_roce_table_get_range(hr_dev, &mr_table->mtt_table, *seg,
+ *seg + (1 << order) - 1)) {
+ hns_roce_buddy_free(&mr_table->mtt_buddy, *seg, order);
+ return -1;
+ }
+
+ return 0;
+}
+
+int hns_roce_mtt_init(struct hns_roce_dev *hr_dev, int npages, int page_shift,
+ struct hns_roce_mtt *mtt)
+{
+ int ret = 0;
+ int i;
+
+ /* Page num is zero, correspond to DMA memory register */
+ if (!npages) {
+ mtt->order = -1;
+ mtt->page_shift = HNS_ROCE_HEM_PAGE_SHIFT;
+ return 0;
+ }
+
+ /* Note: if page_shift is zero, FAST memory regsiter */
+ mtt->page_shift = page_shift;
+
+ /* Compute MTT entry necessary */
+ for (mtt->order = 0, i = HNS_ROCE_MTT_ENTRY_PER_SEG; i < npages;
+ i <<= 1)
+ ++mtt->order;
+
+ /* Allocate MTT entry */
+ ret = hns_roce_alloc_mtt_range(hr_dev, mtt->order, &mtt->first_seg);
+ if (ret == -1)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void hns_roce_mtt_cleanup(struct hns_roce_dev *hr_dev, struct hns_roce_mtt *mtt)
+{
+ struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+
+ if (mtt->order < 0)
+ return;
+
+ hns_roce_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order);
+ hns_roce_table_put_range(hr_dev, &mr_table->mtt_table, mtt->first_seg,
+ mtt->first_seg + (1 << mtt->order) - 1);
+}
+
+static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova,
+ u64 size, u32 access, int npages,
+ struct hns_roce_mr *mr)
+{
+ unsigned long index = 0;
+ int ret = 0;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ /* Allocate a key for mr from mr_table */
+ ret = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &index);
+ if (ret == -1)
+ return -ENOMEM;
+
+ mr->iova = iova; /* MR va starting addr */
+ mr->size = size; /* MR addr range */
+ mr->pd = pd; /* MR num */
+ mr->access = access; /* MR access permit */
+ mr->enabled = 0; /* MR active status */
+ mr->key = hw_index_to_key(index); /* MR key */
+
+ if (size == ~0ull) {
+ mr->type = MR_TYPE_DMA;
+ mr->pbl_buf = NULL;
+ mr->pbl_dma_addr = 0;
+ } else {
+ mr->type = MR_TYPE_MR;
+ mr->pbl_buf = dma_alloc_coherent(dev, npages * 8,
+ &(mr->pbl_dma_addr),
+ GFP_KERNEL);
+ if (!mr->pbl_buf)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void hns_roce_mr_free(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mr *mr)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ int npages = 0;
+ int ret;
+
+ if (mr->enabled) {
+ ret = hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mr->key)
+ & (hr_dev->caps.num_mtpts - 1));
+ if (ret)
+ dev_warn(dev, "HW2SW_MPT failed (%d)\n", ret);
+ }
+
+ if (mr->size != ~0ULL) {
+ npages = ib_umem_page_count(mr->umem);
+ dma_free_coherent(dev, (unsigned int)(npages * 8), mr->pbl_buf,
+ mr->pbl_dma_addr);
+ }
+
+ hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap,
+ key_to_hw_index(mr->key));
+}
+
+static int hns_roce_mr_enable(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mr *mr)
+{
+ int ret;
+ unsigned long mtpt_idx = key_to_hw_index(mr->key);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_cmd_mailbox *mailbox;
+ struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+
+ /* Prepare HEM entry memory */
+ ret = hns_roce_table_get(hr_dev, &mr_table->mtpt_table, mtpt_idx);
+ if (ret)
+ return ret;
+
+ /* Allocate mailbox memory */
+ mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
+ if (IS_ERR(mailbox)) {
+ ret = PTR_ERR(mailbox);
+ goto err_table;
+ }
+
+ ret = hr_dev->hw->write_mtpt(mailbox->buf, mr, mtpt_idx);
+ if (ret) {
+ dev_err(dev, "Write mtpt fail!\n");
+ goto err_page;
+ }
+
+ ret = hns_roce_sw2hw_mpt(hr_dev, mailbox,
+ mtpt_idx & (hr_dev->caps.num_mtpts - 1));
+ if (ret) {
+ dev_err(dev, "SW2HW_MPT failed (%d)\n", ret);
+ goto err_page;
+ }
+
+ mr->enabled = 1;
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+
+ return 0;
+
+err_page:
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+
+err_table:
+ hns_roce_table_put(hr_dev, &mr_table->mtpt_table, mtpt_idx);
+ return ret;
+}
+
+static int hns_roce_write_mtt_chunk(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt, u32 start_index,
+ u32 npages, u64 *page_list)
+{
+ u32 i = 0;
+ __le64 *mtts = NULL;
+ dma_addr_t dma_handle;
+ u32 s = start_index * sizeof(u64);
+
+ /* All MTTs must fit in the same page */
+ if (start_index / (PAGE_SIZE / sizeof(u64)) !=
+ (start_index + npages - 1) / (PAGE_SIZE / sizeof(u64)))
+ return -EINVAL;
+
+ if (start_index & (HNS_ROCE_MTT_ENTRY_PER_SEG - 1))
+ return -EINVAL;
+
+ mtts = hns_roce_table_find(&hr_dev->mr_table.mtt_table,
+ mtt->first_seg + s / hr_dev->caps.mtt_entry_sz,
+ &dma_handle);
+ if (!mtts)
+ return -ENOMEM;
+
+ /* Save page addr, low 12 bits : 0 */
+ for (i = 0; i < npages; ++i)
+ mtts[i] = (cpu_to_le64(page_list[i])) >> PAGE_ADDR_SHIFT;
+
+ return 0;
+}
+
+static int hns_roce_write_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt, u32 start_index,
+ u32 npages, u64 *page_list)
+{
+ int chunk;
+ int ret;
+
+ if (mtt->order < 0)
+ return -EINVAL;
+
+ while (npages > 0) {
+ chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
+
+ ret = hns_roce_write_mtt_chunk(hr_dev, mtt, start_index, chunk,
+ page_list);
+ if (ret)
+ return ret;
+
+ npages -= chunk;
+ start_index += chunk;
+ page_list += chunk;
+ }
+
+ return 0;
+}
+
+int hns_roce_buf_write_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt, struct hns_roce_buf *buf)
+{
+ u32 i = 0;
+ int ret = 0;
+ u64 *page_list = NULL;
+
+ page_list = kmalloc_array(buf->npages, sizeof(*page_list), GFP_KERNEL);
+ if (!page_list)
+ return -ENOMEM;
+
+ for (i = 0; i < buf->npages; ++i) {
+ if (buf->nbufs == 1)
+ page_list[i] = buf->direct.map + (i << buf->page_shift);
+ else
+ page_list[i] = buf->page_list[i].map;
+
+ }
+ ret = hns_roce_write_mtt(hr_dev, mtt, 0, buf->npages, page_list);
+
+ kfree(page_list);
+
+ return ret;
+}
+
+int hns_roce_init_mr_table(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+ int ret = 0;
+
+ ret = hns_roce_bitmap_init(&mr_table->mtpt_bitmap,
+ hr_dev->caps.num_mtpts,
+ hr_dev->caps.num_mtpts - 1,
+ hr_dev->caps.reserved_mrws, 0);
+ if (ret)
+ return ret;
+
+ ret = hns_roce_buddy_init(&mr_table->mtt_buddy,
+ ilog2(hr_dev->caps.num_mtt_segs));
+ if (ret)
+ goto err_buddy;
+
+ return 0;
+
+err_buddy:
+ hns_roce_bitmap_cleanup(&mr_table->mtpt_bitmap);
+ return ret;
+}
+
+void hns_roce_cleanup_mr_table(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+
+ hns_roce_buddy_cleanup(&mr_table->mtt_buddy);
+ hns_roce_bitmap_cleanup(&mr_table->mtpt_bitmap);
+}
+
+struct ib_mr *hns_roce_get_dma_mr(struct ib_pd *pd, int acc)
+{
+ int ret = 0;
+ struct hns_roce_mr *mr = NULL;
+
+ mr = kmalloc(sizeof(*mr), GFP_KERNEL);
+ if (mr == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ /* Allocate memory region key */
+ ret = hns_roce_mr_alloc(to_hr_dev(pd->device), to_hr_pd(pd)->pdn, 0,
+ ~0ULL, acc, 0, mr);
+ if (ret)
+ goto err_free;
+
+ ret = hns_roce_mr_enable(to_hr_dev(pd->device), mr);
+ if (ret)
+ goto err_mr;
+
+ mr->ibmr.rkey = mr->ibmr.lkey = mr->key;
+ mr->umem = NULL;
+
+ return &mr->ibmr;
+
+err_mr:
+ hns_roce_mr_free(to_hr_dev(pd->device), mr);
+
+err_free:
+ kfree(mr);
+ return ERR_PTR(ret);
+}
+
+int hns_roce_ib_umem_write_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtt *mtt, struct ib_umem *umem)
+{
+ struct scatterlist *sg;
+ int i, k, entry;
+ int ret = 0;
+ u64 *pages;
+ u32 n;
+ int len;
+
+ pages = (u64 *) __get_free_page(GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+
+ i = n = 0;
+
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ len = sg_dma_len(sg) >> mtt->page_shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = sg_dma_address(sg) + umem->page_size * k;
+ if (i == PAGE_SIZE / sizeof(u64)) {
+ ret = hns_roce_write_mtt(hr_dev, mtt, n, i,
+ pages);
+ if (ret)
+ goto out;
+ n += i;
+ i = 0;
+ }
+ }
+ }
+
+ if (i)
+ ret = hns_roce_write_mtt(hr_dev, mtt, n, i, pages);
+
+out:
+ free_page((unsigned long) pages);
+ return ret;
+}
+
+static int hns_roce_ib_umem_write_mr(struct hns_roce_mr *mr,
+ struct ib_umem *umem)
+{
+ int i = 0;
+ int entry;
+ struct scatterlist *sg;
+
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+ mr->pbl_buf[i] = ((u64)sg_dma_address(sg)) >> 12;
+ i++;
+ }
+
+ /* Memory barrier */
+ mb();
+
+ return 0;
+}
+
+struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt_addr, int access_flags,
+ struct ib_udata *udata)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_mr *mr = NULL;
+ int ret = 0;
+ int n = 0;
+
+ mr = kmalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ mr->umem = ib_umem_get(pd->uobject->context, start, length,
+ access_flags, 0);
+ if (IS_ERR(mr->umem)) {
+ ret = PTR_ERR(mr->umem);
+ goto err_free;
+ }
+
+ n = ib_umem_page_count(mr->umem);
+ if (mr->umem->page_size != HNS_ROCE_HEM_PAGE_SIZE) {
+ dev_err(dev, "Just support 4K page size but is 0x%x now!\n",
+ mr->umem->page_size);
+ }
+
+ if (n > HNS_ROCE_MAX_MTPT_PBL_NUM) {
+ dev_err(dev, " MR len %lld err. MR is limited to 4G at most!\n",
+ length);
+ goto err_umem;
+ }
+
+ ret = hns_roce_mr_alloc(hr_dev, to_hr_pd(pd)->pdn, virt_addr, length,
+ access_flags, n, mr);
+ if (ret)
+ goto err_umem;
+
+ ret = hns_roce_ib_umem_write_mr(mr, mr->umem);
+ if (ret)
+ goto err_mr;
+
+ ret = hns_roce_mr_enable(hr_dev, mr);
+ if (ret)
+ goto err_mr;
+
+ mr->ibmr.rkey = mr->ibmr.lkey = mr->key;
+
+ return &mr->ibmr;
+
+err_mr:
+ hns_roce_mr_free(hr_dev, mr);
+
+err_umem:
+ ib_umem_release(mr->umem);
+
+err_free:
+ kfree(mr);
+ return ERR_PTR(ret);
+}
+
+int hns_roce_dereg_mr(struct ib_mr *ibmr)
+{
+ struct hns_roce_mr *mr = to_hr_mr(ibmr);
+
+ hns_roce_mr_free(to_hr_dev(ibmr->device), mr);
+ if (mr->umem)
+ ib_umem_release(mr->umem);
+
+ kfree(mr);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c
new file mode 100644
index 000000000000..16271b5bd170
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_pd.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include "hns_roce_device.h"
+
+static int hns_roce_pd_alloc(struct hns_roce_dev *hr_dev, unsigned long *pdn)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ unsigned long pd_number;
+ int ret = 0;
+
+ ret = hns_roce_bitmap_alloc(&hr_dev->pd_bitmap, &pd_number);
+ if (ret == -1) {
+ dev_err(dev, "alloc pdn from pdbitmap failed\n");
+ return -ENOMEM;
+ }
+
+ *pdn = pd_number;
+
+ return 0;
+}
+
+static void hns_roce_pd_free(struct hns_roce_dev *hr_dev, unsigned long pdn)
+{
+ hns_roce_bitmap_free(&hr_dev->pd_bitmap, pdn);
+}
+
+int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev)
+{
+ return hns_roce_bitmap_init(&hr_dev->pd_bitmap, hr_dev->caps.num_pds,
+ hr_dev->caps.num_pds - 1,
+ hr_dev->caps.reserved_pds, 0);
+}
+
+void hns_roce_cleanup_pd_table(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_bitmap_cleanup(&hr_dev->pd_bitmap);
+}
+
+struct ib_pd *hns_roce_alloc_pd(struct ib_device *ib_dev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_pd *pd;
+ int ret;
+
+ pd = kmalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ ret = hns_roce_pd_alloc(to_hr_dev(ib_dev), &pd->pdn);
+ if (ret) {
+ kfree(pd);
+ dev_err(dev, "[alloc_pd]hns_roce_pd_alloc failed!\n");
+ return ERR_PTR(ret);
+ }
+
+ if (context) {
+ if (ib_copy_to_udata(udata, &pd->pdn, sizeof(u64))) {
+ hns_roce_pd_free(to_hr_dev(ib_dev), pd->pdn);
+ dev_err(dev, "[alloc_pd]ib_copy_to_udata failed!\n");
+ kfree(pd);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ return &pd->ibpd;
+}
+
+int hns_roce_dealloc_pd(struct ib_pd *pd)
+{
+ hns_roce_pd_free(to_hr_dev(pd->device), to_hr_pd(pd)->pdn);
+ kfree(to_hr_pd(pd));
+
+ return 0;
+}
+
+int hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar)
+{
+ struct resource *res;
+ int ret = 0;
+
+ /* Using bitmap to manager UAR index */
+ ret = hns_roce_bitmap_alloc(&hr_dev->uar_table.bitmap, &uar->index);
+ if (ret == -1)
+ return -ENOMEM;
+
+ uar->index = (uar->index - 1) % hr_dev->caps.phy_num_uars + 1;
+
+ res = platform_get_resource(hr_dev->pdev, IORESOURCE_MEM, 0);
+ uar->pfn = ((res->start) >> PAGE_SHIFT) + uar->index;
+
+ return 0;
+}
+
+void hns_roce_uar_free(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar)
+{
+ hns_roce_bitmap_free(&hr_dev->uar_table.bitmap, uar->index);
+}
+
+int hns_roce_init_uar_table(struct hns_roce_dev *hr_dev)
+{
+ return hns_roce_bitmap_init(&hr_dev->uar_table.bitmap,
+ hr_dev->caps.num_uars,
+ hr_dev->caps.num_uars - 1,
+ hr_dev->caps.reserved_uars, 0);
+}
+
+void hns_roce_cleanup_uar_table(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_bitmap_cleanup(&hr_dev->uar_table.bitmap);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
new file mode 100644
index 000000000000..645c18d809a5
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -0,0 +1,855 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/platform_device.h>
+#include <rdma/ib_umem.h>
+#include "hns_roce_common.h"
+#include "hns_roce_device.h"
+#include "hns_roce_hem.h"
+#include "hns_roce_user.h"
+
+#define DB_REG_OFFSET 0x1000
+#define SQP_NUM 12
+
+void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_qp *qp;
+
+ spin_lock(&qp_table->lock);
+
+ qp = __hns_roce_qp_lookup(hr_dev, qpn);
+ if (qp)
+ atomic_inc(&qp->refcount);
+
+ spin_unlock(&qp_table->lock);
+
+ if (!qp) {
+ dev_warn(dev, "Async event for bogus QP %08x\n", qpn);
+ return;
+ }
+
+ qp->event(qp, (enum hns_roce_event)event_type);
+
+ if (atomic_dec_and_test(&qp->refcount))
+ complete(&qp->free);
+}
+
+static void hns_roce_ib_qp_event(struct hns_roce_qp *hr_qp,
+ enum hns_roce_event type)
+{
+ struct ib_event event;
+ struct ib_qp *ibqp = &hr_qp->ibqp;
+
+ if (ibqp->event_handler) {
+ event.device = ibqp->device;
+ event.element.qp = ibqp;
+ switch (type) {
+ case HNS_ROCE_EVENT_TYPE_PATH_MIG:
+ event.event = IB_EVENT_PATH_MIG;
+ break;
+ case HNS_ROCE_EVENT_TYPE_COMM_EST:
+ event.event = IB_EVENT_COMM_EST;
+ break;
+ case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
+ event.event = IB_EVENT_SQ_DRAINED;
+ break;
+ case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH:
+ event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ break;
+ case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
+ event.event = IB_EVENT_QP_FATAL;
+ break;
+ case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED:
+ event.event = IB_EVENT_PATH_MIG_ERR;
+ break;
+ case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
+ event.event = IB_EVENT_QP_REQ_ERR;
+ break;
+ case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
+ event.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+ default:
+ dev_dbg(ibqp->device->dma_device, "roce_ib: Unexpected event type %d on QP %06lx\n",
+ type, hr_qp->qpn);
+ return;
+ }
+ ibqp->event_handler(&event, ibqp->qp_context);
+ }
+}
+
+static int hns_roce_reserve_range_qp(struct hns_roce_dev *hr_dev, int cnt,
+ int align, unsigned long *base)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+ int ret = 0;
+ unsigned long qpn;
+
+ ret = hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align, &qpn);
+ if (ret == -1)
+ return -ENOMEM;
+
+ *base = qpn;
+
+ return 0;
+}
+
+enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state)
+{
+ switch (state) {
+ case IB_QPS_RESET:
+ return HNS_ROCE_QP_STATE_RST;
+ case IB_QPS_INIT:
+ return HNS_ROCE_QP_STATE_INIT;
+ case IB_QPS_RTR:
+ return HNS_ROCE_QP_STATE_RTR;
+ case IB_QPS_RTS:
+ return HNS_ROCE_QP_STATE_RTS;
+ case IB_QPS_SQD:
+ return HNS_ROCE_QP_STATE_SQD;
+ case IB_QPS_ERR:
+ return HNS_ROCE_QP_STATE_ERR;
+ default:
+ return HNS_ROCE_QP_NUM_STATE;
+ }
+}
+
+static int hns_roce_gsi_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
+ struct hns_roce_qp *hr_qp)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+ int ret;
+
+ if (!qpn)
+ return -EINVAL;
+
+ hr_qp->qpn = qpn;
+
+ spin_lock_irq(&qp_table->lock);
+ ret = radix_tree_insert(&hr_dev->qp_table_tree,
+ hr_qp->qpn & (hr_dev->caps.num_qps - 1), hr_qp);
+ spin_unlock_irq(&qp_table->lock);
+ if (ret) {
+ dev_err(&hr_dev->pdev->dev, "QPC radix_tree_insert failed\n");
+ goto err_put_irrl;
+ }
+
+ atomic_set(&hr_qp->refcount, 1);
+ init_completion(&hr_qp->free);
+
+ return 0;
+
+err_put_irrl:
+
+ return ret;
+}
+
+static int hns_roce_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
+ struct hns_roce_qp *hr_qp)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+ struct device *dev = &hr_dev->pdev->dev;
+ int ret;
+
+ if (!qpn)
+ return -EINVAL;
+
+ hr_qp->qpn = qpn;
+
+ /* Alloc memory for QPC */
+ ret = hns_roce_table_get(hr_dev, &qp_table->qp_table, hr_qp->qpn);
+ if (ret) {
+ dev_err(dev, "QPC table get failed\n");
+ goto err_out;
+ }
+
+ /* Alloc memory for IRRL */
+ ret = hns_roce_table_get(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
+ if (ret) {
+ dev_err(dev, "IRRL table get failed\n");
+ goto err_put_qp;
+ }
+
+ spin_lock_irq(&qp_table->lock);
+ ret = radix_tree_insert(&hr_dev->qp_table_tree,
+ hr_qp->qpn & (hr_dev->caps.num_qps - 1), hr_qp);
+ spin_unlock_irq(&qp_table->lock);
+ if (ret) {
+ dev_err(dev, "QPC radix_tree_insert failed\n");
+ goto err_put_irrl;
+ }
+
+ atomic_set(&hr_qp->refcount, 1);
+ init_completion(&hr_qp->free);
+
+ return 0;
+
+err_put_irrl:
+ hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
+
+err_put_qp:
+ hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn);
+
+err_out:
+ return ret;
+}
+
+void hns_roce_qp_remove(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp_table->lock, flags);
+ radix_tree_delete(&hr_dev->qp_table_tree,
+ hr_qp->qpn & (hr_dev->caps.num_qps - 1));
+ spin_unlock_irqrestore(&qp_table->lock, flags);
+}
+
+void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+
+ if (atomic_dec_and_test(&hr_qp->refcount))
+ complete(&hr_qp->free);
+ wait_for_completion(&hr_qp->free);
+
+ if ((hr_qp->ibqp.qp_type) != IB_QPT_GSI) {
+ hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
+ hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn);
+ }
+}
+
+void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
+ int cnt)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+
+ if (base_qpn < (hr_dev->caps.sqp_start + 2 * hr_dev->caps.num_ports))
+ return;
+
+ hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt);
+}
+
+static int hns_roce_set_rq_size(struct hns_roce_dev *hr_dev,
+ struct ib_qp_cap *cap, int is_user, int has_srq,
+ struct hns_roce_qp *hr_qp)
+{
+ u32 max_cnt;
+ struct device *dev = &hr_dev->pdev->dev;
+
+ /* Check the validity of QP support capacity */
+ if (cap->max_recv_wr > hr_dev->caps.max_wqes ||
+ cap->max_recv_sge > hr_dev->caps.max_rq_sg) {
+ dev_err(dev, "RQ WR or sge error!max_recv_wr=%d max_recv_sge=%d\n",
+ cap->max_recv_wr, cap->max_recv_sge);
+ return -EINVAL;
+ }
+
+ /* If srq exit, set zero for relative number of rq */
+ if (has_srq) {
+ if (cap->max_recv_wr) {
+ dev_dbg(dev, "srq no need config max_recv_wr\n");
+ return -EINVAL;
+ }
+
+ hr_qp->rq.wqe_cnt = hr_qp->rq.max_gs = 0;
+ } else {
+ if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge)) {
+ dev_err(dev, "user space no need config max_recv_wr max_recv_sge\n");
+ return -EINVAL;
+ }
+
+ /* In v1 engine, parameter verification procession */
+ max_cnt = cap->max_recv_wr > HNS_ROCE_MIN_WQE_NUM ?
+ cap->max_recv_wr : HNS_ROCE_MIN_WQE_NUM;
+ hr_qp->rq.wqe_cnt = roundup_pow_of_two(max_cnt);
+
+ if ((u32)hr_qp->rq.wqe_cnt > hr_dev->caps.max_wqes) {
+ dev_err(dev, "hns_roce_set_rq_size rq.wqe_cnt too large\n");
+ return -EINVAL;
+ }
+
+ max_cnt = max(1U, cap->max_recv_sge);
+ hr_qp->rq.max_gs = roundup_pow_of_two(max_cnt);
+ /* WQE is fixed for 64B */
+ hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz);
+ }
+
+ cap->max_recv_wr = hr_qp->rq.max_post = hr_qp->rq.wqe_cnt;
+ cap->max_recv_sge = hr_qp->rq.max_gs;
+
+ return 0;
+}
+
+static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
+ struct hns_roce_qp *hr_qp,
+ struct hns_roce_ib_create_qp *ucmd)
+{
+ u32 roundup_sq_stride = roundup_pow_of_two(hr_dev->caps.max_sq_desc_sz);
+ u8 max_sq_stride = ilog2(roundup_sq_stride);
+
+ /* Sanity check SQ size before proceeding */
+ if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
+ ucmd->log_sq_stride > max_sq_stride ||
+ ucmd->log_sq_stride < HNS_ROCE_IB_MIN_SQ_STRIDE) {
+ dev_err(&hr_dev->pdev->dev, "check SQ size error!\n");
+ return -EINVAL;
+ }
+
+ hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
+ hr_qp->sq.wqe_shift = ucmd->log_sq_stride;
+
+ /* Get buf size, SQ and RQ are aligned to page_szie */
+ hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
+ hr_qp->rq.wqe_shift), PAGE_SIZE) +
+ HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+ hr_qp->sq.wqe_shift), PAGE_SIZE);
+
+ hr_qp->sq.offset = 0;
+ hr_qp->rq.offset = HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+ hr_qp->sq.wqe_shift), PAGE_SIZE);
+
+ return 0;
+}
+
+static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
+ struct ib_qp_cap *cap,
+ enum ib_qp_type type,
+ struct hns_roce_qp *hr_qp)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ u32 max_cnt;
+ (void)type;
+
+ if (cap->max_send_wr > hr_dev->caps.max_wqes ||
+ cap->max_send_sge > hr_dev->caps.max_sq_sg ||
+ cap->max_inline_data > hr_dev->caps.max_sq_inline) {
+ dev_err(dev, "hns_roce_set_kernel_sq_size error1\n");
+ return -EINVAL;
+ }
+
+ hr_qp->sq.wqe_shift = ilog2(hr_dev->caps.max_sq_desc_sz);
+ hr_qp->sq_max_wqes_per_wr = 1;
+ hr_qp->sq_spare_wqes = 0;
+
+ /* In v1 engine, parameter verification procession */
+ max_cnt = cap->max_send_wr > HNS_ROCE_MIN_WQE_NUM ?
+ cap->max_send_wr : HNS_ROCE_MIN_WQE_NUM;
+ hr_qp->sq.wqe_cnt = roundup_pow_of_two(max_cnt);
+ if ((u32)hr_qp->sq.wqe_cnt > hr_dev->caps.max_wqes) {
+ dev_err(dev, "hns_roce_set_kernel_sq_size sq.wqe_cnt too large\n");
+ return -EINVAL;
+ }
+
+ /* Get data_seg numbers */
+ max_cnt = max(1U, cap->max_send_sge);
+ hr_qp->sq.max_gs = roundup_pow_of_two(max_cnt);
+
+ /* Get buf size, SQ and RQ are aligned to page_szie */
+ hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
+ hr_qp->rq.wqe_shift), PAGE_SIZE) +
+ HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+ hr_qp->sq.wqe_shift), PAGE_SIZE);
+ hr_qp->sq.offset = 0;
+ hr_qp->rq.offset = HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
+ hr_qp->sq.wqe_shift), PAGE_SIZE);
+
+ /* Get wr and sge number which send */
+ cap->max_send_wr = hr_qp->sq.max_post = hr_qp->sq.wqe_cnt;
+ cap->max_send_sge = hr_qp->sq.max_gs;
+
+ /* We don't support inline sends for kernel QPs (yet) */
+ cap->max_inline_data = 0;
+
+ return 0;
+}
+
+static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
+ struct ib_pd *ib_pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, unsigned long sqpn,
+ struct hns_roce_qp *hr_qp)
+{
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_ib_create_qp ucmd;
+ unsigned long qpn = 0;
+ int ret = 0;
+
+ mutex_init(&hr_qp->mutex);
+ spin_lock_init(&hr_qp->sq.lock);
+ spin_lock_init(&hr_qp->rq.lock);
+
+ hr_qp->state = IB_QPS_RESET;
+
+ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+ hr_qp->sq_signal_bits = IB_SIGNAL_ALL_WR;
+ else
+ hr_qp->sq_signal_bits = IB_SIGNAL_REQ_WR;
+
+ ret = hns_roce_set_rq_size(hr_dev, &init_attr->cap, !!ib_pd->uobject,
+ !!init_attr->srq, hr_qp);
+ if (ret) {
+ dev_err(dev, "hns_roce_set_rq_size failed\n");
+ goto err_out;
+ }
+
+ if (ib_pd->uobject) {
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+ dev_err(dev, "ib_copy_from_udata error for create qp\n");
+ ret = -EFAULT;
+ goto err_out;
+ }
+
+ ret = hns_roce_set_user_sq_size(hr_dev, hr_qp, &ucmd);
+ if (ret) {
+ dev_err(dev, "hns_roce_set_user_sq_size error for create qp\n");
+ goto err_out;
+ }
+
+ hr_qp->umem = ib_umem_get(ib_pd->uobject->context,
+ ucmd.buf_addr, hr_qp->buff_size, 0,
+ 0);
+ if (IS_ERR(hr_qp->umem)) {
+ dev_err(dev, "ib_umem_get error for create qp\n");
+ ret = PTR_ERR(hr_qp->umem);
+ goto err_out;
+ }
+
+ ret = hns_roce_mtt_init(hr_dev, ib_umem_page_count(hr_qp->umem),
+ ilog2((unsigned int)hr_qp->umem->page_size),
+ &hr_qp->mtt);
+ if (ret) {
+ dev_err(dev, "hns_roce_mtt_init error for create qp\n");
+ goto err_buf;
+ }
+
+ ret = hns_roce_ib_umem_write_mtt(hr_dev, &hr_qp->mtt,
+ hr_qp->umem);
+ if (ret) {
+ dev_err(dev, "hns_roce_ib_umem_write_mtt error for create qp\n");
+ goto err_mtt;
+ }
+ } else {
+ if (init_attr->create_flags &
+ IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
+ dev_err(dev, "init_attr->create_flags error!\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) {
+ dev_err(dev, "init_attr->create_flags error!\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ /* Set SQ size */
+ ret = hns_roce_set_kernel_sq_size(hr_dev, &init_attr->cap,
+ init_attr->qp_type, hr_qp);
+ if (ret) {
+ dev_err(dev, "hns_roce_set_kernel_sq_size error!\n");
+ goto err_out;
+ }
+
+ /* QP doorbell register address */
+ hr_qp->sq.db_reg_l = hr_dev->reg_base + ROCEE_DB_SQ_L_0_REG +
+ DB_REG_OFFSET * hr_dev->priv_uar.index;
+ hr_qp->rq.db_reg_l = hr_dev->reg_base +
+ ROCEE_DB_OTHERS_L_0_REG +
+ DB_REG_OFFSET * hr_dev->priv_uar.index;
+
+ /* Allocate QP buf */
+ if (hns_roce_buf_alloc(hr_dev, hr_qp->buff_size, PAGE_SIZE * 2,
+ &hr_qp->hr_buf)) {
+ dev_err(dev, "hns_roce_buf_alloc error!\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ /* Write MTT */
+ ret = hns_roce_mtt_init(hr_dev, hr_qp->hr_buf.npages,
+ hr_qp->hr_buf.page_shift, &hr_qp->mtt);
+ if (ret) {
+ dev_err(dev, "hns_roce_mtt_init error for kernel create qp\n");
+ goto err_buf;
+ }
+
+ ret = hns_roce_buf_write_mtt(hr_dev, &hr_qp->mtt,
+ &hr_qp->hr_buf);
+ if (ret) {
+ dev_err(dev, "hns_roce_buf_write_mtt error for kernel create qp\n");
+ goto err_mtt;
+ }
+
+ hr_qp->sq.wrid = kmalloc_array(hr_qp->sq.wqe_cnt, sizeof(u64),
+ GFP_KERNEL);
+ hr_qp->rq.wrid = kmalloc_array(hr_qp->rq.wqe_cnt, sizeof(u64),
+ GFP_KERNEL);
+ if (!hr_qp->sq.wrid || !hr_qp->rq.wrid) {
+ ret = -ENOMEM;
+ goto err_wrid;
+ }
+ }
+
+ if (sqpn) {
+ qpn = sqpn;
+ } else {
+ /* Get QPN */
+ ret = hns_roce_reserve_range_qp(hr_dev, 1, 1, &qpn);
+ if (ret) {
+ dev_err(dev, "hns_roce_reserve_range_qp alloc qpn error\n");
+ goto err_wrid;
+ }
+ }
+
+ if ((init_attr->qp_type) == IB_QPT_GSI) {
+ ret = hns_roce_gsi_qp_alloc(hr_dev, qpn, hr_qp);
+ if (ret) {
+ dev_err(dev, "hns_roce_qp_alloc failed!\n");
+ goto err_qpn;
+ }
+ } else {
+ ret = hns_roce_qp_alloc(hr_dev, qpn, hr_qp);
+ if (ret) {
+ dev_err(dev, "hns_roce_qp_alloc failed!\n");
+ goto err_qpn;
+ }
+ }
+
+ if (sqpn)
+ hr_qp->doorbell_qpn = 1;
+ else
+ hr_qp->doorbell_qpn = cpu_to_le64(hr_qp->qpn);
+
+ hr_qp->event = hns_roce_ib_qp_event;
+
+ return 0;
+
+err_qpn:
+ if (!sqpn)
+ hns_roce_release_range_qp(hr_dev, qpn, 1);
+
+err_wrid:
+ kfree(hr_qp->sq.wrid);
+ kfree(hr_qp->rq.wrid);
+
+err_mtt:
+ hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
+
+err_buf:
+ if (ib_pd->uobject)
+ ib_umem_release(hr_qp->umem);
+ else
+ hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
+
+err_out:
+ return ret;
+}
+
+struct ib_qp *hns_roce_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
+ struct device *dev = &hr_dev->pdev->dev;
+ struct hns_roce_sqp *hr_sqp;
+ struct hns_roce_qp *hr_qp;
+ int ret;
+
+ switch (init_attr->qp_type) {
+ case IB_QPT_RC: {
+ hr_qp = kzalloc(sizeof(*hr_qp), GFP_KERNEL);
+ if (!hr_qp)
+ return ERR_PTR(-ENOMEM);
+
+ ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata, 0,
+ hr_qp);
+ if (ret) {
+ dev_err(dev, "Create RC QP failed\n");
+ kfree(hr_qp);
+ return ERR_PTR(ret);
+ }
+
+ hr_qp->ibqp.qp_num = hr_qp->qpn;
+
+ break;
+ }
+ case IB_QPT_GSI: {
+ /* Userspace is not allowed to create special QPs: */
+ if (pd->uobject) {
+ dev_err(dev, "not support usr space GSI\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ hr_sqp = kzalloc(sizeof(*hr_sqp), GFP_KERNEL);
+ if (!hr_sqp)
+ return ERR_PTR(-ENOMEM);
+
+ hr_qp = &hr_sqp->hr_qp;
+
+ ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata,
+ hr_dev->caps.sqp_start +
+ hr_dev->caps.num_ports +
+ init_attr->port_num - 1, hr_qp);
+ if (ret) {
+ dev_err(dev, "Create GSI QP failed!\n");
+ kfree(hr_sqp);
+ return ERR_PTR(ret);
+ }
+
+ hr_qp->port = (init_attr->port_num - 1);
+ hr_qp->ibqp.qp_num = hr_dev->caps.sqp_start +
+ hr_dev->caps.num_ports +
+ init_attr->port_num - 1;
+ break;
+ }
+ default:{
+ dev_err(dev, "not support QP type %d\n", init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ return &hr_qp->ibqp;
+}
+
+int to_hr_qp_type(int qp_type)
+{
+ int transport_type;
+
+ if (qp_type == IB_QPT_RC)
+ transport_type = SERV_TYPE_RC;
+ else if (qp_type == IB_QPT_UC)
+ transport_type = SERV_TYPE_UC;
+ else if (qp_type == IB_QPT_UD)
+ transport_type = SERV_TYPE_UD;
+ else if (qp_type == IB_QPT_GSI)
+ transport_type = SERV_TYPE_UD;
+ else
+ transport_type = -1;
+
+ return transport_type;
+}
+
+int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+ enum ib_qp_state cur_state, new_state;
+ struct device *dev = &hr_dev->pdev->dev;
+ int ret = -EINVAL;
+ int p;
+
+ mutex_lock(&hr_qp->mutex);
+
+ cur_state = attr_mask & IB_QP_CUR_STATE ?
+ attr->cur_qp_state : (enum ib_qp_state)hr_qp->state;
+ new_state = attr_mask & IB_QP_STATE ?
+ attr->qp_state : cur_state;
+
+ if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask,
+ IB_LINK_LAYER_ETHERNET)) {
+ dev_err(dev, "ib_modify_qp_is_ok failed\n");
+ goto out;
+ }
+
+ if ((attr_mask & IB_QP_PORT) &&
+ (attr->port_num == 0 || attr->port_num > hr_dev->caps.num_ports)) {
+ dev_err(dev, "attr port_num invalid.attr->port_num=%d\n",
+ attr->port_num);
+ goto out;
+ }
+
+ if (attr_mask & IB_QP_PKEY_INDEX) {
+ p = attr_mask & IB_QP_PORT ? (attr->port_num - 1) : hr_qp->port;
+ if (attr->pkey_index >= hr_dev->caps.pkey_table_len[p]) {
+ dev_err(dev, "attr pkey_index invalid.attr->pkey_index=%d\n",
+ attr->pkey_index);
+ goto out;
+ }
+ }
+
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+ attr->max_rd_atomic > hr_dev->caps.max_qp_init_rdma) {
+ dev_err(dev, "attr max_rd_atomic invalid.attr->max_rd_atomic=%d\n",
+ attr->max_rd_atomic);
+ goto out;
+ }
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+ attr->max_dest_rd_atomic > hr_dev->caps.max_qp_dest_rdma) {
+ dev_err(dev, "attr max_dest_rd_atomic invalid.attr->max_dest_rd_atomic=%d\n",
+ attr->max_dest_rd_atomic);
+ goto out;
+ }
+
+ if (cur_state == new_state && cur_state == IB_QPS_RESET) {
+ ret = -EPERM;
+ dev_err(dev, "cur_state=%d new_state=%d\n", cur_state,
+ new_state);
+ goto out;
+ }
+
+ ret = hr_dev->hw->modify_qp(ibqp, attr, attr_mask, cur_state,
+ new_state);
+
+out:
+ mutex_unlock(&hr_qp->mutex);
+
+ return ret;
+}
+
+void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
+ __acquires(&send_cq->lock) __acquires(&recv_cq->lock)
+{
+ if (send_cq == recv_cq) {
+ spin_lock_irq(&send_cq->lock);
+ __acquire(&recv_cq->lock);
+ } else if (send_cq->cqn < recv_cq->cqn) {
+ spin_lock_irq(&send_cq->lock);
+ spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
+ } else {
+ spin_lock_irq(&recv_cq->lock);
+ spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
+ }
+}
+
+void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq,
+ struct hns_roce_cq *recv_cq) __releases(&send_cq->lock)
+ __releases(&recv_cq->lock)
+{
+ if (send_cq == recv_cq) {
+ __release(&recv_cq->lock);
+ spin_unlock_irq(&send_cq->lock);
+ } else if (send_cq->cqn < recv_cq->cqn) {
+ spin_unlock(&recv_cq->lock);
+ spin_unlock_irq(&send_cq->lock);
+ } else {
+ spin_unlock(&send_cq->lock);
+ spin_unlock_irq(&recv_cq->lock);
+ }
+}
+
+__be32 send_ieth(struct ib_send_wr *wr)
+{
+ switch (wr->opcode) {
+ case IB_WR_SEND_WITH_IMM:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ return cpu_to_le32(wr->ex.imm_data);
+ case IB_WR_SEND_WITH_INV:
+ return cpu_to_le32(wr->ex.invalidate_rkey);
+ default:
+ return 0;
+ }
+}
+
+static void *get_wqe(struct hns_roce_qp *hr_qp, int offset)
+{
+
+ return hns_roce_buf_offset(&hr_qp->hr_buf, offset);
+}
+
+void *get_recv_wqe(struct hns_roce_qp *hr_qp, int n)
+{
+ struct ib_qp *ibqp = &hr_qp->ibqp;
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+
+ if ((n < 0) || (n > hr_qp->rq.wqe_cnt)) {
+ dev_err(&hr_dev->pdev->dev, "rq wqe index:%d,rq wqe cnt:%d\r\n",
+ n, hr_qp->rq.wqe_cnt);
+ return NULL;
+ }
+
+ return get_wqe(hr_qp, hr_qp->rq.offset + (n << hr_qp->rq.wqe_shift));
+}
+
+void *get_send_wqe(struct hns_roce_qp *hr_qp, int n)
+{
+ struct ib_qp *ibqp = &hr_qp->ibqp;
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
+
+ if ((n < 0) || (n > hr_qp->sq.wqe_cnt)) {
+ dev_err(&hr_dev->pdev->dev, "sq wqe index:%d,sq wqe cnt:%d\r\n",
+ n, hr_qp->sq.wqe_cnt);
+ return NULL;
+ }
+
+ return get_wqe(hr_qp, hr_qp->sq.offset + (n << hr_qp->sq.wqe_shift));
+}
+
+bool hns_roce_wq_overflow(struct hns_roce_wq *hr_wq, int nreq,
+ struct ib_cq *ib_cq)
+{
+ struct hns_roce_cq *hr_cq;
+ u32 cur;
+
+ cur = hr_wq->head - hr_wq->tail;
+ if (likely(cur + nreq < hr_wq->max_post))
+ return 0;
+
+ hr_cq = to_hr_cq(ib_cq);
+ spin_lock(&hr_cq->lock);
+ cur = hr_wq->head - hr_wq->tail;
+ spin_unlock(&hr_cq->lock);
+
+ return cur + nreq >= hr_wq->max_post;
+}
+
+int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
+ int reserved_from_top = 0;
+ int ret;
+
+ spin_lock_init(&qp_table->lock);
+ INIT_RADIX_TREE(&hr_dev->qp_table_tree, GFP_ATOMIC);
+
+ /* A port include two SQP, six port total 12 */
+ ret = hns_roce_bitmap_init(&qp_table->bitmap, hr_dev->caps.num_qps,
+ hr_dev->caps.num_qps - 1,
+ hr_dev->caps.sqp_start + SQP_NUM,
+ reserved_from_top);
+ if (ret) {
+ dev_err(&hr_dev->pdev->dev, "qp bitmap init failed!error=%d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev)
+{
+ hns_roce_bitmap_cleanup(&hr_dev->qp_table.bitmap);
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_user.h b/drivers/infiniband/hw/hns/hns_roce_user.h
new file mode 100644
index 000000000000..a28f761a9f65
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_user.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _HNS_ROCE_USER_H
+#define _HNS_ROCE_USER_H
+
+struct hns_roce_ib_create_cq {
+ __u64 buf_addr;
+};
+
+struct hns_roce_ib_create_qp {
+ __u64 buf_addr;
+ __u64 db_addr;
+ __u8 log_sq_bb_count;
+ __u8 log_sq_stride;
+ __u8 sq_no_prefetch;
+ __u8 reserved[5];
+};
+
+struct hns_roce_ib_alloc_ucontext_resp {
+ __u32 qp_tab_size;
+};
+
+#endif /*_HNS_ROCE_USER_H */
diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c
index 7ca0638579c0..85637696f6e9 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_cm.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c
@@ -3166,8 +3166,11 @@ void i40iw_setup_cm_core(struct i40iw_device *iwdev)
spin_lock_init(&cm_core->ht_lock);
spin_lock_init(&cm_core->listen_list_lock);
- cm_core->event_wq = create_singlethread_workqueue("iwewq");
- cm_core->disconn_wq = create_singlethread_workqueue("iwdwq");
+ cm_core->event_wq = alloc_ordered_workqueue("iwewq",
+ WQ_MEM_RECLAIM);
+
+ cm_core->disconn_wq = alloc_ordered_workqueue("iwdwq",
+ WQ_MEM_RECLAIM);
}
/**
diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c
index 445e230d5ff8..ac2f3cd9478c 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_main.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_main.c
@@ -1615,7 +1615,7 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client)
status = i40iw_hmc_init_pble(&iwdev->sc_dev, iwdev->pble_rsrc);
if (status)
break;
- iwdev->virtchnl_wq = create_singlethread_workqueue("iwvch");
+ iwdev->virtchnl_wq = alloc_ordered_workqueue("iwvch", WQ_MEM_RECLAIM);
i40iw_register_notifiers();
iwdev->init_state = INET_NOTIFIER;
status = i40iw_add_mac_ip(iwdev);
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index c74ef2620b85..5e9939045852 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -881,7 +881,7 @@ int mlx4_ib_init_alias_guid_service(struct mlx4_ib_dev *dev)
snprintf(alias_wq_name, sizeof alias_wq_name, "alias_guid%d", i);
dev->sriov.alias_guid.ports_guid[i].wq =
- create_singlethread_workqueue(alias_wq_name);
+ alloc_ordered_workqueue(alias_wq_name, WQ_MEM_RECLAIM);
if (!dev->sriov.alias_guid.ports_guid[i].wq) {
ret = -ENOMEM;
goto err_thread;
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 5df63dacaaa3..1ea686b9e0f9 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -37,7 +37,7 @@
#include <linux/slab.h>
#include "mlx4_ib.h"
-#include "user.h"
+#include <rdma/mlx4-abi.h>
static void mlx4_ib_cq_comp(struct mlx4_cq *cq)
{
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 0f21c3a25552..1672907ff219 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -230,6 +230,8 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
mad->mad_hdr.method == IB_MGMT_METHOD_SET)
switch (mad->mad_hdr.attr_id) {
case IB_SMP_ATTR_PORT_INFO:
+ if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
+ return;
pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data;
lid = be16_to_cpu(pinfo->lid);
@@ -245,6 +247,8 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
break;
case IB_SMP_ATTR_PKEY_TABLE:
+ if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
+ return;
if (!mlx4_is_mfunc(dev->dev)) {
mlx4_ib_dispatch_event(dev, port_num,
IB_EVENT_PKEY_CHANGE);
@@ -281,6 +285,8 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
break;
case IB_SMP_ATTR_GUID_INFO:
+ if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
+ return;
/* paravirtualized master's guid is guid 0 -- does not change */
if (!mlx4_is_master(dev->dev))
mlx4_ib_dispatch_event(dev, port_num,
@@ -296,6 +302,26 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad
}
break;
+ case IB_SMP_ATTR_SL_TO_VL_TABLE:
+ /* cache sl to vl mapping changes for use in
+ * filling QP1 LRH VL field when sending packets
+ */
+ if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV &&
+ dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT)
+ return;
+ if (!mlx4_is_slave(dev->dev)) {
+ union sl2vl_tbl_to_u64 sl2vl64;
+ int jj;
+
+ for (jj = 0; jj < 8; jj++) {
+ sl2vl64.sl8[jj] = ((struct ib_smp *)mad)->data[jj];
+ pr_debug("port %u, sl2vl[%d] = %02x\n",
+ port_num, jj, sl2vl64.sl8[jj]);
+ }
+ atomic64_set(&dev->sl2vl[port_num - 1], sl2vl64.sl64);
+ }
+ break;
+
default:
break;
}
@@ -345,7 +371,8 @@ static void node_desc_override(struct ib_device *dev,
mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags);
- memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+ memcpy(((struct ib_smp *) mad)->data, dev->node_desc,
+ IB_DEVICE_NODE_DESC_MAX);
spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags);
}
}
@@ -805,8 +832,7 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
return IB_MAD_RESULT_FAILURE;
if (!out_mad->mad_hdr.status) {
- if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV))
- smp_snoop(ibdev, port_num, in_mad, prev_lid);
+ smp_snoop(ibdev, port_num, in_mad, prev_lid);
/* slaves get node desc from FW */
if (!mlx4_is_slave(to_mdev(ibdev)->dev))
node_desc_override(ibdev, out_mad);
@@ -1037,6 +1063,23 @@ static void handle_client_rereg_event(struct mlx4_ib_dev *dev, u8 port_num)
MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK);
}
}
+
+ /* Update the sl to vl table from inside client rereg
+ * only if in secure-host mode (snooping is not possible)
+ * and the sl-to-vl change event is not generated by FW.
+ */
+ if (!mlx4_is_slave(dev->dev) &&
+ dev->dev->flags & MLX4_FLAG_SECURE_HOST &&
+ !(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT)) {
+ if (mlx4_is_master(dev->dev))
+ /* already in work queue from mlx4_ib_event queueing
+ * mlx4_handle_port_mgmt_change_event, which calls
+ * this procedure. Therefore, call sl2vl_update directly.
+ */
+ mlx4_ib_sl2vl_update(dev, port_num);
+ else
+ mlx4_sched_ib_sl2vl_update_work(dev, port_num);
+ }
mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_CLIENT_REREGISTER);
}
@@ -1176,6 +1219,24 @@ void handle_port_mgmt_change_event(struct work_struct *work)
handle_slaves_guid_change(dev, port, tbl_block, change_bitmap);
}
break;
+
+ case MLX4_DEV_PMC_SUBTYPE_SL_TO_VL_MAP:
+ /* cache sl to vl mapping changes for use in
+ * filling QP1 LRH VL field when sending packets
+ */
+ if (!mlx4_is_slave(dev->dev)) {
+ union sl2vl_tbl_to_u64 sl2vl64;
+ int jj;
+
+ for (jj = 0; jj < 8; jj++) {
+ sl2vl64.sl8[jj] =
+ eqe->event.port_mgmt_change.params.sl2vl_tbl_change_info.sl2vl_table[jj];
+ pr_debug("port %u, sl2vl[%d] = %02x\n",
+ port, jj, sl2vl64.sl8[jj]);
+ }
+ atomic64_set(&dev->sl2vl[port - 1], sl2vl64.sl64);
+ }
+ break;
default:
pr_warn("Unsupported subtype 0x%x for "
"Port Management Change event\n", eqe->subtype);
@@ -1918,7 +1979,7 @@ static int create_pv_resources(struct ib_device *ibdev, int slave, int port,
goto err_buf;
}
- ctx->pd = ib_alloc_pd(ctx->ib_dev);
+ ctx->pd = ib_alloc_pd(ctx->ib_dev, 0);
if (IS_ERR(ctx->pd)) {
ret = PTR_ERR(ctx->pd);
pr_err("Couldn't create tunnel PD (%d)\n", ret);
@@ -2091,7 +2152,7 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
}
snprintf(name, sizeof name, "mlx4_ibt%d", port);
- ctx->wq = create_singlethread_workqueue(name);
+ ctx->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
if (!ctx->wq) {
pr_err("Failed to create tunnelling WQ for port %d\n", port);
ret = -ENOMEM;
@@ -2099,7 +2160,7 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
}
snprintf(name, sizeof name, "mlx4_ibud%d", port);
- ctx->ud_wq = create_singlethread_workqueue(name);
+ ctx->ud_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
if (!ctx->ud_wq) {
pr_err("Failed to create up/down WQ for port %d\n", port);
ret = -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 87ba9bca4181..b597e8227591 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -55,7 +55,7 @@
#include <linux/mlx4/qp.h>
#include "mlx4_ib.h"
-#include "user.h"
+#include <rdma/mlx4-abi.h>
#define DRV_NAME MLX4_IB_DRV_NAME
#define DRV_VERSION "2.2-1"
@@ -832,6 +832,66 @@ static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
return ret;
}
+static int mlx4_ib_query_sl2vl(struct ib_device *ibdev, u8 port, u64 *sl2vl_tbl)
+{
+ union sl2vl_tbl_to_u64 sl2vl64;
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS;
+ int err = -ENOMEM;
+ int jj;
+
+ if (mlx4_is_slave(to_mdev(ibdev)->dev)) {
+ *sl2vl_tbl = 0;
+ return 0;
+ }
+
+ in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+ out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_SL_TO_VL_TABLE;
+ in_mad->attr_mod = 0;
+
+ if (mlx4_is_mfunc(to_mdev(ibdev)->dev))
+ mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW;
+
+ err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, NULL, NULL,
+ in_mad, out_mad);
+ if (err)
+ goto out;
+
+ for (jj = 0; jj < 8; jj++)
+ sl2vl64.sl8[jj] = ((struct ib_smp *)out_mad)->data[jj];
+ *sl2vl_tbl = sl2vl64.sl64;
+
+out:
+ kfree(in_mad);
+ kfree(out_mad);
+ return err;
+}
+
+static void mlx4_init_sl2vl_tbl(struct mlx4_ib_dev *mdev)
+{
+ u64 sl2vl;
+ int i;
+ int err;
+
+ for (i = 1; i <= mdev->dev->caps.num_ports; i++) {
+ if (mdev->dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH)
+ continue;
+ err = mlx4_ib_query_sl2vl(&mdev->ib_dev, i, &sl2vl);
+ if (err) {
+ pr_err("Unable to get default sl to vl mapping for port %d. Using all zeroes (%d)\n",
+ i, err);
+ sl2vl = 0;
+ }
+ atomic64_set(&mdev->sl2vl[i - 1], sl2vl);
+ }
+}
+
int __mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
u16 *pkey, int netw_view)
{
@@ -886,7 +946,7 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
return -EOPNOTSUPP;
spin_lock_irqsave(&to_mdev(ibdev)->sm_lock, flags);
- memcpy(ibdev->node_desc, props->node_desc, 64);
+ memcpy(ibdev->node_desc, props->node_desc, IB_DEVICE_NODE_DESC_MAX);
spin_unlock_irqrestore(&to_mdev(ibdev)->sm_lock, flags);
/*
@@ -897,7 +957,7 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
if (IS_ERR(mailbox))
return 0;
- memcpy(mailbox->buf, props->node_desc, 64);
+ memcpy(mailbox->buf, props->node_desc, IB_DEVICE_NODE_DESC_MAX);
mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
@@ -1259,7 +1319,7 @@ static struct ib_xrcd *mlx4_ib_alloc_xrcd(struct ib_device *ibdev,
if (err)
goto err1;
- xrcd->pd = ib_alloc_pd(ibdev);
+ xrcd->pd = ib_alloc_pd(ibdev, 0);
if (IS_ERR(xrcd->pd)) {
err = PTR_ERR(xrcd->pd);
goto err2;
@@ -1361,6 +1421,19 @@ struct mlx4_ib_steering {
union ib_gid gid;
};
+#define LAST_ETH_FIELD vlan_tag
+#define LAST_IB_FIELD sl
+#define LAST_IPV4_FIELD dst_ip
+#define LAST_TCP_UDP_FIELD src_port
+
+/* Field is the last supported field */
+#define FIELDS_NOT_SUPPORTED(filter, field)\
+ memchr_inv((void *)&filter.field +\
+ sizeof(filter.field), 0,\
+ sizeof(filter) -\
+ offsetof(typeof(filter), field) -\
+ sizeof(filter.field))
+
static int parse_flow_attr(struct mlx4_dev *dev,
u32 qp_num,
union ib_flow_spec *ib_spec,
@@ -1370,6 +1443,9 @@ static int parse_flow_attr(struct mlx4_dev *dev,
switch (ib_spec->type) {
case IB_FLOW_SPEC_ETH:
+ if (FIELDS_NOT_SUPPORTED(ib_spec->eth.mask, LAST_ETH_FIELD))
+ return -ENOTSUPP;
+
type = MLX4_NET_TRANS_RULE_ID_ETH;
memcpy(mlx4_spec->eth.dst_mac, ib_spec->eth.val.dst_mac,
ETH_ALEN);
@@ -1379,6 +1455,9 @@ static int parse_flow_attr(struct mlx4_dev *dev,
mlx4_spec->eth.vlan_tag_msk = ib_spec->eth.mask.vlan_tag;
break;
case IB_FLOW_SPEC_IB:
+ if (FIELDS_NOT_SUPPORTED(ib_spec->ib.mask, LAST_IB_FIELD))
+ return -ENOTSUPP;
+
type = MLX4_NET_TRANS_RULE_ID_IB;
mlx4_spec->ib.l3_qpn =
cpu_to_be32(qp_num);
@@ -1388,6 +1467,9 @@ static int parse_flow_attr(struct mlx4_dev *dev,
case IB_FLOW_SPEC_IPV4:
+ if (FIELDS_NOT_SUPPORTED(ib_spec->ipv4.mask, LAST_IPV4_FIELD))
+ return -ENOTSUPP;
+
type = MLX4_NET_TRANS_RULE_ID_IPV4;
mlx4_spec->ipv4.src_ip = ib_spec->ipv4.val.src_ip;
mlx4_spec->ipv4.src_ip_msk = ib_spec->ipv4.mask.src_ip;
@@ -1397,6 +1479,9 @@ static int parse_flow_attr(struct mlx4_dev *dev,
case IB_FLOW_SPEC_TCP:
case IB_FLOW_SPEC_UDP:
+ if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask, LAST_TCP_UDP_FIELD))
+ return -ENOTSUPP;
+
type = ib_spec->type == IB_FLOW_SPEC_TCP ?
MLX4_NET_TRANS_RULE_ID_TCP :
MLX4_NET_TRANS_RULE_ID_UDP;
@@ -2000,7 +2085,7 @@ static int init_node_data(struct mlx4_ib_dev *dev)
if (err)
goto out;
- memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+ memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX);
in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
@@ -2653,6 +2738,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (init_node_data(ibdev))
goto err_map;
+ mlx4_init_sl2vl_tbl(ibdev);
for (i = 0; i < ibdev->num_ports; ++i) {
mutex_init(&ibdev->counters_table[i].mutex);
@@ -3101,6 +3187,47 @@ static void handle_bonded_port_state_event(struct work_struct *work)
ib_dispatch_event(&ibev);
}
+void mlx4_ib_sl2vl_update(struct mlx4_ib_dev *mdev, int port)
+{
+ u64 sl2vl;
+ int err;
+
+ err = mlx4_ib_query_sl2vl(&mdev->ib_dev, port, &sl2vl);
+ if (err) {
+ pr_err("Unable to get current sl to vl mapping for port %d. Using all zeroes (%d)\n",
+ port, err);
+ sl2vl = 0;
+ }
+ atomic64_set(&mdev->sl2vl[port - 1], sl2vl);
+}
+
+static void ib_sl2vl_update_work(struct work_struct *work)
+{
+ struct ib_event_work *ew = container_of(work, struct ib_event_work, work);
+ struct mlx4_ib_dev *mdev = ew->ib_dev;
+ int port = ew->port;
+
+ mlx4_ib_sl2vl_update(mdev, port);
+
+ kfree(ew);
+}
+
+void mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev,
+ int port)
+{
+ struct ib_event_work *ew;
+
+ ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
+ if (ew) {
+ INIT_WORK(&ew->work, ib_sl2vl_update_work);
+ ew->port = port;
+ ew->ib_dev = ibdev;
+ queue_work(wq, &ew->work);
+ } else {
+ pr_err("failed to allocate memory for sl2vl update work\n");
+ }
+}
+
static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
enum mlx4_dev_event event, unsigned long param)
{
@@ -3131,10 +3258,14 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
case MLX4_DEV_EVENT_PORT_UP:
if (p > ibdev->num_ports)
return;
- if (mlx4_is_master(dev) &&
+ if (!mlx4_is_slave(dev) &&
rdma_port_get_link_layer(&ibdev->ib_dev, p) ==
IB_LINK_LAYER_INFINIBAND) {
- mlx4_ib_invalidate_all_guid_record(ibdev, p);
+ if (mlx4_is_master(dev))
+ mlx4_ib_invalidate_all_guid_record(ibdev, p);
+ if (ibdev->dev->flags & MLX4_FLAG_SECURE_HOST &&
+ !(ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT))
+ mlx4_sched_ib_sl2vl_update_work(ibdev, p);
}
ibev.event = IB_EVENT_PORT_ACTIVE;
break;
@@ -3222,7 +3353,7 @@ static int __init mlx4_ib_init(void)
{
int err;
- wq = create_singlethread_workqueue("mlx4_ib");
+ wq = alloc_ordered_workqueue("mlx4_ib", WQ_MEM_RECLAIM);
if (!wq)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index 097bfcc4ee99..a21d37f02f35 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -1045,7 +1045,7 @@ int mlx4_ib_mcg_port_init(struct mlx4_ib_demux_ctx *ctx)
atomic_set(&ctx->tid, 0);
sprintf(name, "mlx4_ib_mcg%d", ctx->port);
- ctx->mcg_wq = create_singlethread_workqueue(name);
+ ctx->mcg_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
if (!ctx->mcg_wq)
return -ENOMEM;
@@ -1246,7 +1246,7 @@ void clean_vf_mcast(struct mlx4_ib_demux_ctx *ctx, int slave)
int mlx4_ib_mcg_init(void)
{
- clean_wq = create_singlethread_workqueue("mlx4_ib_mcg");
+ clean_wq = alloc_ordered_workqueue("mlx4_ib_mcg", WQ_MEM_RECLAIM);
if (!clean_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 686ab48ff644..35141f451e5c 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -570,6 +570,7 @@ struct mlx4_ib_dev {
struct ib_mad_agent *send_agent[MLX4_MAX_PORTS][2];
struct ib_ah *sm_ah[MLX4_MAX_PORTS];
spinlock_t sm_lock;
+ atomic64_t sl2vl[MLX4_MAX_PORTS];
struct mlx4_ib_sriov sriov;
struct mutex cap_mask_mutex;
@@ -600,6 +601,7 @@ struct ib_event_work {
struct work_struct work;
struct mlx4_ib_dev *ib_dev;
struct mlx4_eqe ib_eqe;
+ int port;
};
struct mlx4_ib_qp_tunnel_init_attr {
@@ -883,4 +885,9 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
int mlx4_ib_gid_index_to_real_index(struct mlx4_ib_dev *ibdev,
u8 port_num, int index);
+void mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev,
+ int port);
+
+void mlx4_ib_sl2vl_update(struct mlx4_ib_dev *mdev, int port);
+
#endif /* MLX4_IB_H */
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 7fb9629bd12b..570bc866b1d6 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -47,7 +47,7 @@
#include <linux/mlx4/qp.h>
#include "mlx4_ib.h"
-#include "user.h"
+#include <rdma/mlx4-abi.h>
static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq,
struct mlx4_ib_cq *recv_cq);
@@ -2405,6 +2405,22 @@ static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp,
return 0;
}
+static u8 sl_to_vl(struct mlx4_ib_dev *dev, u8 sl, int port_num)
+{
+ union sl2vl_tbl_to_u64 tmp_vltab;
+ u8 vl;
+
+ if (sl > 15)
+ return 0xf;
+ tmp_vltab.sl64 = atomic64_read(&dev->sl2vl[port_num - 1]);
+ vl = tmp_vltab.sl8[sl >> 1];
+ if (sl & 1)
+ vl &= 0x0f;
+ else
+ vl >>= 4;
+ return vl;
+}
+
#define MLX4_ROCEV2_QP1_SPORT 0xC000
static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_ud_wr *wr,
void *wqe, unsigned *mlx_seg_len)
@@ -2590,7 +2606,12 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_ud_wr *wr,
sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp);
}
} else {
- sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0;
+ sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 :
+ sl_to_vl(to_mdev(ib_dev),
+ sqp->ud_header.lrh.service_level,
+ sqp->qp.port);
+ if (sqp->qp.ibqp.qp_num && sqp->ud_header.lrh.virtual_lane == 15)
+ return -EINVAL;
if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
}
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 0597f3eef5d0..7dd3f267f06b 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -37,7 +37,7 @@
#include <linux/vmalloc.h>
#include "mlx4_ib.h"
-#include "user.h"
+#include <rdma/mlx4-abi.h>
static void *get_wqe(struct mlx4_ib_srq *srq, int n)
{
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 5de9a65f53bc..79d017baf6f4 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -35,7 +35,6 @@
#include <rdma/ib_user_verbs.h>
#include <rdma/ib_cache.h>
#include "mlx5_ib.h"
-#include "user.h"
static void mlx5_ib_cq_comp(struct mlx5_core_cq *cq)
{
diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c
index 364aab9f3c9e..39e58489dcc2 100644
--- a/drivers/infiniband/hw/mlx5/mad.c
+++ b/drivers/infiniband/hw/mlx5/mad.c
@@ -394,7 +394,7 @@ int mlx5_query_mad_ifc_node_desc(struct mlx5_ib_dev *dev, char *node_desc)
if (err)
goto out;
- memcpy(node_desc, out_mad->data, 64);
+ memcpy(node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX);
out:
kfree(in_mad);
kfree(out_mad);
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 551aa0e789aa..22174774dbb8 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -53,7 +53,6 @@
#include <linux/in.h>
#include <linux/etherdevice.h>
#include <linux/mlx5/fs.h>
-#include "user.h"
#include "mlx5_ib.h"
#define DRIVER_NAME "mlx5_ib"
@@ -106,13 +105,42 @@ static int mlx5_netdev_event(struct notifier_block *this,
struct mlx5_ib_dev *ibdev = container_of(this, struct mlx5_ib_dev,
roce.nb);
- if ((event != NETDEV_UNREGISTER) && (event != NETDEV_REGISTER))
- return NOTIFY_DONE;
+ switch (event) {
+ case NETDEV_REGISTER:
+ case NETDEV_UNREGISTER:
+ write_lock(&ibdev->roce.netdev_lock);
+ if (ndev->dev.parent == &ibdev->mdev->pdev->dev)
+ ibdev->roce.netdev = (event == NETDEV_UNREGISTER) ?
+ NULL : ndev;
+ write_unlock(&ibdev->roce.netdev_lock);
+ break;
+
+ case NETDEV_UP:
+ case NETDEV_DOWN: {
+ struct net_device *lag_ndev = mlx5_lag_get_roce_netdev(ibdev->mdev);
+ struct net_device *upper = NULL;
+
+ if (lag_ndev) {
+ upper = netdev_master_upper_dev_get(lag_ndev);
+ dev_put(lag_ndev);
+ }
+
+ if ((upper == ndev || (!upper && ndev == ibdev->roce.netdev))
+ && ibdev->ib_active) {
+ struct ib_event ibev = {0};
+
+ ibev.device = &ibdev->ib_dev;
+ ibev.event = (event == NETDEV_UP) ?
+ IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
+ ibev.element.port_num = 1;
+ ib_dispatch_event(&ibev);
+ }
+ break;
+ }
- write_lock(&ibdev->roce.netdev_lock);
- if (ndev->dev.parent == &ibdev->mdev->pdev->dev)
- ibdev->roce.netdev = (event == NETDEV_UNREGISTER) ? NULL : ndev;
- write_unlock(&ibdev->roce.netdev_lock);
+ default:
+ break;
+ }
return NOTIFY_DONE;
}
@@ -123,6 +151,10 @@ static struct net_device *mlx5_ib_get_netdev(struct ib_device *device,
struct mlx5_ib_dev *ibdev = to_mdev(device);
struct net_device *ndev;
+ ndev = mlx5_lag_get_roce_netdev(ibdev->mdev);
+ if (ndev)
+ return ndev;
+
/* Ensure ndev does not disappear before we invoke dev_hold()
*/
read_lock(&ibdev->roce.netdev_lock);
@@ -138,7 +170,7 @@ static int mlx5_query_port_roce(struct ib_device *device, u8 port_num,
struct ib_port_attr *props)
{
struct mlx5_ib_dev *dev = to_mdev(device);
- struct net_device *ndev;
+ struct net_device *ndev, *upper;
enum ib_mtu ndev_ib_mtu;
u16 qkey_viol_cntr;
@@ -162,6 +194,17 @@ static int mlx5_query_port_roce(struct ib_device *device, u8 port_num,
if (!ndev)
return 0;
+ if (mlx5_lag_is_active(dev->mdev)) {
+ rcu_read_lock();
+ upper = netdev_master_upper_dev_get_rcu(ndev);
+ if (upper) {
+ dev_put(ndev);
+ ndev = upper;
+ dev_hold(ndev);
+ }
+ rcu_read_unlock();
+ }
+
if (netif_running(ndev) && netif_carrier_ok(ndev)) {
props->state = IB_PORT_ACTIVE;
props->phys_state = 5;
@@ -429,7 +472,7 @@ static int mlx5_query_node_guid(struct mlx5_ib_dev *dev,
}
struct mlx5_reg_node_desc {
- u8 desc[64];
+ u8 desc[IB_DEVICE_NODE_DESC_MAX];
};
static int mlx5_query_node_desc(struct mlx5_ib_dev *dev, char *node_desc)
@@ -532,6 +575,26 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
resp.response_length += sizeof(resp.tso_caps);
}
}
+
+ if (field_avail(typeof(resp), rss_caps, uhw->outlen)) {
+ resp.rss_caps.rx_hash_function =
+ MLX5_RX_HASH_FUNC_TOEPLITZ;
+ resp.rss_caps.rx_hash_fields_mask =
+ MLX5_RX_HASH_SRC_IPV4 |
+ MLX5_RX_HASH_DST_IPV4 |
+ MLX5_RX_HASH_SRC_IPV6 |
+ MLX5_RX_HASH_DST_IPV6 |
+ MLX5_RX_HASH_SRC_PORT_TCP |
+ MLX5_RX_HASH_DST_PORT_TCP |
+ MLX5_RX_HASH_SRC_PORT_UDP |
+ MLX5_RX_HASH_DST_PORT_UDP;
+ resp.response_length += sizeof(resp.rss_caps);
+ }
+ } else {
+ if (field_avail(typeof(resp), tso_caps, uhw->outlen))
+ resp.response_length += sizeof(resp.tso_caps);
+ if (field_avail(typeof(resp), rss_caps, uhw->outlen))
+ resp.response_length += sizeof(resp.rss_caps);
}
if (MLX5_CAP_GEN(mdev, ipoib_basic_offloads)) {
@@ -595,6 +658,17 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
if (!mlx5_core_is_pf(mdev))
props->device_cap_flags |= IB_DEVICE_VIRTUAL_FUNCTION;
+ if (mlx5_ib_port_link_layer(ibdev, 1) ==
+ IB_LINK_LAYER_ETHERNET) {
+ props->rss_caps.max_rwq_indirection_tables =
+ 1 << MLX5_CAP_GEN(dev->mdev, log_max_rqt);
+ props->rss_caps.max_rwq_indirection_table_size =
+ 1 << MLX5_CAP_GEN(dev->mdev, log_max_rqt_size);
+ props->rss_caps.supported_qpts = 1 << IB_QPT_RAW_PACKET;
+ props->max_wq_type_rq =
+ 1 << MLX5_CAP_GEN(dev->mdev, log_max_rq);
+ }
+
if (uhw->outlen) {
err = ib_copy_to_udata(uhw, &resp, resp.response_length);
@@ -846,13 +920,13 @@ static int mlx5_ib_modify_device(struct ib_device *ibdev, int mask,
* If possible, pass node desc to FW, so it can generate
* a 144 trap. If cmd fails, just ignore.
*/
- memcpy(&in, props->node_desc, 64);
+ memcpy(&in, props->node_desc, IB_DEVICE_NODE_DESC_MAX);
err = mlx5_core_access_reg(dev->mdev, &in, sizeof(in), &out,
sizeof(out), MLX5_REG_NODE_DESC, 0, 1);
if (err)
return err;
- memcpy(ibdev->node_desc, props->node_desc, 64);
+ memcpy(ibdev->node_desc, props->node_desc, IB_DEVICE_NODE_DESC_MAX);
return err;
}
@@ -1395,28 +1469,77 @@ static int mlx5_ib_dealloc_pd(struct ib_pd *pd)
return 0;
}
-static bool outer_header_zero(u32 *match_criteria)
+enum {
+ MATCH_CRITERIA_ENABLE_OUTER_BIT,
+ MATCH_CRITERIA_ENABLE_MISC_BIT,
+ MATCH_CRITERIA_ENABLE_INNER_BIT
+};
+
+#define HEADER_IS_ZERO(match_criteria, headers) \
+ !(memchr_inv(MLX5_ADDR_OF(fte_match_param, match_criteria, headers), \
+ 0, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
+
+static u8 get_match_criteria_enable(u32 *match_criteria)
{
- int size = MLX5_ST_SZ_BYTES(fte_match_param);
- char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria,
- outer_headers);
+ u8 match_criteria_enable;
- return outer_headers_c[0] == 0 && !memcmp(outer_headers_c,
- outer_headers_c + 1,
- size - 1);
+ match_criteria_enable =
+ (!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
+ MATCH_CRITERIA_ENABLE_OUTER_BIT;
+ match_criteria_enable |=
+ (!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
+ MATCH_CRITERIA_ENABLE_MISC_BIT;
+ match_criteria_enable |=
+ (!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
+ MATCH_CRITERIA_ENABLE_INNER_BIT;
+
+ return match_criteria_enable;
+}
+
+static void set_proto(void *outer_c, void *outer_v, u8 mask, u8 val)
+{
+ MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_protocol, mask);
+ MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_protocol, val);
}
+static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val)
+{
+ MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_ecn, mask);
+ MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_ecn, val);
+ MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_dscp, mask >> 2);
+ MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_dscp, val >> 2);
+}
+
+#define LAST_ETH_FIELD vlan_tag
+#define LAST_IB_FIELD sl
+#define LAST_IPV4_FIELD tos
+#define LAST_IPV6_FIELD traffic_class
+#define LAST_TCP_UDP_FIELD src_port
+
+/* Field is the last supported field */
+#define FIELDS_NOT_SUPPORTED(filter, field)\
+ memchr_inv((void *)&filter.field +\
+ sizeof(filter.field), 0,\
+ sizeof(filter) -\
+ offsetof(typeof(filter), field) -\
+ sizeof(filter.field))
+
static int parse_flow_attr(u32 *match_c, u32 *match_v,
- union ib_flow_spec *ib_spec)
+ const union ib_flow_spec *ib_spec)
{
void *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_c,
outer_headers);
void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v,
outer_headers);
+ void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c,
+ misc_parameters);
+ void *misc_params_v = MLX5_ADDR_OF(fte_match_param, match_v,
+ misc_parameters);
+
switch (ib_spec->type) {
case IB_FLOW_SPEC_ETH:
- if (ib_spec->size != sizeof(ib_spec->eth))
- return -EINVAL;
+ if (FIELDS_NOT_SUPPORTED(ib_spec->eth.mask, LAST_ETH_FIELD))
+ return -ENOTSUPP;
ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
dmac_47_16),
@@ -1463,8 +1586,8 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v,
ethertype, ntohs(ib_spec->eth.val.ether_type));
break;
case IB_FLOW_SPEC_IPV4:
- if (ib_spec->size != sizeof(ib_spec->ipv4))
- return -EINVAL;
+ if (FIELDS_NOT_SUPPORTED(ib_spec->ipv4.mask, LAST_IPV4_FIELD))
+ return -ENOTSUPP;
MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c,
ethertype, 0xffff);
@@ -1487,10 +1610,16 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v,
dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
&ib_spec->ipv4.val.dst_ip,
sizeof(ib_spec->ipv4.val.dst_ip));
+
+ set_tos(outer_headers_c, outer_headers_v,
+ ib_spec->ipv4.mask.tos, ib_spec->ipv4.val.tos);
+
+ set_proto(outer_headers_c, outer_headers_v,
+ ib_spec->ipv4.mask.proto, ib_spec->ipv4.val.proto);
break;
case IB_FLOW_SPEC_IPV6:
- if (ib_spec->size != sizeof(ib_spec->ipv6))
- return -EINVAL;
+ if (FIELDS_NOT_SUPPORTED(ib_spec->ipv6.mask, LAST_IPV6_FIELD))
+ return -ENOTSUPP;
MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c,
ethertype, 0xffff);
@@ -1513,10 +1642,26 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v,
dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
&ib_spec->ipv6.val.dst_ip,
sizeof(ib_spec->ipv6.val.dst_ip));
+
+ set_tos(outer_headers_c, outer_headers_v,
+ ib_spec->ipv6.mask.traffic_class,
+ ib_spec->ipv6.val.traffic_class);
+
+ set_proto(outer_headers_c, outer_headers_v,
+ ib_spec->ipv6.mask.next_hdr,
+ ib_spec->ipv6.val.next_hdr);
+
+ MLX5_SET(fte_match_set_misc, misc_params_c,
+ outer_ipv6_flow_label,
+ ntohl(ib_spec->ipv6.mask.flow_label));
+ MLX5_SET(fte_match_set_misc, misc_params_v,
+ outer_ipv6_flow_label,
+ ntohl(ib_spec->ipv6.val.flow_label));
break;
case IB_FLOW_SPEC_TCP:
- if (ib_spec->size != sizeof(ib_spec->tcp_udp))
- return -EINVAL;
+ if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask,
+ LAST_TCP_UDP_FIELD))
+ return -ENOTSUPP;
MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol,
0xff);
@@ -1534,8 +1679,9 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v,
ntohs(ib_spec->tcp_udp.val.dst_port));
break;
case IB_FLOW_SPEC_UDP:
- if (ib_spec->size != sizeof(ib_spec->tcp_udp))
- return -EINVAL;
+ if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask,
+ LAST_TCP_UDP_FIELD))
+ return -ENOTSUPP;
MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol,
0xff);
@@ -1582,7 +1728,7 @@ static bool flow_is_multicast_only(struct ib_flow_attr *ib_attr)
is_multicast_ether_addr(eth_spec->val.dst_mac);
}
-static bool is_valid_attr(struct ib_flow_attr *flow_attr)
+static bool is_valid_attr(const struct ib_flow_attr *flow_attr)
{
union ib_flow_spec *ib_spec = (union ib_flow_spec *)(flow_attr + 1);
bool has_ipv4_spec = false;
@@ -1626,12 +1772,13 @@ static int mlx5_ib_destroy_flow(struct ib_flow *flow_id)
list_for_each_entry_safe(iter, tmp, &handler->list, list) {
mlx5_del_flow_rule(iter->rule);
+ put_flow_table(dev, iter->prio, true);
list_del(&iter->list);
kfree(iter);
}
mlx5_del_flow_rule(handler->rule);
- put_flow_table(dev, &dev->flow_db.prios[handler->prio], true);
+ put_flow_table(dev, handler->prio, true);
mutex_unlock(&dev->flow_db.lock);
kfree(handler);
@@ -1647,10 +1794,16 @@ static int ib_prio_to_core_prio(unsigned int priority, bool dont_trap)
return priority;
}
+enum flow_table_type {
+ MLX5_IB_FT_RX,
+ MLX5_IB_FT_TX
+};
+
#define MLX5_FS_MAX_TYPES 10
#define MLX5_FS_MAX_ENTRIES 32000UL
static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
- struct ib_flow_attr *flow_attr)
+ struct ib_flow_attr *flow_attr,
+ enum flow_table_type ft_type)
{
bool dont_trap = flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP;
struct mlx5_flow_namespace *ns = NULL;
@@ -1681,6 +1834,19 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
&num_entries,
&num_groups);
prio = &dev->flow_db.prios[MLX5_IB_FLOW_LEFTOVERS_PRIO];
+ } else if (flow_attr->type == IB_FLOW_ATTR_SNIFFER) {
+ if (!MLX5_CAP_FLOWTABLE(dev->mdev,
+ allow_sniffer_and_nic_rx_shared_tir))
+ return ERR_PTR(-ENOTSUPP);
+
+ ns = mlx5_get_flow_namespace(dev->mdev, ft_type == MLX5_IB_FT_RX ?
+ MLX5_FLOW_NAMESPACE_SNIFFER_RX :
+ MLX5_FLOW_NAMESPACE_SNIFFER_TX);
+
+ prio = &dev->flow_db.sniffer[ft_type];
+ priority = 0;
+ num_entries = 1;
+ num_groups = 1;
}
if (!ns)
@@ -1706,13 +1872,13 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
struct mlx5_ib_flow_prio *ft_prio,
- struct ib_flow_attr *flow_attr,
+ const struct ib_flow_attr *flow_attr,
struct mlx5_flow_destination *dst)
{
struct mlx5_flow_table *ft = ft_prio->flow_table;
struct mlx5_ib_flow_handler *handler;
struct mlx5_flow_spec *spec;
- void *ib_flow = flow_attr + 1;
+ const void *ib_flow = (const void *)flow_attr + sizeof(*flow_attr);
unsigned int spec_index;
u32 action;
int err = 0;
@@ -1738,9 +1904,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
ib_flow += ((union ib_flow_spec *)ib_flow)->size;
}
- /* Outer header support only */
- spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria))
- << 0;
+ spec->match_criteria_enable = get_match_criteria_enable(spec->match_criteria);
action = dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
handler->rule = mlx5_add_flow_rule(ft, spec,
@@ -1753,7 +1917,8 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
goto free;
}
- handler->prio = ft_prio - dev->flow_db.prios;
+ ft_prio->refcount++;
+ handler->prio = ft_prio;
ft_prio->flow_table = ft;
free:
@@ -1777,6 +1942,7 @@ static struct mlx5_ib_flow_handler *create_dont_trap_rule(struct mlx5_ib_dev *de
flow_attr, dst);
if (IS_ERR(handler_dst)) {
mlx5_del_flow_rule(handler->rule);
+ ft_prio->refcount--;
kfree(handler);
handler = handler_dst;
} else {
@@ -1838,6 +2004,8 @@ static struct mlx5_ib_flow_handler *create_leftovers_rule(struct mlx5_ib_dev *de
&leftovers_specs[LEFTOVERS_UC].flow_attr,
dst);
if (IS_ERR(handler_ucast)) {
+ mlx5_del_flow_rule(handler->rule);
+ ft_prio->refcount--;
kfree(handler);
handler = handler_ucast;
} else {
@@ -1848,6 +2016,43 @@ static struct mlx5_ib_flow_handler *create_leftovers_rule(struct mlx5_ib_dev *de
return handler;
}
+static struct mlx5_ib_flow_handler *create_sniffer_rule(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_flow_prio *ft_rx,
+ struct mlx5_ib_flow_prio *ft_tx,
+ struct mlx5_flow_destination *dst)
+{
+ struct mlx5_ib_flow_handler *handler_rx;
+ struct mlx5_ib_flow_handler *handler_tx;
+ int err;
+ static const struct ib_flow_attr flow_attr = {
+ .num_of_specs = 0,
+ .size = sizeof(flow_attr)
+ };
+
+ handler_rx = create_flow_rule(dev, ft_rx, &flow_attr, dst);
+ if (IS_ERR(handler_rx)) {
+ err = PTR_ERR(handler_rx);
+ goto err;
+ }
+
+ handler_tx = create_flow_rule(dev, ft_tx, &flow_attr, dst);
+ if (IS_ERR(handler_tx)) {
+ err = PTR_ERR(handler_tx);
+ goto err_tx;
+ }
+
+ list_add(&handler_tx->list, &handler_rx->list);
+
+ return handler_rx;
+
+err_tx:
+ mlx5_del_flow_rule(handler_rx->rule);
+ ft_rx->refcount--;
+ kfree(handler_rx);
+err:
+ return ERR_PTR(err);
+}
+
static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
struct ib_flow_attr *flow_attr,
int domain)
@@ -1856,6 +2061,7 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
struct mlx5_ib_qp *mqp = to_mqp(qp);
struct mlx5_ib_flow_handler *handler = NULL;
struct mlx5_flow_destination *dst = NULL;
+ struct mlx5_ib_flow_prio *ft_prio_tx = NULL;
struct mlx5_ib_flow_prio *ft_prio;
int err;
@@ -1873,11 +2079,19 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
mutex_lock(&dev->flow_db.lock);
- ft_prio = get_flow_table(dev, flow_attr);
+ ft_prio = get_flow_table(dev, flow_attr, MLX5_IB_FT_RX);
if (IS_ERR(ft_prio)) {
err = PTR_ERR(ft_prio);
goto unlock;
}
+ if (flow_attr->type == IB_FLOW_ATTR_SNIFFER) {
+ ft_prio_tx = get_flow_table(dev, flow_attr, MLX5_IB_FT_TX);
+ if (IS_ERR(ft_prio_tx)) {
+ err = PTR_ERR(ft_prio_tx);
+ ft_prio_tx = NULL;
+ goto destroy_ft;
+ }
+ }
dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
if (mqp->flags & MLX5_IB_QP_RSS)
@@ -1897,6 +2111,8 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT) {
handler = create_leftovers_rule(dev, ft_prio, flow_attr,
dst);
+ } else if (flow_attr->type == IB_FLOW_ATTR_SNIFFER) {
+ handler = create_sniffer_rule(dev, ft_prio, ft_prio_tx, dst);
} else {
err = -EINVAL;
goto destroy_ft;
@@ -1908,7 +2124,6 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
goto destroy_ft;
}
- ft_prio->refcount++;
mutex_unlock(&dev->flow_db.lock);
kfree(dst);
@@ -1916,6 +2131,8 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
destroy_ft:
put_flow_table(dev, ft_prio, false);
+ if (ft_prio_tx)
+ put_flow_table(dev, ft_prio_tx, false);
unlock:
mutex_unlock(&dev->flow_db.lock);
kfree(dst);
@@ -2105,14 +2322,19 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
break;
case MLX5_DEV_EVENT_PORT_UP:
- ibev.event = IB_EVENT_PORT_ACTIVE;
- port = (u8)param;
- break;
-
case MLX5_DEV_EVENT_PORT_DOWN:
case MLX5_DEV_EVENT_PORT_INITIALIZED:
- ibev.event = IB_EVENT_PORT_ERR;
port = (u8)param;
+
+ /* In RoCE, port up/down events are handled in
+ * mlx5_netdev_event().
+ */
+ if (mlx5_ib_port_link_layer(&ibdev->ib_dev, port) ==
+ IB_LINK_LAYER_ETHERNET)
+ return;
+
+ ibev.event = (event == MLX5_DEV_EVENT_PORT_UP) ?
+ IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
break;
case MLX5_DEV_EVENT_LID_CHANGE:
@@ -2235,7 +2457,7 @@ static int create_umr_res(struct mlx5_ib_dev *dev)
goto error_0;
}
- pd = ib_alloc_pd(&dev->ib_dev);
+ pd = ib_alloc_pd(&dev->ib_dev, 0);
if (IS_ERR(pd)) {
mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n");
ret = PTR_ERR(pd);
@@ -2517,30 +2739,88 @@ static void get_dev_fw_str(struct ib_device *ibdev, char *str,
fw_rev_min(dev->mdev), fw_rev_sub(dev->mdev));
}
+static int mlx5_roce_lag_init(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_core_dev *mdev = dev->mdev;
+ struct mlx5_flow_namespace *ns = mlx5_get_flow_namespace(mdev,
+ MLX5_FLOW_NAMESPACE_LAG);
+ struct mlx5_flow_table *ft;
+ int err;
+
+ if (!ns || !mlx5_lag_is_active(mdev))
+ return 0;
+
+ err = mlx5_cmd_create_vport_lag(mdev);
+ if (err)
+ return err;
+
+ ft = mlx5_create_lag_demux_flow_table(ns, 0, 0);
+ if (IS_ERR(ft)) {
+ err = PTR_ERR(ft);
+ goto err_destroy_vport_lag;
+ }
+
+ dev->flow_db.lag_demux_ft = ft;
+ return 0;
+
+err_destroy_vport_lag:
+ mlx5_cmd_destroy_vport_lag(mdev);
+ return err;
+}
+
+static void mlx5_roce_lag_cleanup(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_core_dev *mdev = dev->mdev;
+
+ if (dev->flow_db.lag_demux_ft) {
+ mlx5_destroy_flow_table(dev->flow_db.lag_demux_ft);
+ dev->flow_db.lag_demux_ft = NULL;
+
+ mlx5_cmd_destroy_vport_lag(mdev);
+ }
+}
+
+static void mlx5_remove_roce_notifier(struct mlx5_ib_dev *dev)
+{
+ if (dev->roce.nb.notifier_call) {
+ unregister_netdevice_notifier(&dev->roce.nb);
+ dev->roce.nb.notifier_call = NULL;
+ }
+}
+
static int mlx5_enable_roce(struct mlx5_ib_dev *dev)
{
int err;
dev->roce.nb.notifier_call = mlx5_netdev_event;
err = register_netdevice_notifier(&dev->roce.nb);
- if (err)
+ if (err) {
+ dev->roce.nb.notifier_call = NULL;
return err;
+ }
err = mlx5_nic_vport_enable_roce(dev->mdev);
if (err)
goto err_unregister_netdevice_notifier;
+ err = mlx5_roce_lag_init(dev);
+ if (err)
+ goto err_disable_roce;
+
return 0;
+err_disable_roce:
+ mlx5_nic_vport_disable_roce(dev->mdev);
+
err_unregister_netdevice_notifier:
- unregister_netdevice_notifier(&dev->roce.nb);
+ mlx5_remove_roce_notifier(dev);
return err;
}
static void mlx5_disable_roce(struct mlx5_ib_dev *dev)
{
+ mlx5_roce_lag_cleanup(dev);
mlx5_nic_vport_disable_roce(dev->mdev);
- unregister_netdevice_notifier(&dev->roce.nb);
}
static void mlx5_ib_dealloc_q_counters(struct mlx5_ib_dev *dev)
@@ -2655,6 +2935,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
struct mlx5_ib_dev *dev;
enum rdma_link_layer ll;
int port_type_cap;
+ const char *name;
int err;
int i;
@@ -2687,7 +2968,12 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock);
- strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX);
+ if (!mlx5_lag_is_active(mdev))
+ name = "mlx5_%d";
+ else
+ name = "mlx5_bond_%d";
+
+ strlcpy(dev->ib_dev.name, name, IB_DEVICE_NAME_MAX);
dev->ib_dev.owner = THIS_MODULE;
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
dev->ib_dev.local_dma_lkey = 0 /* not supported for now */;
@@ -2889,8 +3175,10 @@ err_rsrc:
destroy_dev_resources(&dev->devr);
err_disable_roce:
- if (ll == IB_LINK_LAYER_ETHERNET)
+ if (ll == IB_LINK_LAYER_ETHERNET) {
mlx5_disable_roce(dev);
+ mlx5_remove_roce_notifier(dev);
+ }
err_free_port:
kfree(dev->port);
@@ -2906,6 +3194,7 @@ static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context)
struct mlx5_ib_dev *dev = context;
enum rdma_link_layer ll = mlx5_ib_port_link_layer(&dev->ib_dev, 1);
+ mlx5_remove_roce_notifier(dev);
ib_unregister_device(&dev->ib_dev);
mlx5_ib_dealloc_q_counters(dev);
destroy_umrc_res(dev);
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 67cc7416fdff..dcdcd195fe53 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -44,6 +44,7 @@
#include <linux/types.h>
#include <linux/mlx5/transobj.h>
#include <rdma/ib_user_verbs.h>
+#include <rdma/mlx5-abi.h>
#define mlx5_ib_dbg(dev, format, arg...) \
pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
@@ -142,6 +143,7 @@ struct mlx5_ib_pd {
#define MLX5_IB_FLOW_LEFTOVERS_PRIO (MLX5_IB_FLOW_MCAST_PRIO + 1)
#define MLX5_IB_NUM_FLOW_FT (MLX5_IB_FLOW_LEFTOVERS_PRIO + 1)
+#define MLX5_IB_NUM_SNIFFER_FTS 2
struct mlx5_ib_flow_prio {
struct mlx5_flow_table *flow_table;
unsigned int refcount;
@@ -150,12 +152,14 @@ struct mlx5_ib_flow_prio {
struct mlx5_ib_flow_handler {
struct list_head list;
struct ib_flow ibflow;
- unsigned int prio;
+ struct mlx5_ib_flow_prio *prio;
struct mlx5_flow_rule *rule;
};
struct mlx5_ib_flow_db {
struct mlx5_ib_flow_prio prios[MLX5_IB_NUM_FLOW_FT];
+ struct mlx5_ib_flow_prio sniffer[MLX5_IB_NUM_SNIFFER_FTS];
+ struct mlx5_flow_table *lag_demux_ft;
/* Protect flow steering bypass flow tables
* when add/del flow rules.
* only single add/removal of flow steering rule could be done
@@ -225,7 +229,7 @@ struct mlx5_ib_wq {
struct mlx5_ib_rwq {
struct ib_wq ibwq;
- u32 rqn;
+ struct mlx5_core_qp core_qp;
u32 rq_num_pas;
u32 log_rq_stride;
u32 log_rq_size;
@@ -603,6 +607,7 @@ struct mlx5_roce {
rwlock_t netdev_lock;
struct net_device *netdev;
struct notifier_block nb;
+ atomic_t next_port;
};
struct mlx5_ib_dev {
@@ -663,6 +668,11 @@ static inline struct mlx5_ib_qp *to_mibqp(struct mlx5_core_qp *mqp)
return container_of(mqp, struct mlx5_ib_qp_base, mqp)->container_mibqp;
}
+static inline struct mlx5_ib_rwq *to_mibrwq(struct mlx5_core_qp *core_qp)
+{
+ return container_of(core_qp, struct mlx5_ib_rwq, core_qp);
+}
+
static inline struct mlx5_ib_mr *to_mibmr(struct mlx5_core_mkey *mmkey)
{
return container_of(mmkey, struct mlx5_ib_mr, mmkey);
@@ -947,4 +957,40 @@ static inline int verify_assign_uidx(u8 cqe_version, u32 cmd_uidx,
return 0;
}
+
+static inline int get_qp_user_index(struct mlx5_ib_ucontext *ucontext,
+ struct mlx5_ib_create_qp *ucmd,
+ int inlen,
+ u32 *user_index)
+{
+ u8 cqe_version = ucontext->cqe_version;
+
+ if (field_avail(struct mlx5_ib_create_qp, uidx, inlen) &&
+ !cqe_version && (ucmd->uidx == MLX5_IB_DEFAULT_UIDX))
+ return 0;
+
+ if (!!(field_avail(struct mlx5_ib_create_qp, uidx, inlen) !=
+ !!cqe_version))
+ return -EINVAL;
+
+ return verify_assign_uidx(cqe_version, ucmd->uidx, user_index);
+}
+
+static inline int get_srq_user_index(struct mlx5_ib_ucontext *ucontext,
+ struct mlx5_ib_create_srq *ucmd,
+ int inlen,
+ u32 *user_index)
+{
+ u8 cqe_version = ucontext->cqe_version;
+
+ if (field_avail(struct mlx5_ib_create_srq, uidx, inlen) &&
+ !cqe_version && (ucmd->uidx == MLX5_IB_DEFAULT_UIDX))
+ return 0;
+
+ if (!!(field_avail(struct mlx5_ib_create_srq, uidx, inlen) !=
+ !!cqe_version))
+ return -EINVAL;
+
+ return verify_assign_uidx(cqe_version, ucmd->uidx, user_index);
+}
#endif /* MLX5_IB_H */
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 6f7e34753abc..d4ad672b905b 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -40,7 +40,6 @@
#include <rdma/ib_umem_odp.h>
#include <rdma/ib_verbs.h>
#include "mlx5_ib.h"
-#include "user.h"
enum {
MAX_PENDING_REG_MR = 8,
@@ -611,7 +610,7 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
int err;
int i;
- cache->wq = create_singlethread_workqueue("mkey_cache");
+ cache->wq = alloc_ordered_workqueue("mkey_cache", WQ_MEM_RECLAIM);
if (!cache->wq) {
mlx5_ib_warn(dev, "failed to create work queue\n");
return -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index 34e79e709c67..cacb631a7b0a 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -782,8 +782,8 @@ void mlx5_ib_odp_remove_one(struct mlx5_ib_dev *ibdev)
int __init mlx5_ib_odp_init(void)
{
- mlx5_ib_page_fault_wq =
- create_singlethread_workqueue("mlx5_ib_page_faults");
+ mlx5_ib_page_fault_wq = alloc_ordered_workqueue("mlx5_ib_page_faults",
+ WQ_MEM_RECLAIM);
if (!mlx5_ib_page_fault_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 9529b464fbdc..41f4c2afbcdd 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -35,7 +35,6 @@
#include <rdma/ib_cache.h>
#include <rdma/ib_user_verbs.h>
#include "mlx5_ib.h"
-#include "user.h"
/* not supported currently */
static int wq_signature;
@@ -77,6 +76,17 @@ struct mlx5_wqe_eth_pad {
u8 rsvd0[16];
};
+enum raw_qp_set_mask_map {
+ MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID = 1UL << 0,
+};
+
+struct mlx5_modify_raw_qp_param {
+ u16 operation;
+
+ u32 set_mask; /* raw_qp_set_mask_map */
+ u8 rq_q_ctr_id;
+};
+
static void get_cqs(enum ib_qp_type qp_type,
struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq);
@@ -1863,7 +1873,8 @@ static void get_cqs(enum ib_qp_type qp_type,
}
static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
- u16 operation);
+ const struct mlx5_modify_raw_qp_param *raw_qp_param,
+ u8 lag_tx_affinity);
static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
{
@@ -1888,8 +1899,11 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
MLX5_CMD_OP_2RST_QP, 0,
NULL, &base->mqp);
} else {
- err = modify_raw_packet_qp(dev, qp,
- MLX5_CMD_OP_2RST_QP);
+ struct mlx5_modify_raw_qp_param raw_qp_param = {
+ .operation = MLX5_CMD_OP_2RST_QP
+ };
+
+ err = modify_raw_packet_qp(dev, qp, &raw_qp_param, 0);
}
if (err)
mlx5_ib_warn(dev, "mlx5_ib: modify QP 0x%06x to RESET failed\n",
@@ -2153,6 +2167,31 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev,
return err;
}
+static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev,
+ struct mlx5_ib_sq *sq, u8 tx_affinity)
+{
+ void *in;
+ void *tisc;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(modify_tis_in);
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ MLX5_SET(modify_tis_in, in, bitmask.lag_tx_port_affinity, 1);
+
+ tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
+ MLX5_SET(tisc, tisc, lag_tx_port_affinity, tx_affinity);
+
+ err = mlx5_core_modify_tis(dev, sq->tisn, in, inlen);
+
+ kvfree(in);
+
+ return err;
+}
+
static int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
const struct ib_ah_attr *ah,
struct mlx5_qp_path *path, u8 port, int attr_mask,
@@ -2363,8 +2402,9 @@ static int ib_mask_to_mlx5_opt(int ib_mask)
return result;
}
-static int modify_raw_packet_qp_rq(struct mlx5_core_dev *dev,
- struct mlx5_ib_rq *rq, int new_state)
+static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_rq *rq, int new_state,
+ const struct mlx5_modify_raw_qp_param *raw_qp_param)
{
void *in;
void *rqc;
@@ -2381,7 +2421,17 @@ static int modify_raw_packet_qp_rq(struct mlx5_core_dev *dev,
rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
MLX5_SET(rqc, rqc, state, new_state);
- err = mlx5_core_modify_rq(dev, rq->base.mqp.qpn, in, inlen);
+ if (raw_qp_param->set_mask & MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID) {
+ if (MLX5_CAP_GEN(dev->mdev, modify_rq_counter_set_id)) {
+ MLX5_SET64(modify_rq_in, in, modify_bitmask,
+ MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_MODIFY_RQ_COUNTER_SET_ID);
+ MLX5_SET(rqc, rqc, counter_set_id, raw_qp_param->rq_q_ctr_id);
+ } else
+ pr_info_once("%s: RAW PACKET QP counters are not supported on current FW\n",
+ dev->ib_dev.name);
+ }
+
+ err = mlx5_core_modify_rq(dev->mdev, rq->base.mqp.qpn, in, inlen);
if (err)
goto out;
@@ -2422,7 +2472,8 @@ out:
}
static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
- u16 operation)
+ const struct mlx5_modify_raw_qp_param *raw_qp_param,
+ u8 tx_affinity)
{
struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
@@ -2431,7 +2482,7 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
int sq_state;
int err;
- switch (operation) {
+ switch (raw_qp_param->operation) {
case MLX5_CMD_OP_RST2INIT_QP:
rq_state = MLX5_RQC_STATE_RDY;
sq_state = MLX5_SQC_STATE_RDY;
@@ -2448,21 +2499,31 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
case MLX5_CMD_OP_INIT2RTR_QP:
case MLX5_CMD_OP_RTR2RTS_QP:
case MLX5_CMD_OP_RTS2RTS_QP:
- /* Nothing to do here... */
- return 0;
+ if (raw_qp_param->set_mask)
+ return -EINVAL;
+ else
+ return 0;
default:
WARN_ON(1);
return -EINVAL;
}
if (qp->rq.wqe_cnt) {
- err = modify_raw_packet_qp_rq(dev->mdev, rq, rq_state);
+ err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param);
if (err)
return err;
}
- if (qp->sq.wqe_cnt)
+ if (qp->sq.wqe_cnt) {
+ if (tx_affinity) {
+ err = modify_raw_packet_tx_affinity(dev->mdev, sq,
+ tx_affinity);
+ if (err)
+ return err;
+ }
+
return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state);
+ }
return 0;
}
@@ -2514,12 +2575,14 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
struct mlx5_ib_cq *send_cq, *recv_cq;
struct mlx5_qp_context *context;
struct mlx5_ib_pd *pd;
+ struct mlx5_ib_port *mibport = NULL;
enum mlx5_qp_state mlx5_cur, mlx5_new;
enum mlx5_qp_optpar optpar;
int sqd_event;
int mlx5_st;
int err;
u16 op;
+ u8 tx_affinity = 0;
context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context)
@@ -2549,6 +2612,23 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
}
}
+ if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT)) {
+ if ((ibqp->qp_type == IB_QPT_RC) ||
+ (ibqp->qp_type == IB_QPT_UD &&
+ !(qp->flags & MLX5_IB_QP_SQPN_QP1)) ||
+ (ibqp->qp_type == IB_QPT_UC) ||
+ (ibqp->qp_type == IB_QPT_RAW_PACKET) ||
+ (ibqp->qp_type == IB_QPT_XRC_INI) ||
+ (ibqp->qp_type == IB_QPT_XRC_TGT)) {
+ if (mlx5_lag_is_active(dev->mdev)) {
+ tx_affinity = (unsigned int)atomic_add_return(1,
+ &dev->roce.next_port) %
+ MLX5_MAX_PORTS + 1;
+ context->flags |= cpu_to_be32(tx_affinity << 24);
+ }
+ }
+ }
+
if (is_sqp(ibqp->qp_type)) {
context->mtu_msgmax = (IB_MTU_256 << 5) | 8;
} else if (ibqp->qp_type == IB_QPT_UD ||
@@ -2654,8 +2734,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num :
qp->port) - 1;
- struct mlx5_ib_port *mibport = &dev->port[port_num];
-
+ mibport = &dev->port[port_num];
context->qp_counter_set_usr_page |=
cpu_to_be32((u32)(mibport->q_cnt_id) << 24);
}
@@ -2690,11 +2769,20 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
optpar = ib_mask_to_mlx5_opt(attr_mask);
optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
- if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET)
- err = modify_raw_packet_qp(dev, qp, op);
- else
+ if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
+ struct mlx5_modify_raw_qp_param raw_qp_param = {};
+
+ raw_qp_param.operation = op;
+ if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
+ raw_qp_param.rq_q_ctr_id = mibport->q_cnt_id;
+ raw_qp_param.set_mask |= MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID;
+ }
+ err = modify_raw_packet_qp(dev, qp, &raw_qp_param, tx_affinity);
+ } else {
err = mlx5_core_qp_modify(dev->mdev, op, optpar, context,
&base->mqp);
+ }
+
if (err)
goto out;
@@ -4497,6 +4585,28 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
return 0;
}
+static void mlx5_ib_wq_event(struct mlx5_core_qp *core_qp, int type)
+{
+ struct mlx5_ib_rwq *rwq = to_mibrwq(core_qp);
+ struct mlx5_ib_dev *dev = to_mdev(rwq->ibwq.device);
+ struct ib_event event;
+
+ if (rwq->ibwq.event_handler) {
+ event.device = rwq->ibwq.device;
+ event.element.wq = &rwq->ibwq;
+ switch (type) {
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ event.event = IB_EVENT_WQ_FATAL;
+ break;
+ default:
+ mlx5_ib_warn(dev, "Unexpected event type %d on WQ %06x\n", type, core_qp->qpn);
+ return;
+ }
+
+ rwq->ibwq.event_handler(&event, rwq->ibwq.wq_context);
+ }
+}
+
static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
struct ib_wq_init_attr *init_attr)
{
@@ -4534,7 +4644,7 @@ static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
MLX5_SET64(wq, wq, dbr_addr, rwq->db.dma);
rq_pas0 = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
mlx5_ib_populate_pas(dev, rwq->umem, rwq->page_shift, rq_pas0, 0);
- err = mlx5_core_create_rq(dev->mdev, in, inlen, &rwq->rqn);
+ err = mlx5_core_create_rq_tracked(dev->mdev, in, inlen, &rwq->core_qp);
kvfree(in);
return err;
}
@@ -4650,7 +4760,7 @@ struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
return ERR_PTR(-EINVAL);
}
- rwq->ibwq.wq_num = rwq->rqn;
+ rwq->ibwq.wq_num = rwq->core_qp.qpn;
rwq->ibwq.state = IB_WQS_RESET;
if (udata->outlen) {
resp.response_length = offsetof(typeof(resp), response_length) +
@@ -4660,10 +4770,12 @@ struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
goto err_copy;
}
+ rwq->core_qp.event = mlx5_ib_wq_event;
+ rwq->ibwq.event_handler = init_attr->event_handler;
return &rwq->ibwq;
err_copy:
- mlx5_core_destroy_rq(dev->mdev, rwq->rqn);
+ mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
err_user_rq:
destroy_user_rq(pd, rwq);
err:
@@ -4676,7 +4788,7 @@ int mlx5_ib_destroy_wq(struct ib_wq *wq)
struct mlx5_ib_dev *dev = to_mdev(wq->device);
struct mlx5_ib_rwq *rwq = to_mrwq(wq);
- mlx5_core_destroy_rq(dev->mdev, rwq->rqn);
+ mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
destroy_user_rq(wq->pd, rwq);
kfree(rwq);
@@ -4808,7 +4920,7 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state);
MLX5_SET(rqc, rqc, state, wq_state);
- err = mlx5_core_modify_rq(dev->mdev, rwq->rqn, in, inlen);
+ err = mlx5_core_modify_rq(dev->mdev, rwq->core_qp.qpn, in, inlen);
kvfree(in);
if (!err)
rwq->ibwq.state = (wq_state == MLX5_RQC_STATE_ERR) ? IB_WQS_ERR : wq_state;
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index ed6ac52355f1..3857dbd9c956 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -38,7 +38,6 @@
#include <rdma/ib_user_verbs.h>
#include "mlx5_ib.h"
-#include "user.h"
/* not supported currently */
static int srq_signature;
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
index 712d2a30fbe5..f6474c24f193 100644
--- a/drivers/infiniband/hw/mthca/mthca_catas.c
+++ b/drivers/infiniband/hw/mthca/mthca_catas.c
@@ -187,7 +187,7 @@ int __init mthca_catas_init(void)
{
INIT_WORK(&catas_work, catas_reset);
- catas_wq = create_singlethread_workqueue("mthca_catas");
+ catas_wq = alloc_ordered_workqueue("mthca_catas", WQ_MEM_RECLAIM);
if (!catas_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 7c3f2fb44ba5..9139405c4810 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -153,7 +153,8 @@ static void node_desc_override(struct ib_device *dev,
mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
mutex_lock(&to_mdev(dev)->cap_mask_mutex);
- memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+ memcpy(((struct ib_smp *) mad)->data, dev->node_desc,
+ IB_DEVICE_NODE_DESC_MAX);
mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index da2335f7f7c3..358930a41e36 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -46,7 +46,7 @@
#include "mthca_dev.h"
#include "mthca_cmd.h"
-#include "mthca_user.h"
+#include <rdma/mthca-abi.h>
#include "mthca_memfree.h"
static void init_query_mad(struct ib_smp *mad)
@@ -193,7 +193,8 @@ static int mthca_modify_device(struct ib_device *ibdev,
if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
return -ERESTARTSYS;
- memcpy(ibdev->node_desc, props->node_desc, 64);
+ memcpy(ibdev->node_desc, props->node_desc,
+ IB_DEVICE_NODE_DESC_MAX);
mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
}
@@ -1138,7 +1139,7 @@ static int mthca_init_node_data(struct mthca_dev *dev)
if (err)
goto out;
- memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+ memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX);
in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index bd9d132f11c7..e7430c9254d3 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -165,7 +165,7 @@ do { \
#include "nes_hw.h"
#include "nes_verbs.h"
#include "nes_context.h"
-#include "nes_user.h"
+#include <rdma/nes-abi.h>
#include "nes_cm.h"
#include "nes_mgt.h"
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 7f0aa23aef9d..57db9b332f44 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -2692,12 +2692,12 @@ static struct nes_cm_core *nes_cm_alloc_core(void)
nes_debug(NES_DBG_CM, "Init CM Core completed -- cm_core=%p\n", cm_core);
nes_debug(NES_DBG_CM, "Enable QUEUE EVENTS\n");
- cm_core->event_wq = create_singlethread_workqueue("nesewq");
+ cm_core->event_wq = alloc_ordered_workqueue("nesewq", 0);
if (!cm_core->event_wq)
goto out_free_cmcore;
cm_core->post_event = nes_cm_post_event;
nes_debug(NES_DBG_CM, "Enable QUEUE DISCONNECTS\n");
- cm_core->disconn_wq = create_singlethread_workqueue("nesdwq");
+ cm_core->disconn_wq = alloc_ordered_workqueue("nesdwq", 0);
if (!cm_core->disconn_wq)
goto out_free_wq;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 07d0c6c5b046..896071502739 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -56,7 +56,7 @@
#include "be_roce.h"
#include "ocrdma_hw.h"
#include "ocrdma_stats.h"
-#include "ocrdma_abi.h"
+#include <rdma/ocrdma-abi.h>
MODULE_VERSION(OCRDMA_ROCE_DRV_VERSION);
MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION);
@@ -119,6 +119,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
{
strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);
ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid);
+ BUILD_BUG_ON(sizeof(OCRDMA_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC,
sizeof(OCRDMA_NODE_DESC));
dev->ibdev.owner = THIS_MODULE;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index 0aa854737e74..6af44f8db3d5 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -51,7 +51,7 @@
#include "ocrdma.h"
#include "ocrdma_hw.h"
#include "ocrdma_verbs.h"
-#include "ocrdma_abi.h"
+#include <rdma/ocrdma-abi.h>
int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
{
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index c3edc033f7c4..f1e66efea98a 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -64,7 +64,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
inode->i_uid = GLOBAL_ROOT_UID;
inode->i_gid = GLOBAL_ROOT_GID;
inode->i_blocks = 0;
- inode->i_atime = CURRENT_TIME;
+ inode->i_atime = current_time(inode);
inode->i_mtime = inode->i_atime;
inode->i_ctime = inode->i_atime;
inode->i_private = data;
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index f253111e682e..1730aa839a47 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -614,8 +614,8 @@ static int qib_create_workqueues(struct qib_devdata *dd)
snprintf(wq_name, sizeof(wq_name), "qib%d_%d",
dd->unit, pidx);
- ppd->qib_wq =
- create_singlethread_workqueue(wq_name);
+ ppd->qib_wq = alloc_ordered_workqueue(wq_name,
+ WQ_MEM_RECLAIM);
if (!ppd->qib_wq)
goto wq_error;
}
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 876ebb442d38..954f15064514 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -1370,7 +1370,8 @@ static int qib_modify_device(struct ib_device *device,
}
if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC) {
- memcpy(device->node_desc, device_modify->node_desc, 64);
+ memcpy(device->node_desc, device_modify->node_desc,
+ IB_DEVICE_NODE_DESC_MAX);
for (i = 0; i < dd->num_pports; i++) {
struct qib_ibport *ibp = &dd->pport[i].ibport_data;
diff --git a/drivers/infiniband/sw/rdmavt/dma.c b/drivers/infiniband/sw/rdmavt/dma.c
index 33076a5eee2f..01f71caa3ac4 100644
--- a/drivers/infiniband/sw/rdmavt/dma.c
+++ b/drivers/infiniband/sw/rdmavt/dma.c
@@ -138,6 +138,21 @@ static void rvt_unmap_sg(struct ib_device *dev,
/* This is a stub, nothing to be done here */
}
+static int rvt_map_sg_attrs(struct ib_device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction direction,
+ unsigned long attrs)
+{
+ return rvt_map_sg(dev, sgl, nents, direction);
+}
+
+static void rvt_unmap_sg_attrs(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
+ unsigned long attrs)
+{
+ return rvt_unmap_sg(dev, sg, nents, direction);
+}
+
static void rvt_sync_single_for_cpu(struct ib_device *dev, u64 addr,
size_t size, enum dma_data_direction dir)
{
@@ -177,6 +192,8 @@ struct ib_dma_mapping_ops rvt_default_dma_mapping_ops = {
.unmap_page = rvt_dma_unmap_page,
.map_sg = rvt_map_sg,
.unmap_sg = rvt_unmap_sg,
+ .map_sg_attrs = rvt_map_sg_attrs,
+ .unmap_sg_attrs = rvt_unmap_sg_attrs,
.sync_single_for_cpu = rvt_sync_single_for_cpu,
.sync_single_for_device = rvt_sync_single_for_device,
.alloc_coherent = rvt_dma_alloc_coherent,
diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c
index ddd59270ff6d..ab6c3c25d7ff 100644
--- a/drivers/infiniband/sw/rxe/rxe.c
+++ b/drivers/infiniband/sw/rxe/rxe.c
@@ -358,38 +358,16 @@ static int __init rxe_module_init(void)
/* initialize slab caches for managed objects */
err = rxe_cache_init();
if (err) {
- pr_err("rxe: unable to init object pools\n");
+ pr_err("unable to init object pools\n");
return err;
}
- err = rxe_net_ipv4_init();
- if (err) {
- pr_err("rxe: unable to init ipv4 tunnel\n");
- rxe_cache_exit();
- goto exit;
- }
-
- err = rxe_net_ipv6_init();
- if (err) {
- pr_err("rxe: unable to init ipv6 tunnel\n");
- rxe_cache_exit();
- goto exit;
- }
-
- err = register_netdevice_notifier(&rxe_net_notifier);
- if (err) {
- pr_err("rxe: Failed to rigister netdev notifier\n");
- goto exit;
- }
-
- pr_info("rxe: loaded\n");
+ err = rxe_net_init();
+ if (err)
+ return err;
+ pr_info("loaded\n");
return 0;
-
-exit:
- rxe_release_udp_tunnel(recv_sockets.sk4);
- rxe_release_udp_tunnel(recv_sockets.sk6);
- return err;
}
static void __exit rxe_module_exit(void)
@@ -398,8 +376,8 @@ static void __exit rxe_module_exit(void)
rxe_net_exit();
rxe_cache_exit();
- pr_info("rxe: unloaded\n");
+ pr_info("unloaded\n");
}
-module_init(rxe_module_init);
+late_initcall(rxe_module_init);
module_exit(rxe_module_exit);
diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h
index 12c71c549f97..a696af81e4a5 100644
--- a/drivers/infiniband/sw/rxe/rxe.h
+++ b/drivers/infiniband/sw/rxe/rxe.h
@@ -34,6 +34,11 @@
#ifndef RXE_H
#define RXE_H
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/crc32.h>
diff --git a/drivers/infiniband/sw/rxe/rxe_av.c b/drivers/infiniband/sw/rxe/rxe_av.c
index 5c9474212d4e..604f6fee96bd 100644
--- a/drivers/infiniband/sw/rxe/rxe_av.c
+++ b/drivers/infiniband/sw/rxe/rxe_av.c
@@ -39,7 +39,7 @@ int rxe_av_chk_attr(struct rxe_dev *rxe, struct ib_ah_attr *attr)
struct rxe_port *port;
if (attr->port_num != 1) {
- pr_info("rxe: invalid port_num = %d\n", attr->port_num);
+ pr_info("invalid port_num = %d\n", attr->port_num);
return -EINVAL;
}
@@ -47,7 +47,7 @@ int rxe_av_chk_attr(struct rxe_dev *rxe, struct ib_ah_attr *attr)
if (attr->ah_flags & IB_AH_GRH) {
if (attr->grh.sgid_index > port->attr.gid_tbl_len) {
- pr_info("rxe: invalid sgid index = %d\n",
+ pr_info("invalid sgid index = %d\n",
attr->grh.sgid_index);
return -EINVAL;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
index 1c59ef2c67aa..6c5e29db88e3 100644
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -567,7 +567,8 @@ int rxe_completer(void *arg)
state = COMPST_GET_ACK;
while (1) {
- pr_debug("state = %s\n", comp_state_name[state]);
+ pr_debug("qp#%d state = %s\n", qp_num(qp),
+ comp_state_name[state]);
switch (state) {
case COMPST_GET_ACK:
skb = skb_dequeue(&qp->resp_pkts);
@@ -709,7 +710,8 @@ int rxe_completer(void *arg)
qp->comp.rnr_retry--;
qp->req.need_retry = 1;
- pr_debug("set rnr nak timer\n");
+ pr_debug("qp#%d set rnr nak timer\n",
+ qp_num(qp));
mod_timer(&qp->rnr_nak_timer,
jiffies + rnrnak_jiffies(aeth_syn(pkt)
& ~AETH_TYPE_MASK));
diff --git a/drivers/infiniband/sw/rxe/rxe_dma.c b/drivers/infiniband/sw/rxe/rxe_dma.c
index 7634c1a81b2b..a0f8af5851ae 100644
--- a/drivers/infiniband/sw/rxe/rxe_dma.c
+++ b/drivers/infiniband/sw/rxe/rxe_dma.c
@@ -117,6 +117,21 @@ static void rxe_unmap_sg(struct ib_device *dev,
WARN_ON(!valid_dma_direction(direction));
}
+static int rxe_map_sg_attrs(struct ib_device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction direction,
+ unsigned long attrs)
+{
+ return rxe_map_sg(dev, sgl, nents, direction);
+}
+
+static void rxe_unmap_sg_attrs(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
+ unsigned long attrs)
+{
+ rxe_unmap_sg(dev, sg, nents, direction);
+}
+
static void rxe_sync_single_for_cpu(struct ib_device *dev,
u64 addr,
size_t size, enum dma_data_direction dir)
@@ -159,6 +174,8 @@ struct ib_dma_mapping_ops rxe_dma_mapping_ops = {
.unmap_page = rxe_dma_unmap_page,
.map_sg = rxe_map_sg,
.unmap_sg = rxe_unmap_sg,
+ .map_sg_attrs = rxe_map_sg_attrs,
+ .unmap_sg_attrs = rxe_unmap_sg_attrs,
.sync_single_for_cpu = rxe_sync_single_for_cpu,
.sync_single_for_device = rxe_sync_single_for_device,
.alloc_coherent = rxe_dma_alloc_coherent,
diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
index 4a5484ef604f..73849a5a91b3 100644
--- a/drivers/infiniband/sw/rxe/rxe_loc.h
+++ b/drivers/infiniband/sw/rxe/rxe_loc.h
@@ -198,7 +198,7 @@ void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res);
static inline void rxe_advance_resp_resource(struct rxe_qp *qp)
{
qp->resp.res_head++;
- if (unlikely(qp->resp.res_head == qp->attr.max_rd_atomic))
+ if (unlikely(qp->resp.res_head == qp->attr.max_dest_rd_atomic))
qp->resp.res_head = 0;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_mmap.c b/drivers/infiniband/sw/rxe/rxe_mmap.c
index 54b3c7c99eff..c572a4c09359 100644
--- a/drivers/infiniband/sw/rxe/rxe_mmap.c
+++ b/drivers/infiniband/sw/rxe/rxe_mmap.c
@@ -126,7 +126,7 @@ found_it:
ret = remap_vmalloc_range(vma, ip->obj, 0);
if (ret) {
- pr_err("rxe: err %d from remap_vmalloc_range\n", ret);
+ pr_err("err %d from remap_vmalloc_range\n", ret);
goto done;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index f3dab6574504..1869152f1d23 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -39,7 +39,7 @@
*/
static u8 rxe_get_key(void)
{
- static unsigned key = 1;
+ static u32 key = 1;
key = key << 1;
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
index eedf2f1cafdf..b8258e4f0aea 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -65,7 +65,7 @@ struct rxe_dev *net_to_rxe(struct net_device *ndev)
return found;
}
-struct rxe_dev *get_rxe_by_name(const char* name)
+struct rxe_dev *get_rxe_by_name(const char *name)
{
struct rxe_dev *rxe;
struct rxe_dev *found = NULL;
@@ -350,14 +350,14 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb,
ip6h->payload_len = htons(skb->len - sizeof(*ip6h));
}
-static int prepare4(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
+static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+ struct sk_buff *skb, struct rxe_av *av)
{
struct dst_entry *dst;
bool xnet = false;
__be16 df = htons(IP_DF);
struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr;
struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr;
- struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
dst = rxe_find_route4(rxe->ndev, saddr, daddr);
if (!dst) {
@@ -376,12 +376,12 @@ static int prepare4(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
return 0;
}
-static int prepare6(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
+static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+ struct sk_buff *skb, struct rxe_av *av)
{
struct dst_entry *dst;
struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr;
struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr;
- struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
dst = rxe_find_route6(rxe->ndev, saddr, daddr);
if (!dst) {
@@ -408,9 +408,9 @@ static int prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
struct rxe_av *av = rxe_get_av(pkt);
if (av->network_type == RDMA_NETWORK_IPV4)
- err = prepare4(rxe, skb, av);
+ err = prepare4(rxe, pkt, skb, av);
else if (av->network_type == RDMA_NETWORK_IPV6)
- err = prepare6(rxe, skb, av);
+ err = prepare6(rxe, pkt, skb, av);
*crc = rxe_icrc_hdr(pkt, skb);
@@ -601,8 +601,7 @@ void rxe_port_up(struct rxe_dev *rxe)
port->attr.phys_state = IB_PHYS_STATE_LINK_UP;
rxe_port_event(rxe, IB_EVENT_PORT_ACTIVE);
- pr_info("rxe: set %s active\n", rxe->ib_dev.name);
- return;
+ pr_info("set %s active\n", rxe->ib_dev.name);
}
/* Caller must hold net_info_lock */
@@ -615,8 +614,7 @@ void rxe_port_down(struct rxe_dev *rxe)
port->attr.phys_state = IB_PHYS_STATE_LINK_DOWN;
rxe_port_event(rxe, IB_EVENT_PORT_ERR);
- pr_info("rxe: set %s down\n", rxe->ib_dev.name);
- return;
+ pr_info("set %s down\n", rxe->ib_dev.name);
}
static int rxe_notify(struct notifier_block *not_blk,
@@ -641,7 +639,7 @@ static int rxe_notify(struct notifier_block *not_blk,
rxe_port_down(rxe);
break;
case NETDEV_CHANGEMTU:
- pr_info("rxe: %s changed mtu to %d\n", ndev->name, ndev->mtu);
+ pr_info("%s changed mtu to %d\n", ndev->name, ndev->mtu);
rxe_set_mtu(rxe, ndev->mtu);
break;
case NETDEV_REBOOT:
@@ -651,7 +649,7 @@ static int rxe_notify(struct notifier_block *not_blk,
case NETDEV_CHANGENAME:
case NETDEV_FEAT_CHANGE:
default:
- pr_info("rxe: ignoring netdev event = %ld for %s\n",
+ pr_info("ignoring netdev event = %ld for %s\n",
event, ndev->name);
break;
}
@@ -671,7 +669,7 @@ int rxe_net_ipv4_init(void)
htons(ROCE_V2_UDP_DPORT), false);
if (IS_ERR(recv_sockets.sk4)) {
recv_sockets.sk4 = NULL;
- pr_err("rxe: Failed to create IPv4 UDP tunnel\n");
+ pr_err("Failed to create IPv4 UDP tunnel\n");
return -1;
}
@@ -688,7 +686,7 @@ int rxe_net_ipv6_init(void)
htons(ROCE_V2_UDP_DPORT), true);
if (IS_ERR(recv_sockets.sk6)) {
recv_sockets.sk6 = NULL;
- pr_err("rxe: Failed to create IPv6 UDP tunnel\n");
+ pr_err("Failed to create IPv6 UDP tunnel\n");
return -1;
}
#endif
@@ -701,3 +699,26 @@ void rxe_net_exit(void)
rxe_release_udp_tunnel(recv_sockets.sk4);
unregister_netdevice_notifier(&rxe_net_notifier);
}
+
+int rxe_net_init(void)
+{
+ int err;
+
+ recv_sockets.sk6 = NULL;
+
+ err = rxe_net_ipv4_init();
+ if (err)
+ return err;
+ err = rxe_net_ipv6_init();
+ if (err)
+ goto err_out;
+ err = register_netdevice_notifier(&rxe_net_notifier);
+ if (err) {
+ pr_err("Failed to register netdev notifier\n");
+ goto err_out;
+ }
+ return 0;
+err_out:
+ rxe_net_exit();
+ return err;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_net.h b/drivers/infiniband/sw/rxe/rxe_net.h
index 0daf7f09e5b5..1c06b3bfe1b6 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.h
+++ b/drivers/infiniband/sw/rxe/rxe_net.h
@@ -49,8 +49,7 @@ void rxe_release_udp_tunnel(struct socket *sk);
struct rxe_dev *rxe_net_add(struct net_device *ndev);
-int rxe_net_ipv4_init(void);
-int rxe_net_ipv6_init(void);
+int rxe_net_init(void);
void rxe_net_exit(void);
#endif /* RXE_NET_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
index 22ba24f2a2c1..b8036cfbce04 100644
--- a/drivers/infiniband/sw/rxe/rxe_qp.c
+++ b/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -146,7 +146,7 @@ static void free_rd_atomic_resources(struct rxe_qp *qp)
if (qp->resp.resources) {
int i;
- for (i = 0; i < qp->attr.max_rd_atomic; i++) {
+ for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) {
struct resp_res *res = &qp->resp.resources[i];
free_rd_atomic_resource(qp, res);
@@ -174,7 +174,7 @@ static void cleanup_rd_atomic_resources(struct rxe_qp *qp)
struct resp_res *res;
if (qp->resp.resources) {
- for (i = 0; i < qp->attr.max_rd_atomic; i++) {
+ for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) {
res = &qp->resp.resources[i];
free_rd_atomic_resource(qp, res);
}
@@ -298,8 +298,8 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
wqe_size = rcv_wqe_size(qp->rq.max_sge);
- pr_debug("max_wr = %d, max_sge = %d, wqe_size = %d\n",
- qp->rq.max_wr, qp->rq.max_sge, wqe_size);
+ pr_debug("qp#%d max_wr = %d, max_sge = %d, wqe_size = %d\n",
+ qp_num(qp), qp->rq.max_wr, qp->rq.max_sge, wqe_size);
qp->rq.queue = rxe_queue_init(rxe,
&qp->rq.max_wr,
@@ -596,14 +596,21 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
int max_rd_atomic = __roundup_pow_of_two(attr->max_rd_atomic);
+ qp->attr.max_rd_atomic = max_rd_atomic;
+ atomic_set(&qp->req.rd_atomic, max_rd_atomic);
+ }
+
+ if (mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+ int max_dest_rd_atomic =
+ __roundup_pow_of_two(attr->max_dest_rd_atomic);
+
+ qp->attr.max_dest_rd_atomic = max_dest_rd_atomic;
+
free_rd_atomic_resources(qp);
- err = alloc_rd_atomic_resources(qp, max_rd_atomic);
+ err = alloc_rd_atomic_resources(qp, max_dest_rd_atomic);
if (err)
return err;
-
- qp->attr.max_rd_atomic = max_rd_atomic;
- atomic_set(&qp->req.rd_atomic, max_rd_atomic);
}
if (mask & IB_QP_CUR_STATE)
@@ -673,24 +680,27 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
if (mask & IB_QP_RETRY_CNT) {
qp->attr.retry_cnt = attr->retry_cnt;
qp->comp.retry_cnt = attr->retry_cnt;
- pr_debug("set retry count = %d\n", attr->retry_cnt);
+ pr_debug("qp#%d set retry count = %d\n", qp_num(qp),
+ attr->retry_cnt);
}
if (mask & IB_QP_RNR_RETRY) {
qp->attr.rnr_retry = attr->rnr_retry;
qp->comp.rnr_retry = attr->rnr_retry;
- pr_debug("set rnr retry count = %d\n", attr->rnr_retry);
+ pr_debug("qp#%d set rnr retry count = %d\n", qp_num(qp),
+ attr->rnr_retry);
}
if (mask & IB_QP_RQ_PSN) {
qp->attr.rq_psn = (attr->rq_psn & BTH_PSN_MASK);
qp->resp.psn = qp->attr.rq_psn;
- pr_debug("set resp psn = 0x%x\n", qp->resp.psn);
+ pr_debug("qp#%d set resp psn = 0x%x\n", qp_num(qp),
+ qp->resp.psn);
}
if (mask & IB_QP_MIN_RNR_TIMER) {
qp->attr.min_rnr_timer = attr->min_rnr_timer;
- pr_debug("set min rnr timer = 0x%x\n",
+ pr_debug("qp#%d set min rnr timer = 0x%x\n", qp_num(qp),
attr->min_rnr_timer);
}
@@ -698,12 +708,7 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
qp->attr.sq_psn = (attr->sq_psn & BTH_PSN_MASK);
qp->req.psn = qp->attr.sq_psn;
qp->comp.psn = qp->attr.sq_psn;
- pr_debug("set req psn = 0x%x\n", qp->req.psn);
- }
-
- if (mask & IB_QP_MAX_DEST_RD_ATOMIC) {
- qp->attr.max_dest_rd_atomic =
- __roundup_pow_of_two(attr->max_dest_rd_atomic);
+ pr_debug("qp#%d set req psn = 0x%x\n", qp_num(qp), qp->req.psn);
}
if (mask & IB_QP_PATH_MIG_STATE)
@@ -717,38 +722,38 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
switch (attr->qp_state) {
case IB_QPS_RESET:
- pr_debug("qp state -> RESET\n");
+ pr_debug("qp#%d state -> RESET\n", qp_num(qp));
rxe_qp_reset(qp);
break;
case IB_QPS_INIT:
- pr_debug("qp state -> INIT\n");
+ pr_debug("qp#%d state -> INIT\n", qp_num(qp));
qp->req.state = QP_STATE_INIT;
qp->resp.state = QP_STATE_INIT;
break;
case IB_QPS_RTR:
- pr_debug("qp state -> RTR\n");
+ pr_debug("qp#%d state -> RTR\n", qp_num(qp));
qp->resp.state = QP_STATE_READY;
break;
case IB_QPS_RTS:
- pr_debug("qp state -> RTS\n");
+ pr_debug("qp#%d state -> RTS\n", qp_num(qp));
qp->req.state = QP_STATE_READY;
break;
case IB_QPS_SQD:
- pr_debug("qp state -> SQD\n");
+ pr_debug("qp#%d state -> SQD\n", qp_num(qp));
rxe_qp_drain(qp);
break;
case IB_QPS_SQE:
- pr_warn("qp state -> SQE !!?\n");
+ pr_warn("qp#%d state -> SQE !!?\n", qp_num(qp));
/* Not possible from modify_qp. */
break;
case IB_QPS_ERR:
- pr_debug("qp state -> ERR\n");
+ pr_debug("qp#%d state -> ERR\n", qp_num(qp));
rxe_qp_error(qp);
break;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c
index 144d2f129fcd..46f062842a9a 100644
--- a/drivers/infiniband/sw/rxe/rxe_recv.c
+++ b/drivers/infiniband/sw/rxe/rxe_recv.c
@@ -387,7 +387,8 @@ int rxe_rcv(struct sk_buff *skb)
pack_icrc = be32_to_cpu(*icrcp);
calc_icrc = rxe_icrc_hdr(pkt, skb);
- calc_icrc = crc32_le(calc_icrc, (u8 *)payload_addr(pkt), payload_size(pkt));
+ calc_icrc = crc32_le(calc_icrc, (u8 *)payload_addr(pkt),
+ payload_size(pkt));
calc_icrc = cpu_to_be32(~calc_icrc);
if (unlikely(calc_icrc != pack_icrc)) {
char saddr[sizeof(struct in6_addr)];
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
index 13a848a518e8..832846b73ea0 100644
--- a/drivers/infiniband/sw/rxe/rxe_req.c
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
@@ -38,7 +38,7 @@
#include "rxe_queue.h"
static int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
- unsigned opcode);
+ u32 opcode);
static inline void retry_first_write_send(struct rxe_qp *qp,
struct rxe_send_wqe *wqe,
@@ -121,7 +121,7 @@ void rnr_nak_timer(unsigned long data)
{
struct rxe_qp *qp = (struct rxe_qp *)data;
- pr_debug("rnr nak timer fired\n");
+ pr_debug("qp#%d rnr nak timer fired\n", qp_num(qp));
rxe_run_task(&qp->req.task, 1);
}
@@ -187,7 +187,7 @@ static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
return wqe;
}
-static int next_opcode_rc(struct rxe_qp *qp, unsigned opcode, int fits)
+static int next_opcode_rc(struct rxe_qp *qp, u32 opcode, int fits)
{
switch (opcode) {
case IB_WR_RDMA_WRITE:
@@ -259,7 +259,7 @@ static int next_opcode_rc(struct rxe_qp *qp, unsigned opcode, int fits)
return -EINVAL;
}
-static int next_opcode_uc(struct rxe_qp *qp, unsigned opcode, int fits)
+static int next_opcode_uc(struct rxe_qp *qp, u32 opcode, int fits)
{
switch (opcode) {
case IB_WR_RDMA_WRITE:
@@ -311,7 +311,7 @@ static int next_opcode_uc(struct rxe_qp *qp, unsigned opcode, int fits)
}
static int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
- unsigned opcode)
+ u32 opcode)
{
int fits = (wqe->dma.resid <= qp->mtu);
@@ -588,7 +588,7 @@ int rxe_requester(void *arg)
struct rxe_pkt_info pkt;
struct sk_buff *skb;
struct rxe_send_wqe *wqe;
- unsigned mask;
+ enum rxe_hdr_mask mask;
int payload;
int mtu;
int opcode;
@@ -626,7 +626,8 @@ next_wqe:
rmr = rxe_pool_get_index(&rxe->mr_pool,
wqe->wr.ex.invalidate_rkey >> 8);
if (!rmr) {
- pr_err("No mr for key %#x\n", wqe->wr.ex.invalidate_rkey);
+ pr_err("No mr for key %#x\n",
+ wqe->wr.ex.invalidate_rkey);
wqe->state = wqe_state_error;
wqe->status = IB_WC_MW_BIND_ERR;
goto exit;
@@ -702,12 +703,12 @@ next_wqe:
skb = init_req_packet(qp, wqe, opcode, payload, &pkt);
if (unlikely(!skb)) {
- pr_err("Failed allocating skb\n");
+ pr_err("qp#%d Failed allocating skb\n", qp_num(qp));
goto err;
}
if (fill_packet(qp, wqe, &pkt, skb, payload)) {
- pr_debug("Error during fill packet\n");
+ pr_debug("qp#%d Error during fill packet\n", qp_num(qp));
goto err;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index 3e0f0f2baace..dd3d88adc003 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -383,7 +383,7 @@ static enum resp_states check_resource(struct rxe_qp *qp,
* too many read/atomic ops, we just
* recycle the responder resource queue
*/
- if (likely(qp->attr.max_rd_atomic > 0))
+ if (likely(qp->attr.max_dest_rd_atomic > 0))
return RESPST_CHK_LENGTH;
else
return RESPST_ERR_TOO_MANY_RDMA_ATM_REQ;
@@ -749,6 +749,18 @@ static enum resp_states read_reply(struct rxe_qp *qp,
return state;
}
+static void build_rdma_network_hdr(union rdma_network_hdr *hdr,
+ struct rxe_pkt_info *pkt)
+{
+ struct sk_buff *skb = PKT_TO_SKB(pkt);
+
+ memset(hdr, 0, sizeof(*hdr));
+ if (skb->protocol == htons(ETH_P_IP))
+ memcpy(&hdr->roce4grh, ip_hdr(skb), sizeof(hdr->roce4grh));
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ memcpy(&hdr->ibgrh, ipv6_hdr(skb), sizeof(hdr->ibgrh));
+}
+
/* Executes a new request. A retried request never reach that function (send
* and writes are discarded, and reads and atomics are retried elsewhere.
*/
@@ -761,13 +773,8 @@ static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
qp_type(qp) == IB_QPT_SMI ||
qp_type(qp) == IB_QPT_GSI) {
union rdma_network_hdr hdr;
- struct sk_buff *skb = PKT_TO_SKB(pkt);
- memset(&hdr, 0, sizeof(hdr));
- if (skb->protocol == htons(ETH_P_IP))
- memcpy(&hdr.roce4grh, ip_hdr(skb), sizeof(hdr.roce4grh));
- else if (skb->protocol == htons(ETH_P_IPV6))
- memcpy(&hdr.ibgrh, ipv6_hdr(skb), sizeof(hdr.ibgrh));
+ build_rdma_network_hdr(&hdr, pkt);
err = send_data_in(qp, &hdr, sizeof(hdr));
if (err)
@@ -881,7 +888,8 @@ static enum resp_states do_complete(struct rxe_qp *qp,
rmr = rxe_pool_get_index(&rxe->mr_pool,
wc->ex.invalidate_rkey >> 8);
if (unlikely(!rmr)) {
- pr_err("Bad rkey %#x invalidation\n", wc->ex.invalidate_rkey);
+ pr_err("Bad rkey %#x invalidation\n",
+ wc->ex.invalidate_rkey);
return RESPST_ERROR;
}
rmr->state = RXE_MEM_STATE_FREE;
@@ -1208,7 +1216,8 @@ int rxe_responder(void *arg)
}
while (1) {
- pr_debug("state = %s\n", resp_state_name[state]);
+ pr_debug("qp#%d state = %s\n", qp_num(qp),
+ resp_state_name[state]);
switch (state) {
case RESPST_GET_REQ:
state = get_req(qp, &pkt);
diff --git a/drivers/infiniband/sw/rxe/rxe_sysfs.c b/drivers/infiniband/sw/rxe/rxe_sysfs.c
index cf8e77800046..d5ed7571128f 100644
--- a/drivers/infiniband/sw/rxe/rxe_sysfs.c
+++ b/drivers/infiniband/sw/rxe/rxe_sysfs.c
@@ -79,7 +79,7 @@ static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
len = sanitize_arg(val, intf, sizeof(intf));
if (!len) {
- pr_err("rxe: add: invalid interface name\n");
+ pr_err("add: invalid interface name\n");
err = -EINVAL;
goto err;
}
@@ -92,20 +92,20 @@ static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
}
if (net_to_rxe(ndev)) {
- pr_err("rxe: already configured on %s\n", intf);
+ pr_err("already configured on %s\n", intf);
err = -EINVAL;
goto err;
}
rxe = rxe_net_add(ndev);
if (!rxe) {
- pr_err("rxe: failed to add %s\n", intf);
+ pr_err("failed to add %s\n", intf);
err = -EINVAL;
goto err;
}
rxe_set_port_state(ndev);
- pr_info("rxe: added %s to %s\n", rxe->ib_dev.name, intf);
+ pr_info("added %s to %s\n", rxe->ib_dev.name, intf);
err:
if (ndev)
dev_put(ndev);
@@ -120,7 +120,7 @@ static int rxe_param_set_remove(const char *val, const struct kernel_param *kp)
len = sanitize_arg(val, intf, sizeof(intf));
if (!len) {
- pr_err("rxe: add: invalid interface name\n");
+ pr_err("add: invalid interface name\n");
return -EINVAL;
}
@@ -133,7 +133,7 @@ static int rxe_param_set_remove(const char *val, const struct kernel_param *kp)
rxe = get_rxe_by_name(intf);
if (!rxe) {
- pr_err("rxe: not configured on %s\n", intf);
+ pr_err("not configured on %s\n", intf);
return -EINVAL;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 4552be960c6a..19841c863daf 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -100,10 +100,12 @@ static int rxe_query_port(struct ib_device *dev,
rxe->ndev->ethtool_ops->get_settings(rxe->ndev, &cmd);
speed = cmd.speed;
} else {
- pr_warn("%s speed is unknown, defaulting to 1000\n", rxe->ndev->name);
+ pr_warn("%s speed is unknown, defaulting to 1000\n",
+ rxe->ndev->name);
speed = 1000;
}
- rxe_eth_speed_to_ib_speed(speed, &attr->active_speed, &attr->active_width);
+ rxe_eth_speed_to_ib_speed(speed, &attr->active_speed,
+ &attr->active_width);
mutex_unlock(&rxe->usdev_lock);
return 0;
@@ -761,7 +763,7 @@ static int init_send_wqe(struct rxe_qp *qp, struct ib_send_wr *ibwr,
}
static int post_one_send(struct rxe_qp *qp, struct ib_send_wr *ibwr,
- unsigned mask, u32 length)
+ unsigned int mask, u32 length)
{
int err;
struct rxe_sq *sq = &qp->sq;
@@ -801,26 +803,15 @@ err1:
return err;
}
-static int rxe_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
- struct ib_send_wr **bad_wr)
+static int rxe_post_send_kernel(struct rxe_qp *qp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
{
int err = 0;
- struct rxe_qp *qp = to_rqp(ibqp);
unsigned int mask;
unsigned int length = 0;
int i;
int must_sched;
- if (unlikely(!qp->valid)) {
- *bad_wr = wr;
- return -EINVAL;
- }
-
- if (unlikely(qp->req.state < QP_STATE_READY)) {
- *bad_wr = wr;
- return -EINVAL;
- }
-
while (wr) {
mask = wr_opcode_mask(wr->opcode, qp);
if (unlikely(!mask)) {
@@ -861,6 +852,29 @@ static int rxe_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
return err;
}
+static int rxe_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
+{
+ struct rxe_qp *qp = to_rqp(ibqp);
+
+ if (unlikely(!qp->valid)) {
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ if (unlikely(qp->req.state < QP_STATE_READY)) {
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ if (qp->is_user) {
+ /* Utilize process context to do protocol processing */
+ rxe_run_task(&qp->req.task, 0);
+ return 0;
+ } else
+ return rxe_post_send_kernel(qp, wr, bad_wr);
+}
+
static int rxe_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
struct ib_recv_wr **bad_wr)
{
@@ -1133,8 +1147,8 @@ static int rxe_set_page(struct ib_mr *ibmr, u64 addr)
return 0;
}
-static int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
- unsigned int *sg_offset)
+static int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset)
{
struct rxe_mem *mr = to_rmr(ibmr);
int n;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 9dbfcc0ab577..7b8d2d9e2263 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -772,7 +772,13 @@ static inline void ipoib_unregister_debugfs(void) { }
#define ipoib_printk(level, priv, format, arg...) \
printk(level "%s: " format, ((struct ipoib_dev_priv *) priv)->dev->name , ## arg)
#define ipoib_warn(priv, format, arg...) \
- ipoib_printk(KERN_WARNING, priv, format , ## arg)
+do { \
+ static DEFINE_RATELIMIT_STATE(_rs, \
+ 10 * HZ /*10 seconds */, \
+ 100); \
+ if (__ratelimit(&_rs)) \
+ ipoib_printk(KERN_WARNING, priv, format , ## arg);\
+} while (0)
extern int ipoib_sendq_size;
extern int ipoib_recvq_size;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index cc1c1b062ea5..5636fc3da6b8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -2196,7 +2196,8 @@ static int __init ipoib_init_module(void)
* its private workqueue, and we only queue up flush events
* on our global flush workqueue. This avoids the deadlocks.
*/
- ipoib_workqueue = create_singlethread_workqueue("ipoib_flush");
+ ipoib_workqueue = alloc_ordered_workqueue("ipoib_flush",
+ WQ_MEM_RECLAIM);
if (!ipoib_workqueue) {
ret = -ENOMEM;
goto err_fs;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index c55ecb2c3736..189dcd1709d2 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -147,7 +147,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
int ret, size;
int i;
- priv->pd = ib_alloc_pd(priv->ca);
+ priv->pd = ib_alloc_pd(priv->ca, 0);
if (IS_ERR(priv->pd)) {
printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name);
return -ENODEV;
@@ -157,7 +157,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
* the various IPoIB tasks assume they will never race against
* themselves, so always use a single thread workqueue
*/
- priv->wq = create_singlethread_workqueue("ipoib_wq");
+ priv->wq = alloc_ordered_workqueue("ipoib_wq", WQ_MEM_RECLAIM);
if (!priv->wq) {
printk(KERN_WARNING "ipoib: failed to allocate device WQ\n");
goto out_free_pd;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 0351059783b1..0be6a7c5ddb5 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -374,7 +374,6 @@ struct iser_reg_ops {
struct iser_device {
struct ib_device *ib_device;
struct ib_pd *pd;
- struct ib_mr *mr;
struct ib_event_handler event_handler;
struct list_head ig_list;
int refcount;
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 90be56893414..9c3e9ab53a41 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -199,7 +199,11 @@ iser_reg_dma(struct iser_device *device, struct iser_data_buf *mem,
* FIXME: rework the registration code path to differentiate
* rkey/lkey use cases
*/
- reg->rkey = device->mr ? device->mr->rkey : 0;
+
+ if (device->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)
+ reg->rkey = device->pd->unsafe_global_rkey;
+ else
+ reg->rkey = 0;
reg->sge.addr = ib_sg_dma_address(device->ib_device, &sg[0]);
reg->sge.length = ib_sg_dma_len(device->ib_device, &sg[0]);
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 1b4945367e4f..a4b791dfaa1d 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -88,7 +88,8 @@ static int iser_create_device_ib_res(struct iser_device *device)
device->comps_used, ib_dev->name,
ib_dev->num_comp_vectors, max_cqe);
- device->pd = ib_alloc_pd(ib_dev);
+ device->pd = ib_alloc_pd(ib_dev,
+ iser_always_reg ? 0 : IB_PD_UNSAFE_GLOBAL_RKEY);
if (IS_ERR(device->pd))
goto pd_err;
@@ -103,26 +104,13 @@ static int iser_create_device_ib_res(struct iser_device *device)
}
}
- if (!iser_always_reg) {
- int access = IB_ACCESS_LOCAL_WRITE |
- IB_ACCESS_REMOTE_WRITE |
- IB_ACCESS_REMOTE_READ;
-
- device->mr = ib_get_dma_mr(device->pd, access);
- if (IS_ERR(device->mr))
- goto cq_err;
- }
-
INIT_IB_EVENT_HANDLER(&device->event_handler, ib_dev,
iser_event_handler);
if (ib_register_event_handler(&device->event_handler))
- goto handler_err;
+ goto cq_err;
return 0;
-handler_err:
- if (device->mr)
- ib_dereg_mr(device->mr);
cq_err:
for (i = 0; i < device->comps_used; i++) {
struct iser_comp *comp = &device->comps[i];
@@ -154,14 +142,10 @@ static void iser_free_device_ib_res(struct iser_device *device)
}
(void)ib_unregister_event_handler(&device->event_handler);
- if (device->mr)
- (void)ib_dereg_mr(device->mr);
ib_dealloc_pd(device->pd);
kfree(device->comps);
device->comps = NULL;
-
- device->mr = NULL;
device->pd = NULL;
}
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index cae9bbcc27e7..6dd43f63238e 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -309,7 +309,7 @@ isert_create_device_ib_res(struct isert_device *device)
if (ret)
goto out;
- device->pd = ib_alloc_pd(ib_dev);
+ device->pd = ib_alloc_pd(ib_dev, 0);
if (IS_ERR(device->pd)) {
ret = PTR_ERR(device->pd);
isert_err("failed to allocate pd, device %p, ret=%d\n",
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 3322ed750172..d980fb458ad4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1262,6 +1262,7 @@ static int srp_map_finish_fmr(struct srp_map_state *state,
{
struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
+ struct ib_pd *pd = target->pd;
struct ib_pool_fmr *fmr;
u64 io_addr = 0;
@@ -1273,9 +1274,9 @@ static int srp_map_finish_fmr(struct srp_map_state *state,
if (state->npages == 0)
return 0;
- if (state->npages == 1 && target->global_mr) {
+ if (state->npages == 1 && (pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)) {
srp_map_desc(state, state->base_dma_addr, state->dma_len,
- target->global_mr->rkey);
+ pd->unsafe_global_rkey);
goto reset_state;
}
@@ -1315,6 +1316,7 @@ static int srp_map_finish_fr(struct srp_map_state *state,
{
struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
+ struct ib_pd *pd = target->pd;
struct ib_send_wr *bad_wr;
struct ib_reg_wr wr;
struct srp_fr_desc *desc;
@@ -1326,12 +1328,12 @@ static int srp_map_finish_fr(struct srp_map_state *state,
WARN_ON_ONCE(!dev->use_fast_reg);
- if (sg_nents == 1 && target->global_mr) {
+ if (sg_nents == 1 && (pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)) {
unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0;
srp_map_desc(state, sg_dma_address(state->sg) + sg_offset,
sg_dma_len(state->sg) - sg_offset,
- target->global_mr->rkey);
+ pd->unsafe_global_rkey);
if (sg_offset_p)
*sg_offset_p = 0;
return 1;
@@ -1386,7 +1388,7 @@ static int srp_map_finish_fr(struct srp_map_state *state,
static int srp_map_sg_entry(struct srp_map_state *state,
struct srp_rdma_ch *ch,
- struct scatterlist *sg, int sg_index)
+ struct scatterlist *sg)
{
struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
@@ -1400,7 +1402,9 @@ static int srp_map_sg_entry(struct srp_map_state *state,
while (dma_len) {
unsigned offset = dma_addr & ~dev->mr_page_mask;
- if (state->npages == dev->max_pages_per_mr || offset != 0) {
+
+ if (state->npages == dev->max_pages_per_mr ||
+ (state->npages > 0 && offset != 0)) {
ret = srp_map_finish_fmr(state, ch);
if (ret)
return ret;
@@ -1417,12 +1421,12 @@ static int srp_map_sg_entry(struct srp_map_state *state,
}
/*
- * If the last entry of the MR wasn't a full page, then we need to
+ * If the end of the MR is not on a page boundary then we need to
* close it out and start a new one -- we can only merge at page
* boundaries.
*/
ret = 0;
- if (len != dev->mr_page_size)
+ if ((dma_addr & ~dev->mr_page_mask) != 0)
ret = srp_map_finish_fmr(state, ch);
return ret;
}
@@ -1439,7 +1443,7 @@ static int srp_map_sg_fmr(struct srp_map_state *state, struct srp_rdma_ch *ch,
state->fmr.end = req->fmr_list + ch->target->mr_per_cmd;
for_each_sg(scat, sg, count, i) {
- ret = srp_map_sg_entry(state, ch, sg, i);
+ ret = srp_map_sg_entry(state, ch, sg);
if (ret)
return ret;
}
@@ -1491,7 +1495,7 @@ static int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch,
for_each_sg(scat, sg, count, i) {
srp_map_desc(state, ib_sg_dma_address(dev->dev, sg),
ib_sg_dma_len(dev->dev, sg),
- target->global_mr->rkey);
+ target->pd->unsafe_global_rkey);
}
return 0;
@@ -1591,6 +1595,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
struct srp_request *req)
{
struct srp_target_port *target = ch->target;
+ struct ib_pd *pd = target->pd;
struct scatterlist *scat;
struct srp_cmd *cmd = req->cmd->buf;
int len, nents, count, ret;
@@ -1626,7 +1631,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
fmt = SRP_DATA_DESC_DIRECT;
len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
- if (count == 1 && target->global_mr) {
+ if (count == 1 && (pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)) {
/*
* The midlayer only generated a single gather/scatter
* entry, or DMA mapping coalesced everything to a
@@ -1636,7 +1641,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
struct srp_direct_buf *buf = (void *) cmd->add_data;
buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat));
- buf->key = cpu_to_be32(target->global_mr->rkey);
+ buf->key = cpu_to_be32(pd->unsafe_global_rkey);
buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat));
req->nmdesc = 0;
@@ -1709,14 +1714,14 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
memcpy(indirect_hdr->desc_list, req->indirect_desc,
count * sizeof (struct srp_direct_buf));
- if (!target->global_mr) {
+ if (!(pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)) {
ret = srp_map_idb(ch, req, state.gen.next, state.gen.end,
idb_len, &idb_rkey);
if (ret < 0)
goto unmap;
req->nmdesc++;
} else {
- idb_rkey = cpu_to_be32(target->global_mr->rkey);
+ idb_rkey = cpu_to_be32(pd->unsafe_global_rkey);
}
indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr);
@@ -3268,8 +3273,8 @@ static ssize_t srp_create_target(struct device *dev,
target->io_class = SRP_REV16A_IB_IO_CLASS;
target->scsi_host = target_host;
target->srp_host = host;
+ target->pd = host->srp_dev->pd;
target->lkey = host->srp_dev->pd->local_dma_lkey;
- target->global_mr = host->srp_dev->global_mr;
target->cmd_sg_cnt = cmd_sg_entries;
target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries;
target->allow_ext_sg = allow_ext_sg;
@@ -3524,6 +3529,7 @@ static void srp_add_one(struct ib_device *device)
struct srp_host *host;
int mr_page_shift, p;
u64 max_pages_per_mr;
+ unsigned int flags = 0;
srp_dev = kzalloc(sizeof(*srp_dev), GFP_KERNEL);
if (!srp_dev)
@@ -3558,6 +3564,10 @@ static void srp_add_one(struct ib_device *device)
srp_dev->use_fmr = !srp_dev->use_fast_reg && srp_dev->has_fmr;
}
+ if (never_register || !register_always ||
+ (!srp_dev->has_fmr && !srp_dev->has_fr))
+ flags |= IB_PD_UNSAFE_GLOBAL_RKEY;
+
if (srp_dev->use_fast_reg) {
srp_dev->max_pages_per_mr =
min_t(u32, srp_dev->max_pages_per_mr,
@@ -3573,19 +3583,10 @@ static void srp_add_one(struct ib_device *device)
INIT_LIST_HEAD(&srp_dev->dev_list);
srp_dev->dev = device;
- srp_dev->pd = ib_alloc_pd(device);
+ srp_dev->pd = ib_alloc_pd(device, flags);
if (IS_ERR(srp_dev->pd))
goto free_dev;
- if (never_register || !register_always ||
- (!srp_dev->has_fmr && !srp_dev->has_fr)) {
- srp_dev->global_mr = ib_get_dma_mr(srp_dev->pd,
- IB_ACCESS_LOCAL_WRITE |
- IB_ACCESS_REMOTE_READ |
- IB_ACCESS_REMOTE_WRITE);
- if (IS_ERR(srp_dev->global_mr))
- goto err_pd;
- }
for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
host = srp_add_port(srp_dev, p);
@@ -3596,9 +3597,6 @@ static void srp_add_one(struct ib_device *device)
ib_set_client_data(device, &srp_client, srp_dev);
return;
-err_pd:
- ib_dealloc_pd(srp_dev->pd);
-
free_dev:
kfree(srp_dev);
}
@@ -3638,8 +3636,6 @@ static void srp_remove_one(struct ib_device *device, void *client_data)
kfree(host);
}
- if (srp_dev->global_mr)
- ib_dereg_mr(srp_dev->global_mr);
ib_dealloc_pd(srp_dev->pd);
kfree(srp_dev);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 26bb9b0a7a63..21c69695f9d4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -90,7 +90,6 @@ struct srp_device {
struct list_head dev_list;
struct ib_device *dev;
struct ib_pd *pd;
- struct ib_mr *global_mr;
u64 mr_page_mask;
int mr_page_size;
int mr_max_size;
@@ -179,7 +178,7 @@ struct srp_target_port {
spinlock_t lock;
/* read only in the hot path */
- struct ib_mr *global_mr;
+ struct ib_pd *pd;
struct srp_rdma_ch *ch;
u32 ch_count;
u32 lkey;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 883bbfe08e0e..0b1f69ed2e92 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -2480,7 +2480,7 @@ static void srpt_add_one(struct ib_device *device)
init_waitqueue_head(&sdev->ch_releaseQ);
mutex_init(&sdev->mutex);
- sdev->pd = ib_alloc_pd(device);
+ sdev->pd = ib_alloc_pd(device, 0);
if (IS_ERR(sdev->pd))
goto free_dev;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 509608c95994..cbd75cf44739 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -12,6 +12,21 @@ menuconfig INPUT_KEYBOARD
if INPUT_KEYBOARD
+config KEYBOARD_ADC
+ tristate "ADC Ladder Buttons"
+ depends on IIO
+ select INPUT_POLLDEV
+ help
+ This driver implements support for buttons connected
+ to an ADC using a resistor ladder.
+
+ Say Y here if your device has such buttons connected to an ADC. Your
+ board-specific setup logic must also provide a configuration data
+ for mapping voltages to buttons.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adc_keys.
+
config KEYBOARD_ADP5520
tristate "Keypad Support for ADP5520 PMIC"
depends on PMIC_ADP5520
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 1d416ddf84e4..d9f4cfcf3410 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -4,6 +4,7 @@
# Each configuration option enables a list of files.
+obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
new file mode 100644
index 000000000000..f8cf2ccacefd
--- /dev/null
+++ b/drivers/input/keyboard/adc-keys.c
@@ -0,0 +1,210 @@
+/*
+ * Input driver for resistor ladder connected on ADC
+ *
+ * Copyright (c) 2016 Alexandre Belloni
+ *
+ * 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/err.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+struct adc_keys_button {
+ u32 voltage;
+ u32 keycode;
+};
+
+struct adc_keys_state {
+ struct iio_channel *channel;
+ u32 num_keys;
+ u32 last_key;
+ u32 keyup_voltage;
+ const struct adc_keys_button *map;
+};
+
+static void adc_keys_poll(struct input_polled_dev *dev)
+{
+ struct adc_keys_state *st = dev->private;
+ int i, value, ret;
+ u32 diff, closest = 0xffffffff;
+ int keycode = 0;
+
+ ret = iio_read_channel_processed(st->channel, &value);
+ if (unlikely(ret < 0)) {
+ /* Forcibly release key if any was pressed */
+ value = st->keyup_voltage;
+ } else {
+ for (i = 0; i < st->num_keys; i++) {
+ diff = abs(st->map[i].voltage - value);
+ if (diff < closest) {
+ closest = diff;
+ keycode = st->map[i].keycode;
+ }
+ }
+ }
+
+ if (abs(st->keyup_voltage - value) < closest)
+ keycode = 0;
+
+ if (st->last_key && st->last_key != keycode)
+ input_report_key(dev->input, st->last_key, 0);
+
+ if (keycode)
+ input_report_key(dev->input, keycode, 1);
+
+ input_sync(dev->input);
+ st->last_key = keycode;
+}
+
+static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
+{
+ struct adc_keys_button *map;
+ struct fwnode_handle *child;
+ int i;
+
+ st->num_keys = device_get_child_node_count(dev);
+ if (st->num_keys == 0) {
+ dev_err(dev, "keymap is missing\n");
+ return -EINVAL;
+ }
+
+ map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ i = 0;
+ device_for_each_child_node(dev, child) {
+ if (fwnode_property_read_u32(child, "press-threshold-microvolt",
+ &map[i].voltage)) {
+ dev_err(dev, "Key with invalid or missing voltage\n");
+ fwnode_handle_put(child);
+ return -EINVAL;
+ }
+ map[i].voltage /= 1000;
+
+ if (fwnode_property_read_u32(child, "linux,code",
+ &map[i].keycode)) {
+ dev_err(dev, "Key with invalid or missing linux,code\n");
+ fwnode_handle_put(child);
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ st->map = map;
+ return 0;
+}
+
+static int adc_keys_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct adc_keys_state *st;
+ struct input_polled_dev *poll_dev;
+ struct input_dev *input;
+ enum iio_chan_type type;
+ int i, value;
+ int error;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->channel = devm_iio_channel_get(dev, "buttons");
+ if (IS_ERR(st->channel))
+ return PTR_ERR(st->channel);
+
+ if (!st->channel->indio_dev)
+ return -ENXIO;
+
+ error = iio_get_channel_type(st->channel, &type);
+ if (error < 0)
+ return error;
+
+ if (type != IIO_VOLTAGE) {
+ dev_err(dev, "Incompatible channel type %d\n", type);
+ return -EINVAL;
+ }
+
+ if (device_property_read_u32(dev, "keyup-threshold-microvolt",
+ &st->keyup_voltage)) {
+ dev_err(dev, "Invalid or missing keyup voltage\n");
+ return -EINVAL;
+ }
+ st->keyup_voltage /= 1000;
+
+ error = adc_keys_load_keymap(dev, st);
+ if (error)
+ return error;
+
+ platform_set_drvdata(pdev, st);
+
+ poll_dev = devm_input_allocate_polled_device(dev);
+ if (!poll_dev) {
+ dev_err(dev, "failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ if (!device_property_read_u32(dev, "poll-interval", &value))
+ poll_dev->poll_interval = value;
+
+ poll_dev->poll = adc_keys_poll;
+ poll_dev->private = st;
+
+ input = poll_dev->input;
+
+ input->name = pdev->name;
+ input->phys = "adc-keys/input0";
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ __set_bit(EV_KEY, input->evbit);
+ for (i = 0; i < st->num_keys; i++)
+ __set_bit(st->map[i].keycode, input->keybit);
+
+ if (device_property_read_bool(dev, "autorepeat"))
+ __set_bit(EV_REP, input->evbit);
+
+ error = input_register_polled_device(poll_dev);
+ if (error) {
+ dev_err(dev, "Unable to register input device: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id adc_keys_of_match[] = {
+ { .compatible = "adc-keys", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adc_keys_of_match);
+#endif
+
+static struct platform_driver __refdata adc_keys_driver = {
+ .driver = {
+ .name = "adc_keys",
+ .of_match_table = of_match_ptr(adc_keys_of_match),
+ },
+ .probe = adc_keys_probe,
+};
+module_platform_driver(adc_keys_driver);
+
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 4b0878f35471..25943e9bc8bf 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/input/matrix_keypad.h>
@@ -44,6 +45,7 @@
* @dev: Device pointer
* @idev: Input device
* @ec: Top level ChromeOS device to use to talk to EC
+ * @notifier: interrupt event notifier for transport devices
*/
struct cros_ec_keyb {
unsigned int rows;
@@ -57,6 +59,7 @@ struct cros_ec_keyb {
struct device *dev;
struct input_dev *idev;
struct cros_ec_device *ec;
+ struct notifier_block notifier;
};
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
input_sync(ckdev->idev);
}
-static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
-{
- int ret = 0;
- struct cros_ec_command *msg;
-
- msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
-
- msg->version = 0;
- msg->command = EC_CMD_MKBP_STATE;
- msg->insize = ckdev->cols;
- msg->outsize = 0;
-
- ret = cros_ec_cmd_xfer(ckdev->ec, msg);
- if (ret < 0) {
- dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
- goto exit;
- }
-
- memcpy(kb_state, msg->data, ckdev->cols);
-exit:
- kfree(msg);
- return ret;
-}
-
-static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+static int cros_ec_keyb_open(struct input_dev *dev)
{
- struct cros_ec_keyb *ckdev = data;
- struct cros_ec_device *ec = ckdev->ec;
- int ret;
- uint8_t kb_state[ckdev->cols];
-
- if (device_may_wakeup(ec->dev))
- pm_wakeup_event(ec->dev, 0);
-
- ret = cros_ec_keyb_get_state(ckdev, kb_state);
- if (ret >= 0)
- cros_ec_keyb_process(ckdev, kb_state, ret);
- else
- dev_err(ckdev->dev, "failed to get keyboard state: %d\n", ret);
+ struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
- return IRQ_HANDLED;
+ return blocking_notifier_chain_register(&ckdev->ec->event_notifier,
+ &ckdev->notifier);
}
-static int cros_ec_keyb_open(struct input_dev *dev)
+static void cros_ec_keyb_close(struct input_dev *dev)
{
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
- struct cros_ec_device *ec = ckdev->ec;
- return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "cros_ec_keyb", ckdev);
+ blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
+ &ckdev->notifier);
}
-static void cros_ec_keyb_close(struct input_dev *dev)
+static int cros_ec_keyb_work(struct notifier_block *nb,
+ unsigned long queued_during_suspend, void *_notify)
{
- struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
- struct cros_ec_device *ec = ckdev->ec;
+ struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
+ notifier);
- free_irq(ec->irq, ckdev);
+ if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
+ return NOTIFY_DONE;
+ /*
+ * If EC is not the wake source, discard key state changes during
+ * suspend.
+ */
+ if (queued_during_suspend)
+ return NOTIFY_OK;
+ if (ckdev->ec->event_size != ckdev->cols) {
+ dev_err(ckdev->dev,
+ "Discarded incomplete key matrix event.\n");
+ return NOTIFY_OK;
+ }
+ cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix,
+ ckdev->ec->event_size);
+ return NOTIFY_OK;
}
/*
@@ -265,12 +245,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
if (!idev)
return -ENOMEM;
- if (!ec->irq) {
- dev_err(dev, "no EC IRQ specified\n");
- return -EINVAL;
- }
-
ckdev->ec = ec;
+ ckdev->notifier.notifier_call = cros_ec_keyb_work;
ckdev->dev = dev;
dev_set_drvdata(dev, ckdev);
@@ -311,54 +287,6 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-/* Clear any keys in the buffer */
-static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
-{
- uint8_t old_state[ckdev->cols];
- uint8_t new_state[ckdev->cols];
- unsigned long duration;
- int i, ret;
-
- /*
- * Keep reading until we see that the scan state does not change.
- * That indicates that we are done.
- *
- * Assume that the EC keyscan buffer is at most 32 deep.
- */
- duration = jiffies;
- ret = cros_ec_keyb_get_state(ckdev, new_state);
- for (i = 1; !ret && i < 32; i++) {
- memcpy(old_state, new_state, sizeof(old_state));
- ret = cros_ec_keyb_get_state(ckdev, new_state);
- if (0 == memcmp(old_state, new_state, sizeof(old_state)))
- break;
- }
- duration = jiffies - duration;
- dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
- jiffies_to_usecs(duration));
-}
-
-static int cros_ec_keyb_resume(struct device *dev)
-{
- struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
-
- /*
- * When the EC is not a wake source, then it could not have caused the
- * resume, so we clear the EC's key scan buffer. If the EC was a
- * wake source (e.g. the lid is open and the user might press a key to
- * wake) then the key scan buffer should be preserved.
- */
- if (!ckdev->ec->was_wake_device)
- cros_ec_keyb_clear_keyboard(ckdev);
-
- return 0;
-}
-
-#endif
-
-static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
-
#ifdef CONFIG_OF
static const struct of_device_id cros_ec_keyb_of_match[] = {
{ .compatible = "google,cros-ec-keyb" },
@@ -372,7 +300,6 @@ static struct platform_driver cros_ec_keyb_driver = {
.driver = {
.name = "cros-ec-keyb",
.of_match_table = of_match_ptr(cros_ec_keyb_of_match),
- .pm = &cros_ec_keyb_pm_ops,
},
};
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index 421d9c55b0e8..1277c39f9482 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -25,8 +25,6 @@
#include <linux/slab.h>
#include <mach/jornada720.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
@@ -66,10 +64,8 @@ static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id)
jornada_ssp_start();
if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) {
- printk(KERN_DEBUG
- "jornada720_kbd: "
- "GetKeycode command failed with ETIMEDOUT, "
- "flushed bus\n");
+ dev_dbg(&pdev->dev,
+ "GetKeycode command failed with ETIMEDOUT, flushed bus\n");
} else {
/* How many keycodes are waiting for us? */
count = jornada_ssp_byte(TXDUMMY);
@@ -97,14 +93,16 @@ static int jornada720_kbd_probe(struct platform_device *pdev)
{
struct jornadakbd *jornadakbd;
struct input_dev *input_dev;
- int i, err;
+ int i, err, irq;
- jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!jornadakbd || !input_dev) {
- err = -ENOMEM;
- goto fail1;
- }
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return irq < 0 ? irq : -EINVAL;
+
+ jornadakbd = devm_kzalloc(&pdev->dev, sizeof(*jornadakbd), GFP_KERNEL);
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!jornadakbd || !input_dev)
+ return -ENOMEM;
platform_set_drvdata(pdev, jornadakbd);
@@ -127,40 +125,16 @@ static int jornada720_kbd_probe(struct platform_device *pdev)
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- err = request_irq(IRQ_GPIO0,
- jornada720_kbd_interrupt,
- IRQF_TRIGGER_FALLING,
- "jornadakbd", pdev);
+ err = devm_request_irq(&pdev->dev, irq, jornada720_kbd_interrupt,
+ IRQF_TRIGGER_FALLING, "jornadakbd", pdev);
if (err) {
- printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n");
- goto fail1;
+ dev_err(&pdev->dev, "unable to grab IRQ%d: %d\n", irq, err);
+ return err;
}
- err = input_register_device(jornadakbd->input);
- if (err)
- goto fail2;
-
- return 0;
-
- fail2: /* IRQ, DEVICE, MEMORY */
- free_irq(IRQ_GPIO0, pdev);
- fail1: /* DEVICE, MEMORY */
- input_free_device(input_dev);
- kfree(jornadakbd);
- return err;
+ return input_register_device(jornadakbd->input);
};
-static int jornada720_kbd_remove(struct platform_device *pdev)
-{
- struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
-
- free_irq(IRQ_GPIO0, pdev);
- input_unregister_device(jornadakbd->input);
- kfree(jornadakbd);
-
- return 0;
-}
-
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:jornada720_kbd");
@@ -169,6 +143,5 @@ static struct platform_driver jornada720_kbd_driver = {
.name = "jornada720_kbd",
},
.probe = jornada720_kbd_probe,
- .remove = jornada720_kbd_remove,
};
module_platform_driver(jornada720_kbd_driver);
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 24a9f599082f..7544888c4749 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -168,7 +168,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
error = input_register_device(input);
if (error < 0) {
dev_err(&pdev->dev, "failed to register input device\n");
- input_free_device(input);
return error;
}
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index efb0ca871327..7ffb614ce566 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -292,6 +292,18 @@ config INPUT_GPIO_TILT_POLLED
To compile this driver as a module, choose M here: the
module will be called gpio_tilt_polled.
+config INPUT_GPIO_DECODER
+ tristate "Polled GPIO Decoder Input driver"
+ depends on GPIOLIB || COMPILE_TEST
+ select INPUT_POLLDEV
+ help
+ Say Y here if you want driver to read status of multiple GPIO
+ lines and report the encoded value as an absolute integer to
+ input subsystem.
+
+ To compile this driver as a module, choose M here: the module
+ will be called gpio_decoder.
+
config INPUT_IXP4XX_BEEPER
tristate "IXP4XX Beeper support"
depends on ARCH_IXP4XX
@@ -454,10 +466,10 @@ config INPUT_RETU_PWRBUTTON
config INPUT_TPS65218_PWRBUTTON
tristate "TPS65218 Power button driver"
- depends on MFD_TPS65218
+ depends on (MFD_TPS65217 || MFD_TPS65218)
help
Say Y here if you want to enable power buttong reporting for
- the TPS65218 Power Management IC device.
+ TPS65217 and TPS65218 Power Management IC devices.
To compile this driver as a module, choose M here. The module will
be called tps65218-pwrbutton.
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 6a1e5e20fc1c..0b6d025f0487 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
+obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c
new file mode 100644
index 000000000000..ca7e0bacb2d8
--- /dev/null
+++ b/drivers/input/misc/gpio_decoder.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * A generic driver to read multiple gpio lines and translate the
+ * encoded numeric value into an input event.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+struct gpio_decoder {
+ struct input_polled_dev *poll_dev;
+ struct gpio_descs *input_gpios;
+ struct device *dev;
+ u32 axis;
+ u32 last_stable;
+};
+
+static int gpio_decoder_get_gpios_state(struct gpio_decoder *decoder)
+{
+ struct gpio_descs *gpios = decoder->input_gpios;
+ unsigned int ret = 0;
+ int i, val;
+
+ for (i = 0; i < gpios->ndescs; i++) {
+ val = gpiod_get_value_cansleep(gpios->desc[i]);
+ if (val < 0) {
+ dev_err(decoder->dev,
+ "Error reading gpio %d: %d\n",
+ desc_to_gpio(gpios->desc[i]), val);
+ return val;
+ }
+
+ val = !!val;
+ ret = (ret << 1) | val;
+ }
+
+ return ret;
+}
+
+static void gpio_decoder_poll_gpios(struct input_polled_dev *poll_dev)
+{
+ struct gpio_decoder *decoder = poll_dev->private;
+ int state;
+
+ state = gpio_decoder_get_gpios_state(decoder);
+ if (state >= 0 && state != decoder->last_stable) {
+ input_report_abs(poll_dev->input, decoder->axis, state);
+ input_sync(poll_dev->input);
+ decoder->last_stable = state;
+ }
+}
+
+static int gpio_decoder_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_decoder *decoder;
+ struct input_polled_dev *poll_dev;
+ u32 max;
+ int err;
+
+ decoder = devm_kzalloc(dev, sizeof(struct gpio_decoder), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
+
+ device_property_read_u32(dev, "linux,axis", &decoder->axis);
+ decoder->input_gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
+ if (IS_ERR(decoder->input_gpios)) {
+ dev_err(dev, "unable to acquire input gpios\n");
+ return PTR_ERR(decoder->input_gpios);
+ }
+ if (decoder->input_gpios->ndescs < 2) {
+ dev_err(dev, "not enough gpios found\n");
+ return -EINVAL;
+ }
+
+ if (device_property_read_u32(dev, "decoder-max-value", &max))
+ max = (1U << decoder->input_gpios->ndescs) - 1;
+
+ decoder->dev = dev;
+ poll_dev = devm_input_allocate_polled_device(decoder->dev);
+ if (!poll_dev)
+ return -ENOMEM;
+
+ poll_dev->private = decoder;
+ poll_dev->poll = gpio_decoder_poll_gpios;
+ decoder->poll_dev = poll_dev;
+
+ poll_dev->input->name = pdev->name;
+ poll_dev->input->id.bustype = BUS_HOST;
+ input_set_abs_params(poll_dev->input, decoder->axis, 0, max, 0, 0);
+
+ err = input_register_polled_device(poll_dev);
+ if (err) {
+ dev_err(dev, "failed to register polled device\n");
+ return err;
+ }
+ platform_set_drvdata(pdev, decoder);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_decoder_of_match[] = {
+ { .compatible = "gpio-decoder", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, gpio_decoder_of_match);
+#endif
+
+static struct platform_driver gpio_decoder_driver = {
+ .probe = gpio_decoder_probe,
+ .driver = {
+ .name = "gpio-decoder",
+ .of_match_table = of_match_ptr(gpio_decoder_of_match),
+ }
+};
+module_platform_driver(gpio_decoder_driver);
+
+MODULE_DESCRIPTION("GPIO decoder input driver");
+MODULE_AUTHOR("Vignesh R <vigneshr@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
index 29ddeb7be84b..46b0f48fbf49 100644
--- a/drivers/input/misc/max77693-haptic.c
+++ b/drivers/input/misc/max77693-haptic.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014,2015 Samsung Electronics
* Jaewon Kim <jaewon02.kim@samsung.com>
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.org>
*
* This program is not provided / owned by Maxim Integrated Products.
*
@@ -426,7 +426,7 @@ static struct platform_driver max77693_haptic_driver = {
module_platform_driver(max77693_haptic_driver);
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
-MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver");
MODULE_ALIAS("platform:max77693-haptic");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c
index a39b62651a4b..3273217ce80c 100644
--- a/drivers/input/misc/tps65218-pwrbutton.c
+++ b/drivers/input/misc/tps65218-pwrbutton.c
@@ -1,8 +1,9 @@
/*
- * Texas Instruments' TPS65218 Power Button Input Driver
+ * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
* Author: Felipe Balbi <balbi@ti.com>
+ * Author: Marcin Niestroj <m.niestroj@grinn-global.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
@@ -18,31 +19,61 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/mfd/tps65217.h>
#include <linux/mfd/tps65218.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
-struct tps65218_pwrbutton {
+struct tps6521x_data {
+ unsigned int reg_status;
+ unsigned int pb_mask;
+ const char *name;
+};
+
+static const struct tps6521x_data tps65217_data = {
+ .reg_status = TPS65217_REG_STATUS,
+ .pb_mask = TPS65217_STATUS_PB,
+ .name = "tps65217_pwrbutton",
+};
+
+static const struct tps6521x_data tps65218_data = {
+ .reg_status = TPS65218_REG_STATUS,
+ .pb_mask = TPS65218_STATUS_PB_STATE,
+ .name = "tps65218_pwrbutton",
+};
+
+struct tps6521x_pwrbutton {
struct device *dev;
- struct tps65218 *tps;
+ struct regmap *regmap;
struct input_dev *idev;
+ const struct tps6521x_data *data;
+ char phys[32];
+};
+
+static const struct of_device_id of_tps6521x_pb_match[] = {
+ { .compatible = "ti,tps65217-pwrbutton", .data = &tps65217_data },
+ { .compatible = "ti,tps65218-pwrbutton", .data = &tps65218_data },
+ { },
};
+MODULE_DEVICE_TABLE(of, of_tps6521x_pb_match);
-static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr)
+static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr)
{
- struct tps65218_pwrbutton *pwr = _pwr;
+ struct tps6521x_pwrbutton *pwr = _pwr;
+ const struct tps6521x_data *tps_data = pwr->data;
unsigned int reg;
int error;
- error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, &reg);
+ error = regmap_read(pwr->regmap, tps_data->reg_status, &reg);
if (error) {
dev_err(pwr->dev, "can't read register: %d\n", error);
goto out;
}
- if (reg & TPS65218_STATUS_PB_STATE) {
+ if (reg & tps_data->pb_mask) {
input_report_key(pwr->idev, KEY_POWER, 1);
pm_wakeup_event(pwr->dev, 0);
} else {
@@ -55,42 +86,55 @@ out:
return IRQ_HANDLED;
}
-static int tps65218_pwron_probe(struct platform_device *pdev)
+static int tps6521x_pb_probe(struct platform_device *pdev)
{
- struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
- struct tps65218_pwrbutton *pwr;
+ struct tps6521x_pwrbutton *pwr;
struct input_dev *idev;
+ const struct of_device_id *match;
int error;
int irq;
+ match = of_match_node(of_tps6521x_pb_match, pdev->dev.of_node);
+ if (!match)
+ return -ENXIO;
+
pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
if (!pwr)
return -ENOMEM;
+ pwr->data = match->data;
+
idev = devm_input_allocate_device(dev);
if (!idev)
return -ENOMEM;
- idev->name = "tps65218_pwrbutton";
- idev->phys = "tps65218_pwrbutton/input0";
+ idev->name = pwr->data->name;
+ snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0",
+ pwr->data->name);
+ idev->phys = pwr->phys;
idev->dev.parent = dev;
idev->id.bustype = BUS_I2C;
input_set_capability(idev, EV_KEY, KEY_POWER);
- pwr->tps = tps;
+ pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL);
pwr->dev = dev;
pwr->idev = idev;
platform_set_drvdata(pdev, pwr);
device_init_wakeup(dev, true);
irq = platform_get_irq(pdev, 0);
- error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq,
+ if (irq < 0) {
+ dev_err(dev, "No IRQ resource!\n");
+ return -EINVAL;
+ }
+
+ error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
- "tps65218-pwrbutton", pwr);
+ pwr->data->name, pwr);
if (error) {
dev_err(dev, "failed to request IRQ #%d: %d\n",
irq, error);
@@ -106,21 +150,15 @@ static int tps65218_pwron_probe(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id of_tps65218_pwr_match[] = {
- { .compatible = "ti,tps65218-pwrbutton" },
- { },
-};
-MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match);
-
-static struct platform_driver tps65218_pwron_driver = {
- .probe = tps65218_pwron_probe,
+static struct platform_driver tps6521x_pb_driver = {
+ .probe = tps6521x_pb_probe,
.driver = {
- .name = "tps65218_pwrbutton",
- .of_match_table = of_tps65218_pwr_match,
+ .name = "tps6521x_pwrbutton",
+ .of_match_table = of_tps6521x_pb_match,
},
};
-module_platform_driver(tps65218_pwron_driver);
+module_platform_driver(tps6521x_pb_driver);
-MODULE_DESCRIPTION("TPS65218 Power Button");
+MODULE_DESCRIPTION("TPS6521X Power Button");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index cb6aecbc1dc2..e23b2495d52e 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -222,11 +222,13 @@ static int elan_smbus_get_checksum(struct i2c_client *client,
static int elan_smbus_get_max(struct i2c_client *client,
unsigned int *max_x, unsigned int *max_y)
{
+ int ret;
int error;
u8 val[3];
- error = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val);
- if (error) {
+ ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val);
+ if (ret != 3) {
+ error = ret < 0 ? ret : -EIO;
dev_err(&client->dev, "failed to get dimensions: %d\n", error);
return error;
}
@@ -240,12 +242,13 @@ static int elan_smbus_get_max(struct i2c_client *client,
static int elan_smbus_get_resolution(struct i2c_client *client,
u8 *hw_res_x, u8 *hw_res_y)
{
+ int ret;
int error;
u8 val[3];
- error = i2c_smbus_read_block_data(client,
- ETP_SMBUS_RESOLUTION_CMD, val);
- if (error) {
+ ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val);
+ if (ret != 3) {
+ error = ret < 0 ? ret : -EIO;
dev_err(&client->dev, "failed to get resolution: %d\n", error);
return error;
}
@@ -260,12 +263,13 @@ static int elan_smbus_get_num_traces(struct i2c_client *client,
unsigned int *x_traces,
unsigned int *y_traces)
{
+ int ret;
int error;
u8 val[3];
- error = i2c_smbus_read_block_data(client,
- ETP_SMBUS_XY_TRACENUM_CMD, val);
- if (error) {
+ ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val);
+ if (ret != 3) {
+ error = ret < 0 ? ret : -EIO;
dev_err(&client->dev, "failed to get trace info: %d\n", error);
return error;
}
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index c8c6a8cc329d..54eceb30ede5 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -390,7 +390,8 @@ static int focaltech_read_size(struct psmouse *psmouse)
return 0;
}
-void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+static void focaltech_set_resolution(struct psmouse *psmouse,
+ unsigned int resolution)
{
/* not supported yet */
}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 5784e20542a4..fb4b185dea96 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1916,7 +1916,7 @@ static int __init psmouse_init(void)
synaptics_module_init();
hgpk_module_init();
- kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
+ kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0);
if (!kpsmoused_wq) {
pr_err("failed to create kpsmoused workqueue\n");
return -ENOMEM;
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 9c927d35c1f5..d189843f3727 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -71,10 +71,7 @@ static void serport_serio_close(struct serio *serio)
spin_lock_irqsave(&serport->lock, flags);
clear_bit(SERPORT_ACTIVE, &serport->flags);
- set_bit(SERPORT_DEAD, &serport->flags);
spin_unlock_irqrestore(&serport->lock, flags);
-
- wake_up_interruptible(&serport->wait);
}
/*
@@ -248,6 +245,19 @@ static long serport_ldisc_compat_ioctl(struct tty_struct *tty,
}
#endif
+static int serport_ldisc_hangup(struct tty_struct *tty)
+{
+ struct serport *serport = (struct serport *) tty->disc_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serport->lock, flags);
+ set_bit(SERPORT_DEAD, &serport->flags);
+ spin_unlock_irqrestore(&serport->lock, flags);
+
+ wake_up_interruptible(&serport->wait);
+ return 0;
+}
+
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{
struct serport *serport = (struct serport *) tty->disc_data;
@@ -274,6 +284,7 @@ static struct tty_ldisc_ops serport_ldisc = {
.compat_ioctl = serport_ldisc_compat_ioctl,
#endif
.receive_buf = serport_ldisc_receive,
+ .hangup = serport_ldisc_hangup,
.write_wakeup = serport_ldisc_write_wakeup
};
diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c
index 949dacc78664..47de5a81172f 100644
--- a/drivers/input/tablet/pegasus_notetaker.c
+++ b/drivers/input/tablet/pegasus_notetaker.c
@@ -40,6 +40,7 @@
#include <linux/input.h>
#include <linux/usb/input.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
/* USB HID defines */
#define USB_REQ_GET_REPORT 0x01
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 2fb1f430a431..507981356921 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -305,19 +305,6 @@ config TOUCHSCREEN_EGALAX_SERIAL
To compile this driver as a module, choose M here: the
module will be called egalax_ts_serial.
-config TOUCHSCREEN_FT6236
- tristate "FT6236 I2C touchscreen"
- depends on I2C
- depends on GPIOLIB || COMPILE_TEST
- help
- Say Y here to enable support for the I2C connected FT6x06 and
- FT6x36 family of capacitive touchscreen drivers.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called ft6236.
-
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
@@ -397,6 +384,18 @@ config TOUCHSCREEN_GUNZE
To compile this driver as a module, choose M here: the
module will be called gunze.
+config TOUCHSCREEN_EKTF2127
+ tristate "Elan eKTF2127 I2C touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have an Elan eKTF2127 touchscreen
+ connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ektf2127.
+
config TOUCHSCREEN_ELAN
tristate "Elan eKTH I2C touchscreen"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index b4373d6be402..81b86451782d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -32,11 +32,11 @@ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
+obj-$(CONFIG_TOUCHSCREEN_EKTF2127) += ektf2127.o
obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
-obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 703e295a37ed..28466e358fee 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1063,9 +1063,15 @@ static const struct edt_i2c_chip_data edt_ft5506_data = {
.max_support_points = 10,
};
+static const struct edt_i2c_chip_data edt_ft6236_data = {
+ .max_support_points = 2,
+};
+
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
+ /* Note no edt- prefix for compatibility with the ft6236.c driver */
+ { .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
@@ -1076,6 +1082,8 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
+ /* Note focaltech vendor prefix for compatibility with ft6236.c */
+ { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c
new file mode 100644
index 000000000000..0ed34ff787ce
--- /dev/null
+++ b/drivers/input/touchscreen/ektf2127.c
@@ -0,0 +1,336 @@
+/*
+ * Driver for ELAN eKTF2127 i2c touchscreen controller
+ *
+ * For this driver the layout of the Chipone icn8318 i2c
+ * touchscreencontroller is used.
+ *
+ * This program is free software; 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.
+ *
+ * Author:
+ * Michel Verlaan <michel.verl@gmail.com>
+ * Siebren Vroegindeweij <siebren.vroegindeweij@hotmail.com>
+ *
+ * Original chipone_icn8318 driver:
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+
+/* Packet header defines (first byte of data send / received) */
+#define EKTF2127_NOISE 0x40
+#define EKTF2127_RESPONSE 0x52
+#define EKTF2127_REQUEST 0x53
+#define EKTF2127_HELLO 0x55
+#define EKTF2127_REPORT 0x5d
+#define EKTF2127_CALIB_DONE 0x66
+
+/* Register defines (second byte of data send / received) */
+#define EKTF2127_ENV_NOISY 0x41
+#define EKTF2127_HEIGHT 0x60
+#define EKTF2127_WIDTH 0x63
+
+/* 2 bytes header + 5 * 3 bytes coordinates + 3 bytes pressure info + footer */
+#define EKTF2127_TOUCH_REPORT_SIZE 21
+#define EKTF2127_MAX_TOUCHES 5
+
+struct ektf2127_ts {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct gpio_desc *power_gpios;
+ struct touchscreen_properties prop;
+};
+
+static void ektf2127_parse_coordinates(const u8* buf, unsigned int touch_count,
+ struct input_mt_pos *touches)
+{
+ int index = 0;
+ int i;
+
+ for (i = 0; i < touch_count; i++) {
+ index = 2 + i * 3;
+
+ touches[i].x = (buf[index] & 0x0f);
+ touches[i].x <<= 8;
+ touches[i].x |= buf[index + 2];
+
+ touches[i].y = (buf[index] & 0xf0);
+ touches[i].y <<= 4;
+ touches[i].y |= buf[index + 1];
+ }
+}
+
+static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf)
+{
+ struct input_mt_pos touches[EKTF2127_MAX_TOUCHES];
+ int slots[EKTF2127_MAX_TOUCHES];
+ unsigned int touch_count, i;
+
+ touch_count = buf[1] & 0x07;
+ if (touch_count > EKTF2127_MAX_TOUCHES) {
+ dev_err(&ts->client->dev,
+ "Too many touches %d > %d\n",
+ touch_count, EKTF2127_MAX_TOUCHES);
+ touch_count = EKTF2127_MAX_TOUCHES;
+ }
+
+ ektf2127_parse_coordinates(buf, touch_count, touches);
+ input_mt_assign_slots(ts->input, slots, touches,
+ touch_count, 0);
+
+ for (i = 0; i < touch_count; i++) {
+ input_mt_slot(ts->input, slots[i]);
+ input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
+ touchscreen_report_pos(ts->input, &ts->prop,
+ touches[i].x, touches[i].y, true);
+ }
+
+ input_mt_sync_frame(ts->input);
+ input_sync(ts->input);
+}
+
+static irqreturn_t ektf2127_irq(int irq, void *dev_id)
+{
+ struct ektf2127_ts *ts = dev_id;
+ struct device *dev = &ts->client->dev;
+ char buf[EKTF2127_TOUCH_REPORT_SIZE];
+ int ret;
+
+ ret = i2c_master_recv(ts->client, buf, EKTF2127_TOUCH_REPORT_SIZE);
+ if (ret != EKTF2127_TOUCH_REPORT_SIZE) {
+ dev_err(dev, "Error reading touch data: %d\n", ret);
+ goto out;
+ }
+
+ switch (buf[0]) {
+ case EKTF2127_REPORT:
+ ektf2127_report_event(ts, buf);
+ break;
+
+ case EKTF2127_NOISE:
+ if (buf[1] == EKTF2127_ENV_NOISY)
+ dev_dbg(dev, "Environment is electrically noisy\n");
+ break;
+
+ case EKTF2127_HELLO:
+ case EKTF2127_CALIB_DONE:
+ break;
+
+ default:
+ dev_err(dev, "Unexpected packet header byte %#02x\n", buf[0]);
+ break;
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int ektf2127_start(struct input_dev *dev)
+{
+ struct ektf2127_ts *ts = input_get_drvdata(dev);
+
+ enable_irq(ts->client->irq);
+ gpiod_set_value_cansleep(ts->power_gpios, 1);
+
+ return 0;
+}
+
+static void ektf2127_stop(struct input_dev *dev)
+{
+ struct ektf2127_ts *ts = input_get_drvdata(dev);
+
+ disable_irq(ts->client->irq);
+ gpiod_set_value_cansleep(ts->power_gpios, 0);
+}
+
+static int __maybe_unused ektf2127_suspend(struct device *dev)
+{
+ struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
+
+ mutex_lock(&ts->input->mutex);
+ if (ts->input->users)
+ ektf2127_stop(ts->input);
+ mutex_unlock(&ts->input->mutex);
+
+ return 0;
+}
+
+static int __maybe_unused ektf2127_resume(struct device *dev)
+{
+ struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
+
+ mutex_lock(&ts->input->mutex);
+ if (ts->input->users)
+ ektf2127_start(ts->input);
+ mutex_unlock(&ts->input->mutex);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend,
+ ektf2127_resume);
+
+static int ektf2127_query_dimension(struct i2c_client *client, bool width)
+{
+ struct device *dev = &client->dev;
+ const char *what = width ? "width" : "height";
+ u8 what_code = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT;
+ u8 buf[4];
+ int ret;
+ int error;
+
+ /* Request dimension */
+ buf[0] = EKTF2127_REQUEST;
+ buf[1] = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ ret = i2c_master_send(client, buf, sizeof(buf));
+ if (ret != sizeof(buf)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(dev, "Failed to request %s: %d\n", what, error);
+ return error;
+ }
+
+ msleep(20);
+
+ /* Read response */
+ ret = i2c_master_recv(client, buf, sizeof(buf));
+ if (ret != sizeof(buf)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(dev, "Failed to receive %s data: %d\n", what, error);
+ return error;
+ }
+
+ if (buf[0] != EKTF2127_RESPONSE || buf[1] != what_code) {
+ dev_err(dev, "Unexpected %s data: %#02x %#02x\n",
+ what, buf[0], buf[1]);
+ return -EIO;
+ }
+
+ return (((buf[3] & 0xf0) << 4) | buf[2]) - 1;
+}
+
+static int ektf2127_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ektf2127_ts *ts;
+ struct input_dev *input;
+ u8 buf[4];
+ int max_x, max_y;
+ int error;
+
+ if (!client->irq) {
+ dev_err(dev, "Error no irq specified\n");
+ return -EINVAL;
+ }
+
+ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ /* This requests the gpio *and* turns on the touchscreen controller */
+ ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH);
+ if (IS_ERR(ts->power_gpios)) {
+ error = PTR_ERR(ts->power_gpios);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "Error getting power gpio: %d\n", error);
+ return error;
+ }
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->open = ektf2127_start;
+ input->close = ektf2127_stop;
+
+ ts->client = client;
+
+ /* Read hello (ignore result, depends on initial power state) */
+ msleep(20);
+ i2c_master_recv(ts->client, buf, sizeof(buf));
+
+ /* Read resolution from chip */
+ max_x = ektf2127_query_dimension(client, true);
+ if (max_x < 0)
+ return max_x;
+
+ max_y = ektf2127_query_dimension(client, false);
+ if (max_y < 0)
+ return max_y;
+
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
+ touchscreen_parse_properties(input, true, &ts->prop);
+
+ error = input_mt_init_slots(input, EKTF2127_MAX_TOUCHES,
+ INPUT_MT_DIRECT |
+ INPUT_MT_DROP_UNUSED |
+ INPUT_MT_TRACK);
+ if (error)
+ return error;
+
+ ts->input = input;
+ input_set_drvdata(input, ts);
+
+ error = devm_request_threaded_irq(dev, client->irq,
+ NULL, ektf2127_irq,
+ IRQF_ONESHOT, client->name, ts);
+ if (error) {
+ dev_err(dev, "Error requesting irq: %d\n", error);
+ return error;
+ }
+
+ /* Stop device till opened */
+ ektf2127_stop(ts->input);
+
+ error = input_register_device(input);
+ if (error)
+ return error;
+
+ i2c_set_clientdata(client, ts);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ektf2127_of_match[] = {
+ { .compatible = "elan,ektf2127" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ektf2127_of_match);
+#endif
+
+static const struct i2c_device_id ektf2127_i2c_id[] = {
+ { "ektf2127", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
+
+static struct i2c_driver ektf2127_driver = {
+ .driver = {
+ .name = "elan_ektf2127",
+ .pm = &ektf2127_pm_ops,
+ .of_match_table = of_match_ptr(ektf2127_of_match),
+ },
+ .probe = ektf2127_probe,
+ .id_table = ektf2127_i2c_id,
+};
+module_i2c_driver(ektf2127_driver);
+
+MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver");
+MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index ac09855fa435..02aec284deca 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -298,7 +298,7 @@ static u16 elants_i2c_parse_version(u8 *buf)
return get_unaligned_be32(buf) >> 4;
}
-static int elants_i2c_query_fw_id(struct elants_data *ts)
+static int elants_i2c_query_hw_version(struct elants_data *ts)
{
struct i2c_client *client = ts->client;
int error, retry_cnt;
@@ -318,8 +318,13 @@ static int elants_i2c_query_fw_id(struct elants_data *ts)
error, (int)sizeof(resp), resp);
}
- dev_err(&client->dev,
- "Failed to read fw id or fw id is invalid\n");
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read fw id: %d\n", error);
+ return error;
+ }
+
+ dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version);
return -EINVAL;
}
@@ -508,7 +513,7 @@ static int elants_i2c_fastboot(struct i2c_client *client)
static int elants_i2c_initialize(struct elants_data *ts)
{
struct i2c_client *client = ts->client;
- int error, retry_cnt;
+ int error, error2, retry_cnt;
const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 };
const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 };
u8 buf[HEADER_SIZE];
@@ -553,18 +558,22 @@ static int elants_i2c_initialize(struct elants_data *ts)
}
}
+ /* hw version is available even if device in recovery state */
+ error2 = elants_i2c_query_hw_version(ts);
if (!error)
- error = elants_i2c_query_fw_id(ts);
+ error = error2;
+
if (!error)
error = elants_i2c_query_fw_version(ts);
+ if (!error)
+ error = elants_i2c_query_test_version(ts);
+ if (!error)
+ error = elants_i2c_query_bc_version(ts);
+ if (!error)
+ error = elants_i2c_query_ts_info(ts);
- if (error) {
+ if (error)
ts->iap_mode = ELAN_IAP_RECOVERY;
- } else {
- elants_i2c_query_test_version(ts);
- elants_i2c_query_bc_version(ts);
- elants_i2c_query_ts_info(ts);
- }
return 0;
}
diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c
deleted file mode 100644
index d240d2e212bd..000000000000
--- a/drivers/input/touchscreen/ft6236.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * FocalTech FT6236 TouchScreen driver.
- *
- * Copyright (c) 2010 Focal tech Ltd.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/input/mt.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/property.h>
-
-#define FT6236_MAX_TOUCH_POINTS 2
-
-#define FT6236_REG_TH_GROUP 0x80
-#define FT6236_REG_PERIODACTIVE 0x88
-#define FT6236_REG_LIB_VER_H 0xa1
-#define FT6236_REG_LIB_VER_L 0xa2
-#define FT6236_REG_CIPHER 0xa3
-#define FT6236_REG_FIRMID 0xa6
-#define FT6236_REG_FOCALTECH_ID 0xa8
-#define FT6236_REG_RELEASE_CODE_ID 0xaf
-
-#define FT6236_EVENT_PRESS_DOWN 0
-#define FT6236_EVENT_LIFT_UP 1
-#define FT6236_EVENT_CONTACT 2
-#define FT6236_EVENT_NO_EVENT 3
-
-struct ft6236_data {
- struct i2c_client *client;
- struct input_dev *input;
- struct gpio_desc *reset_gpio;
- u32 max_x;
- u32 max_y;
- bool invert_x;
- bool invert_y;
- bool swap_xy;
-};
-
-/*
- * This struct is a touchpoint as stored in hardware. Note that the id,
- * as well as the event, are stored in the upper nybble of the hi byte.
- */
-struct ft6236_touchpoint {
- union {
- u8 xhi;
- u8 event;
- };
- u8 xlo;
- union {
- u8 yhi;
- u8 id;
- };
- u8 ylo;
- u8 weight;
- u8 misc;
-} __packed;
-
-/* This packet represents the register map as read from offset 0 */
-struct ft6236_packet {
- u8 dev_mode;
- u8 gest_id;
- u8 touches;
- struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS];
-} __packed;
-
-static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data)
-{
- int error;
-
- error = i2c_smbus_read_i2c_block_data(client, reg, len, data);
- if (error < 0)
- return error;
-
- if (error != len)
- return -EIO;
-
- return 0;
-}
-
-static irqreturn_t ft6236_interrupt(int irq, void *dev_id)
-{
- struct ft6236_data *ft6236 = dev_id;
- struct device *dev = &ft6236->client->dev;
- struct input_dev *input = ft6236->input;
- struct ft6236_packet buf;
- u8 touches;
- int i, error;
-
- error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf);
- if (error) {
- dev_err(dev, "read touchdata failed %d\n", error);
- return IRQ_HANDLED;
- }
-
- touches = buf.touches & 0xf;
- if (touches > FT6236_MAX_TOUCH_POINTS) {
- dev_dbg(dev,
- "%d touch points reported, only %d are supported\n",
- touches, FT6236_MAX_TOUCH_POINTS);
- touches = FT6236_MAX_TOUCH_POINTS;
- }
-
- for (i = 0; i < touches; i++) {
- struct ft6236_touchpoint *point = &buf.points[i];
- u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo;
- u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo;
- u8 event = point->event >> 6;
- u8 id = point->id >> 4;
- bool act = (event == FT6236_EVENT_PRESS_DOWN ||
- event == FT6236_EVENT_CONTACT);
-
- input_mt_slot(input, id);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, act);
- if (!act)
- continue;
-
- if (ft6236->invert_x)
- x = ft6236->max_x - x;
-
- if (ft6236->invert_y)
- y = ft6236->max_y - y;
-
- if (ft6236->swap_xy) {
- input_report_abs(input, ABS_MT_POSITION_X, y);
- input_report_abs(input, ABS_MT_POSITION_Y, x);
- } else {
- input_report_abs(input, ABS_MT_POSITION_X, x);
- input_report_abs(input, ABS_MT_POSITION_Y, y);
- }
- }
-
- input_mt_sync_frame(input);
- input_sync(input);
-
- return IRQ_HANDLED;
-}
-
-static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg)
-{
- struct i2c_client *client = ft6236->client;
- u8 val = 0;
- int error;
-
- error = ft6236_read(client, reg, 1, &val);
- if (error)
- dev_dbg(&client->dev,
- "error reading register 0x%02x: %d\n", reg, error);
-
- return val;
-}
-
-static void ft6236_debug_info(struct ft6236_data *ft6236)
-{
- struct device *dev = &ft6236->client->dev;
-
- dev_dbg(dev, "Touch threshold is %d\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4);
- dev_dbg(dev, "Report rate is %dHz\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10);
- dev_dbg(dev, "Firmware library version 0x%02x%02x\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H),
- ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L));
- dev_dbg(dev, "Firmware version 0x%02x\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID));
- dev_dbg(dev, "Chip vendor ID 0x%02x\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER));
- dev_dbg(dev, "CTPM vendor ID 0x%02x\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID));
- dev_dbg(dev, "Release code version 0x%02x\n",
- ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID));
-}
-
-static void ft6236_reset(struct ft6236_data *ft6236)
-{
- if (!ft6236->reset_gpio)
- return;
-
- gpiod_set_value_cansleep(ft6236->reset_gpio, 1);
- usleep_range(5000, 20000);
- gpiod_set_value_cansleep(ft6236->reset_gpio, 0);
- msleep(300);
-}
-
-static int ft6236_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct device *dev = &client->dev;
- struct ft6236_data *ft6236;
- struct input_dev *input;
- u32 fuzz_x = 0, fuzz_y = 0;
- u8 val;
- int error;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- return -ENXIO;
-
- if (!client->irq) {
- dev_err(dev, "irq is missing\n");
- return -EINVAL;
- }
-
- ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL);
- if (!ft6236)
- return -ENOMEM;
-
- ft6236->client = client;
- ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(ft6236->reset_gpio)) {
- error = PTR_ERR(ft6236->reset_gpio);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "error getting reset gpio: %d\n", error);
- return error;
- }
-
- ft6236_reset(ft6236);
-
- /* verify that the controller is present */
- error = ft6236_read(client, 0x00, 1, &val);
- if (error) {
- dev_err(dev, "failed to read from controller: %d\n", error);
- return error;
- }
-
- ft6236_debug_info(ft6236);
-
- input = devm_input_allocate_device(dev);
- if (!input)
- return -ENOMEM;
-
- ft6236->input = input;
- input->name = client->name;
- input->id.bustype = BUS_I2C;
-
- if (device_property_read_u32(dev, "touchscreen-size-x",
- &ft6236->max_x) ||
- device_property_read_u32(dev, "touchscreen-size-y",
- &ft6236->max_y)) {
- dev_err(dev, "touchscreen-size-x and/or -y missing\n");
- return -EINVAL;
- }
-
- device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x);
- device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y);
- ft6236->invert_x = device_property_read_bool(dev,
- "touchscreen-inverted-x");
- ft6236->invert_y = device_property_read_bool(dev,
- "touchscreen-inverted-y");
- ft6236->swap_xy = device_property_read_bool(dev,
- "touchscreen-swapped-x-y");
-
- if (ft6236->swap_xy) {
- input_set_abs_params(input, ABS_MT_POSITION_X, 0,
- ft6236->max_y, fuzz_y, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
- ft6236->max_x, fuzz_x, 0);
- } else {
- input_set_abs_params(input, ABS_MT_POSITION_X, 0,
- ft6236->max_x, fuzz_x, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
- ft6236->max_y, fuzz_y, 0);
- }
-
- error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS,
- INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
- if (error)
- return error;
-
- error = devm_request_threaded_irq(dev, client->irq, NULL,
- ft6236_interrupt, IRQF_ONESHOT,
- client->name, ft6236);
- if (error) {
- dev_err(dev, "request irq %d failed: %d\n", client->irq, error);
- return error;
- }
-
- error = input_register_device(input);
- if (error) {
- dev_err(dev, "failed to register input device: %d\n", error);
- return error;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id ft6236_of_match[] = {
- { .compatible = "focaltech,ft6236", },
- { }
-};
-MODULE_DEVICE_TABLE(of, ft6236_of_match);
-#endif
-
-static const struct i2c_device_id ft6236_id[] = {
- { "ft6236", },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ft6236_id);
-
-static struct i2c_driver ft6236_driver = {
- .driver = {
- .name = "ft6236",
- .of_match_table = of_match_ptr(ft6236_of_match),
- },
- .probe = ft6236_probe,
- .id_table = ft6236_id,
-};
-module_i2c_driver(ft6236_driver);
-
-MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
-MODULE_AUTHOR("Noralf Trønnes <noralf@tronnes.org>");
-MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index ea3b6a5b83e6..729b3c89324c 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -13,6 +13,7 @@
* HP Jornada 710/720/729 Touchscreen Driver
*/
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -20,9 +21,7 @@
#include <linux/slab.h>
#include <linux/io.h>
-#include <mach/hardware.h>
#include <mach/jornada720.h>
-#include <mach/irqs.h>
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
@@ -30,6 +29,7 @@ MODULE_LICENSE("GPL v2");
struct jornada_ts {
struct input_dev *dev;
+ struct gpio_desc *gpio;
int x_data[4]; /* X sample values */
int y_data[4]; /* Y sample values */
};
@@ -71,8 +71,8 @@ static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
struct input_dev *input = jornada_ts->dev;
int x, y;
- /* If GPIO_GPIO9 is set to high then report pen up */
- if (GPLR & GPIO_GPIO(9)) {
+ /* If gpio is high then report pen up */
+ if (gpiod_get_value(jornada_ts->gpio)) {
input_report_key(input, BTN_TOUCH, 0);
input_sync(input);
} else {
@@ -101,7 +101,7 @@ static int jornada720_ts_probe(struct platform_device *pdev)
{
struct jornada_ts *jornada_ts;
struct input_dev *input_dev;
- int error;
+ int error, irq;
jornada_ts = devm_kzalloc(&pdev->dev, sizeof(*jornada_ts), GFP_KERNEL);
if (!jornada_ts)
@@ -113,6 +113,14 @@ static int jornada720_ts_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, jornada_ts);
+ jornada_ts->gpio = devm_gpiod_get(&pdev->dev, "penup", GPIOD_IN);
+ if (IS_ERR(jornada_ts->gpio))
+ return PTR_ERR(jornada_ts->gpio);
+
+ irq = gpiod_to_irq(jornada_ts->gpio);
+ if (irq <= 0)
+ return irq < 0 ? irq : -EINVAL;
+
jornada_ts->dev = input_dev;
input_dev->name = "HP Jornada 7xx Touchscreen";
@@ -125,8 +133,7 @@ static int jornada720_ts_probe(struct platform_device *pdev)
input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
- error = devm_request_irq(&pdev->dev, IRQ_GPIO9,
- jornada720_ts_interrupt,
+ error = devm_request_irq(&pdev->dev, irq, jornada720_ts_interrupt,
IRQF_TRIGGER_RISING,
"HP7XX Touchscreen driver", pdev);
if (error) {
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index 913e25a994b4..ef64f36c5ffc 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -37,7 +37,6 @@ struct mc13783_ts_priv {
struct input_dev *idev;
struct mc13xxx *mc13xxx;
struct delayed_work work;
- struct workqueue_struct *workq;
unsigned int sample[4];
struct mc13xxx_ts_platform_data *touch;
};
@@ -54,7 +53,7 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data)
* be rescheduled for immediate execution here. However the rearm
* delay is HZ / 50 which is acceptable.
*/
- queue_delayed_work(priv->workq, &priv->work, 0);
+ schedule_delayed_work(&priv->work, 0);
return IRQ_HANDLED;
}
@@ -106,16 +105,18 @@ static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv)
dev_dbg(&idev->dev, "report (%d, %d, %d)\n",
x1, y1, 0x1000 - cr0);
- queue_delayed_work(priv->workq, &priv->work, HZ / 50);
- } else
+ schedule_delayed_work(&priv->work, HZ / 50);
+ } else {
dev_dbg(&idev->dev, "report release\n");
+ }
input_report_abs(idev, ABS_PRESSURE,
cr0 ? 0x1000 - cr0 : cr0);
input_report_key(idev, BTN_TOUCH, cr0);
input_sync(idev);
- } else
+ } else {
dev_dbg(&idev->dev, "discard event\n");
+ }
}
static void mc13783_ts_work(struct work_struct *work)
@@ -189,14 +190,6 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
goto err_free_mem;
}
- /*
- * We need separate workqueue because mc13783_adc_do_conversion
- * uses keventd and thus would deadlock.
- */
- priv->workq = create_singlethread_workqueue("mc13783_ts");
- if (!priv->workq)
- goto err_free_mem;
-
idev->name = MC13783_TS_NAME;
idev->dev.parent = &pdev->dev;
@@ -215,14 +208,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"register input device failed with %d\n", ret);
- goto err_destroy_wq;
+ goto err_free_mem;
}
platform_set_drvdata(pdev, priv);
return 0;
-err_destroy_wq:
- destroy_workqueue(priv->workq);
err_free_mem:
input_free_device(idev);
kfree(priv);
@@ -233,7 +224,6 @@ static int mc13783_ts_remove(struct platform_device *pdev)
{
struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
- destroy_workqueue(priv->workq);
input_unregister_device(priv->idev);
kfree(priv);
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index d159e14f4d20..3bb0637d832e 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -11,10 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
@@ -404,7 +400,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev)
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
-
if (!input->users) {
ret = pixcir_stop(ts);
if (ret) {
@@ -431,13 +426,7 @@ static const struct of_device_id pixcir_of_match[];
static int pixcir_parse_dt(struct device *dev,
struct pixcir_i2c_ts_data *tsdata)
{
- const struct of_device_id *match;
-
- match = of_match_device(of_match_ptr(pixcir_of_match), dev);
- if (!match)
- return -EINVAL;
-
- tsdata->chip = (const struct pixcir_i2c_chip_data *)match->data;
+ tsdata->chip = of_device_get_match_data(dev);
if (!tsdata->chip)
return -EINVAL;
diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c
index 73861ad22df4..a9132603ab34 100644
--- a/drivers/input/touchscreen/wdt87xx_i2c.c
+++ b/drivers/input/touchscreen/wdt87xx_i2c.c
@@ -23,7 +23,7 @@
#include <asm/unaligned.h>
#define WDT87XX_NAME "wdt87xx_i2c"
-#define WDT87XX_DRV_VER "0.9.7"
+#define WDT87XX_DRV_VER "0.9.8"
#define WDT87XX_FW_NAME "wdt87xx_fw.bin"
#define WDT87XX_CFG_NAME "wdt87xx_cfg.bin"
@@ -157,6 +157,7 @@
/* Controller requires minimum 300us between commands */
#define WDT_COMMAND_DELAY_MS 2
#define WDT_FLASH_WRITE_DELAY_MS 4
+#define WDT_FLASH_ERASE_DELAY_MS 200
#define WDT_FW_RESET_TIME 2500
struct wdt87xx_sys_param {
@@ -726,7 +727,7 @@ static int wdt87xx_write_firmware(struct i2c_client *client, const void *chunk)
break;
}
- msleep(50);
+ msleep(WDT_FLASH_ERASE_DELAY_MS);
error = wdt87xx_write_data(client, data, start_addr,
page_size);
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 1534e9b0788c..90d6be3c26cc 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -500,7 +500,7 @@ static int wm97xx_ts_input_open(struct input_dev *idev)
{
struct wm97xx *wm = input_get_drvdata(idev);
- wm->ts_workq = create_singlethread_workqueue("kwm97xx");
+ wm->ts_workq = alloc_ordered_workqueue("kwm97xx", 0);
if (wm->ts_workq == NULL) {
dev_err(wm->dev,
"Failed to create workqueue\n");
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index b372e792adc2..e4dbfc85abdb 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o
-obj-$(CONFIG_REALVIEW_DT) += irq-gic-realview.o
+obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o
obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o
obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c
index 8c38b3d92e1c..0cdd923d1535 100644
--- a/drivers/irqchip/irq-metag-ext.c
+++ b/drivers/irqchip/irq-metag-ext.c
@@ -436,7 +436,6 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type)
/**
* meta_intc_irq_demux() - external irq de-multiplexer
- * @irq: the virtual interrupt number
* @desc: the interrupt description structure for this irq
*
* The cpu receives an interrupt on TR2 when a SoC interrupt has occurred. It is
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index f811a7de5857..74192f62dd67 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -498,7 +498,6 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
* vic_init_cascaded() - initialise a cascaded vectored interrupt controller
* @base: iomem base address
* @parent_irq: the parent IRQ we're cascaded off
- * @irq_start: starting interrupt number, must be muliple of 32
* @vic_sources: bitmask of interrupt sources to allow
* @resume_sources: bitmask of interrupt sources to allow for resume
*
diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig
index 61c68a1f054a..2f5d5f4a4c75 100644
--- a/drivers/lightnvm/Kconfig
+++ b/drivers/lightnvm/Kconfig
@@ -4,7 +4,7 @@
menuconfig NVM
bool "Open-Channel SSD target support"
- depends on BLOCK
+ depends on BLOCK && HAS_DMA
help
Say Y here to get to enable Open-channel SSDs.
diff --git a/drivers/lightnvm/Makefile b/drivers/lightnvm/Makefile
index a7a0a22cf1a5..1f6b6521016a 100644
--- a/drivers/lightnvm/Makefile
+++ b/drivers/lightnvm/Makefile
@@ -2,6 +2,6 @@
# Makefile for Open-Channel SSDs.
#
-obj-$(CONFIG_NVM) := core.o sysblk.o
+obj-$(CONFIG_NVM) := core.o sysblk.o sysfs.o
obj-$(CONFIG_NVM_GENNVM) += gennvm.o
obj-$(CONFIG_NVM_RRPC) += rrpc.o
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index c784ddcd4405..1cac0f8bc0dc 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -27,6 +27,8 @@
#include <linux/lightnvm.h>
#include <linux/sched/sysctl.h>
+#include "lightnvm.h"
+
static LIST_HEAD(nvm_tgt_types);
static DECLARE_RWSEM(nvm_tgtt_lock);
static LIST_HEAD(nvm_mgrs);
@@ -581,6 +583,8 @@ static int nvm_core_init(struct nvm_dev *dev)
mutex_init(&dev->mlock);
spin_lock_init(&dev->lock);
+ blk_queue_logical_block_size(dev->q, dev->sec_size);
+
return 0;
err_fmtype:
kfree(dev->lun_map);
@@ -596,15 +600,19 @@ static void nvm_free_mgr(struct nvm_dev *dev)
dev->mt = NULL;
}
-static void nvm_free(struct nvm_dev *dev)
+void nvm_free(struct nvm_dev *dev)
{
if (!dev)
return;
nvm_free_mgr(dev);
+ if (dev->dma_pool)
+ dev->ops->destroy_dma_pool(dev->dma_pool);
+
kfree(dev->lptbl);
kfree(dev->lun_map);
+ kfree(dev);
}
static int nvm_init(struct nvm_dev *dev)
@@ -651,30 +659,19 @@ err:
static void nvm_exit(struct nvm_dev *dev)
{
- if (dev->dma_pool)
- dev->ops->destroy_dma_pool(dev->dma_pool);
- nvm_free(dev);
+ nvm_sysfs_unregister_dev(dev);
+}
- pr_info("nvm: successfully unloaded\n");
+struct nvm_dev *nvm_alloc_dev(int node)
+{
+ return kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
}
+EXPORT_SYMBOL(nvm_alloc_dev);
-int nvm_register(struct request_queue *q, char *disk_name,
- struct nvm_dev_ops *ops)
+int nvm_register(struct nvm_dev *dev)
{
- struct nvm_dev *dev;
int ret;
- if (!ops->identity)
- return -EINVAL;
-
- dev = kzalloc(sizeof(struct nvm_dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- dev->q = q;
- dev->ops = ops;
- strncpy(dev->name, disk_name, DISK_NAME_LEN);
-
ret = nvm_init(dev);
if (ret)
goto err_init;
@@ -694,6 +691,10 @@ int nvm_register(struct request_queue *q, char *disk_name,
}
}
+ ret = nvm_sysfs_register_dev(dev);
+ if (ret)
+ goto err_ppalist;
+
if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
ret = nvm_get_sysblock(dev, &dev->sb);
if (!ret)
@@ -710,31 +711,21 @@ int nvm_register(struct request_queue *q, char *disk_name,
up_write(&nvm_lock);
return 0;
+err_ppalist:
+ dev->ops->destroy_dma_pool(dev->dma_pool);
err_init:
kfree(dev->lun_map);
- kfree(dev);
return ret;
}
EXPORT_SYMBOL(nvm_register);
-void nvm_unregister(char *disk_name)
+void nvm_unregister(struct nvm_dev *dev)
{
- struct nvm_dev *dev;
-
down_write(&nvm_lock);
- dev = nvm_find_nvm_dev(disk_name);
- if (!dev) {
- pr_err("nvm: could not find device %s to unregister\n",
- disk_name);
- up_write(&nvm_lock);
- return;
- }
-
list_del(&dev->devices);
up_write(&nvm_lock);
nvm_exit(dev);
- kfree(dev);
}
EXPORT_SYMBOL(nvm_unregister);
diff --git a/drivers/lightnvm/lightnvm.h b/drivers/lightnvm/lightnvm.h
new file mode 100644
index 000000000000..305c181509a6
--- /dev/null
+++ b/drivers/lightnvm/lightnvm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 CNEX Labs. All rights reserved.
+ * Initial release: Matias Bjorling <matias@cnexlabs.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ */
+
+#ifndef LIGHTNVM_H
+#define LIGHTNVM_H
+
+#include <linux/lightnvm.h>
+
+/* core -> sysfs.c */
+int __must_check nvm_sysfs_register_dev(struct nvm_dev *);
+void nvm_sysfs_unregister_dev(struct nvm_dev *);
+int nvm_sysfs_register(void);
+void nvm_sysfs_unregister(void);
+
+/* sysfs > core */
+void nvm_free(struct nvm_dev *);
+
+#endif
diff --git a/drivers/lightnvm/sysfs.c b/drivers/lightnvm/sysfs.c
new file mode 100644
index 000000000000..0338c27ab95a
--- /dev/null
+++ b/drivers/lightnvm/sysfs.c
@@ -0,0 +1,198 @@
+#include <linux/kernel.h>
+#include <linux/lightnvm.h>
+#include <linux/miscdevice.h>
+#include <linux/kobject.h>
+#include <linux/blk-mq.h>
+
+#include "lightnvm.h"
+
+static ssize_t nvm_dev_attr_show(struct device *dev,
+ struct device_attribute *dattr, char *page)
+{
+ struct nvm_dev *ndev = container_of(dev, struct nvm_dev, dev);
+ struct nvm_id *id = &ndev->identity;
+ struct nvm_id_group *grp = &id->groups[0];
+ struct attribute *attr = &dattr->attr;
+
+ if (strcmp(attr->name, "version") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", id->ver_id);
+ } else if (strcmp(attr->name, "vendor_opcode") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", id->vmnt);
+ } else if (strcmp(attr->name, "capabilities") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", id->cap);
+ } else if (strcmp(attr->name, "device_mode") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", id->dom);
+ } else if (strcmp(attr->name, "media_manager") == 0) {
+ if (!ndev->mt)
+ return scnprintf(page, PAGE_SIZE, "%s\n", "none");
+ return scnprintf(page, PAGE_SIZE, "%s\n", ndev->mt->name);
+ } else if (strcmp(attr->name, "ppa_format") == 0) {
+ return scnprintf(page, PAGE_SIZE,
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ id->ppaf.ch_offset, id->ppaf.ch_len,
+ id->ppaf.lun_offset, id->ppaf.lun_len,
+ id->ppaf.pln_offset, id->ppaf.pln_len,
+ id->ppaf.blk_offset, id->ppaf.blk_len,
+ id->ppaf.pg_offset, id->ppaf.pg_len,
+ id->ppaf.sect_offset, id->ppaf.sect_len);
+ } else if (strcmp(attr->name, "media_type") == 0) { /* u8 */
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->mtype);
+ } else if (strcmp(attr->name, "flash_media_type") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->fmtype);
+ } else if (strcmp(attr->name, "num_channels") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_ch);
+ } else if (strcmp(attr->name, "num_luns") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_lun);
+ } else if (strcmp(attr->name, "num_planes") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_pln);
+ } else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_blk);
+ } else if (strcmp(attr->name, "num_pages") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_pg);
+ } else if (strcmp(attr->name, "page_size") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->fpg_sz);
+ } else if (strcmp(attr->name, "hw_sector_size") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->csecs);
+ } else if (strcmp(attr->name, "oob_sector_size") == 0) {/* u32 */
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->sos);
+ } else if (strcmp(attr->name, "read_typ") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->trdt);
+ } else if (strcmp(attr->name, "read_max") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->trdm);
+ } else if (strcmp(attr->name, "prog_typ") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->tprt);
+ } else if (strcmp(attr->name, "prog_max") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->tprm);
+ } else if (strcmp(attr->name, "erase_typ") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->tbet);
+ } else if (strcmp(attr->name, "erase_max") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", grp->tbem);
+ } else if (strcmp(attr->name, "multiplane_modes") == 0) {
+ return scnprintf(page, PAGE_SIZE, "0x%08x\n", grp->mpos);
+ } else if (strcmp(attr->name, "media_capabilities") == 0) {
+ return scnprintf(page, PAGE_SIZE, "0x%08x\n", grp->mccap);
+ } else if (strcmp(attr->name, "max_phys_secs") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n",
+ ndev->ops->max_phys_sect);
+ } else {
+ return scnprintf(page,
+ PAGE_SIZE,
+ "Unhandled attr(%s) in `nvm_dev_attr_show`\n",
+ attr->name);
+ }
+}
+
+#define NVM_DEV_ATTR_RO(_name) \
+ DEVICE_ATTR(_name, S_IRUGO, nvm_dev_attr_show, NULL)
+
+static NVM_DEV_ATTR_RO(version);
+static NVM_DEV_ATTR_RO(vendor_opcode);
+static NVM_DEV_ATTR_RO(capabilities);
+static NVM_DEV_ATTR_RO(device_mode);
+static NVM_DEV_ATTR_RO(ppa_format);
+static NVM_DEV_ATTR_RO(media_manager);
+
+static NVM_DEV_ATTR_RO(media_type);
+static NVM_DEV_ATTR_RO(flash_media_type);
+static NVM_DEV_ATTR_RO(num_channels);
+static NVM_DEV_ATTR_RO(num_luns);
+static NVM_DEV_ATTR_RO(num_planes);
+static NVM_DEV_ATTR_RO(num_blocks);
+static NVM_DEV_ATTR_RO(num_pages);
+static NVM_DEV_ATTR_RO(page_size);
+static NVM_DEV_ATTR_RO(hw_sector_size);
+static NVM_DEV_ATTR_RO(oob_sector_size);
+static NVM_DEV_ATTR_RO(read_typ);
+static NVM_DEV_ATTR_RO(read_max);
+static NVM_DEV_ATTR_RO(prog_typ);
+static NVM_DEV_ATTR_RO(prog_max);
+static NVM_DEV_ATTR_RO(erase_typ);
+static NVM_DEV_ATTR_RO(erase_max);
+static NVM_DEV_ATTR_RO(multiplane_modes);
+static NVM_DEV_ATTR_RO(media_capabilities);
+static NVM_DEV_ATTR_RO(max_phys_secs);
+
+#define NVM_DEV_ATTR(_name) (dev_attr_##_name##)
+
+static struct attribute *nvm_dev_attrs[] = {
+ &dev_attr_version.attr,
+ &dev_attr_vendor_opcode.attr,
+ &dev_attr_capabilities.attr,
+ &dev_attr_device_mode.attr,
+ &dev_attr_media_manager.attr,
+
+ &dev_attr_ppa_format.attr,
+ &dev_attr_media_type.attr,
+ &dev_attr_flash_media_type.attr,
+ &dev_attr_num_channels.attr,
+ &dev_attr_num_luns.attr,
+ &dev_attr_num_planes.attr,
+ &dev_attr_num_blocks.attr,
+ &dev_attr_num_pages.attr,
+ &dev_attr_page_size.attr,
+ &dev_attr_hw_sector_size.attr,
+ &dev_attr_oob_sector_size.attr,
+ &dev_attr_read_typ.attr,
+ &dev_attr_read_max.attr,
+ &dev_attr_prog_typ.attr,
+ &dev_attr_prog_max.attr,
+ &dev_attr_erase_typ.attr,
+ &dev_attr_erase_max.attr,
+ &dev_attr_multiplane_modes.attr,
+ &dev_attr_media_capabilities.attr,
+ &dev_attr_max_phys_secs.attr,
+ NULL,
+};
+
+static struct attribute_group nvm_dev_attr_group = {
+ .name = "lightnvm",
+ .attrs = nvm_dev_attrs,
+};
+
+static const struct attribute_group *nvm_dev_attr_groups[] = {
+ &nvm_dev_attr_group,
+ NULL,
+};
+
+static void nvm_dev_release(struct device *device)
+{
+ struct nvm_dev *dev = container_of(device, struct nvm_dev, dev);
+ struct request_queue *q = dev->q;
+
+ pr_debug("nvm/sysfs: `nvm_dev_release`\n");
+
+ blk_mq_unregister_dev(device, q);
+
+ nvm_free(dev);
+}
+
+static struct device_type nvm_type = {
+ .name = "lightnvm",
+ .groups = nvm_dev_attr_groups,
+ .release = nvm_dev_release,
+};
+
+int nvm_sysfs_register_dev(struct nvm_dev *dev)
+{
+ int ret;
+
+ if (!dev->parent_dev)
+ return 0;
+
+ dev->dev.parent = dev->parent_dev;
+ dev_set_name(&dev->dev, "%s", dev->name);
+ dev->dev.type = &nvm_type;
+ device_initialize(&dev->dev);
+ ret = device_add(&dev->dev);
+
+ if (!ret)
+ blk_mq_register_dev(&dev->dev, dev->q);
+
+ return ret;
+}
+
+void nvm_sysfs_unregister_dev(struct nvm_dev *dev)
+{
+ if (dev && dev->parent_dev)
+ kobject_put(&dev->dev.kobj);
+}
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index b6819f0fc608..3f041b187033 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -236,7 +236,7 @@ static void macio_create_fixup_irq(struct macio_dev *dev, int index,
unsigned int irq;
irq = irq_create_mapping(NULL, line);
- if (irq != NO_IRQ) {
+ if (!irq) {
dev->interrupt[index].start = irq;
dev->interrupt[index].flags = IORESOURCE_IRQ;
dev->interrupt[index].name = dev_name(&dev->ofdev.dev);
@@ -299,7 +299,7 @@ static void macio_setup_interrupts(struct macio_dev *dev)
break;
res = &dev->interrupt[j];
irq = irq_of_parse_and_map(np, i++);
- if (irq == NO_IRQ)
+ if (!irq)
break;
res->start = irq;
res->flags = IORESOURCE_IRQ;
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 465c52219639..775527135b93 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -427,7 +427,7 @@ static int rackmeter_probe(struct macio_dev* mdev,
rm->irq = macio_irq(mdev, 1);
#else
rm->irq = irq_of_parse_and_map(i2s, 1);
- if (rm->irq == NO_IRQ ||
+ if (!rm->irq ||
of_address_to_resource(i2s, 0, &ri2s) ||
of_address_to_resource(i2s, 1, &rdma)) {
printk(KERN_ERR
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index d6f72c826c1c..08edb2c25b60 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -279,7 +279,7 @@ int smu_queue_cmd(struct smu_cmd *cmd)
spin_unlock_irqrestore(&smu->lock, flags);
/* Workaround for early calls when irq isn't available */
- if (!smu_irq_inited || smu->db_irq == NO_IRQ)
+ if (!smu_irq_inited || !smu->db_irq)
smu_spinwait_cmd(cmd);
return 0;
@@ -498,8 +498,8 @@ int __init smu_init (void)
INIT_LIST_HEAD(&smu->cmd_list);
INIT_LIST_HEAD(&smu->cmd_i2c_list);
smu->of_node = np;
- smu->db_irq = NO_IRQ;
- smu->msg_irq = NO_IRQ;
+ smu->db_irq = 0;
+ smu->msg_irq = 0;
/* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
* 32 bits value safely
@@ -587,13 +587,13 @@ static int smu_late_init(void)
if (smu->db_node) {
smu->db_irq = irq_of_parse_and_map(smu->db_node, 0);
- if (smu->db_irq == NO_IRQ)
+ if (!smu->db_irq)
printk(KERN_ERR "smu: failed to map irq for node %s\n",
smu->db_node->full_name);
}
if (smu->msg_node) {
smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0);
- if (smu->msg_irq == NO_IRQ)
+ if (!smu->msg_irq)
printk(KERN_ERR "smu: failed to map irq for node %s\n",
smu->msg_node->full_name);
}
@@ -602,23 +602,23 @@ static int smu_late_init(void)
* Try to request the interrupts
*/
- if (smu->db_irq != NO_IRQ) {
+ if (smu->db_irq) {
if (request_irq(smu->db_irq, smu_db_intr,
IRQF_SHARED, "SMU doorbell", smu) < 0) {
printk(KERN_WARNING "SMU: can't "
"request interrupt %d\n",
smu->db_irq);
- smu->db_irq = NO_IRQ;
+ smu->db_irq = 0;
}
}
- if (smu->msg_irq != NO_IRQ) {
+ if (smu->msg_irq) {
if (request_irq(smu->msg_irq, smu_msg_intr,
IRQF_SHARED, "SMU message", smu) < 0) {
printk(KERN_WARNING "SMU: can't "
"request interrupt %d\n",
smu->msg_irq);
- smu->msg_irq = NO_IRQ;
+ smu->msg_irq = 0;
}
}
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index bad18130f125..2088e23a8002 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -209,7 +209,7 @@ static int __init via_cuda_start(void)
cuda_irq = IRQ_MAC_ADB;
#else
cuda_irq = irq_of_parse_and_map(vias, 0);
- if (cuda_irq == NO_IRQ) {
+ if (!cuda_irq) {
printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
vias->full_name);
return -ENODEV;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index f8b6d1403c16..91081dcdc272 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -145,7 +145,7 @@ static int pmu_fully_inited;
static int pmu_has_adb;
static struct device_node *gpio_node;
static unsigned char __iomem *gpio_reg;
-static int gpio_irq = NO_IRQ;
+static int gpio_irq = 0;
static int gpio_irq_enabled = -1;
static volatile int pmu_suspended;
static spinlock_t pmu_lock;
@@ -402,7 +402,7 @@ static int __init via_pmu_start(void)
batt_req.complete = 1;
irq = irq_of_parse_and_map(vias, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
printk(KERN_ERR "via-pmu: can't map interrupt\n");
return -ENODEV;
}
@@ -424,7 +424,7 @@ static int __init via_pmu_start(void)
if (gpio_node)
gpio_irq = irq_of_parse_and_map(gpio_node, 0);
- if (gpio_irq != NO_IRQ) {
+ if (gpio_irq) {
if (request_irq(gpio_irq, gpio1_interrupt,
IRQF_NO_SUSPEND, "GPIO1 ADB",
(void *)0))
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 7817d40d81e7..11eebfe8a4cb 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -15,6 +15,16 @@ config ARM_MHU
The controller has 3 mailbox channels, the last of which can be
used in Secure mode only.
+config PLATFORM_MHU
+ tristate "Platform MHU Mailbox"
+ depends on OF
+ depends on HAS_IOMEM
+ help
+ Say Y here if you want to build a platform specific variant MHU
+ controller driver.
+ The controller has a maximum of 3 mailbox channels, the last of
+ which can be used in Secure mode only.
+
config PL320_MBOX
bool "ARM PL320 Mailbox"
depends on ARM_AMBA
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 66c38e300dfc..ace6fed8fea9 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o
obj-$(CONFIG_ARM_MHU) += arm_mhu.o
+obj-$(CONFIG_PLATFORM_MHU) += platform_mhu.o
+
obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
diff --git a/drivers/mailbox/platform_mhu.c b/drivers/mailbox/platform_mhu.c
new file mode 100644
index 000000000000..e13201a5cec6
--- /dev/null
+++ b/drivers/mailbox/platform_mhu.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2016 BayLibre SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Synchronised with arm_mhu.c from :
+ * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Jassi Brar <jaswinder.singh@linaro.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_controller.h>
+
+#define INTR_SET_OFS 0x0
+#define INTR_STAT_OFS 0x4
+#define INTR_CLR_OFS 0x8
+
+#define MHU_SEC_OFFSET 0x0
+#define MHU_LP_OFFSET 0xc
+#define MHU_HP_OFFSET 0x18
+#define TX_REG_OFFSET 0x24
+
+#define MHU_CHANS 3
+
+struct platform_mhu_link {
+ int irq;
+ void __iomem *tx_reg;
+ void __iomem *rx_reg;
+};
+
+struct platform_mhu {
+ void __iomem *base;
+ struct platform_mhu_link mlink[MHU_CHANS];
+ struct mbox_chan chan[MHU_CHANS];
+ struct mbox_controller mbox;
+};
+
+static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)
+{
+ struct mbox_chan *chan = p;
+ struct platform_mhu_link *mlink = chan->con_priv;
+ u32 val;
+
+ val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
+ if (!val)
+ return IRQ_NONE;
+
+ mbox_chan_received_data(chan, (void *)&val);
+
+ writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
+
+ return IRQ_HANDLED;
+}
+
+static bool platform_mhu_last_tx_done(struct mbox_chan *chan)
+{
+ struct platform_mhu_link *mlink = chan->con_priv;
+ u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
+
+ return (val == 0);
+}
+
+static int platform_mhu_send_data(struct mbox_chan *chan, void *data)
+{
+ struct platform_mhu_link *mlink = chan->con_priv;
+ u32 *arg = data;
+
+ writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
+
+ return 0;
+}
+
+static int platform_mhu_startup(struct mbox_chan *chan)
+{
+ struct platform_mhu_link *mlink = chan->con_priv;
+ u32 val;
+ int ret;
+
+ val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
+ writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
+
+ ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,
+ IRQF_SHARED, "platform_mhu_link", chan);
+ if (ret) {
+ dev_err(chan->mbox->dev,
+ "Unable to acquire IRQ %d\n", mlink->irq);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void platform_mhu_shutdown(struct mbox_chan *chan)
+{
+ struct platform_mhu_link *mlink = chan->con_priv;
+
+ free_irq(mlink->irq, chan);
+}
+
+static const struct mbox_chan_ops platform_mhu_ops = {
+ .send_data = platform_mhu_send_data,
+ .startup = platform_mhu_startup,
+ .shutdown = platform_mhu_shutdown,
+ .last_tx_done = platform_mhu_last_tx_done,
+};
+
+static int platform_mhu_probe(struct platform_device *pdev)
+{
+ int i, err;
+ struct platform_mhu *mhu;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int platform_mhu_reg[MHU_CHANS] = {
+ MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET
+ };
+
+ /* Allocate memory for device */
+ mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
+ if (!mhu)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mhu->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mhu->base)) {
+ dev_err(dev, "ioremap failed\n");
+ return PTR_ERR(mhu->base);
+ }
+
+ for (i = 0; i < MHU_CHANS; i++) {
+ mhu->chan[i].con_priv = &mhu->mlink[i];
+ mhu->mlink[i].irq = platform_get_irq(pdev, i);
+ if (mhu->mlink[i].irq < 0) {
+ dev_err(dev, "failed to get irq%d\n", i);
+ return mhu->mlink[i].irq;
+ }
+ mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];
+ mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
+ }
+
+ mhu->mbox.dev = dev;
+ mhu->mbox.chans = &mhu->chan[0];
+ mhu->mbox.num_chans = MHU_CHANS;
+ mhu->mbox.ops = &platform_mhu_ops;
+ mhu->mbox.txdone_irq = false;
+ mhu->mbox.txdone_poll = true;
+ mhu->mbox.txpoll_period = 1;
+
+ platform_set_drvdata(pdev, mhu);
+
+ err = mbox_controller_register(&mhu->mbox);
+ if (err) {
+ dev_err(dev, "Failed to register mailboxes %d\n", err);
+ return err;
+ }
+
+ dev_info(dev, "Platform MHU Mailbox registered\n");
+ return 0;
+}
+
+static int platform_mhu_remove(struct platform_device *pdev)
+{
+ struct platform_mhu *mhu = platform_get_drvdata(pdev);
+
+ mbox_controller_unregister(&mhu->mbox);
+
+ return 0;
+}
+
+static const struct of_device_id platform_mhu_dt_ids[] = {
+ { .compatible = "amlogic,meson-gxbb-mhu", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);
+
+static struct platform_driver platform_mhu_driver = {
+ .probe = platform_mhu_probe,
+ .remove = platform_mhu_remove,
+ .driver = {
+ .name = "platform-mhu",
+ .of_match_table = platform_mhu_dt_ids,
+ },
+};
+
+module_platform_driver(platform_mhu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:platform-mhu");
+MODULE_DESCRIPTION("Platform MHU Driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 76f7534d1dd1..81d3db40cd7b 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -361,12 +361,8 @@ static void __btree_node_write_done(struct closure *cl)
static void btree_node_write_done(struct closure *cl)
{
struct btree *b = container_of(cl, struct btree, io);
- struct bio_vec *bv;
- int n;
-
- bio_for_each_segment_all(bv, b->bio, n)
- __free_page(bv->bv_page);
+ bio_free_pages(b->bio);
__btree_node_write_done(cl);
}
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
index c28df164701e..333a1e5f6ae6 100644
--- a/drivers/md/bcache/debug.c
+++ b/drivers/md/bcache/debug.c
@@ -107,9 +107,8 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio)
{
char name[BDEVNAME_SIZE];
struct bio *check;
- struct bio_vec bv, *bv2;
+ struct bio_vec bv;
struct bvec_iter iter;
- int i;
check = bio_clone(bio, GFP_NOIO);
if (!check)
@@ -136,8 +135,7 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio)
kunmap_atomic(p1);
}
- bio_for_each_segment_all(bv2, check, i)
- __free_page(bv2->bv_page);
+ bio_free_pages(check);
out_put:
bio_put(check);
}
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
index 1881319f2298..5c4bddecfaf0 100644
--- a/drivers/md/bcache/movinggc.c
+++ b/drivers/md/bcache/movinggc.c
@@ -44,11 +44,8 @@ static void write_moving_finish(struct closure *cl)
{
struct moving_io *io = container_of(cl, struct moving_io, cl);
struct bio *bio = &io->bio.bio;
- struct bio_vec *bv;
- int i;
- bio_for_each_segment_all(bv, bio, i)
- __free_page(bv->bv_page);
+ bio_free_pages(bio);
if (io->op.replace_collision)
trace_bcache_gc_copy_collision(&io->w->key);
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 4b177fe11ebb..40ffe5e424b3 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -694,13 +694,8 @@ static void cached_dev_cache_miss_done(struct closure *cl)
if (s->iop.replace_collision)
bch_mark_cache_miss_collision(s->iop.c, s->d);
- if (s->iop.bio) {
- int i;
- struct bio_vec *bv;
-
- bio_for_each_segment_all(bv, s->iop.bio, i)
- __free_page(bv->bv_page);
- }
+ if (s->iop.bio)
+ bio_free_pages(s->iop.bio);
cached_dev_bio_complete(cl);
}
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index d9fd2a62e5f6..e51644e503a5 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -128,11 +128,8 @@ static void write_dirty_finish(struct closure *cl)
struct dirty_io *io = container_of(cl, struct dirty_io, cl);
struct keybuf_key *w = io->bio.bi_private;
struct cached_dev *dc = io->dc;
- struct bio_vec *bv;
- int i;
- bio_for_each_segment_all(bv, &io->bio, i)
- __free_page(bv->bv_page);
+ bio_free_pages(&io->bio);
/* This is kind of a dumb way of signalling errors. */
if (KEY_DIRTY(&w->key)) {
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 13041ee37ad6..2d826927a3bf 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1903,10 +1903,8 @@ int bitmap_copy_from_slot(struct mddev *mddev, int slot,
struct bitmap_counts *counts;
struct bitmap *bitmap = bitmap_create(mddev, slot);
- if (IS_ERR(bitmap)) {
- bitmap_free(bitmap);
+ if (IS_ERR(bitmap))
return PTR_ERR(bitmap);
- }
rv = bitmap_init_from_disk(bitmap, 0);
if (rv)
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 8625040bae92..125aedc3875f 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -191,19 +191,6 @@ static void dm_bufio_unlock(struct dm_bufio_client *c)
mutex_unlock(&c->lock);
}
-/*
- * FIXME Move to sched.h?
- */
-#ifdef CONFIG_PREEMPT_VOLUNTARY
-# define dm_bufio_cond_resched() \
-do { \
- if (unlikely(need_resched())) \
- _cond_resched(); \
-} while (0)
-#else
-# define dm_bufio_cond_resched() do { } while (0)
-#endif
-
/*----------------------------------------------------------------*/
/*
@@ -741,7 +728,7 @@ static void __flush_write_list(struct list_head *write_list)
list_entry(write_list->next, struct dm_buffer, write_list);
list_del(&b->write_list);
submit_io(b, WRITE, b->block, write_endio);
- dm_bufio_cond_resched();
+ cond_resched();
}
blk_finish_plug(&plug);
}
@@ -780,7 +767,7 @@ static struct dm_buffer *__get_unclaimed_buffer(struct dm_bufio_client *c)
__unlink_buffer(b);
return b;
}
- dm_bufio_cond_resched();
+ cond_resched();
}
list_for_each_entry_reverse(b, &c->lru[LIST_DIRTY], lru_list) {
@@ -791,7 +778,7 @@ static struct dm_buffer *__get_unclaimed_buffer(struct dm_bufio_client *c)
__unlink_buffer(b);
return b;
}
- dm_bufio_cond_resched();
+ cond_resched();
}
return NULL;
@@ -923,7 +910,7 @@ static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait,
return;
__write_dirty_buffer(b, write_list);
- dm_bufio_cond_resched();
+ cond_resched();
}
}
@@ -973,7 +960,7 @@ static void __check_watermark(struct dm_bufio_client *c,
return;
__free_buffer_wake(b);
- dm_bufio_cond_resched();
+ cond_resched();
}
if (c->n_buffers[LIST_DIRTY] > threshold_buffers)
@@ -1170,7 +1157,7 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
submit_io(b, READ, b->block, read_endio);
dm_bufio_release(b);
- dm_bufio_cond_resched();
+ cond_resched();
if (!n_blocks)
goto flush_plug;
@@ -1291,7 +1278,7 @@ again:
!test_bit(B_WRITING, &b->state))
__relink_lru(b, LIST_CLEAN);
- dm_bufio_cond_resched();
+ cond_resched();
/*
* If we dropped the lock, the list is no longer consistent,
@@ -1574,7 +1561,7 @@ static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
freed++;
if (!--nr_to_scan || ((count - freed) <= retain_target))
return freed;
- dm_bufio_cond_resched();
+ cond_resched();
}
}
return freed;
@@ -1808,7 +1795,7 @@ static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz)
if (__try_evict_buffer(b, 0))
count--;
- dm_bufio_cond_resched();
+ cond_resched();
}
dm_bufio_unlock(c);
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 3970cda10080..695577812cf6 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -140,6 +140,13 @@ struct dm_cache_metadata {
* the device.
*/
bool fail_io:1;
+
+ /*
+ * These structures are used when loading metadata. They're too
+ * big to put on the stack.
+ */
+ struct dm_array_cursor mapping_cursor;
+ struct dm_array_cursor hint_cursor;
};
/*-------------------------------------------------------------------
@@ -1171,31 +1178,37 @@ static bool hints_array_available(struct dm_cache_metadata *cmd,
hints_array_initialized(cmd);
}
-static int __load_mapping(void *context, uint64_t cblock, void *leaf)
+static int __load_mapping(struct dm_cache_metadata *cmd,
+ uint64_t cb, bool hints_valid,
+ struct dm_array_cursor *mapping_cursor,
+ struct dm_array_cursor *hint_cursor,
+ load_mapping_fn fn, void *context)
{
int r = 0;
- bool dirty;
- __le64 value;
- __le32 hint_value = 0;
+
+ __le64 mapping;
+ __le32 hint = 0;
+
+ __le64 *mapping_value_le;
+ __le32 *hint_value_le;
+
dm_oblock_t oblock;
unsigned flags;
- struct thunk *thunk = context;
- struct dm_cache_metadata *cmd = thunk->cmd;
- memcpy(&value, leaf, sizeof(value));
- unpack_value(value, &oblock, &flags);
+ dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le);
+ memcpy(&mapping, mapping_value_le, sizeof(mapping));
+ unpack_value(mapping, &oblock, &flags);
if (flags & M_VALID) {
- if (thunk->hints_valid) {
- r = dm_array_get_value(&cmd->hint_info, cmd->hint_root,
- cblock, &hint_value);
- if (r && r != -ENODATA)
- return r;
+ if (hints_valid) {
+ dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le);
+ memcpy(&hint, hint_value_le, sizeof(hint));
}
- dirty = thunk->respect_dirty_flags ? (flags & M_DIRTY) : true;
- r = thunk->fn(thunk->context, oblock, to_cblock(cblock),
- dirty, le32_to_cpu(hint_value), thunk->hints_valid);
+ r = fn(context, oblock, to_cblock(cb), flags & M_DIRTY,
+ le32_to_cpu(hint), hints_valid);
+ if (r)
+ DMERR("policy couldn't load cblock");
}
return r;
@@ -1205,16 +1218,60 @@ static int __load_mappings(struct dm_cache_metadata *cmd,
struct dm_cache_policy *policy,
load_mapping_fn fn, void *context)
{
- struct thunk thunk;
+ int r;
+ uint64_t cb;
+
+ bool hints_valid = hints_array_available(cmd, policy);
+
+ if (from_cblock(cmd->cache_blocks) == 0)
+ /* Nothing to do */
+ return 0;
+
+ r = dm_array_cursor_begin(&cmd->info, cmd->root, &cmd->mapping_cursor);
+ if (r)
+ return r;
- thunk.fn = fn;
- thunk.context = context;
+ if (hints_valid) {
+ r = dm_array_cursor_begin(&cmd->hint_info, cmd->hint_root, &cmd->hint_cursor);
+ if (r) {
+ dm_array_cursor_end(&cmd->mapping_cursor);
+ return r;
+ }
+ }
+
+ for (cb = 0; ; cb++) {
+ r = __load_mapping(cmd, cb, hints_valid,
+ &cmd->mapping_cursor, &cmd->hint_cursor,
+ fn, context);
+ if (r)
+ goto out;
+
+ /*
+ * We need to break out before we move the cursors.
+ */
+ if (cb >= (from_cblock(cmd->cache_blocks) - 1))
+ break;
- thunk.cmd = cmd;
- thunk.respect_dirty_flags = cmd->clean_when_opened;
- thunk.hints_valid = hints_array_available(cmd, policy);
+ r = dm_array_cursor_next(&cmd->mapping_cursor);
+ if (r) {
+ DMERR("dm_array_cursor_next for mapping failed");
+ goto out;
+ }
- return dm_array_walk(&cmd->info, cmd->root, __load_mapping, &thunk);
+ if (hints_valid) {
+ r = dm_array_cursor_next(&cmd->hint_cursor);
+ if (r) {
+ DMERR("dm_array_cursor_next for hint failed");
+ goto out;
+ }
+ }
+ }
+out:
+ dm_array_cursor_end(&cmd->mapping_cursor);
+ if (hints_valid)
+ dm_array_cursor_end(&cmd->hint_cursor);
+
+ return r;
}
int dm_cache_load_mappings(struct dm_cache_metadata *cmd,
@@ -1368,10 +1425,24 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
/*----------------------------------------------------------------*/
-static int begin_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
+static int get_hint(uint32_t index, void *value_le, void *context)
+{
+ uint32_t value;
+ struct dm_cache_policy *policy = context;
+
+ value = policy_get_hint(policy, to_cblock(index));
+ *((__le32 *) value_le) = cpu_to_le32(value);
+
+ return 0;
+}
+
+/*
+ * It's quicker to always delete the hint array, and recreate with
+ * dm_array_new().
+ */
+static int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
{
int r;
- __le32 value;
size_t hint_size;
const char *policy_name = dm_cache_policy_get_name(policy);
const unsigned *policy_version = dm_cache_policy_get_version(policy);
@@ -1380,63 +1451,23 @@ static int begin_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *po
(strlen(policy_name) > sizeof(cmd->policy_name) - 1))
return -EINVAL;
- if (!policy_unchanged(cmd, policy)) {
- strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name));
- memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version));
-
- hint_size = dm_cache_policy_get_hint_size(policy);
- if (!hint_size)
- return 0; /* short-circuit hints initialization */
- cmd->policy_hint_size = hint_size;
+ strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name));
+ memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version));
- if (cmd->hint_root) {
- r = dm_array_del(&cmd->hint_info, cmd->hint_root);
- if (r)
- return r;
- }
+ hint_size = dm_cache_policy_get_hint_size(policy);
+ if (!hint_size)
+ return 0; /* short-circuit hints initialization */
+ cmd->policy_hint_size = hint_size;
- r = dm_array_empty(&cmd->hint_info, &cmd->hint_root);
+ if (cmd->hint_root) {
+ r = dm_array_del(&cmd->hint_info, cmd->hint_root);
if (r)
return r;
-
- value = cpu_to_le32(0);
- __dm_bless_for_disk(&value);
- r = dm_array_resize(&cmd->hint_info, cmd->hint_root, 0,
- from_cblock(cmd->cache_blocks),
- &value, &cmd->hint_root);
- if (r)
- return r;
- }
-
- return 0;
-}
-
-static int save_hint(void *context, dm_cblock_t cblock, dm_oblock_t oblock, uint32_t hint)
-{
- struct dm_cache_metadata *cmd = context;
- __le32 value = cpu_to_le32(hint);
- int r;
-
- __dm_bless_for_disk(&value);
-
- r = dm_array_set_value(&cmd->hint_info, cmd->hint_root,
- from_cblock(cblock), &value, &cmd->hint_root);
- cmd->changed = true;
-
- return r;
-}
-
-static int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
-{
- int r;
-
- r = begin_hints(cmd, policy);
- if (r) {
- DMERR("begin_hints failed");
- return r;
}
- return policy_walk_mappings(policy, save_hint, cmd);
+ return dm_array_new(&cmd->hint_info, &cmd->hint_root,
+ from_cblock(cmd->cache_blocks),
+ get_hint, policy);
}
int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy)
diff --git a/drivers/md/dm-cache-policy-cleaner.c b/drivers/md/dm-cache-policy-cleaner.c
index 14aaaf059f06..2e8a8f1d8358 100644
--- a/drivers/md/dm-cache-policy-cleaner.c
+++ b/drivers/md/dm-cache-policy-cleaner.c
@@ -395,7 +395,7 @@ static void init_policy_functions(struct policy *p)
p->policy.set_dirty = wb_set_dirty;
p->policy.clear_dirty = wb_clear_dirty;
p->policy.load_mapping = wb_load_mapping;
- p->policy.walk_mappings = NULL;
+ p->policy.get_hint = NULL;
p->policy.remove_mapping = wb_remove_mapping;
p->policy.writeback_work = wb_writeback_work;
p->policy.force_mapping = wb_force_mapping;
diff --git a/drivers/md/dm-cache-policy-internal.h b/drivers/md/dm-cache-policy-internal.h
index 2816018faa7f..808ee0e2b2c4 100644
--- a/drivers/md/dm-cache-policy-internal.h
+++ b/drivers/md/dm-cache-policy-internal.h
@@ -48,10 +48,10 @@ static inline int policy_load_mapping(struct dm_cache_policy *p,
return p->load_mapping(p, oblock, cblock, hint, hint_valid);
}
-static inline int policy_walk_mappings(struct dm_cache_policy *p,
- policy_walk_fn fn, void *context)
+static inline uint32_t policy_get_hint(struct dm_cache_policy *p,
+ dm_cblock_t cblock)
{
- return p->walk_mappings ? p->walk_mappings(p, fn, context) : 0;
+ return p->get_hint ? p->get_hint(p, cblock) : 0;
}
static inline int policy_writeback_work(struct dm_cache_policy *p,
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index cf48a617a3a4..c33f4a6e1d7d 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -1359,6 +1359,11 @@ static void smq_clear_dirty(struct dm_cache_policy *p, dm_oblock_t oblock)
spin_unlock_irqrestore(&mq->lock, flags);
}
+static unsigned random_level(dm_cblock_t cblock)
+{
+ return hash_32_generic(from_cblock(cblock), 9) & (NR_CACHE_LEVELS - 1);
+}
+
static int smq_load_mapping(struct dm_cache_policy *p,
dm_oblock_t oblock, dm_cblock_t cblock,
uint32_t hint, bool hint_valid)
@@ -1369,47 +1374,21 @@ static int smq_load_mapping(struct dm_cache_policy *p,
e = alloc_particular_entry(&mq->cache_alloc, from_cblock(cblock));
e->oblock = oblock;
e->dirty = false; /* this gets corrected in a minute */
- e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : 1;
+ e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : random_level(cblock);
push(mq, e);
return 0;
}
-static int smq_save_hints(struct smq_policy *mq, struct queue *q,
- policy_walk_fn fn, void *context)
-{
- int r;
- unsigned level;
- struct entry *e;
-
- for (level = 0; level < q->nr_levels; level++)
- for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) {
- if (!e->sentinel) {
- r = fn(context, infer_cblock(mq, e),
- e->oblock, e->level);
- if (r)
- return r;
- }
- }
-
- return 0;
-}
-
-static int smq_walk_mappings(struct dm_cache_policy *p, policy_walk_fn fn,
- void *context)
+static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock)
{
struct smq_policy *mq = to_smq_policy(p);
- int r = 0;
+ struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
- /*
- * We don't need to lock here since this method is only called once
- * the IO has stopped.
- */
- r = smq_save_hints(mq, &mq->clean, fn, context);
- if (!r)
- r = smq_save_hints(mq, &mq->dirty, fn, context);
+ if (!e->allocated)
+ return 0;
- return r;
+ return e->level;
}
static void __remove_mapping(struct smq_policy *mq, dm_oblock_t oblock)
@@ -1616,7 +1595,7 @@ static void init_policy_functions(struct smq_policy *mq, bool mimic_mq)
mq->policy.set_dirty = smq_set_dirty;
mq->policy.clear_dirty = smq_clear_dirty;
mq->policy.load_mapping = smq_load_mapping;
- mq->policy.walk_mappings = smq_walk_mappings;
+ mq->policy.get_hint = smq_get_hint;
mq->policy.remove_mapping = smq_remove_mapping;
mq->policy.remove_cblock = smq_remove_cblock;
mq->policy.writeback_work = smq_writeback_work;
diff --git a/drivers/md/dm-cache-policy.h b/drivers/md/dm-cache-policy.h
index 05db56eedb6a..aa10b1493f34 100644
--- a/drivers/md/dm-cache-policy.h
+++ b/drivers/md/dm-cache-policy.h
@@ -90,9 +90,6 @@ struct policy_result {
dm_cblock_t cblock; /* POLICY_HIT, POLICY_NEW, POLICY_REPLACE */
};
-typedef int (*policy_walk_fn)(void *context, dm_cblock_t cblock,
- dm_oblock_t oblock, uint32_t hint);
-
/*
* The cache policy object. Just a bunch of methods. It is envisaged that
* this structure will be embedded in a bigger, policy specific structure
@@ -158,8 +155,11 @@ struct dm_cache_policy {
int (*load_mapping)(struct dm_cache_policy *p, dm_oblock_t oblock,
dm_cblock_t cblock, uint32_t hint, bool hint_valid);
- int (*walk_mappings)(struct dm_cache_policy *p, policy_walk_fn fn,
- void *context);
+ /*
+ * Gets the hint for a given cblock. Called in a single threaded
+ * context. So no locking required.
+ */
+ uint32_t (*get_hint)(struct dm_cache_policy *p, dm_cblock_t cblock);
/*
* Override functions used on the error paths of the core target.
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 874295757caa..a2768835d394 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -113,8 +113,7 @@ struct iv_tcw_private {
* and encrypts / decrypts at the same time.
*/
enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
- DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD,
- DM_CRYPT_EXIT_THREAD};
+ DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
/*
* The fields in here must be read only after initialization.
@@ -1136,7 +1135,7 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
clone->bi_private = io;
clone->bi_end_io = crypt_endio;
clone->bi_bdev = cc->dev->bdev;
- bio_set_op_attrs(clone, bio_op(io->base_bio), io->base_bio->bi_opf);
+ bio_set_op_attrs(clone, bio_op(io->base_bio), bio_flags(io->base_bio));
}
static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
@@ -1207,18 +1206,20 @@ continue_locked:
if (!RB_EMPTY_ROOT(&cc->write_tree))
goto pop_from_list;
- if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) {
- spin_unlock_irq(&cc->write_thread_wait.lock);
- break;
- }
-
- __set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_INTERRUPTIBLE);
__add_wait_queue(&cc->write_thread_wait, &wait);
spin_unlock_irq(&cc->write_thread_wait.lock);
+ if (unlikely(kthread_should_stop())) {
+ set_task_state(current, TASK_RUNNING);
+ remove_wait_queue(&cc->write_thread_wait, &wait);
+ break;
+ }
+
schedule();
+ set_task_state(current, TASK_RUNNING);
spin_lock_irq(&cc->write_thread_wait.lock);
__remove_wait_queue(&cc->write_thread_wait, &wait);
goto continue_locked;
@@ -1533,13 +1534,8 @@ static void crypt_dtr(struct dm_target *ti)
if (!cc)
return;
- if (cc->write_thread) {
- spin_lock_irq(&cc->write_thread_wait.lock);
- set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags);
- wake_up_locked(&cc->write_thread_wait);
- spin_unlock_irq(&cc->write_thread_wait.lock);
+ if (cc->write_thread)
kthread_stop(cc->write_thread);
- }
if (cc->io_queue)
destroy_workqueue(cc->io_queue);
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 49e4d8d4558f..4dfe38655a49 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -149,8 +149,6 @@ static void put_io_block(struct log_writes_c *lc)
static void log_end_io(struct bio *bio)
{
struct log_writes_c *lc = bio->bi_private;
- struct bio_vec *bvec;
- int i;
if (bio->bi_error) {
unsigned long flags;
@@ -161,9 +159,7 @@ static void log_end_io(struct bio *bio)
spin_unlock_irqrestore(&lc->blocks_lock, flags);
}
- bio_for_each_segment_all(bvec, bio, i)
- __free_page(bvec->bv_page);
-
+ bio_free_pages(bio);
put_io_block(lc);
bio_put(bio);
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index ac734e5bbe48..e477af8596e2 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -550,9 +550,9 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
pgpath = choose_pgpath(m, nr_bytes);
if (!pgpath) {
- if (!must_push_back_rq(m))
- r = -EIO; /* Failed */
- return r;
+ if (must_push_back_rq(m))
+ return DM_MAPIO_DELAY_REQUEUE;
+ return -EIO; /* Failed */
} else if (test_bit(MPATHF_QUEUE_IO, &m->flags) ||
test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags)) {
pg_init_all_paths(m);
@@ -680,9 +680,11 @@ static int multipath_map_bio(struct dm_target *ti, struct bio *bio)
return __multipath_map_bio(m, bio, mpio);
}
-static void process_queued_bios_list(struct multipath *m)
+static void process_queued_io_list(struct multipath *m)
{
- if (m->queue_mode == DM_TYPE_BIO_BASED)
+ if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED)
+ dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table));
+ else if (m->queue_mode == DM_TYPE_BIO_BASED)
queue_work(kmultipathd, &m->process_queued_bios);
}
@@ -752,7 +754,7 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
if (!queue_if_no_path) {
dm_table_run_md_queue_async(m->ti->table);
- process_queued_bios_list(m);
+ process_queued_io_list(m);
}
return 0;
@@ -1193,21 +1195,17 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)
static void multipath_wait_for_pg_init_completion(struct multipath *m)
{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&m->pg_init_wait, &wait);
+ DEFINE_WAIT(wait);
while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
+ prepare_to_wait(&m->pg_init_wait, &wait, TASK_UNINTERRUPTIBLE);
if (!atomic_read(&m->pg_init_in_progress))
break;
io_schedule();
}
- set_current_state(TASK_RUNNING);
-
- remove_wait_queue(&m->pg_init_wait, &wait);
+ finish_wait(&m->pg_init_wait, &wait);
}
static void flush_multipath_work(struct multipath *m)
@@ -1308,7 +1306,7 @@ out:
spin_unlock_irqrestore(&m->lock, flags);
if (run_queue) {
dm_table_run_md_queue_async(m->ti->table);
- process_queued_bios_list(m);
+ process_queued_io_list(m);
}
return r;
@@ -1506,7 +1504,7 @@ static void pg_init_done(void *data, int errors)
}
clear_bit(MPATHF_QUEUE_IO, &m->flags);
- process_queued_bios_list(m);
+ process_queued_io_list(m);
/*
* Wake up any thread waiting to suspend.
@@ -1521,10 +1519,10 @@ static void activate_path(struct work_struct *work)
{
struct pgpath *pgpath =
container_of(work, struct pgpath, activate_path.work);
+ struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev);
- if (pgpath->is_active)
- scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
- pg_init_done, pgpath);
+ if (pgpath->is_active && !blk_queue_dying(q))
+ scsi_dh_activate(q, pg_init_done, pgpath);
else
pg_init_done(pgpath, SCSI_DH_DEV_OFFLINED);
}
@@ -1532,6 +1530,14 @@ static void activate_path(struct work_struct *work)
static int noretry_error(int error)
{
switch (error) {
+ case -EBADE:
+ /*
+ * EBADE signals an reservation conflict.
+ * We shouldn't fail the path here as we can communicate with
+ * the target. We should failover to the next path, but in
+ * doing so we might be causing a ping-pong between paths.
+ * So just return the reservation conflict error.
+ */
case -EOPNOTSUPP:
case -EREMOTEIO:
case -EILSEQ:
@@ -1576,9 +1582,6 @@ static int do_end_io(struct multipath *m, struct request *clone,
if (!test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
if (!must_push_back_rq(m))
r = -EIO;
- } else {
- if (error == -EBADE)
- r = error;
}
}
@@ -1627,9 +1630,6 @@ static int do_end_io_bio(struct multipath *m, struct bio *clone,
if (!must_push_back_bio(m))
return -EIO;
return DM_ENDIO_REQUEUE;
- } else {
- if (error == -EBADE)
- return error;
}
}
@@ -1941,7 +1941,7 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
if (test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags))
pg_init_all_paths(m);
dm_table_run_md_queue_async(m->ti->table);
- process_queued_bios_list(m);
+ process_queued_io_list(m);
}
/*
@@ -1994,11 +1994,14 @@ static int multipath_busy(struct dm_target *ti)
struct priority_group *pg, *next_pg;
struct pgpath *pgpath;
- /* pg_init in progress or no paths available */
- if (atomic_read(&m->pg_init_in_progress) ||
- (!atomic_read(&m->nr_valid_paths) && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)))
+ /* pg_init in progress */
+ if (atomic_read(&m->pg_init_in_progress))
return true;
+ /* no paths available, for blk-mq: rely on IO mapping to delay requeue */
+ if (!atomic_read(&m->nr_valid_paths) && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
+ return (m->queue_mode != DM_TYPE_MQ_REQUEST_BASED);
+
/* Guess which priority_group will be used at next mapping time */
pg = lockless_dereference(m->current_pg);
next_pg = lockless_dereference(m->next_pg);
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index 1ca7463e8bb2..5eacce1ef88b 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -73,15 +73,24 @@ static void dm_old_start_queue(struct request_queue *q)
spin_unlock_irqrestore(q->queue_lock, flags);
}
+static void dm_mq_start_queue(struct request_queue *q)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ queue_flag_clear(QUEUE_FLAG_STOPPED, q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ blk_mq_start_stopped_hw_queues(q, true);
+ blk_mq_kick_requeue_list(q);
+}
+
void dm_start_queue(struct request_queue *q)
{
if (!q->mq_ops)
dm_old_start_queue(q);
- else {
- queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, q);
- blk_mq_start_stopped_hw_queues(q, true);
- blk_mq_kick_requeue_list(q);
- }
+ else
+ dm_mq_start_queue(q);
}
static void dm_old_stop_queue(struct request_queue *q)
@@ -89,27 +98,35 @@ static void dm_old_stop_queue(struct request_queue *q)
unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags);
+ if (!blk_queue_stopped(q))
+ blk_stop_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static void dm_mq_stop_queue(struct request_queue *q)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
if (blk_queue_stopped(q)) {
spin_unlock_irqrestore(q->queue_lock, flags);
return;
}
- blk_stop_queue(q);
+ queue_flag_set(QUEUE_FLAG_STOPPED, q);
spin_unlock_irqrestore(q->queue_lock, flags);
+
+ /* Avoid that requeuing could restart the queue. */
+ blk_mq_cancel_requeue_work(q);
+ blk_mq_stop_hw_queues(q);
}
void dm_stop_queue(struct request_queue *q)
{
if (!q->mq_ops)
dm_old_stop_queue(q);
- else {
- spin_lock_irq(q->queue_lock);
- queue_flag_set(QUEUE_FLAG_STOPPED, q);
- spin_unlock_irq(q->queue_lock);
-
- blk_mq_cancel_requeue_work(q);
- blk_mq_stop_hw_queues(q);
- }
+ else
+ dm_mq_stop_queue(q);
}
static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md,
@@ -319,21 +336,32 @@ static void dm_old_requeue_request(struct request *rq)
spin_unlock_irqrestore(q->queue_lock, flags);
}
-static void dm_mq_requeue_request(struct request *rq)
+static void __dm_mq_kick_requeue_list(struct request_queue *q, unsigned long msecs)
{
- struct request_queue *q = rq->q;
unsigned long flags;
- blk_mq_requeue_request(rq);
spin_lock_irqsave(q->queue_lock, flags);
if (!blk_queue_stopped(q))
- blk_mq_kick_requeue_list(q);
+ blk_mq_delay_kick_requeue_list(q, msecs);
spin_unlock_irqrestore(q->queue_lock, flags);
}
-static void dm_requeue_original_request(struct mapped_device *md,
- struct request *rq)
+void dm_mq_kick_requeue_list(struct mapped_device *md)
+{
+ __dm_mq_kick_requeue_list(dm_get_md_queue(md), 0);
+}
+EXPORT_SYMBOL(dm_mq_kick_requeue_list);
+
+static void dm_mq_delay_requeue_request(struct request *rq, unsigned long msecs)
+{
+ blk_mq_requeue_request(rq);
+ __dm_mq_kick_requeue_list(rq->q, msecs);
+}
+
+static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_requeue)
{
+ struct mapped_device *md = tio->md;
+ struct request *rq = tio->orig;
int rw = rq_data_dir(rq);
rq_end_stats(md, rq);
@@ -342,7 +370,7 @@ static void dm_requeue_original_request(struct mapped_device *md,
if (!rq->q->mq_ops)
dm_old_requeue_request(rq);
else
- dm_mq_requeue_request(rq);
+ dm_mq_delay_requeue_request(rq, delay_requeue ? 5000 : 0);
rq_completed(md, rw, false);
}
@@ -372,7 +400,7 @@ static void dm_done(struct request *clone, int error, bool mapped)
return;
else if (r == DM_ENDIO_REQUEUE)
/* The target wants to requeue the I/O */
- dm_requeue_original_request(tio->md, tio->orig);
+ dm_requeue_original_request(tio, false);
else {
DMWARN("unimplemented target endio return value: %d", r);
BUG();
@@ -612,20 +640,23 @@ static int dm_old_prep_fn(struct request_queue *q, struct request *rq)
/*
* Returns:
- * 0 : the request has been processed
- * DM_MAPIO_REQUEUE : the original request needs to be requeued
+ * DM_MAPIO_* : the request has been processed as indicated
+ * DM_MAPIO_REQUEUE : the original request needs to be immediately requeued
* < 0 : the request was completed due to failure
*/
-static int map_request(struct dm_rq_target_io *tio, struct request *rq,
- struct mapped_device *md)
+static int map_request(struct dm_rq_target_io *tio)
{
int r;
struct dm_target *ti = tio->ti;
+ struct mapped_device *md = tio->md;
+ struct request *rq = tio->orig;
struct request *clone = NULL;
if (tio->clone) {
clone = tio->clone;
r = ti->type->map_rq(ti, clone, &tio->info);
+ if (r == DM_MAPIO_DELAY_REQUEUE)
+ return DM_MAPIO_REQUEUE; /* .request_fn requeue is always immediate */
} else {
r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone);
if (r < 0) {
@@ -633,9 +664,8 @@ static int map_request(struct dm_rq_target_io *tio, struct request *rq,
dm_kill_unmapped_request(rq, r);
return r;
}
- if (r != DM_MAPIO_REMAPPED)
- return r;
- if (setup_clone(clone, rq, tio, GFP_ATOMIC)) {
+ if (r == DM_MAPIO_REMAPPED &&
+ setup_clone(clone, rq, tio, GFP_ATOMIC)) {
/* -ENOMEM */
ti->type->release_clone_rq(clone);
return DM_MAPIO_REQUEUE;
@@ -654,7 +684,10 @@ static int map_request(struct dm_rq_target_io *tio, struct request *rq,
break;
case DM_MAPIO_REQUEUE:
/* The target wants to requeue the I/O */
- dm_requeue_original_request(md, tio->orig);
+ break;
+ case DM_MAPIO_DELAY_REQUEUE:
+ /* The target wants to requeue the I/O after a delay */
+ dm_requeue_original_request(tio, true);
break;
default:
if (r > 0) {
@@ -664,10 +697,9 @@ static int map_request(struct dm_rq_target_io *tio, struct request *rq,
/* The target wants to complete the I/O */
dm_kill_unmapped_request(rq, r);
- return r;
}
- return 0;
+ return r;
}
static void dm_start_request(struct mapped_device *md, struct request *orig)
@@ -706,11 +738,9 @@ static void dm_start_request(struct mapped_device *md, struct request *orig)
static void map_tio_request(struct kthread_work *work)
{
struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work);
- struct request *rq = tio->orig;
- struct mapped_device *md = tio->md;
- if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE)
- dm_requeue_original_request(md, rq);
+ if (map_request(tio) == DM_MAPIO_REQUEUE)
+ dm_requeue_original_request(tio, false);
}
ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf)
@@ -896,7 +926,7 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
tio->ti = ti;
/* Direct call is fine since .queue_rq allows allocations */
- if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE) {
+ if (map_request(tio) == DM_MAPIO_REQUEUE) {
/* Undo dm_start_request() before requeuing */
rq_end_stats(md, rq);
rq_completed(md, rq_data_dir(rq), false);
@@ -908,7 +938,6 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
static struct blk_mq_ops dm_mq_ops = {
.queue_rq = dm_mq_queue_rq,
- .map_queue = blk_mq_map_queue,
.complete = dm_softirq_done,
.init_request = dm_mq_init_request,
};
@@ -955,7 +984,7 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t)
dm_init_md_queue(md);
/* backfill 'mq' sysfs registration normally done in blk_register_queue */
- blk_mq_register_disk(md->disk);
+ blk_mq_register_dev(disk_to_dev(md->disk), q);
return 0;
diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h
index 9e6f0a3773d4..4da06cae7bad 100644
--- a/drivers/md/dm-rq.h
+++ b/drivers/md/dm-rq.h
@@ -55,6 +55,8 @@ void dm_mq_cleanup_mapped_device(struct mapped_device *md);
void dm_start_queue(struct request_queue *q);
void dm_stop_queue(struct request_queue *q);
+void dm_mq_kick_requeue_list(struct mapped_device *md);
+
unsigned dm_get_reserved_rq_based_ios(void);
ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index fa9b1cb4438a..be35258324c1 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1648,6 +1648,8 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
struct request_queue *q = md->queue;
sector_t size;
+ lockdep_assert_held(&md->suspend_lock);
+
size = dm_table_get_size(t);
/*
@@ -1873,6 +1875,7 @@ EXPORT_SYMBOL_GPL(dm_device_name);
static void __dm_destroy(struct mapped_device *md, bool wait)
{
+ struct request_queue *q = dm_get_md_queue(md);
struct dm_table *map;
int srcu_idx;
@@ -1883,6 +1886,10 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
set_bit(DMF_FREEING, &md->flags);
spin_unlock(&_minor_lock);
+ spin_lock_irq(q->queue_lock);
+ queue_flag_set(QUEUE_FLAG_DYING, q);
+ spin_unlock_irq(q->queue_lock);
+
if (dm_request_based(md) && md->kworker_task)
flush_kthread_worker(&md->kworker);
@@ -1934,30 +1941,25 @@ void dm_put(struct mapped_device *md)
}
EXPORT_SYMBOL_GPL(dm_put);
-static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
+static int dm_wait_for_completion(struct mapped_device *md, long task_state)
{
int r = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&md->wait, &wait);
+ DEFINE_WAIT(wait);
while (1) {
- set_current_state(interruptible);
+ prepare_to_wait(&md->wait, &wait, task_state);
if (!md_in_flight(md))
break;
- if (interruptible == TASK_INTERRUPTIBLE &&
- signal_pending(current)) {
+ if (signal_pending_state(task_state, current)) {
r = -EINTR;
break;
}
io_schedule();
}
- set_current_state(TASK_RUNNING);
-
- remove_wait_queue(&md->wait, &wait);
+ finish_wait(&md->wait, &wait);
return r;
}
@@ -2075,6 +2077,10 @@ static void unlock_fs(struct mapped_device *md)
}
/*
+ * @suspend_flags: DM_SUSPEND_LOCKFS_FLAG and/or DM_SUSPEND_NOFLUSH_FLAG
+ * @task_state: e.g. TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE
+ * @dmf_suspended_flag: DMF_SUSPENDED or DMF_SUSPENDED_INTERNALLY
+ *
* If __dm_suspend returns 0, the device is completely quiescent
* now. There is no request-processing activity. All new requests
* are being added to md->deferred list.
@@ -2082,13 +2088,15 @@ static void unlock_fs(struct mapped_device *md)
* Caller must hold md->suspend_lock
*/
static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
- unsigned suspend_flags, int interruptible,
+ unsigned suspend_flags, long task_state,
int dmf_suspended_flag)
{
bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG;
int r;
+ lockdep_assert_held(&md->suspend_lock);
+
/*
* DMF_NOFLUSH_SUSPENDING must be set before presuspend.
* This flag is cleared before dm_suspend returns.
@@ -2149,7 +2157,7 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
* We call dm_wait_for_completion to wait for all existing requests
* to finish.
*/
- r = dm_wait_for_completion(md, interruptible);
+ r = dm_wait_for_completion(md, task_state);
if (!r)
set_bit(dmf_suspended_flag, &md->flags);
@@ -2249,10 +2257,11 @@ static int __dm_resume(struct mapped_device *md, struct dm_table *map)
int dm_resume(struct mapped_device *md)
{
- int r = -EINVAL;
+ int r;
struct dm_table *map = NULL;
retry:
+ r = -EINVAL;
mutex_lock_nested(&md->suspend_lock, SINGLE_DEPTH_NESTING);
if (!dm_suspended_md(md))
@@ -2276,8 +2285,6 @@ retry:
goto out;
clear_bit(DMF_SUSPENDED, &md->flags);
-
- r = 0;
out:
mutex_unlock(&md->suspend_lock);
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index 34a840d9df76..2b13117fb918 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
+#include <linux/kthread.h>
#include <linux/dlm.h>
#include <linux/sched.h>
#include <linux/raid/md_p.h>
@@ -25,7 +26,8 @@ struct dlm_lock_resource {
struct dlm_lksb lksb;
char *name; /* lock name. */
uint32_t flags; /* flags to pass to dlm_lock() */
- struct completion completion; /* completion for synchronized locking */
+ wait_queue_head_t sync_locking; /* wait queue for synchronized locking */
+ bool sync_locking_done;
void (*bast)(void *arg, int mode); /* blocking AST function pointer*/
struct mddev *mddev; /* pointing back to mddev. */
int mode;
@@ -118,7 +120,8 @@ static void sync_ast(void *arg)
struct dlm_lock_resource *res;
res = arg;
- complete(&res->completion);
+ res->sync_locking_done = true;
+ wake_up(&res->sync_locking);
}
static int dlm_lock_sync(struct dlm_lock_resource *res, int mode)
@@ -130,7 +133,8 @@ static int dlm_lock_sync(struct dlm_lock_resource *res, int mode)
0, sync_ast, res, res->bast);
if (ret)
return ret;
- wait_for_completion(&res->completion);
+ wait_event(res->sync_locking, res->sync_locking_done);
+ res->sync_locking_done = false;
if (res->lksb.sb_status == 0)
res->mode = mode;
return res->lksb.sb_status;
@@ -141,6 +145,44 @@ static int dlm_unlock_sync(struct dlm_lock_resource *res)
return dlm_lock_sync(res, DLM_LOCK_NL);
}
+/*
+ * An variation of dlm_lock_sync, which make lock request could
+ * be interrupted
+ */
+static int dlm_lock_sync_interruptible(struct dlm_lock_resource *res, int mode,
+ struct mddev *mddev)
+{
+ int ret = 0;
+
+ ret = dlm_lock(res->ls, mode, &res->lksb,
+ res->flags, res->name, strlen(res->name),
+ 0, sync_ast, res, res->bast);
+ if (ret)
+ return ret;
+
+ wait_event(res->sync_locking, res->sync_locking_done
+ || kthread_should_stop()
+ || test_bit(MD_CLOSING, &mddev->flags));
+ if (!res->sync_locking_done) {
+ /*
+ * the convert queue contains the lock request when request is
+ * interrupted, and sync_ast could still be run, so need to
+ * cancel the request and reset completion
+ */
+ ret = dlm_unlock(res->ls, res->lksb.sb_lkid, DLM_LKF_CANCEL,
+ &res->lksb, res);
+ res->sync_locking_done = false;
+ if (unlikely(ret != 0))
+ pr_info("failed to cancel previous lock request "
+ "%s return %d\n", res->name, ret);
+ return -EPERM;
+ } else
+ res->sync_locking_done = false;
+ if (res->lksb.sb_status == 0)
+ res->mode = mode;
+ return res->lksb.sb_status;
+}
+
static struct dlm_lock_resource *lockres_init(struct mddev *mddev,
char *name, void (*bastfn)(void *arg, int mode), int with_lvb)
{
@@ -151,7 +193,8 @@ static struct dlm_lock_resource *lockres_init(struct mddev *mddev,
res = kzalloc(sizeof(struct dlm_lock_resource), GFP_KERNEL);
if (!res)
return NULL;
- init_completion(&res->completion);
+ init_waitqueue_head(&res->sync_locking);
+ res->sync_locking_done = false;
res->ls = cinfo->lockspace;
res->mddev = mddev;
res->mode = DLM_LOCK_IV;
@@ -194,25 +237,21 @@ out_err:
static void lockres_free(struct dlm_lock_resource *res)
{
- int ret;
+ int ret = 0;
if (!res)
return;
- /* cancel a lock request or a conversion request that is blocked */
- res->flags |= DLM_LKF_CANCEL;
-retry:
- ret = dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res);
- if (unlikely(ret != 0)) {
- pr_info("%s: failed to unlock %s return %d\n", __func__, res->name, ret);
-
- /* if a lock conversion is cancelled, then the lock is put
- * back to grant queue, need to ensure it is unlocked */
- if (ret == -DLM_ECANCEL)
- goto retry;
- }
- res->flags &= ~DLM_LKF_CANCEL;
- wait_for_completion(&res->completion);
+ /*
+ * use FORCEUNLOCK flag, so we can unlock even the lock is on the
+ * waiting or convert queue
+ */
+ ret = dlm_unlock(res->ls, res->lksb.sb_lkid, DLM_LKF_FORCEUNLOCK,
+ &res->lksb, res);
+ if (unlikely(ret != 0))
+ pr_err("failed to unlock %s return %d\n", res->name, ret);
+ else
+ wait_event(res->sync_locking, res->sync_locking_done);
kfree(res->name);
kfree(res->lksb.sb_lvbptr);
@@ -279,7 +318,7 @@ static void recover_bitmaps(struct md_thread *thread)
goto clear_bit;
}
- ret = dlm_lock_sync(bm_lockres, DLM_LOCK_PW);
+ ret = dlm_lock_sync_interruptible(bm_lockres, DLM_LOCK_PW, mddev);
if (ret) {
pr_err("md-cluster: Could not DLM lock %s: %d\n",
str, ret);
@@ -288,7 +327,7 @@ static void recover_bitmaps(struct md_thread *thread)
ret = bitmap_copy_from_slot(mddev, slot, &lo, &hi, true);
if (ret) {
pr_err("md-cluster: Could not copy data from bitmap %d\n", slot);
- goto dlm_unlock;
+ goto clear_bit;
}
if (hi > 0) {
if (lo < mddev->recovery_cp)
@@ -300,8 +339,6 @@ static void recover_bitmaps(struct md_thread *thread)
md_wakeup_thread(mddev->thread);
}
}
-dlm_unlock:
- dlm_unlock_sync(bm_lockres);
clear_bit:
lockres_free(bm_lockres);
clear_bit(slot, &cinfo->recovery_map);
@@ -495,9 +532,10 @@ static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg
static void process_remove_disk(struct mddev *mddev, struct cluster_msg *msg)
{
- struct md_rdev *rdev = md_find_rdev_nr_rcu(mddev,
- le32_to_cpu(msg->raid_slot));
+ struct md_rdev *rdev;
+ rcu_read_lock();
+ rdev = md_find_rdev_nr_rcu(mddev, le32_to_cpu(msg->raid_slot));
if (rdev) {
set_bit(ClusterRemove, &rdev->flags);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -506,18 +544,21 @@ static void process_remove_disk(struct mddev *mddev, struct cluster_msg *msg)
else
pr_warn("%s: %d Could not find disk(%d) to REMOVE\n",
__func__, __LINE__, le32_to_cpu(msg->raid_slot));
+ rcu_read_unlock();
}
static void process_readd_disk(struct mddev *mddev, struct cluster_msg *msg)
{
- struct md_rdev *rdev = md_find_rdev_nr_rcu(mddev,
- le32_to_cpu(msg->raid_slot));
+ struct md_rdev *rdev;
+ rcu_read_lock();
+ rdev = md_find_rdev_nr_rcu(mddev, le32_to_cpu(msg->raid_slot));
if (rdev && test_bit(Faulty, &rdev->flags))
clear_bit(Faulty, &rdev->flags);
else
pr_warn("%s: %d Could not find disk(%d) which is faulty",
__func__, __LINE__, le32_to_cpu(msg->raid_slot));
+ rcu_read_unlock();
}
static int process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg)
@@ -770,7 +811,6 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots)
md_check_recovery(mddev);
}
- dlm_unlock_sync(bm_lockres);
lockres_free(bm_lockres);
}
out:
@@ -1006,7 +1046,7 @@ static void metadata_update_cancel(struct mddev *mddev)
static int resync_start(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
- return dlm_lock_sync(cinfo->resync_lockres, DLM_LOCK_EX);
+ return dlm_lock_sync_interruptible(cinfo->resync_lockres, DLM_LOCK_EX, mddev);
}
static int resync_info_update(struct mddev *mddev, sector_t lo, sector_t hi)
@@ -1186,7 +1226,6 @@ static void unlock_all_bitmaps(struct mddev *mddev)
if (cinfo->other_bitmap_lockres) {
for (i = 0; i < mddev->bitmap_info.nodes - 1; i++) {
if (cinfo->other_bitmap_lockres[i]) {
- dlm_unlock_sync(cinfo->other_bitmap_lockres[i]);
lockres_free(cinfo->other_bitmap_lockres[i]);
}
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 915e84d631a2..eac84d8ff724 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5297,6 +5297,21 @@ int md_run(struct mddev *mddev)
return err;
}
if (mddev->queue) {
+ bool nonrot = true;
+
+ rdev_for_each(rdev, mddev) {
+ if (rdev->raid_disk >= 0 &&
+ !blk_queue_nonrot(bdev_get_queue(rdev->bdev))) {
+ nonrot = false;
+ break;
+ }
+ }
+ if (mddev->degraded)
+ nonrot = false;
+ if (nonrot)
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
+ else
+ queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
mddev->queue->backing_dev_info.congested_data = mddev;
mddev->queue->backing_dev_info.congested_fn = md_congested;
}
@@ -5454,12 +5469,14 @@ static void md_clean(struct mddev *mddev)
mddev->degraded = 0;
mddev->safemode = 0;
mddev->private = NULL;
+ mddev->cluster_info = NULL;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.default_offset = 0;
mddev->bitmap_info.default_space = 0;
mddev->bitmap_info.chunksize = 0;
mddev->bitmap_info.daemon_sleep = 0;
mddev->bitmap_info.max_write_behind = 0;
+ mddev->bitmap_info.nodes = 0;
}
static void __md_stop_writes(struct mddev *mddev)
@@ -5573,8 +5590,7 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
mutex_lock(&mddev->open_mutex);
if ((mddev->pers && atomic_read(&mddev->openers) > !!bdev) ||
mddev->sync_thread ||
- test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
- (bdev && !test_bit(MD_STILL_CLOSED, &mddev->flags))) {
+ test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
printk("md: %s still in use.\n",mdname(mddev));
if (did_freeze) {
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
@@ -5636,8 +5652,7 @@ static int do_md_stop(struct mddev *mddev, int mode,
if ((mddev->pers && atomic_read(&mddev->openers) > !!bdev) ||
mddev->sysfs_active ||
mddev->sync_thread ||
- test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
- (bdev && !test_bit(MD_STILL_CLOSED, &mddev->flags))) {
+ test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
printk("md: %s still in use.\n",mdname(mddev));
mutex_unlock(&mddev->open_mutex);
if (did_freeze) {
@@ -6101,9 +6116,14 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info)
export_rdev(rdev);
if (mddev_is_clustered(mddev)) {
- if (info->state & (1 << MD_DISK_CANDIDATE))
- md_cluster_ops->new_disk_ack(mddev, (err == 0));
- else {
+ if (info->state & (1 << MD_DISK_CANDIDATE)) {
+ if (!err) {
+ err = md_cluster_ops->new_disk_ack(mddev,
+ err == 0);
+ if (err)
+ md_kick_rdev_from_array(rdev);
+ }
+ } else {
if (err)
md_cluster_ops->add_new_disk_cancel(mddev);
else
@@ -6821,7 +6841,7 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
err = -EBUSY;
goto out;
}
- set_bit(MD_STILL_CLOSED, &mddev->flags);
+ set_bit(MD_CLOSING, &mddev->flags);
mutex_unlock(&mddev->open_mutex);
sync_blockdev(bdev);
}
@@ -7070,9 +7090,13 @@ static int md_open(struct block_device *bdev, fmode_t mode)
if ((err = mutex_lock_interruptible(&mddev->open_mutex)))
goto out;
+ if (test_bit(MD_CLOSING, &mddev->flags)) {
+ mutex_unlock(&mddev->open_mutex);
+ return -ENODEV;
+ }
+
err = 0;
atomic_inc(&mddev->openers);
- clear_bit(MD_STILL_CLOSED, &mddev->flags);
mutex_unlock(&mddev->open_mutex);
check_disk_change(bdev);
@@ -8873,7 +8897,9 @@ static void autostart_arrays(int part)
list_del(&node_detected_dev->list);
dev = node_detected_dev->dev;
kfree(node_detected_dev);
+ mutex_unlock(&detected_devices_mutex);
rdev = md_import_device(dev,0, 90);
+ mutex_lock(&detected_devices_mutex);
if (IS_ERR(rdev))
continue;
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 20c667579ede..2b2041773e79 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -201,9 +201,8 @@ struct mddev {
#define MD_CHANGE_PENDING 2 /* switch from 'clean' to 'active' in progress */
#define MD_UPDATE_SB_FLAGS (1 | 2 | 4) /* If these are set, md_update_sb needed */
#define MD_ARRAY_FIRST_USE 3 /* First use of array, needs initialization */
-#define MD_STILL_CLOSED 4 /* If set, then array has not been opened since
- * md_ioctl checked on it.
- */
+#define MD_CLOSING 4 /* If set, we are closing the array, do not open
+ * it then */
#define MD_JOURNAL_CLEAN 5 /* A raid with journal is already clean */
#define MD_HAS_JOURNAL 6 /* The raid array has journal feature set */
#define MD_RELOAD_SB 7 /* Reload the superblock because another node
diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c
index 431a03067d64..e83047cbb2da 100644
--- a/drivers/md/persistent-data/dm-array.c
+++ b/drivers/md/persistent-data/dm-array.c
@@ -277,6 +277,48 @@ static int insert_ablock(struct dm_array_info *info, uint64_t index,
return dm_btree_insert(&info->btree_info, *root, &index, &block_le, root);
}
+/*----------------------------------------------------------------*/
+
+static int __shadow_ablock(struct dm_array_info *info, dm_block_t b,
+ struct dm_block **block, struct array_block **ab)
+{
+ int inc;
+ int r = dm_tm_shadow_block(info->btree_info.tm, b,
+ &array_validator, block, &inc);
+ if (r)
+ return r;
+
+ *ab = dm_block_data(*block);
+ if (inc)
+ inc_ablock_entries(info, *ab);
+
+ return 0;
+}
+
+/*
+ * The shadow op will often be a noop. Only insert if it really
+ * copied data.
+ */
+static int __reinsert_ablock(struct dm_array_info *info, unsigned index,
+ struct dm_block *block, dm_block_t b,
+ dm_block_t *root)
+{
+ int r = 0;
+
+ if (dm_block_location(block) != b) {
+ /*
+ * dm_tm_shadow_block will have already decremented the old
+ * block, but it is still referenced by the btree. We
+ * increment to stop the insert decrementing it below zero
+ * when overwriting the old value.
+ */
+ dm_tm_inc(info->btree_info.tm, b);
+ r = insert_ablock(info, index, block, root);
+ }
+
+ return r;
+}
+
/*
* Looks up an array block in the btree. Then shadows it, and updates the
* btree to point to this new shadow. 'root' is an input/output parameter
@@ -286,49 +328,21 @@ static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
unsigned index, struct dm_block **block,
struct array_block **ab)
{
- int r, inc;
+ int r;
uint64_t key = index;
dm_block_t b;
__le64 block_le;
- /*
- * lookup
- */
r = dm_btree_lookup(&info->btree_info, *root, &key, &block_le);
if (r)
return r;
b = le64_to_cpu(block_le);
- /*
- * shadow
- */
- r = dm_tm_shadow_block(info->btree_info.tm, b,
- &array_validator, block, &inc);
+ r = __shadow_ablock(info, b, block, ab);
if (r)
return r;
- *ab = dm_block_data(*block);
- if (inc)
- inc_ablock_entries(info, *ab);
-
- /*
- * Reinsert.
- *
- * The shadow op will often be a noop. Only insert if it really
- * copied data.
- */
- if (dm_block_location(*block) != b) {
- /*
- * dm_tm_shadow_block will have already decremented the old
- * block, but it is still referenced by the btree. We
- * increment to stop the insert decrementing it below zero
- * when overwriting the old value.
- */
- dm_tm_inc(info->btree_info.tm, b);
- r = insert_ablock(info, index, *block, root);
- }
-
- return r;
+ return __reinsert_ablock(info, index, *block, b, root);
}
/*
@@ -681,6 +695,72 @@ int dm_array_resize(struct dm_array_info *info, dm_block_t root,
}
EXPORT_SYMBOL_GPL(dm_array_resize);
+static int populate_ablock_with_values(struct dm_array_info *info, struct array_block *ab,
+ value_fn fn, void *context, unsigned base, unsigned new_nr)
+{
+ int r;
+ unsigned i;
+ uint32_t nr_entries;
+ struct dm_btree_value_type *vt = &info->value_type;
+
+ BUG_ON(le32_to_cpu(ab->nr_entries));
+ BUG_ON(new_nr > le32_to_cpu(ab->max_entries));
+
+ nr_entries = le32_to_cpu(ab->nr_entries);
+ for (i = 0; i < new_nr; i++) {
+ r = fn(base + i, element_at(info, ab, i), context);
+ if (r)
+ return r;
+
+ if (vt->inc)
+ vt->inc(vt->context, element_at(info, ab, i));
+ }
+
+ ab->nr_entries = cpu_to_le32(new_nr);
+ return 0;
+}
+
+int dm_array_new(struct dm_array_info *info, dm_block_t *root,
+ uint32_t size, value_fn fn, void *context)
+{
+ int r;
+ struct dm_block *block;
+ struct array_block *ab;
+ unsigned block_index, end_block, size_of_block, max_entries;
+
+ r = dm_array_empty(info, root);
+ if (r)
+ return r;
+
+ size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm));
+ max_entries = calc_max_entries(info->value_type.size, size_of_block);
+ end_block = dm_div_up(size, max_entries);
+
+ for (block_index = 0; block_index != end_block; block_index++) {
+ r = alloc_ablock(info, size_of_block, max_entries, &block, &ab);
+ if (r)
+ break;
+
+ r = populate_ablock_with_values(info, ab, fn, context,
+ block_index * max_entries,
+ min(max_entries, size));
+ if (r) {
+ unlock_ablock(info, block);
+ break;
+ }
+
+ r = insert_ablock(info, block_index, block, root);
+ unlock_ablock(info, block);
+ if (r)
+ break;
+
+ size -= max_entries;
+ }
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_array_new);
+
int dm_array_del(struct dm_array_info *info, dm_block_t root)
{
return dm_btree_del(&info->btree_info, root);
@@ -819,3 +899,89 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root,
EXPORT_SYMBOL_GPL(dm_array_walk);
/*----------------------------------------------------------------*/
+
+static int load_ablock(struct dm_array_cursor *c)
+{
+ int r;
+ __le64 value_le;
+ uint64_t key;
+
+ if (c->block)
+ unlock_ablock(c->info, c->block);
+
+ c->block = NULL;
+ c->ab = NULL;
+ c->index = 0;
+
+ r = dm_btree_cursor_get_value(&c->cursor, &key, &value_le);
+ if (r) {
+ DMERR("dm_btree_cursor_get_value failed");
+ dm_btree_cursor_end(&c->cursor);
+
+ } else {
+ r = get_ablock(c->info, le64_to_cpu(value_le), &c->block, &c->ab);
+ if (r) {
+ DMERR("get_ablock failed");
+ dm_btree_cursor_end(&c->cursor);
+ }
+ }
+
+ return r;
+}
+
+int dm_array_cursor_begin(struct dm_array_info *info, dm_block_t root,
+ struct dm_array_cursor *c)
+{
+ int r;
+
+ memset(c, 0, sizeof(*c));
+ c->info = info;
+ r = dm_btree_cursor_begin(&info->btree_info, root, true, &c->cursor);
+ if (r) {
+ DMERR("couldn't create btree cursor");
+ return r;
+ }
+
+ return load_ablock(c);
+}
+EXPORT_SYMBOL_GPL(dm_array_cursor_begin);
+
+void dm_array_cursor_end(struct dm_array_cursor *c)
+{
+ if (c->block) {
+ unlock_ablock(c->info, c->block);
+ dm_btree_cursor_end(&c->cursor);
+ }
+}
+EXPORT_SYMBOL_GPL(dm_array_cursor_end);
+
+int dm_array_cursor_next(struct dm_array_cursor *c)
+{
+ int r;
+
+ if (!c->block)
+ return -ENODATA;
+
+ c->index++;
+
+ if (c->index >= le32_to_cpu(c->ab->nr_entries)) {
+ r = dm_btree_cursor_next(&c->cursor);
+ if (r)
+ return r;
+
+ r = load_ablock(c);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dm_array_cursor_next);
+
+void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le)
+{
+ *value_le = element_at(c->info, c->ab, c->index);
+}
+EXPORT_SYMBOL_GPL(dm_array_cursor_get_value);
+
+/*----------------------------------------------------------------*/
diff --git a/drivers/md/persistent-data/dm-array.h b/drivers/md/persistent-data/dm-array.h
index ea177d6fa58f..27ee49a55473 100644
--- a/drivers/md/persistent-data/dm-array.h
+++ b/drivers/md/persistent-data/dm-array.h
@@ -112,6 +112,25 @@ int dm_array_resize(struct dm_array_info *info, dm_block_t root,
__dm_written_to_disk(value);
/*
+ * Creates a new array populated with values provided by a callback
+ * function. This is more efficient than creating an empty array,
+ * resizing, and then setting values since that process incurs a lot of
+ * copying.
+ *
+ * Assumes 32bit values for now since it's only used by the cache hint
+ * array.
+ *
+ * info - describes the array
+ * root - the root block of the array on disk
+ * size - the number of entries in the array
+ * fn - the callback
+ * context - passed to the callback
+ */
+typedef int (*value_fn)(uint32_t index, void *value_le, void *context);
+int dm_array_new(struct dm_array_info *info, dm_block_t *root,
+ uint32_t size, value_fn fn, void *context);
+
+/*
* Frees a whole array. The value_type's decrement operation will be called
* for all values in the array
*/
@@ -163,4 +182,37 @@ int dm_array_walk(struct dm_array_info *info, dm_block_t root,
/*----------------------------------------------------------------*/
+/*
+ * Cursor api.
+ *
+ * This lets you iterate through all the entries in an array efficiently
+ * (it will preload metadata).
+ *
+ * I'm using a cursor, rather than a walk function with a callback because
+ * the cache target needs to iterate both the mapping and hint arrays in
+ * unison.
+ */
+struct dm_array_cursor {
+ struct dm_array_info *info;
+ struct dm_btree_cursor cursor;
+
+ struct dm_block *block;
+ struct array_block *ab;
+ unsigned index;
+};
+
+int dm_array_cursor_begin(struct dm_array_info *info,
+ dm_block_t root, struct dm_array_cursor *c);
+void dm_array_cursor_end(struct dm_array_cursor *c);
+
+uint32_t dm_array_cursor_index(struct dm_array_cursor *c);
+int dm_array_cursor_next(struct dm_array_cursor *c);
+
+/*
+ * value_le is only valid while the cursor points at the current value.
+ */
+void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le);
+
+/*----------------------------------------------------------------*/
+
#endif /* _LINUX_DM_ARRAY_H */
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index 2cc1877804c2..20a40329d84a 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -994,3 +994,165 @@ int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
return walk_node(info, root, fn, context);
}
EXPORT_SYMBOL_GPL(dm_btree_walk);
+
+/*----------------------------------------------------------------*/
+
+static void prefetch_values(struct dm_btree_cursor *c)
+{
+ unsigned i, nr;
+ __le64 value_le;
+ struct cursor_node *n = c->nodes + c->depth - 1;
+ struct btree_node *bn = dm_block_data(n->b);
+ struct dm_block_manager *bm = dm_tm_get_bm(c->info->tm);
+
+ BUG_ON(c->info->value_type.size != sizeof(value_le));
+
+ nr = le32_to_cpu(bn->header.nr_entries);
+ for (i = 0; i < nr; i++) {
+ memcpy(&value_le, value_ptr(bn, i), sizeof(value_le));
+ dm_bm_prefetch(bm, le64_to_cpu(value_le));
+ }
+}
+
+static bool leaf_node(struct dm_btree_cursor *c)
+{
+ struct cursor_node *n = c->nodes + c->depth - 1;
+ struct btree_node *bn = dm_block_data(n->b);
+
+ return le32_to_cpu(bn->header.flags) & LEAF_NODE;
+}
+
+static int push_node(struct dm_btree_cursor *c, dm_block_t b)
+{
+ int r;
+ struct cursor_node *n = c->nodes + c->depth;
+
+ if (c->depth >= DM_BTREE_CURSOR_MAX_DEPTH - 1) {
+ DMERR("couldn't push cursor node, stack depth too high");
+ return -EINVAL;
+ }
+
+ r = bn_read_lock(c->info, b, &n->b);
+ if (r)
+ return r;
+
+ n->index = 0;
+ c->depth++;
+
+ if (c->prefetch_leaves || !leaf_node(c))
+ prefetch_values(c);
+
+ return 0;
+}
+
+static void pop_node(struct dm_btree_cursor *c)
+{
+ c->depth--;
+ unlock_block(c->info, c->nodes[c->depth].b);
+}
+
+static int inc_or_backtrack(struct dm_btree_cursor *c)
+{
+ struct cursor_node *n;
+ struct btree_node *bn;
+
+ for (;;) {
+ if (!c->depth)
+ return -ENODATA;
+
+ n = c->nodes + c->depth - 1;
+ bn = dm_block_data(n->b);
+
+ n->index++;
+ if (n->index < le32_to_cpu(bn->header.nr_entries))
+ break;
+
+ pop_node(c);
+ }
+
+ return 0;
+}
+
+static int find_leaf(struct dm_btree_cursor *c)
+{
+ int r = 0;
+ struct cursor_node *n;
+ struct btree_node *bn;
+ __le64 value_le;
+
+ for (;;) {
+ n = c->nodes + c->depth - 1;
+ bn = dm_block_data(n->b);
+
+ if (le32_to_cpu(bn->header.flags) & LEAF_NODE)
+ break;
+
+ memcpy(&value_le, value_ptr(bn, n->index), sizeof(value_le));
+ r = push_node(c, le64_to_cpu(value_le));
+ if (r) {
+ DMERR("push_node failed");
+ break;
+ }
+ }
+
+ if (!r && (le32_to_cpu(bn->header.nr_entries) == 0))
+ return -ENODATA;
+
+ return r;
+}
+
+int dm_btree_cursor_begin(struct dm_btree_info *info, dm_block_t root,
+ bool prefetch_leaves, struct dm_btree_cursor *c)
+{
+ int r;
+
+ c->info = info;
+ c->root = root;
+ c->depth = 0;
+ c->prefetch_leaves = prefetch_leaves;
+
+ r = push_node(c, root);
+ if (r)
+ return r;
+
+ return find_leaf(c);
+}
+EXPORT_SYMBOL_GPL(dm_btree_cursor_begin);
+
+void dm_btree_cursor_end(struct dm_btree_cursor *c)
+{
+ while (c->depth)
+ pop_node(c);
+}
+EXPORT_SYMBOL_GPL(dm_btree_cursor_end);
+
+int dm_btree_cursor_next(struct dm_btree_cursor *c)
+{
+ int r = inc_or_backtrack(c);
+ if (!r) {
+ r = find_leaf(c);
+ if (r)
+ DMERR("find_leaf failed");
+ }
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_btree_cursor_next);
+
+int dm_btree_cursor_get_value(struct dm_btree_cursor *c, uint64_t *key, void *value_le)
+{
+ if (c->depth) {
+ struct cursor_node *n = c->nodes + c->depth - 1;
+ struct btree_node *bn = dm_block_data(n->b);
+
+ if (le32_to_cpu(bn->header.flags) & INTERNAL_NODE)
+ return -EINVAL;
+
+ *key = le64_to_cpu(*key_ptr(bn, n->index));
+ memcpy(value_le, value_ptr(bn, n->index), c->info->value_type.size);
+ return 0;
+
+ } else
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(dm_btree_cursor_get_value);
diff --git a/drivers/md/persistent-data/dm-btree.h b/drivers/md/persistent-data/dm-btree.h
index c74301fa5a37..db9bd26adf31 100644
--- a/drivers/md/persistent-data/dm-btree.h
+++ b/drivers/md/persistent-data/dm-btree.h
@@ -176,4 +176,39 @@ int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
int (*fn)(void *context, uint64_t *keys, void *leaf),
void *context);
+
+/*----------------------------------------------------------------*/
+
+/*
+ * Cursor API. This does not follow the rolling lock convention. Since we
+ * know the order that values are required we can issue prefetches to speed
+ * up iteration. Use on a single level btree only.
+ */
+#define DM_BTREE_CURSOR_MAX_DEPTH 16
+
+struct cursor_node {
+ struct dm_block *b;
+ unsigned index;
+};
+
+struct dm_btree_cursor {
+ struct dm_btree_info *info;
+ dm_block_t root;
+
+ bool prefetch_leaves;
+ unsigned depth;
+ struct cursor_node nodes[DM_BTREE_CURSOR_MAX_DEPTH];
+};
+
+/*
+ * Creates a fresh cursor. If prefetch_leaves is set then it is assumed
+ * the btree contains block indexes that will be prefetched. The cursor is
+ * quite large, so you probably don't want to put it on the stack.
+ */
+int dm_btree_cursor_begin(struct dm_btree_info *info, dm_block_t root,
+ bool prefetch_leaves, struct dm_btree_cursor *c);
+void dm_btree_cursor_end(struct dm_btree_cursor *c);
+int dm_btree_cursor_next(struct dm_btree_cursor *c);
+int dm_btree_cursor_get_value(struct dm_btree_cursor *c, uint64_t *key, void *value_le);
+
#endif /* _LINUX_DM_BTREE_H */
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 21dc00eb1989..1961d827dbd1 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -145,12 +145,8 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
return r1_bio;
out_free_pages:
- while (--j >= 0) {
- struct bio_vec *bv;
-
- bio_for_each_segment_all(bv, r1_bio->bios[j], i)
- __free_page(bv->bv_page);
- }
+ while (--j >= 0)
+ bio_free_pages(r1_bio->bios[j]);
out_free_bio:
while (++j < pi->raid_disks)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 5287e79e0b78..92ac251e91e6 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6370,7 +6370,7 @@ static void free_conf(struct r5conf *conf)
{
if (conf->log)
r5l_exit_log(conf->log);
- if (conf->shrinker.seeks)
+ if (conf->shrinker.nr_deferred)
unregister_shrinker(&conf->shrinker);
free_thread_groups(conf);
@@ -6632,7 +6632,12 @@ static struct r5conf *setup_conf(struct mddev *mddev)
conf->shrinker.count_objects = raid5_cache_count;
conf->shrinker.batch = 128;
conf->shrinker.flags = 0;
- register_shrinker(&conf->shrinker);
+ if (register_shrinker(&conf->shrinker)) {
+ printk(KERN_ERR
+ "md/raid:%s: couldn't register shrinker.\n",
+ mdname(mddev));
+ goto abort;
+ }
sprintf(pers_name, "raid%d", mddev->new_level);
conf->thread = md_register_thread(raid5d, mddev, pers_name);
@@ -7028,6 +7033,8 @@ static int raid5_run(struct mddev *mddev)
else
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD,
mddev->queue);
+
+ blk_queue_max_hw_sectors(mddev->queue, UINT_MAX);
}
if (journal_dev) {
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index fcc3b82d1454..003fff07ade2 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -24,6 +24,7 @@
#define DRIVER_NAME "meson-ir"
+/* valid on all Meson platforms */
#define IR_DEC_LDR_ACTIVE 0x00
#define IR_DEC_LDR_IDLE 0x04
#define IR_DEC_LDR_REPEAT 0x08
@@ -32,12 +33,21 @@
#define IR_DEC_FRAME 0x14
#define IR_DEC_STATUS 0x18
#define IR_DEC_REG1 0x1c
+/* only available on Meson 8b and newer */
+#define IR_DEC_REG2 0x20
#define REG0_RATE_MASK (BIT(11) - 1)
-#define REG1_MODE_MASK (BIT(7) | BIT(8))
-#define REG1_MODE_NEC (0 << 7)
-#define REG1_MODE_GENERAL (2 << 7)
+#define DECODE_MODE_NEC 0x0
+#define DECODE_MODE_RAW 0x2
+
+/* Meson 6b uses REG1 to configure the mode */
+#define REG1_MODE_MASK GENMASK(8, 7)
+#define REG1_MODE_SHIFT 7
+
+/* Meson 8b / GXBB use REG2 to configure the mode */
+#define REG2_MODE_MASK GENMASK(3, 0)
+#define REG2_MODE_SHIFT 0
#define REG1_TIME_IV_SHIFT 16
#define REG1_TIME_IV_MASK ((BIT(13) - 1) << REG1_TIME_IV_SHIFT)
@@ -158,8 +168,15 @@ static int meson_ir_probe(struct platform_device *pdev)
/* Reset the decoder */
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET);
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0);
- /* Set general operation mode */
- meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, REG1_MODE_GENERAL);
+
+ /* Set general operation mode (= raw/software decoding) */
+ if (of_device_is_compatible(node, "amlogic,meson6-ir"))
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK,
+ DECODE_MODE_RAW << REG1_MODE_SHIFT);
+ else
+ meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK,
+ DECODE_MODE_RAW << REG2_MODE_SHIFT);
+
/* Set rate */
meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1);
/* IRQ on rising and falling edges */
@@ -197,6 +214,8 @@ static int meson_ir_remove(struct platform_device *pdev)
static const struct of_device_id meson_ir_match[] = {
{ .compatible = "amlogic,meson6-ir" },
+ { .compatible = "amlogic,meson8b-ir" },
+ { .compatible = "amlogic,meson-gxbb-ir" },
{ },
};
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index f87ad6f5d2dc..b5ed3bd082b5 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -410,10 +410,7 @@ static int at91sam9_ebi_init(struct at91_ebi *ebi)
field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
- if (IS_ERR(fields->mode))
- return PTR_ERR(fields->mode);
-
- return 0;
+ return PTR_ERR_OR_ZERO(fields->mode);
}
static int sama5d3_ebi_init(struct at91_ebi *ebi)
@@ -441,10 +438,7 @@ static int sama5d3_ebi_init(struct at91_ebi *ebi)
field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC);
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
- if (IS_ERR(fields->mode))
- return PTR_ERR(fields->mode);
-
- return 0;
+ return PTR_ERR_OR_ZERO(fields->mode);
}
static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c
index 53a341f3b305..12080b05e3e6 100644
--- a/drivers/memory/atmel-sdramc.c
+++ b/drivers/memory/atmel-sdramc.c
@@ -53,12 +53,10 @@ static const struct of_device_id atmel_ramc_of_match[] = {
static int atmel_ramc_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
const struct at91_ramc_caps *caps;
struct clk *clk;
- match = of_match_device(atmel_ramc_of_match, &pdev->dev);
- caps = match->data;
+ caps = of_device_get_match_data(&pdev->dev);
if (caps->has_ddrck) {
clk = devm_clk_get(&pdev->dev, "ddrck");
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index f00f3e742265..5457c361ad58 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -350,8 +350,8 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
return (time_ps + tick_ps - 1) / tick_ps;
}
-unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs,
- enum gpmc_clk_domain cd)
+static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
+ enum gpmc_clk_domain cd)
{
return ticks * gpmc_get_clk_period(cs, cd) / 1000;
}
@@ -2143,9 +2143,7 @@ err_child_fail:
ret = -ENODEV;
err_cs:
- if (waitpin_desc)
- gpiochip_free_own_desc(waitpin_desc);
-
+ gpiochip_free_own_desc(waitpin_desc);
err:
gpmc_cs_free(cs);
@@ -2265,7 +2263,7 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc)
gpmc->gpio_chip.get = gpmc_gpio_get;
gpmc->gpio_chip.base = -1;
- ret = gpiochip_add(&gpmc->gpio_chip);
+ ret = devm_gpiochip_add_data(gpmc->dev, &gpmc->gpio_chip, NULL);
if (ret < 0) {
dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
return ret;
@@ -2274,11 +2272,6 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc)
return 0;
}
-static void gpmc_gpio_exit(struct gpmc_device *gpmc)
-{
- gpiochip_remove(&gpmc->gpio_chip);
-}
-
static int gpmc_probe(struct platform_device *pdev)
{
int rc;
@@ -2365,15 +2358,13 @@ static int gpmc_probe(struct platform_device *pdev)
rc = gpmc_setup_irq(gpmc);
if (rc) {
dev_err(gpmc->dev, "gpmc_setup_irq failed\n");
- goto setup_irq_failed;
+ goto gpio_init_failed;
}
gpmc_probe_dt_children(pdev);
return 0;
-setup_irq_failed:
- gpmc_gpio_exit(gpmc);
gpio_init_failed:
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);
@@ -2387,7 +2378,6 @@ static int gpmc_remove(struct platform_device *pdev)
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
gpmc_free_irq(gpmc);
- gpmc_gpio_exit(gpmc);
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5537f8df8512..89c7ed16b4df 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1865,8 +1865,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
"mpt_poll_%d", ioc->id);
- ioc->reset_work_q =
- create_singlethread_workqueue(ioc->reset_work_q_name);
+ ioc->reset_work_q = alloc_workqueue(ioc->reset_work_q_name,
+ WQ_MEM_RECLAIM, 0);
if (!ioc->reset_work_q) {
printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
ioc->name);
@@ -1992,7 +1992,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->fw_event_list);
spin_lock_init(&ioc->fw_event_lock);
snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
- ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
+ ioc->fw_event_q = alloc_workqueue(ioc->fw_event_q_name,
+ WQ_MEM_RECLAIM, 0);
if (!ioc->fw_event_q) {
printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
ioc->name);
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index d8bf84aef602..add6a3a6ef0d 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1324,9 +1324,12 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name),
"mptfc_wq_%d", sh->host_no);
ioc->fc_rescan_work_q =
- create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
- if (!ioc->fc_rescan_work_q)
+ alloc_ordered_workqueue(ioc->fc_rescan_work_q_name,
+ WQ_MEM_RECLAIM);
+ if (!ioc->fc_rescan_work_q) {
+ error = -ENOMEM;
goto out_mptfc_probe;
+ }
/*
* Pre-fetch FC port WWN and stuff...
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2caf7e967390..c6df6442ba2b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -50,7 +50,7 @@ config MFD_AS3711
Support for the AS3711 PMIC from AMS
config MFD_AS3722
- bool "ams AS3722 Power Management IC"
+ tristate "ams AS3722 Power Management IC"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -112,6 +112,16 @@ config MFD_BCM590XX
help
Support for the BCM590xx PMUs from Broadcom
+config MFD_AC100
+ tristate "X-Powers AC100"
+ select MFD_CORE
+ depends on SUNXI_RSB
+ help
+ If you say Y here you get support for the X-Powers AC100 audio codec
+ IC.
+ This driver include only the core APIs. You have to select individual
+ components like codecs or RTC under the corresponding menus.
+
config MFD_AXP20X
tristate
select MFD_CORE
@@ -281,6 +291,14 @@ config MFD_DLN2
etc. must be enabled in order to use the functionality of
the device.
+config MFD_EXYNOS_LPASS
+ tristate "Samsung Exynos SoC Low Power Audio Subsystem"
+ select MFD_CORE
+ select REGMAP_MMIO
+ help
+ Select this option to enable support for Samsung Exynos Low Power
+ Audio Subsystem.
+
config MFD_MC13XXX
tristate
depends on (SPI_MASTER || I2C)
@@ -844,13 +862,13 @@ config MFD_RC5T583
different functionality of the device.
config MFD_RK808
- tristate "Rockchip RK808 Power Management chip"
+ tristate "Rockchip RK808/RK818 Power Management Chip"
depends on I2C && OF
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
- If you say yes here you get support for the RK808
+ If you say yes here you get support for the RK808 and RK818
Power Management chips.
This driver provides common support for accessing the device
through I2C interface. The device supports multiple sub-devices
@@ -1206,6 +1224,7 @@ config MFD_TPS65217
depends on I2C
select MFD_CORE
select REGMAP_I2C
+ select IRQ_DOMAIN
help
If you say yes here you get support for the TPS65217 series of
Power Management / White LED chips.
@@ -1555,6 +1574,7 @@ config MFD_WM8350
config MFD_WM8350_I2C
bool "Wolfson Microelectronics WM8350 with I2C"
select MFD_WM8350
+ select REGMAP_I2C
depends on I2C=y
help
The WM8350 is an integrated audio and power management
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2bf6a1ac7428..9834e669d985 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
@@ -114,6 +115,8 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o
obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
+
+obj-$(CONFIG_MFD_AC100) += ac100.o
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 0aecd7bd35f8..acf6c00b14b9 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -153,14 +153,14 @@ static struct hwreg_cfg hwreg_cfg = {
#define AB8500_NAME_STRING "ab8500"
#define AB8500_ADC_NAME_STRING "gpadc"
-#define AB8500_NUM_BANKS 24
+#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST
#define AB8500_REV_REG 0x80
static struct ab8500_prcmu_ranges *debug_ranges;
static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
- [0x0] = {
+ [AB8500_M_FSM_RANK] = {
.num_ranges = 0,
.range = NULL,
},
@@ -315,7 +315,7 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
},
},
},
- [0x9] = {
+ [AB8500_RESERVED] = {
.num_ranges = 0,
.range = NULL,
},
@@ -386,24 +386,6 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
},
},
},
- [AB8500_DEVELOPMENT] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- },
- },
- [AB8500_DEBUG] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x05,
- .last = 0x07,
- },
- },
- },
[AB8500_AUDIO] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
@@ -463,19 +445,29 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
},
},
},
- [0x11] = {
- .num_ranges = 0,
- .range = NULL,
+ [AB8500_DEVELOPMENT] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ },
},
- [0x12] = {
- .num_ranges = 0,
- .range = NULL,
+ [AB8500_DEBUG] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x05,
+ .last = 0x07,
+ },
+ },
},
- [0x13] = {
+ [AB8500_PROD_TEST] = {
.num_ranges = 0,
.range = NULL,
},
- [0x14] = {
+ [AB8500_STE_TEST] = {
.num_ranges = 0,
.range = NULL,
},
@@ -1382,60 +1374,6 @@ void ab8500_dump_all_banks(struct device *dev)
}
}
-/* Space for 500 registers. */
-#define DUMP_MAX_REGS 700
-static struct ab8500_register_dump
-{
- u8 bank;
- u8 reg;
- u8 value;
-} ab8500_complete_register_dump[DUMP_MAX_REGS];
-
-/* This shall only be called upon kernel panic! */
-void ab8500_dump_all_banks_to_mem(void)
-{
- int i, r = 0;
- u8 bank;
- int err = 0;
-
- pr_info("Saving all ABB registers for crash analysis.\n");
-
- for (bank = 0; bank < AB8500_NUM_BANKS; bank++) {
- for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
- u8 reg;
-
- for (reg = debug_ranges[bank].range[i].first;
- reg <= debug_ranges[bank].range[i].last;
- reg++) {
- u8 value;
-
- err = prcmu_abb_read(bank, reg, &value, 1);
-
- if (err < 0)
- goto out;
-
- ab8500_complete_register_dump[r].bank = bank;
- ab8500_complete_register_dump[r].reg = reg;
- ab8500_complete_register_dump[r].value = value;
-
- r++;
-
- if (r >= DUMP_MAX_REGS) {
- pr_err("%s: too many register to dump!\n",
- __func__);
- err = -EINVAL;
- goto out;
- }
- }
- }
- }
-out:
- if (err >= 0)
- pr_info("Saved all ABB registers.\n");
- else
- pr_info("Failed to save all ABB registers.\n");
-}
-
static int ab8500_all_banks_open(struct inode *inode, struct file *file)
{
struct seq_file *s;
@@ -1584,18 +1522,10 @@ static u32 num_interrupts[AB8500_MAX_NR_IRQS];
static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS];
static int num_interrupt_lines;
-bool __attribute__((weak)) suspend_test_wake_cause_interrupt_is_mine(u32 my_int)
-{
- return false;
-}
-
void ab8500_debug_register_interrupt(int line)
{
- if (line < num_interrupt_lines) {
+ if (line < num_interrupt_lines)
num_interrupts[line]++;
- if (suspend_test_wake_cause_interrupt_is_mine(irq_ab8500))
- num_wake_interrupts[line]++;
- }
}
static int ab8500_interrupts_print(struct seq_file *s, void *p)
diff --git a/drivers/mfd/ac100.c b/drivers/mfd/ac100.c
new file mode 100644
index 000000000000..9bc69cd7807d
--- /dev/null
+++ b/drivers/mfd/ac100.c
@@ -0,0 +1,137 @@
+/*
+ * MFD core driver for X-Powers' AC100 Audio Codec IC
+ *
+ * The AC100 is a highly integrated audio codec and RTC subsystem designed
+ * for mobile applications. It has 3 I2S/PCM interfaces, a 2 channel DAC,
+ * a 2 channel ADC with 5 inputs and a builtin mixer. The RTC subsystem has
+ * 3 clock outputs.
+ *
+ * The audio codec and RTC parts are completely separate, sharing only the
+ * host interface for access to its registers.
+ *
+ * Copyright (2016) Chen-Yu Tsai
+ *
+ * Author: Chen-Yu Tsai <wens@csie.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/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ac100.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/sunxi-rsb.h>
+
+static const struct regmap_range ac100_writeable_ranges[] = {
+ regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_I2S_SR_CTRL),
+ regmap_reg_range(AC100_I2S1_CLK_CTRL, AC100_I2S1_MXR_GAIN),
+ regmap_reg_range(AC100_I2S2_CLK_CTRL, AC100_I2S2_MXR_GAIN),
+ regmap_reg_range(AC100_I2S3_CLK_CTRL, AC100_I2S3_SIG_PATH_CTRL),
+ regmap_reg_range(AC100_ADC_DIG_CTRL, AC100_ADC_VOL_CTRL),
+ regmap_reg_range(AC100_HMIC_CTRL1, AC100_HMIC_STATUS),
+ regmap_reg_range(AC100_DAC_DIG_CTRL, AC100_DAC_MXR_GAIN),
+ regmap_reg_range(AC100_ADC_APC_CTRL, AC100_LINEOUT_CTRL),
+ regmap_reg_range(AC100_ADC_DAP_L_CTRL, AC100_ADC_DAP_OPT),
+ regmap_reg_range(AC100_DAC_DAP_CTRL, AC100_DAC_DAP_OPT),
+ regmap_reg_range(AC100_ADC_DAP_ENA, AC100_DAC_DAP_ENA),
+ regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL2),
+ regmap_reg_range(AC100_SRC2_CTRL1, AC100_SRC2_CTRL2),
+ regmap_reg_range(AC100_CLK32K_ANALOG_CTRL, AC100_CLKOUT_CTRL3),
+ regmap_reg_range(AC100_RTC_RST, AC100_RTC_UPD),
+ regmap_reg_range(AC100_ALM_INT_ENA, AC100_ALM_INT_STA),
+ regmap_reg_range(AC100_ALM_SEC, AC100_RTC_GP(15)),
+};
+
+static const struct regmap_range ac100_volatile_ranges[] = {
+ regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_PLL_CTRL2),
+ regmap_reg_range(AC100_HMIC_STATUS, AC100_HMIC_STATUS),
+ regmap_reg_range(AC100_ADC_DAP_L_STA, AC100_ADC_DAP_L_STA),
+ regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL1),
+ regmap_reg_range(AC100_SRC1_CTRL3, AC100_SRC2_CTRL1),
+ regmap_reg_range(AC100_SRC2_CTRL3, AC100_SRC2_CTRL4),
+ regmap_reg_range(AC100_RTC_RST, AC100_RTC_RST),
+ regmap_reg_range(AC100_RTC_SEC, AC100_ALM_INT_STA),
+ regmap_reg_range(AC100_ALM_SEC, AC100_ALM_UPD),
+};
+
+static const struct regmap_access_table ac100_writeable_table = {
+ .yes_ranges = ac100_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ac100_writeable_ranges),
+};
+
+static const struct regmap_access_table ac100_volatile_table = {
+ .yes_ranges = ac100_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ac100_volatile_ranges),
+};
+
+static const struct regmap_config ac100_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .wr_table = &ac100_writeable_table,
+ .volatile_table = &ac100_volatile_table,
+ .max_register = AC100_RTC_GP(15),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static struct mfd_cell ac100_cells[] = {
+ {
+ .name = "ac100-codec",
+ .of_compatible = "x-powers,ac100-codec",
+ }, {
+ .name = "ac100-rtc",
+ .of_compatible = "x-powers,ac100-rtc",
+ },
+};
+
+static int ac100_rsb_probe(struct sunxi_rsb_device *rdev)
+{
+ struct ac100_dev *ac100;
+ int ret;
+
+ ac100 = devm_kzalloc(&rdev->dev, sizeof(*ac100), GFP_KERNEL);
+ if (!ac100)
+ return -ENOMEM;
+
+ ac100->dev = &rdev->dev;
+ sunxi_rsb_device_set_drvdata(rdev, ac100);
+
+ ac100->regmap = devm_regmap_init_sunxi_rsb(rdev, &ac100_regmap_config);
+ if (IS_ERR(ac100->regmap)) {
+ ret = PTR_ERR(ac100->regmap);
+ dev_err(ac100->dev, "regmap init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_mfd_add_devices(ac100->dev, PLATFORM_DEVID_NONE, ac100_cells,
+ ARRAY_SIZE(ac100_cells), NULL, 0, NULL);
+ if (ret) {
+ dev_err(ac100->dev, "failed to add MFD devices: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id ac100_of_match[] = {
+ { .compatible = "x-powers,ac100" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ac100_of_match);
+
+static struct sunxi_rsb_driver ac100_rsb_driver = {
+ .driver = {
+ .name = "ac100",
+ .of_match_table = of_match_ptr(ac100_of_match),
+ },
+ .probe = ac100_rsb_probe,
+};
+module_sunxi_rsb_driver(ac100_rsb_driver);
+
+MODULE_DESCRIPTION("Audio codec MFD core driver for AC100");
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/act8945a.c b/drivers/mfd/act8945a.c
index 10c6d2da8822..a4024d91da01 100644
--- a/drivers/mfd/act8945a.c
+++ b/drivers/mfd/act8945a.c
@@ -23,6 +23,7 @@ static const struct mfd_cell act8945a_devs[] = {
},
{
.name = "act8945a-charger",
+ .of_compatible = "active-semi,act8945a-charger",
},
};
diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c
index c05aa4ff57fd..06e1f7fc5605 100644
--- a/drivers/mfd/altera-a10sr.c
+++ b/drivers/mfd/altera-a10sr.c
@@ -1,4 +1,8 @@
/*
+ * Altera Arria10 DevKit System Resource MFD Driver
+ *
+ * Author: Thor Thayer <tthayer@opensource.altera.com>
+ *
* Copyright Intel Corporation (C) 2014-2016. All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +24,7 @@
#include <linux/mfd/altera-a10sr.h>
#include <linux/mfd/core.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
@@ -94,7 +98,7 @@ static bool altr_a10sr_reg_volatile(struct device *dev, unsigned int reg)
}
}
-const struct regmap_config altr_a10sr_regmap_config = {
+static const struct regmap_config altr_a10sr_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -152,7 +156,6 @@ static const struct of_device_id altr_a10sr_spi_of_match[] = {
{ .compatible = "altr,a10sr" },
{ },
};
-MODULE_DEVICE_TABLE(of, altr_a10sr_spi_of_match);
static struct spi_driver altr_a10sr_spi_driver = {
.probe = altr_a10sr_spi_probe,
@@ -161,9 +164,4 @@ static struct spi_driver altr_a10sr_spi_driver = {
.of_match_table = of_match_ptr(altr_a10sr_spi_of_match),
},
};
-
-module_spi_driver(altr_a10sr_spi_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Thor Thayer <tthayer@opensource.altera.com>");
-MODULE_DESCRIPTION("Altera Arria10 DevKit System Resource MFD Driver");
+builtin_driver(altr_a10sr_spi_driver, spi_register_driver)
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index e4f97b3c824b..41767f7239bb 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
@@ -49,7 +50,15 @@ int arizona_clk32k_enable(struct arizona *arizona)
case ARIZONA_32KZ_MCLK1:
ret = pm_runtime_get_sync(arizona->dev);
if (ret != 0)
- goto out;
+ goto err_ref;
+ ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
+ if (ret != 0)
+ goto err_pm;
+ break;
+ case ARIZONA_32KZ_MCLK2:
+ ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
+ if (ret != 0)
+ goto err_ref;
break;
}
@@ -58,7 +67,9 @@ int arizona_clk32k_enable(struct arizona *arizona)
ARIZONA_CLK_32K_ENA);
}
-out:
+err_pm:
+ pm_runtime_put_sync(arizona->dev);
+err_ref:
if (ret != 0)
arizona->clk32k_ref--;
@@ -83,6 +94,10 @@ int arizona_clk32k_disable(struct arizona *arizona)
switch (arizona->pdata.clk32k_src) {
case ARIZONA_32KZ_MCLK1:
pm_runtime_put_sync(arizona->dev);
+ clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
+ break;
+ case ARIZONA_32KZ_MCLK2:
+ clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]);
break;
}
}
@@ -735,7 +750,7 @@ static int arizona_suspend(struct device *dev)
return 0;
}
-static int arizona_suspend_late(struct device *dev)
+static int arizona_suspend_noirq(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
@@ -759,7 +774,7 @@ static int arizona_resume(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
- dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
+ dev_dbg(arizona->dev, "Resume, reenabling IRQ\n");
enable_irq(arizona->irq);
return 0;
@@ -771,10 +786,8 @@ const struct dev_pm_ops arizona_pm_ops = {
arizona_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
-#ifdef CONFIG_PM_SLEEP
- .suspend_late = arizona_suspend_late,
- .resume_noirq = arizona_resume_noirq,
-#endif
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq,
+ arizona_resume_noirq)
};
EXPORT_SYMBOL_GPL(arizona_pm_ops);
@@ -790,35 +803,25 @@ unsigned long 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;
struct property *prop;
const __be32 *cur;
u32 val;
+ u32 pdm_val[ARIZONA_MAX_PDM_SPK];
int ret, i;
int count = 0;
- pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
+ pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0);
+ if (pdata->reset == -EPROBE_DEFER) {
+ return pdata->reset;
+ } else if (pdata->reset < 0) {
+ dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n",
+ pdata->reset);
+
+ pdata->reset = 0;
+ }
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,gpio-defaults",
@@ -871,6 +874,35 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
count++;
}
+ count = 0;
+ of_property_for_each_u32(arizona->dev->of_node,
+ "wlf,max-channels-clocked",
+ prop, cur, val) {
+ if (count == ARRAY_SIZE(pdata->max_channels_clocked))
+ break;
+
+ pdata->max_channels_clocked[count] = val;
+ count++;
+ }
+
+ ret = of_property_read_u32_array(arizona->dev->of_node,
+ "wlf,spk-fmt",
+ pdm_val,
+ ARRAY_SIZE(pdm_val));
+
+ if (ret >= 0)
+ for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
+ pdata->spk_fmt[count] = pdm_val[count];
+
+ ret = of_property_read_u32_array(arizona->dev->of_node,
+ "wlf,spk-mute",
+ pdm_val,
+ ARRAY_SIZE(pdm_val));
+
+ if (ret >= 0)
+ for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
+ pdata->spk_mute[count] = pdm_val[count];
+
return 0;
}
@@ -1000,6 +1032,7 @@ static const struct mfd_cell wm8998_devs[] = {
int arizona_dev_init(struct arizona *arizona)
{
+ const char * const mclk_name[] = { "mclk1", "mclk2" };
struct device *dev = arizona->dev;
const char *type_name = NULL;
unsigned int reg, val, mask;
@@ -1010,11 +1043,24 @@ int arizona_dev_init(struct arizona *arizona)
dev_set_drvdata(arizona->dev, arizona);
mutex_init(&arizona->clk_lock);
- if (dev_get_platdata(arizona->dev))
+ if (dev_get_platdata(arizona->dev)) {
memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
sizeof(arizona->pdata));
- else
- arizona_of_get_core_pdata(arizona);
+ } else {
+ ret = arizona_of_get_core_pdata(arizona);
+ if (ret < 0)
+ return ret;
+ }
+
+ BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
+ for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
+ arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
+ if (IS_ERR(arizona->mclk[i])) {
+ dev_info(arizona->dev, "Failed to get %s: %ld\n",
+ mclk_name[i], PTR_ERR(arizona->mclk[i]));
+ arizona->mclk[i] = NULL;
+ }
+ }
regcache_cache_only(arizona->regmap, true);
@@ -1035,7 +1081,7 @@ int arizona_dev_init(struct arizona *arizona)
default:
dev_err(arizona->dev, "Unknown device type %d\n",
arizona->type);
- return -EINVAL;
+ return -ENODEV;
}
/* Mark DCVDD as external, LDO1 driver will clear if internal */
@@ -1121,6 +1167,7 @@ int arizona_dev_init(struct arizona *arizona)
break;
default:
dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
+ ret = -ENODEV;
goto err_reset;
}
@@ -1280,12 +1327,14 @@ int arizona_dev_init(struct arizona *arizona)
break;
default:
dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+ ret = -ENODEV;
goto err_reset;
}
if (!subdevs) {
dev_err(arizona->dev,
"No kernel support for device ID %x\n", reg);
+ ret = -ENODEV;
goto err_reset;
}
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
index eca7ea69b81c..4b15b0840f16 100644
--- a/drivers/mfd/atmel-hlcdc.c
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -50,8 +50,9 @@ static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
if (reg <= ATMEL_HLCDC_DIS) {
u32 status;
- readl_poll_timeout(hregmap->regs + ATMEL_HLCDC_SR, status,
- !(status & ATMEL_HLCDC_SIP), 1, 100);
+ readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
+ status, !(status & ATMEL_HLCDC_SIP),
+ 1, 100);
}
writel(val, hregmap->regs + reg);
diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
index a407527bcd09..a732cb50bcff 100644
--- a/drivers/mfd/axp20x-rsb.c
+++ b/drivers/mfd/axp20x-rsb.c
@@ -61,6 +61,7 @@ static int axp20x_rsb_remove(struct sunxi_rsb_device *rdev)
static const struct of_device_id axp20x_rsb_of_match[] = {
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
+ { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
{ .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
{ },
};
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index fd80b0981f0f..ba130be32e61 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -38,6 +38,7 @@ static const char * const axp20x_model_names[] = {
"AXP221",
"AXP223",
"AXP288",
+ "AXP806",
"AXP809",
};
@@ -129,6 +130,27 @@ static const struct regmap_access_table axp288_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
};
+static const struct regmap_range axp806_writeable_ranges[] = {
+ regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_DATACACHE(3)),
+ regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL),
+ regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN),
+ regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
+};
+
+static const struct regmap_range axp806_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
+};
+
+static const struct regmap_access_table axp806_writeable_table = {
+ .yes_ranges = axp806_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp806_writeable_ranges),
+};
+
+static const struct regmap_access_table axp806_volatile_table = {
+ .yes_ranges = axp806_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges),
+};
+
static struct resource axp152_pek_resources[] = {
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
@@ -278,6 +300,15 @@ static const struct regmap_config axp288_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+static const struct regmap_config axp806_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp806_writeable_table,
+ .volatile_table = &axp806_volatile_table,
+ .max_register = AXP806_VREF_TEMP_WARN_L,
+ .cache_type = REGCACHE_RBTREE,
+};
+
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
@@ -409,6 +440,21 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
};
+static const struct regmap_irq axp806_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV1, 0, 0),
+ INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV2, 0, 1),
+ INIT_REGMAP_IRQ(AXP806, DCDCA_V_LOW, 0, 3),
+ INIT_REGMAP_IRQ(AXP806, DCDCB_V_LOW, 0, 4),
+ INIT_REGMAP_IRQ(AXP806, DCDCC_V_LOW, 0, 5),
+ INIT_REGMAP_IRQ(AXP806, DCDCD_V_LOW, 0, 6),
+ INIT_REGMAP_IRQ(AXP806, DCDCE_V_LOW, 0, 7),
+ INIT_REGMAP_IRQ(AXP806, PWROK_LONG, 1, 0),
+ INIT_REGMAP_IRQ(AXP806, PWROK_SHORT, 1, 1),
+ INIT_REGMAP_IRQ(AXP806, WAKEUP, 1, 4),
+ INIT_REGMAP_IRQ(AXP806, PWROK_FALL, 1, 5),
+ INIT_REGMAP_IRQ(AXP806, PWROK_RISE, 1, 6),
+};
+
static const struct regmap_irq axp809_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP809, ACIN_OVER_V, 0, 7),
INIT_REGMAP_IRQ(AXP809, ACIN_PLUGIN, 0, 6),
@@ -494,6 +540,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = {
};
+static const struct regmap_irq_chip axp806_regmap_irq_chip = {
+ .name = "axp806",
+ .status_base = AXP20X_IRQ1_STATE,
+ .ack_base = AXP20X_IRQ1_STATE,
+ .mask_base = AXP20X_IRQ1_EN,
+ .mask_invert = true,
+ .init_ack_masked = true,
+ .irqs = axp806_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp806_regmap_irqs),
+ .num_regs = 2,
+};
+
static const struct regmap_irq_chip axp809_regmap_irq_chip = {
.name = "axp809",
.status_base = AXP20X_IRQ1_STATE,
@@ -508,6 +566,9 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = {
static struct mfd_cell axp20x_cells[] = {
{
+ .name = "axp20x-gpio",
+ .of_compatible = "x-powers,axp209-gpio",
+ }, {
.name = "axp20x-pek",
.num_resources = ARRAY_SIZE(axp20x_pek_resources),
.resources = axp20x_pek_resources,
@@ -660,12 +721,20 @@ static struct mfd_cell axp288_cells[] = {
},
};
+static struct mfd_cell axp806_cells[] = {
+ {
+ .id = 2,
+ .name = "axp20x-regulator",
+ },
+};
+
static struct mfd_cell axp809_cells[] = {
{
.name = "axp20x-pek",
.num_resources = ARRAY_SIZE(axp809_pek_resources),
.resources = axp809_pek_resources,
}, {
+ .id = 1,
.name = "axp20x-regulator",
},
};
@@ -732,6 +801,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_cfg = &axp288_regmap_config;
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
break;
+ case AXP806_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
+ axp20x->cells = axp806_cells;
+ axp20x->regmap_cfg = &axp806_regmap_config;
+ axp20x->regmap_irq_chip = &axp806_regmap_irq_chip;
+ break;
case AXP809_ID:
axp20x->nr_cells = ARRAY_SIZE(axp809_cells);
axp20x->cells = axp809_cells;
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 0eee63542038..abd83424b498 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/mfd/cros_ec.h>
+#include <asm/unaligned.h>
#define CROS_EC_DEV_EC_INDEX 0
#define CROS_EC_DEV_PD_INDEX 1
@@ -49,11 +50,28 @@ static const struct mfd_cell ec_pd_cell = {
.pdata_size = sizeof(pd_p),
};
+static irqreturn_t ec_irq_thread(int irq, void *data)
+{
+ struct cros_ec_device *ec_dev = data;
+ int ret;
+
+ if (device_may_wakeup(ec_dev->dev))
+ pm_wakeup_event(ec_dev->dev, 0);
+
+ ret = cros_ec_get_next_event(ec_dev);
+ if (ret > 0)
+ blocking_notifier_call_chain(&ec_dev->event_notifier,
+ 0, ec_dev);
+ return IRQ_HANDLED;
+}
+
int cros_ec_register(struct cros_ec_device *ec_dev)
{
struct device *dev = ec_dev->dev;
int err = 0;
+ BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
+
ec_dev->max_request = sizeof(struct ec_params_hello);
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
ec_dev->max_passthru = 0;
@@ -70,13 +88,24 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
cros_ec_query_all(ec_dev);
+ if (ec_dev->irq) {
+ err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "chromeos-ec", ec_dev);
+ if (err) {
+ dev_err(dev, "Failed to request IRQ %d: %d",
+ ec_dev->irq, err);
+ return err;
+ }
+ }
+
err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1,
NULL, ec_dev->irq, NULL);
if (err) {
dev_err(dev,
"Failed to register Embedded Controller subdevice %d\n",
err);
- return err;
+ goto fail_mfd;
}
if (ec_dev->max_passthru) {
@@ -94,7 +123,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
dev_err(dev,
"Failed to register Power Delivery subdevice %d\n",
err);
- return err;
+ goto fail_mfd;
}
}
@@ -103,13 +132,18 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (err) {
mfd_remove_devices(dev);
dev_err(dev, "Failed to register sub-devices\n");
- return err;
+ goto fail_mfd;
}
}
dev_info(dev, "Chrome EC device registered\n");
return 0;
+
+fail_mfd:
+ if (ec_dev->irq)
+ free_irq(ec_dev->irq, ec_dev);
+ return err;
}
EXPORT_SYMBOL(cros_ec_register);
@@ -136,13 +170,31 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
}
EXPORT_SYMBOL(cros_ec_suspend);
+static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
+{
+ while (cros_ec_get_next_event(ec_dev) > 0)
+ blocking_notifier_call_chain(&ec_dev->event_notifier,
+ 1, ec_dev);
+}
+
int cros_ec_resume(struct cros_ec_device *ec_dev)
{
enable_irq(ec_dev->irq);
+ /*
+ * In some cases, we need to distinguish between events that occur
+ * during suspend if the EC is not a wake source. For example,
+ * keypresses during suspend should be discarded if it does not wake
+ * the system.
+ *
+ * If the EC is not a wake source, drain the event queue and mark them
+ * as "queued during suspend".
+ */
if (ec_dev->wake_enabled) {
disable_irq_wake(ec_dev->irq);
ec_dev->wake_enabled = 0;
+ } else {
+ cros_ec_drain_events(ec_dev);
}
return 0;
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index ebe9b9477cb2..a518832ed5f5 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -366,7 +366,6 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
struct cros_ec_command *ec_msg)
{
- struct ec_host_request *request;
struct ec_host_response *response;
struct cros_ec_spi *ec_spi = ec_dev->priv;
struct spi_transfer trans, trans_delay;
@@ -378,7 +377,6 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
int ret = 0, final_ret;
len = cros_ec_prepare_tx(ec_dev, ec_msg);
- request = (struct ec_host_request *)ec_dev->dout;
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
/* If it's too soon to do another transaction, wait */
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
index c0bf68a3e614..a88c2065d8ab 100644
--- a/drivers/mfd/da9052-core.c
+++ b/drivers/mfd/da9052-core.c
@@ -167,6 +167,7 @@ static bool da9052_reg_writeable(struct device *dev, unsigned int reg)
case DA9052_EVENT_B_REG:
case DA9052_EVENT_C_REG:
case DA9052_EVENT_D_REG:
+ case DA9052_FAULTLOG_REG:
case DA9052_IRQ_MASK_A_REG:
case DA9052_IRQ_MASK_B_REG:
case DA9052_IRQ_MASK_C_REG:
@@ -541,6 +542,52 @@ const struct regmap_config da9052_regmap_config = {
};
EXPORT_SYMBOL_GPL(da9052_regmap_config);
+static int da9052_clear_fault_log(struct da9052 *da9052)
+{
+ int ret = 0;
+ int fault_log = 0;
+
+ fault_log = da9052_reg_read(da9052, DA9052_FAULTLOG_REG);
+ if (fault_log < 0) {
+ dev_err(da9052->dev,
+ "Cannot read FAULT_LOG %d\n", fault_log);
+ return fault_log;
+ }
+
+ if (fault_log) {
+ if (fault_log & DA9052_FAULTLOG_TWDERROR)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: TWD_ERROR\n");
+ if (fault_log & DA9052_FAULTLOG_VDDFAULT)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: VDD_FAULT\n");
+ if (fault_log & DA9052_FAULTLOG_VDDSTART)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: VDD_START\n");
+ if (fault_log & DA9052_FAULTLOG_TEMPOVER)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: TEMP_OVER\n");
+ if (fault_log & DA9052_FAULTLOG_KEYSHUT)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: KEY_SHUT\n");
+ if (fault_log & DA9052_FAULTLOG_NSDSET)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: nSD_SHUT\n");
+ if (fault_log & DA9052_FAULTLOG_WAITSET)
+ dev_dbg(da9052->dev,
+ "Fault log entry detected: WAIT_SHUT\n");
+
+ ret = da9052_reg_write(da9052,
+ DA9052_FAULTLOG_REG,
+ 0xFF);
+ if (ret < 0)
+ dev_err(da9052->dev,
+ "Cannot reset FAULT_LOG values %d\n", ret);
+ }
+
+ return ret;
+}
+
int da9052_device_init(struct da9052 *da9052, u8 chip_id)
{
struct da9052_pdata *pdata = dev_get_platdata(da9052->dev);
@@ -549,6 +596,10 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id)
mutex_init(&da9052->auxadc_lock);
init_completion(&da9052->done);
+ ret = da9052_clear_fault_log(da9052);
+ if (ret < 0)
+ dev_warn(da9052->dev, "Cannot clear FAULT_LOG\n");
+
if (pdata && pdata->init != NULL)
pdata->init(da9052);
diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c
index af841c165787..6c2870d4e754 100644
--- a/drivers/mfd/da9063-core.c
+++ b/drivers/mfd/da9063-core.c
@@ -4,8 +4,8 @@
* Copyright 2012 Dialog Semiconductors Ltd.
* Copyright 2013 Philipp Zabel, Pengutronix
*
- * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>,
- * Michal Hajduk <michal.hajduk@diasemi.com>
+ * Author: Krystian Garbaciak, Dialog Semiconductor
+ * Author: Michal Hajduk, Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -242,5 +242,6 @@ void da9063_device_exit(struct da9063 *da9063)
}
MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
-MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>, Michal Hajduk <michal.hajduk@diasemi.com>");
+MODULE_AUTHOR("Krystian Garbaciak");
+MODULE_AUTHOR("Michal Hajduk");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c
index 73901084945f..981805a2c521 100644
--- a/drivers/mfd/da9063-i2c.c
+++ b/drivers/mfd/da9063-i2c.c
@@ -3,7 +3,7 @@
* Copyright 2012 Dialog Semiconductor Ltd.
* Copyright 2013 Philipp Zabel, Pengutronix
*
- * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
+ * Author: Krystian Garbaciak, Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c
index 7e903fcb8813..207bbfe55449 100644
--- a/drivers/mfd/da9063-irq.c
+++ b/drivers/mfd/da9063-irq.c
@@ -3,7 +3,7 @@
* Copyright 2012 Dialog Semiconductor Ltd.
* Copyright 2013 Philipp Zabel, Pengutronix
*
- * Author: Michal Hajduk <michal.hajduk@diasemi.com>
+ * Author: Michal Hajduk, Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 388e268b9bcf..ca38a6a14110 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -938,25 +938,6 @@ int db8500_prcmu_get_ddr_opp(void)
return readb(PRCM_DDR_SUBSYS_APE_MINBW);
}
-/**
- * db8500_set_ddr_opp - set the appropriate DDR OPP
- * @opp: The new DDR operating point to which transition is to be made
- * Returns: 0 on success, non-zero on failure
- *
- * This function sets the operating point of the DDR.
- */
-static bool enable_set_ddr_opp;
-int db8500_prcmu_set_ddr_opp(u8 opp)
-{
- if (opp < DDR_100_OPP || opp > DDR_25_OPP)
- return -EINVAL;
- /* Changing the DDR OPP can hang the hardware pre-v21 */
- if (enable_set_ddr_opp)
- writeb(opp, PRCM_DDR_SUBSYS_APE_MINBW);
-
- return 0;
-}
-
/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
static void request_even_slower_clocks(bool enable)
{
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
index 270e19c0bba1..86eca614507b 100644
--- a/drivers/mfd/dm355evm_msp.c
+++ b/drivers/mfd/dm355evm_msp.c
@@ -209,7 +209,7 @@ static struct device *add_child(struct i2c_client *client, const char *name,
status = platform_device_add_data(pdev, pdata, pdata_len);
if (status < 0) {
dev_dbg(&pdev->dev, "can't add platform_data\n");
- goto err;
+ goto put_device;
}
}
@@ -222,19 +222,20 @@ static struct device *add_child(struct i2c_client *client, const char *name,
status = platform_device_add_resources(pdev, &r, 1);
if (status < 0) {
dev_dbg(&pdev->dev, "can't add irq\n");
- goto err;
+ goto put_device;
}
}
status = platform_device_add(pdev);
+ if (status)
+ goto put_device;
-err:
- if (status < 0) {
- platform_device_put(pdev);
- dev_err(&client->dev, "can't add %s dev\n", name);
- return ERR_PTR(status);
- }
return &pdev->dev;
+
+put_device:
+ platform_device_put(pdev);
+ dev_err(&client->dev, "failed to add device %s\n", name);
+ return ERR_PTR(status);
}
static int add_children(struct i2c_client *client)
diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c
new file mode 100644
index 000000000000..2e064fb8826f
--- /dev/null
+++ b/drivers/mfd/exynos-lpass.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Inha Song <ideal.song@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Samsung Exynos SoC series Low Power Audio Subsystem driver.
+ *
+ * This module provides regmap for the Top SFR region and instantiates
+ * devices for IP blocks like DMAC, I2S, UART.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/exynos5-pmu.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+/* LPASS Top register definitions */
+#define SFR_LPASS_CORE_SW_RESET 0x08
+#define LPASS_SB_SW_RESET BIT(11)
+#define LPASS_UART_SW_RESET BIT(10)
+#define LPASS_PCM_SW_RESET BIT(9)
+#define LPASS_I2S_SW_RESET BIT(8)
+#define LPASS_WDT1_SW_RESET BIT(4)
+#define LPASS_WDT0_SW_RESET BIT(3)
+#define LPASS_TIMER_SW_RESET BIT(2)
+#define LPASS_MEM_SW_RESET BIT(1)
+#define LPASS_DMA_SW_RESET BIT(0)
+
+#define SFR_LPASS_INTR_CA5_MASK 0x48
+#define SFR_LPASS_INTR_CPU_MASK 0x58
+#define LPASS_INTR_APM BIT(9)
+#define LPASS_INTR_MIF BIT(8)
+#define LPASS_INTR_TIMER BIT(7)
+#define LPASS_INTR_DMA BIT(6)
+#define LPASS_INTR_GPIO BIT(5)
+#define LPASS_INTR_I2S BIT(4)
+#define LPASS_INTR_PCM BIT(3)
+#define LPASS_INTR_SLIMBUS BIT(2)
+#define LPASS_INTR_UART BIT(1)
+#define LPASS_INTR_SFR BIT(0)
+
+struct exynos_lpass {
+ /* pointer to the Power Management Unit regmap */
+ struct regmap *pmu;
+ /* pointer to the LPASS TOP regmap */
+ struct regmap *top;
+};
+
+static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
+{
+ unsigned int val = 0;
+
+ regmap_read(lpass->top, SFR_LPASS_CORE_SW_RESET, &val);
+
+ val &= ~mask;
+ regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
+
+ usleep_range(100, 150);
+
+ val |= mask;
+ regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
+}
+
+static void exynos_lpass_enable(struct exynos_lpass *lpass)
+{
+ /* Unmask SFR, DMA and I2S interrupt */
+ regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
+ LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
+
+ regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
+ LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
+
+ /* Activate related PADs from retention state */
+ regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION,
+ EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR);
+
+ exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
+ exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
+ exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
+}
+
+static void exynos_lpass_disable(struct exynos_lpass *lpass)
+{
+ /* Mask any unmasked IP interrupt sources */
+ regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
+ regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
+
+ /* Deactivate related PADs from retention state */
+ regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION, 0);
+}
+
+static const struct regmap_config exynos_lpass_reg_conf = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static int exynos_lpass_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct exynos_lpass *lpass;
+ void __iomem *base_top;
+ struct resource *res;
+
+ lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL);
+ if (!lpass)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base_top = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base_top))
+ return PTR_ERR(base_top);
+
+ lpass->top = regmap_init_mmio(dev, base_top,
+ &exynos_lpass_reg_conf);
+ if (IS_ERR(lpass->top)) {
+ dev_err(dev, "LPASS top regmap initialization failed\n");
+ return PTR_ERR(lpass->top);
+ }
+
+ lpass->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,pmu-syscon");
+ if (IS_ERR(lpass->pmu)) {
+ dev_err(dev, "Failed to lookup PMU regmap\n");
+ return PTR_ERR(lpass->pmu);
+ }
+
+ platform_set_drvdata(pdev, lpass);
+ exynos_lpass_enable(lpass);
+
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
+}
+
+static int __maybe_unused exynos_lpass_suspend(struct device *dev)
+{
+ struct exynos_lpass *lpass = dev_get_drvdata(dev);
+
+ exynos_lpass_disable(lpass);
+
+ return 0;
+}
+
+static int __maybe_unused exynos_lpass_resume(struct device *dev)
+{
+ struct exynos_lpass *lpass = dev_get_drvdata(dev);
+
+ exynos_lpass_enable(lpass);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(lpass_pm_ops, exynos_lpass_suspend,
+ exynos_lpass_resume);
+
+static const struct of_device_id exynos_lpass_of_match[] = {
+ { .compatible = "samsung,exynos5433-lpass" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, exynos_lpass_of_match);
+
+static struct platform_driver exynos_lpass_driver = {
+ .driver = {
+ .name = "exynos-lpass",
+ .pm = &lpass_pm_ops,
+ .of_match_table = exynos_lpass_of_match,
+ },
+ .probe = exynos_lpass_probe,
+};
+module_platform_driver(exynos_lpass_driver);
+
+MODULE_DESCRIPTION("Samsung Low Power Audio Subsystem driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index 7ddc4a9563ea..6bf8d643d942 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -52,6 +52,18 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
.properties = bxt_i2c_properties,
};
+static struct property_entry apl_i2c_properties[] = {
+ PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
+ PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+ PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
+ { },
+};
+
+static const struct intel_lpss_platform_info apl_i2c_info = {
+ .clk_rate = 133000000,
+ .properties = apl_i2c_properties,
+};
+
static const struct acpi_device_id intel_lpss_acpi_ids[] = {
/* SPT */
{ "INT3446", (kernel_ulong_t)&spt_i2c_info },
@@ -61,7 +73,7 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = {
{ "80860ABC", (kernel_ulong_t)&bxt_info },
{ "80860AC2", (kernel_ulong_t)&bxt_info },
/* APL */
- { "80865AAC", (kernel_ulong_t)&bxt_i2c_info },
+ { "80865AAC", (kernel_ulong_t)&apl_i2c_info },
{ "80865ABC", (kernel_ulong_t)&bxt_info },
{ "80865AC2", (kernel_ulong_t)&bxt_info },
{ }
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 1d79a3c9370f..3228fd182a99 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -111,6 +111,31 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
.properties = bxt_i2c_properties,
};
+static struct property_entry apl_i2c_properties[] = {
+ PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
+ PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
+ PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
+ { },
+};
+
+static const struct intel_lpss_platform_info apl_i2c_info = {
+ .clk_rate = 133000000,
+ .properties = apl_i2c_properties,
+};
+
+static const struct intel_lpss_platform_info kbl_info = {
+ .clk_rate = 120000000,
+};
+
+static const struct intel_lpss_platform_info kbl_uart_info = {
+ .clk_rate = 120000000,
+ .clk_con_id = "baudclk",
+};
+
+static const struct intel_lpss_platform_info kbl_i2c_info = {
+ .clk_rate = 133000000,
+};
+
static const struct pci_device_id intel_lpss_pci_ids[] = {
/* BXT A-Step */
{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
@@ -146,14 +171,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info },
/* APL */
- { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&bxt_i2c_info },
- { PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&apl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&apl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x5abc), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x5abe), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x5ac0), (kernel_ulong_t)&bxt_uart_info },
@@ -181,6 +206,16 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info },
+ /* KBL-H */
+ { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&kbl_uart_info },
+ { PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&kbl_uart_info },
+ { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&kbl_info },
+ { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&kbl_info },
+ { PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&kbl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&kbl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&kbl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&kbl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&kbl_uart_info },
{ }
};
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index 25d486c543cb..2017446c5b4b 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -12,7 +12,7 @@
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel_msic.h>
#include <linux/platform_device.h>
@@ -449,9 +449,4 @@ static struct platform_driver intel_msic_driver = {
.name = "intel_msic",
},
};
-
-module_platform_driver(intel_msic_driver);
-
-MODULE_DESCRIPTION("Driver for Intel MSIC");
-MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(intel_msic_driver);
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index b9428767e615..43e54b7e908f 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -47,6 +47,8 @@
#define BXTWC_MIRQLVL1 0x4E0E
#define BXTWC_MPWRTNIRQ 0x4E0F
+#define BXTWC_MIRQLVL1_MCHGR BIT(5)
+
#define BXTWC_MTHRM0IRQ 0x4E12
#define BXTWC_MTHRM1IRQ 0x4E13
#define BXTWC_MTHRM2IRQ 0x4E14
@@ -109,7 +111,7 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
REGMAP_IRQ_REG(BXTWC_THRM2_IRQ, 2, 0xff),
REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 3, 0x1f),
REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 4, 0xff),
- REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x1f),
+ REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x3f),
REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 6, 0x1f),
REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 7, 0xff),
REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 8, 0x3f),
@@ -143,6 +145,10 @@ static struct resource adc_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"),
};
+static struct resource usbc_resources[] = {
+ DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "USBC"),
+};
+
static struct resource charger_resources[] = {
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"),
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"),
@@ -170,6 +176,11 @@ static struct mfd_cell bxt_wc_dev[] = {
.resources = thermal_resources,
},
{
+ .name = "bxt_wcove_usbc",
+ .num_resources = ARRAY_SIZE(usbc_resources),
+ .resources = usbc_resources,
+ },
+ {
.name = "bxt_wcove_ext_charger",
.num_resources = ARRAY_SIZE(charger_resources),
.resources = charger_resources,
@@ -403,6 +414,16 @@ static int bxtwc_probe(struct platform_device *pdev)
goto err_sysfs;
}
+ /*
+ * There is known hw bug. Upon reset BIT 5 of register
+ * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However,
+ * later it's set to 1(masked) automatically by hardware. So we
+ * have the software workaround here to unmaksed it in order to let
+ * charger interrutp work.
+ */
+ regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1,
+ BXTWC_MIRQLVL1_MCHGR, 0);
+
return 0;
err_sysfs:
diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c
index 9af064c940ee..873c608e6a5d 100644
--- a/drivers/mfd/lp873x.c
+++ b/drivers/mfd/lp873x.c
@@ -53,8 +53,6 @@ static int lp873x_probe(struct i2c_client *client,
return ret;
}
- mutex_init(&lp873->lock);
-
ret = regmap_read(lp873->regmap, LP873X_REG_OTP_REV, &otpid);
if (ret) {
dev_err(lp873->dev, "Failed to read OTP ID\n");
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 6c245128ab2e..6cbe96b28f42 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014 Samsung Electronics
* Chanwoo Choi <cw00.choi@samsung.com>
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.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
@@ -569,6 +569,6 @@ 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_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c
index b95a46d79b9d..326f17b632a7 100644
--- a/drivers/mfd/max8997-irq.c
+++ b/drivers/mfd/max8997-irq.c
@@ -139,7 +139,7 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
mutex_unlock(&max8997->irqlock);
}
-static const inline struct max8997_irq_data *
+inline static const struct max8997_irq_data *
irq_to_max8997_irq(struct max8997_dev *max8997, struct irq_data *data)
{
return &max8997_irqs[data->hwirq];
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 1d924d1533c0..7aab376ecb84 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -162,7 +162,7 @@ static const char * const port_modes[] = {
* provided port mode string as per the port_modes table.
* If no match is found it returns -ENODEV
*/
-static const int omap_usbhs_get_dt_port_mode(const char *mode)
+static int omap_usbhs_get_dt_port_mode(const char *mode)
{
int i;
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 1b7ec0870c2a..0e3a2ea25942 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -309,6 +309,7 @@ static const struct regmap_config ssbi_regmap_config = {
};
static const struct of_device_id pm8921_id_table[] = {
+ { .compatible = "qcom,pm8018", },
{ .compatible = "qcom,pm8058", },
{ .compatible = "qcom,pm8921", },
{ }
diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c
index 2e44323455dd..52fafea06067 100644
--- a/drivers/mfd/qcom_rpm.c
+++ b/drivers/mfd/qcom_rpm.c
@@ -21,6 +21,7 @@
#include <linux/mfd/qcom_rpm.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <linux/clk.h>
#include <dt-bindings/mfd/qcom-rpm.h>
@@ -48,6 +49,7 @@ struct qcom_rpm {
struct regmap *ipc_regmap;
unsigned ipc_offset;
unsigned ipc_bit;
+ struct clk *ramclk;
struct completion ack;
struct mutex lock;
@@ -388,11 +390,62 @@ static const struct qcom_rpm_data ipq806x_template = {
.ack_sel_size = 7,
};
+static const struct qcom_rpm_resource mdm9615_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 26, 10, 9, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 27, 11, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 28, 12, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 29, 13, 13, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 30, 14, 16, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 31, 15, 22, 2 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 33, 16, 23, 3 },
+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 36, 17, 24, 1 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 37, 18, 25, 27 },
+ [QCOM_RPM_PM8018_SMPS1] = { 64, 19, 30, 2 },
+ [QCOM_RPM_PM8018_SMPS2] = { 66, 21, 31, 2 },
+ [QCOM_RPM_PM8018_SMPS3] = { 68, 23, 32, 2 },
+ [QCOM_RPM_PM8018_SMPS4] = { 70, 25, 33, 2 },
+ [QCOM_RPM_PM8018_SMPS5] = { 72, 27, 34, 2 },
+ [QCOM_RPM_PM8018_LDO1] = { 74, 29, 35, 2 },
+ [QCOM_RPM_PM8018_LDO2] = { 76, 31, 36, 2 },
+ [QCOM_RPM_PM8018_LDO3] = { 78, 33, 37, 2 },
+ [QCOM_RPM_PM8018_LDO4] = { 80, 35, 38, 2 },
+ [QCOM_RPM_PM8018_LDO5] = { 82, 37, 39, 2 },
+ [QCOM_RPM_PM8018_LDO6] = { 84, 39, 40, 2 },
+ [QCOM_RPM_PM8018_LDO7] = { 86, 41, 41, 2 },
+ [QCOM_RPM_PM8018_LDO8] = { 88, 43, 42, 2 },
+ [QCOM_RPM_PM8018_LDO9] = { 90, 45, 43, 2 },
+ [QCOM_RPM_PM8018_LDO10] = { 92, 47, 44, 2 },
+ [QCOM_RPM_PM8018_LDO11] = { 94, 49, 45, 2 },
+ [QCOM_RPM_PM8018_LDO12] = { 96, 51, 46, 2 },
+ [QCOM_RPM_PM8018_LDO13] = { 98, 53, 47, 2 },
+ [QCOM_RPM_PM8018_LDO14] = { 100, 55, 48, 2 },
+ [QCOM_RPM_PM8018_LVS1] = { 102, 57, 49, 1 },
+ [QCOM_RPM_PM8018_NCP] = { 103, 58, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 105, 60, 81, 1 },
+ [QCOM_RPM_USB_OTG_SWITCH] = { 106, 61, 82, 1 },
+ [QCOM_RPM_HDMI_SWITCH] = { 107, 62, 83, 1 },
+ [QCOM_RPM_VOLTAGE_CORNER] = { 109, 64, 87, 1 },
+};
+
+static const struct qcom_rpm_data mdm9615_template = {
+ .version = 3,
+ .resource_table = mdm9615_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(mdm9615_rpm_resource_table),
+ .req_ctx_off = 3,
+ .req_sel_off = 11,
+ .ack_ctx_off = 15,
+ .ack_sel_off = 23,
+ .req_sel_size = 4,
+ .ack_sel_size = 7,
+};
+
static const struct of_device_id qcom_rpm_of_match[] = {
{ .compatible = "qcom,rpm-apq8064", .data = &apq8064_template },
{ .compatible = "qcom,rpm-msm8660", .data = &msm8660_template },
{ .compatible = "qcom,rpm-msm8960", .data = &msm8960_template },
{ .compatible = "qcom,rpm-ipq8064", .data = &ipq806x_template },
+ { .compatible = "qcom,rpm-mdm9615", .data = &mdm9615_template },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_rpm_of_match);
@@ -501,6 +554,20 @@ static int qcom_rpm_probe(struct platform_device *pdev)
mutex_init(&rpm->lock);
init_completion(&rpm->ack);
+ /* Enable message RAM clock */
+ rpm->ramclk = devm_clk_get(&pdev->dev, "ram");
+ if (IS_ERR(rpm->ramclk)) {
+ ret = PTR_ERR(rpm->ramclk);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ /*
+ * Fall through in all other cases, as the clock is
+ * optional. (Does not exist on all platforms.)
+ */
+ rpm->ramclk = NULL;
+ }
+ clk_prepare_enable(rpm->ramclk); /* Accepts NULL */
+
irq_ack = platform_get_irq_byname(pdev, "ack");
if (irq_ack < 0) {
dev_err(&pdev->dev, "required ack interrupt missing\n");
@@ -538,6 +605,7 @@ static int qcom_rpm_probe(struct platform_device *pdev)
}
rpm->ipc_regmap = syscon_node_to_regmap(syscon_np);
+ of_node_put(syscon_np);
if (IS_ERR(rpm->ipc_regmap))
return PTR_ERR(rpm->ipc_regmap);
@@ -620,7 +688,11 @@ static int qcom_rpm_probe(struct platform_device *pdev)
static int qcom_rpm_remove(struct platform_device *pdev)
{
+ struct qcom_rpm *rpm = dev_get_drvdata(&pdev->dev);
+
of_platform_depopulate(&pdev->dev);
+ clk_disable_unprepare(rpm->ramclk);
+
return 0;
}
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index 49d7f624fc94..0f8acc5882a4 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -1,11 +1,15 @@
/*
- * MFD core driver for Rockchip RK808
+ * MFD core driver for Rockchip RK808/RK818
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
* Author: Chris Zhong <zyw@rock-chips.com>
* Author: Zhang Qing <zhangqing@rock-chips.com>
*
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ *
* 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.
@@ -21,6 +25,7 @@
#include <linux/mfd/rk808.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/regmap.h>
struct rk808_reg_data {
@@ -57,6 +62,14 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
+static const struct regmap_config rk818_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RK818_USB_CTRL_REG,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = rk808_is_volatile_reg,
+};
+
static const struct regmap_config rk808_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -79,11 +92,21 @@ static const struct mfd_cell rk808s[] = {
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
- .resources = &rtc_resources[0],
+ .resources = rtc_resources,
},
};
-static const struct rk808_reg_data pre_init_reg[] = {
+static const struct mfd_cell rk818s[] = {
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
+ {
+ .name = "rk808-rtc",
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resources = rtc_resources,
+ },
+};
+
+static const struct rk808_reg_data rk808_pre_init_reg[] = {
{ RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA },
{ RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA },
{ RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
@@ -94,6 +117,24 @@ static const struct rk808_reg_data pre_init_reg[] = {
VB_LO_SEL_3500MV },
};
+static const struct rk808_reg_data rk818_pre_init_reg[] = {
+ /* improve efficiency */
+ { RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA },
+ { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA },
+ { RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
+ { RK818_USB_CTRL_REG, RK818_USB_ILIM_SEL_MASK,
+ RK818_USB_ILMIN_2000MA },
+ /* close charger when usb lower then 3.4V */
+ { RK818_USB_CTRL_REG, RK818_USB_CHG_SD_VSEL_MASK,
+ (0x7 << 4) },
+ /* no action when vref */
+ { RK818_H5V_EN_REG, BIT(1), RK818_REF_RDY_CTRL },
+ /* enable HDMI 5V */
+ { RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN },
+ { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
+ VB_LO_SEL_3500MV },
+};
+
static const struct regmap_irq rk808_irqs[] = {
/* INT_STS */
[RK808_IRQ_VOUT_LO] = {
@@ -136,6 +177,76 @@ static const struct regmap_irq rk808_irqs[] = {
},
};
+static const struct regmap_irq rk818_irqs[] = {
+ /* INT_STS */
+ [RK818_IRQ_VOUT_LO] = {
+ .mask = RK818_IRQ_VOUT_LO_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_VB_LO] = {
+ .mask = RK818_IRQ_VB_LO_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_PWRON] = {
+ .mask = RK818_IRQ_PWRON_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_PWRON_LP] = {
+ .mask = RK818_IRQ_PWRON_LP_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_HOTDIE] = {
+ .mask = RK818_IRQ_HOTDIE_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_RTC_ALARM] = {
+ .mask = RK818_IRQ_RTC_ALARM_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_RTC_PERIOD] = {
+ .mask = RK818_IRQ_RTC_PERIOD_MSK,
+ .reg_offset = 0,
+ },
+ [RK818_IRQ_USB_OV] = {
+ .mask = RK818_IRQ_USB_OV_MSK,
+ .reg_offset = 0,
+ },
+
+ /* INT_STS2 */
+ [RK818_IRQ_PLUG_IN] = {
+ .mask = RK818_IRQ_PLUG_IN_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_PLUG_OUT] = {
+ .mask = RK818_IRQ_PLUG_OUT_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_CHG_OK] = {
+ .mask = RK818_IRQ_CHG_OK_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_CHG_TE] = {
+ .mask = RK818_IRQ_CHG_TE_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_CHG_TS1] = {
+ .mask = RK818_IRQ_CHG_TS1_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_TS2] = {
+ .mask = RK818_IRQ_TS2_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_CHG_CVTLIM] = {
+ .mask = RK818_IRQ_CHG_CVTLIM_MSK,
+ .reg_offset = 1,
+ },
+ [RK818_IRQ_DISCHG_ILIM] = {
+ .mask = RK818_IRQ_DISCHG_ILIM_MSK,
+ .reg_offset = 1,
+ },
+};
+
static struct regmap_irq_chip rk808_irq_chip = {
.name = "rk808",
.irqs = rk808_irqs,
@@ -148,6 +259,18 @@ static struct regmap_irq_chip rk808_irq_chip = {
.init_ack_masked = true,
};
+static struct regmap_irq_chip rk818_irq_chip = {
+ .name = "rk818",
+ .irqs = rk818_irqs,
+ .num_irqs = ARRAY_SIZE(rk818_irqs),
+ .num_regs = 2,
+ .irq_reg_stride = 2,
+ .status_base = RK818_INT_STS_REG1,
+ .mask_base = RK818_INT_STS_MSK_REG1,
+ .ack_base = RK818_INT_STS_REG1,
+ .init_ack_masked = true,
+};
+
static struct i2c_client *rk808_i2c_client;
static void rk808_device_shutdown(void)
{
@@ -167,55 +290,100 @@ static void rk808_device_shutdown(void)
dev_err(&rk808_i2c_client->dev, "power off error!\n");
}
+static const struct of_device_id rk808_of_match[] = {
+ { .compatible = "rockchip,rk808" },
+ { .compatible = "rockchip,rk818" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rk808_of_match);
+
static int rk808_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device_node *np = client->dev.of_node;
struct rk808 *rk808;
+ const struct rk808_reg_data *pre_init_reg;
+ const struct mfd_cell *cells;
+ int nr_pre_init_regs;
+ int nr_cells;
int pm_off = 0;
int ret;
int i;
- if (!client->irq) {
- dev_err(&client->dev, "No interrupt support, no core IRQ\n");
- return -EINVAL;
- }
-
rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
if (!rk808)
return -ENOMEM;
- rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config);
+ rk808->variant = i2c_smbus_read_word_data(client, RK808_ID_MSB);
+ if (rk808->variant < 0) {
+ dev_err(&client->dev, "Failed to read the chip id at 0x%02x\n",
+ RK808_ID_MSB);
+ return rk808->variant;
+ }
+
+ dev_dbg(&client->dev, "Chip id: 0x%x\n", (unsigned int)rk808->variant);
+
+ switch (rk808->variant) {
+ case RK808_ID:
+ rk808->regmap_cfg = &rk808_regmap_config;
+ rk808->regmap_irq_chip = &rk808_irq_chip;
+ pre_init_reg = rk808_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
+ cells = rk808s;
+ nr_cells = ARRAY_SIZE(rk808s);
+ break;
+ case RK818_ID:
+ rk808->regmap_cfg = &rk818_regmap_config;
+ rk808->regmap_irq_chip = &rk818_irq_chip;
+ pre_init_reg = rk818_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
+ cells = rk818s;
+ nr_cells = ARRAY_SIZE(rk818s);
+ break;
+ default:
+ dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
+ rk808->variant);
+ return -EINVAL;
+ }
+
+ rk808->i2c = client;
+ i2c_set_clientdata(client, rk808);
+
+ rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg);
if (IS_ERR(rk808->regmap)) {
dev_err(&client->dev, "regmap initialization failed\n");
return PTR_ERR(rk808->regmap);
}
- for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) {
- ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr,
- pre_init_reg[i].mask,
- pre_init_reg[i].value);
- if (ret) {
- dev_err(&client->dev,
- "0x%x write err\n", pre_init_reg[i].addr);
- return ret;
- }
+ if (!client->irq) {
+ dev_err(&client->dev, "No interrupt support, no core IRQ\n");
+ return -EINVAL;
}
ret = regmap_add_irq_chip(rk808->regmap, client->irq,
IRQF_ONESHOT, -1,
- &rk808_irq_chip, &rk808->irq_data);
+ rk808->regmap_irq_chip, &rk808->irq_data);
if (ret) {
dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
return ret;
}
- rk808->i2c = client;
- i2c_set_clientdata(client, rk808);
+ for (i = 0; i < nr_pre_init_regs; i++) {
+ ret = regmap_update_bits(rk808->regmap,
+ pre_init_reg[i].addr,
+ pre_init_reg[i].mask,
+ pre_init_reg[i].value);
+ if (ret) {
+ dev_err(&client->dev,
+ "0x%x write err\n",
+ pre_init_reg[i].addr);
+ return ret;
+ }
+ }
- ret = devm_mfd_add_devices(&client->dev, -1,
- rk808s, ARRAY_SIZE(rk808s), NULL, 0,
- regmap_irq_get_domain(rk808->irq_data));
+ ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+ cells, nr_cells, NULL, 0,
+ regmap_irq_get_domain(rk808->irq_data));
if (ret) {
dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
goto err_irq;
@@ -245,14 +413,9 @@ static int rk808_remove(struct i2c_client *client)
return 0;
}
-static const struct of_device_id rk808_of_match[] = {
- { .compatible = "rockchip,rk808" },
- { },
-};
-MODULE_DEVICE_TABLE(of, rk808_of_match);
-
static const struct i2c_device_id rk808_ids[] = {
{ "rk808" },
+ { "rk818" },
{ },
};
MODULE_DEVICE_TABLE(i2c, rk808_ids);
@@ -272,4 +435,5 @@ module_i2c_driver(rk808_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
-MODULE_DESCRIPTION("RK808 PMIC driver");
+MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
+MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c
index dbd907d7170e..691dab791f7a 100644
--- a/drivers/mfd/rtsx_usb.c
+++ b/drivers/mfd/rtsx_usb.c
@@ -46,9 +46,6 @@ static void rtsx_usb_sg_timed_out(unsigned long data)
dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
usb_sg_cancel(&ucr->current_sg);
-
- /* we know the cancellation is caused by time-out */
- ucr->current_sg.status = -ETIMEDOUT;
}
static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
@@ -67,12 +64,15 @@ 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_sync(&ucr->sg_timer);
+ if (!del_timer_sync(&ucr->sg_timer))
+ ret = -ETIMEDOUT;
+ else
+ ret = ucr->current_sg.status;
if (act_len)
*act_len = ucr->current_sg.bytes;
- return ucr->current_sg.status;
+ return ret;
}
int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 65cd0d2a822a..40534352e574 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -1001,7 +1001,7 @@ static int sm501_gpio_output(struct gpio_chip *chip,
return 0;
}
-static struct gpio_chip gpio_chip_template = {
+static const struct gpio_chip gpio_chip_template = {
.ngpio = 32,
.direction_input = sm501_gpio_input,
.direction_output = sm501_gpio_output,
diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c
index cd18c09827ef..1f40baf1234e 100644
--- a/drivers/mfd/smsc-ece1099.c
+++ b/drivers/mfd/smsc-ece1099.c
@@ -11,8 +11,7 @@
*
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
+#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
@@ -81,7 +80,6 @@ static const struct i2c_device_id smsc_i2c_id[] = {
{ "smscece1099", 0},
{},
};
-MODULE_DEVICE_TABLE(i2c, smsc_i2c_id);
static struct i2c_driver smsc_i2c_driver = {
.driver = {
@@ -90,9 +88,4 @@ static struct i2c_driver smsc_i2c_driver = {
.probe = smsc_i2c_probe,
.id_table = smsc_i2c_id,
};
-
-module_i2c_driver(smsc_i2c_driver);
-
-MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
-MODULE_DESCRIPTION("SMSC chip multi-function driver");
-MODULE_LICENSE("GPL v2");
+builtin_i2c_driver(smsc_i2c_driver);
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c
index 191173166d65..011fcc555945 100644
--- a/drivers/mfd/sun6i-prcm.c
+++ b/drivers/mfd/sun6i-prcm.c
@@ -9,7 +9,7 @@
*/
#include <linux/mfd/core.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of.h>
struct prcm_data {
@@ -170,8 +170,4 @@ static struct platform_driver sun6i_prcm_driver = {
},
.probe = sun6i_prcm_probe,
};
-module_platform_driver(sun6i_prcm_driver);
-
-MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
-MODULE_DESCRIPTION("Allwinner sun6i PRCM driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(sun6i_prcm_driver);
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 049a6fcac651..9a4d8684dd32 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -15,22 +15,103 @@
* GNU General Public License for more details.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/err.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/regmap.h>
-#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.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/slab.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65217.h>
-static const struct mfd_cell tps65217s[] = {
+static struct resource charger_resources[] = {
+ DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_AC, "AC"),
+ DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_USB, "USB"),
+};
+
+static struct resource pb_resources[] = {
+ DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
+};
+
+struct tps65217_irq {
+ int mask;
+ int interrupt;
+};
+
+static const struct tps65217_irq tps65217_irqs[] = {
+ [TPS65217_IRQ_PB] = {
+ .mask = TPS65217_INT_PBM,
+ .interrupt = TPS65217_INT_PBI,
+ },
+ [TPS65217_IRQ_AC] = {
+ .mask = TPS65217_INT_ACM,
+ .interrupt = TPS65217_INT_ACI,
+ },
+ [TPS65217_IRQ_USB] = {
+ .mask = TPS65217_INT_USBM,
+ .interrupt = TPS65217_INT_USBI,
+ },
+};
+
+static void tps65217_irq_lock(struct irq_data *data)
+{
+ struct tps65217 *tps = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&tps->irq_lock);
+}
+
+static void tps65217_irq_sync_unlock(struct irq_data *data)
+{
+ struct tps65217 *tps = irq_data_get_irq_chip_data(data);
+ int ret;
+
+ ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
+ TPS65217_PROTECT_NONE);
+ if (ret != 0)
+ dev_err(tps->dev, "Failed to sync IRQ masks\n");
+
+ mutex_unlock(&tps->irq_lock);
+}
+
+static inline const struct tps65217_irq *
+irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data)
+{
+ return &tps65217_irqs[data->hwirq];
+}
+
+static void tps65217_irq_enable(struct irq_data *data)
+{
+ struct tps65217 *tps = irq_data_get_irq_chip_data(data);
+ const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+
+ tps->irq_mask &= ~irq_data->mask;
+}
+
+static void tps65217_irq_disable(struct irq_data *data)
+{
+ struct tps65217 *tps = irq_data_get_irq_chip_data(data);
+ const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+
+ tps->irq_mask |= irq_data->mask;
+}
+
+static struct irq_chip tps65217_irq_chip = {
+ .irq_bus_lock = tps65217_irq_lock,
+ .irq_bus_sync_unlock = tps65217_irq_sync_unlock,
+ .irq_enable = tps65217_irq_enable,
+ .irq_disable = tps65217_irq_disable,
+};
+
+static struct mfd_cell tps65217s[] = {
{
.name = "tps65217-pmic",
.of_compatible = "ti,tps65217-pmic",
@@ -41,10 +122,96 @@ static const struct mfd_cell tps65217s[] = {
},
{
.name = "tps65217-charger",
+ .num_resources = ARRAY_SIZE(charger_resources),
+ .resources = charger_resources,
.of_compatible = "ti,tps65217-charger",
},
+ {
+ .name = "tps65217-pwrbutton",
+ .num_resources = ARRAY_SIZE(pb_resources),
+ .resources = pb_resources,
+ .of_compatible = "ti,tps65217-pwrbutton",
+ },
+};
+
+static irqreturn_t tps65217_irq_thread(int irq, void *data)
+{
+ struct tps65217 *tps = data;
+ unsigned int status;
+ bool handled = false;
+ int i;
+ int ret;
+
+ ret = tps65217_reg_read(tps, TPS65217_REG_INT, &status);
+ if (ret < 0) {
+ dev_err(tps->dev, "Failed to read IRQ status: %d\n",
+ ret);
+ return IRQ_NONE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) {
+ if (status & tps65217_irqs[i].interrupt) {
+ handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
+ handled = true;
+ }
+ }
+
+ if (handled)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
+static int tps65217_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct tps65217 *tps = h->host_data;
+
+ irq_set_chip_data(virq, tps);
+ irq_set_chip_and_handler(virq, &tps65217_irq_chip, handle_edge_irq);
+ irq_set_nested_thread(virq, 1);
+ irq_set_parent(virq, tps->irq);
+ irq_set_noprobe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops tps65217_irq_domain_ops = {
+ .map = tps65217_irq_map,
};
+static int tps65217_irq_init(struct tps65217 *tps, int irq)
+{
+ int ret;
+
+ mutex_init(&tps->irq_lock);
+ tps->irq = irq;
+
+ /* Mask all interrupt sources */
+ tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
+ | TPS65217_INT_ACM | TPS65217_INT_USBM);
+ tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
+ TPS65217_PROTECT_NONE);
+
+ tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
+ TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
+ if (!tps->irq_domain) {
+ dev_err(tps->dev, "Could not create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_request_threaded_irq(tps->dev, irq, NULL,
+ tps65217_irq_thread, IRQF_ONESHOT,
+ "tps65217-irq", tps);
+ if (ret) {
+ dev_err(tps->dev, "Failed to request IRQ %d: %d\n",
+ irq, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* tps65217_reg_read: Read a single tps65217 register.
*
@@ -149,11 +316,22 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
}
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+static bool tps65217_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TPS65217_REG_INT:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct regmap_config tps65217_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TPS65217_REG_MAX,
+ .volatile_reg = tps65217_volatile_reg,
};
static const struct of_device_id tps65217_of_match[] = {
@@ -205,8 +383,19 @@ static int tps65217_probe(struct i2c_client *client,
return ret;
}
+ if (client->irq) {
+ tps65217_irq_init(tps, client->irq);
+ } else {
+ int i;
+
+ /* Don't tell children about IRQ resources which won't fire */
+ for (i = 0; i < ARRAY_SIZE(tps65217s); i++)
+ tps65217s[i].num_resources = 0;
+ }
+
ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
- ARRAY_SIZE(tps65217s), NULL, 0, NULL);
+ ARRAY_SIZE(tps65217s), NULL, 0,
+ tps->irq_domain);
if (ret < 0) {
dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
return ret;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index a49d3db6d936..c64615dca2bd 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -30,7 +30,6 @@
#include <linux/init.h>
#include <linux/mutex.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/clk.h>
@@ -1258,7 +1257,6 @@ static const struct i2c_device_id twl_ids[] = {
{ "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
{ /* end of list */ },
};
-MODULE_DEVICE_TABLE(i2c, twl_ids);
/* One Client Driver , 4 Clients */
static struct i2c_driver twl_driver = {
@@ -1267,9 +1265,4 @@ static struct i2c_driver twl_driver = {
.probe = twl_probe,
.remove = twl_remove,
};
-
-module_i2c_driver(twl_driver);
-
-MODULE_AUTHOR("Texas Instruments, Inc.");
-MODULE_DESCRIPTION("I2C Core interface for TWL");
-MODULE_LICENSE("GPL");
+builtin_i2c_driver(twl_driver);
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c
index ab328ec49353..d66502d36ba0 100644
--- a/drivers/mfd/twl6040.c
+++ b/drivers/mfd/twl6040.c
@@ -609,6 +609,7 @@ static const struct regmap_config twl6040_regmap_config = {
.writeable_reg = twl6040_writeable_reg,
.cache_type = REGCACHE_RBTREE,
+ .use_single_rw = true,
};
static const struct regmap_irq twl6040_irqs[] = {
@@ -782,6 +783,11 @@ static int twl6040_probe(struct i2c_client *client,
cell->name = "twl6040-gpo";
children++;
+ /* PDM clock support */
+ cell = &twl6040->cells[children];
+ cell->name = "twl6040-pdmclk";
+ children++;
+
/* The chip is powered down so mark regmap to cache only and dirty */
regcache_cache_only(twl6040->regmap, true);
regcache_mark_dirty(twl6040->regmap);
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 9ab9ec47ea75..d6fb2e1a759a 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -446,10 +446,6 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
unsigned long mask;
mask = probe_irq_on();
- if (!mask) {
- probe_irq_off(mask);
- return NO_IRQ;
- }
/*
* Enable the ADC interrupt.
@@ -541,7 +537,7 @@ static int ucb1x00_probe(struct mcp *mcp)
ucb1x00_enable(ucb);
ucb->irq = ucb1x00_detect_irq(ucb);
ucb1x00_disable(ucb);
- if (ucb->irq == NO_IRQ) {
+ if (!ucb->irq) {
dev_err(&ucb->dev, "IRQ probe failed\n");
ret = -ENODEV;
goto err_no_irq;
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index 344a0ff8f8c7..01d372aba131 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -162,7 +162,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0};
#define CXL_PSL_SPAP_V 0x0000000000000001ULL
/****** CXL_PSL_Control ****************************************************/
-#define CXL_PSL_Control_tb 0x0000000000000001ULL
+#define CXL_PSL_Control_tb (0x1ull << (63-63))
+#define CXL_PSL_Control_Fr (0x1ull << (63-31))
+#define CXL_PSL_Control_Fs_MASK (0x3ull << (63-29))
+#define CXL_PSL_Control_Fs_Complete (0x3ull << (63-29))
/****** CXL_PSL_DLCNTL *****************************************************/
#define CXL_PSL_DLCNTL_D (0x1ull << (63-28))
@@ -854,6 +857,7 @@ int cxl_register_one_irq(struct cxl *adapter, irq_handler_t handler,
int cxl_check_error(struct cxl_afu *afu);
int cxl_afu_slbia(struct cxl_afu *afu);
int cxl_tlb_slb_invalidate(struct cxl *adapter);
+int cxl_data_cache_flush(struct cxl *adapter);
int cxl_afu_disable(struct cxl_afu *afu);
int cxl_psl_purge(struct cxl_afu *afu);
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
index e606fdc4bc9c..a217a74ccc98 100644
--- a/drivers/misc/cxl/native.c
+++ b/drivers/misc/cxl/native.c
@@ -290,6 +290,37 @@ int cxl_tlb_slb_invalidate(struct cxl *adapter)
return 0;
}
+int cxl_data_cache_flush(struct cxl *adapter)
+{
+ u64 reg;
+ unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+
+ pr_devel("Flushing data cache\n");
+
+ reg = cxl_p1_read(adapter, CXL_PSL_Control);
+ reg |= CXL_PSL_Control_Fr;
+ cxl_p1_write(adapter, CXL_PSL_Control, reg);
+
+ reg = cxl_p1_read(adapter, CXL_PSL_Control);
+ while ((reg & CXL_PSL_Control_Fs_MASK) != CXL_PSL_Control_Fs_Complete) {
+ if (time_after_eq(jiffies, timeout)) {
+ dev_warn(&adapter->dev, "WARNING: cache flush timed out!\n");
+ return -EBUSY;
+ }
+
+ if (!cxl_ops->link_ok(adapter, NULL)) {
+ dev_warn(&adapter->dev, "WARNING: link down when flushing cache\n");
+ return -EIO;
+ }
+ cpu_relax();
+ reg = cxl_p1_read(adapter, CXL_PSL_Control);
+ }
+
+ reg &= ~CXL_PSL_Control_Fr;
+ cxl_p1_write(adapter, CXL_PSL_Control, reg);
+ return 0;
+}
+
static int cxl_write_sstp(struct cxl_afu *afu, u64 sstp0, u64 sstp1)
{
int rc;
diff --git a/drivers/misc/cxl/of.c b/drivers/misc/cxl/of.c
index edc458395f68..ec175ea5dfba 100644
--- a/drivers/misc/cxl/of.c
+++ b/drivers/misc/cxl/of.c
@@ -460,7 +460,7 @@ int cxl_of_probe(struct platform_device *pdev)
struct device_node *afu_np = NULL;
struct cxl *adapter = NULL;
int ret;
- int slice, slice_ok;
+ int slice = 0, slice_ok = 0;
pr_devel("in %s\n", __func__);
@@ -476,13 +476,13 @@ int cxl_of_probe(struct platform_device *pdev)
}
/* init afu */
- slice_ok = 0;
- for (afu_np = NULL, slice = 0; (afu_np = of_get_next_child(np, afu_np)); slice++) {
+ for_each_child_of_node(np, afu_np) {
if ((ret = cxl_guest_init_afu(adapter, slice, afu_np)))
dev_err(&pdev->dev, "AFU %i failed to initialise: %i\n",
slice, ret);
else
slice_ok++;
+ slice++;
}
if (slice_ok == 0) {
@@ -490,8 +490,6 @@ int cxl_of_probe(struct platform_device *pdev)
adapter->slices = 0;
}
- if (afu_np)
- of_node_put(afu_np);
return 0;
}
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 6f0c4ac4b649..7afad8477ad5 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -1239,6 +1239,9 @@ int cxl_pci_reset(struct cxl *adapter)
dev_info(&dev->dev, "CXL reset\n");
+ /* the adapter is about to be reset, so ignore errors */
+ cxl_data_cache_flush(adapter);
+
/* pcie_warm_reset requests a fundamental pci reset which includes a
* PERST assert/deassert. PERST triggers a loading of the image
* if "user" or "factory" is selected in sysfs */
@@ -1530,11 +1533,11 @@ static void set_sl_ops(struct cxl *adapter, struct pci_dev *dev)
{
if (dev->vendor == PCI_VENDOR_ID_MELLANOX && dev->device == 0x1013) {
/* Mellanox CX-4 */
- dev_info(&adapter->dev, "Device uses an XSL\n");
+ dev_info(&dev->dev, "Device uses an XSL\n");
adapter->native->sl_ops = &xsl_ops;
adapter->min_pe = 1; /* Workaround for CX-4 hardware bug */
} else {
- dev_info(&adapter->dev, "Device uses a PSL\n");
+ dev_info(&dev->dev, "Device uses a PSL\n");
adapter->native->sl_ops = &psl_ops;
}
}
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 3cdf8e1ca0ad..051b14766ef9 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -593,6 +593,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct at24_data *at24;
int err;
unsigned i, num_addresses;
+ u8 test_byte;
if (client->dev.platform_data) {
chip = *(struct at24_platform_data *)client->dev.platform_data;
@@ -743,6 +744,18 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}
+ i2c_set_clientdata(client, at24);
+
+ /*
+ * Perform a one-byte test read to verify that the
+ * chip is functional.
+ */
+ err = at24_read(at24, 0, &test_byte, 1);
+ if (err) {
+ err = -ENODEV;
+ goto err_clients;
+ }
+
at24->nvmem_config.name = dev_name(&client->dev);
at24->nvmem_config.dev = &client->dev;
at24->nvmem_config.read_only = !writable;
@@ -764,8 +777,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
goto err_clients;
}
- i2c_set_clientdata(client, at24);
-
dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
chip.byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 9c677f3f3c26..520f58439080 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -144,7 +144,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_ino = get_next_ino();
ret->i_mode = mode;
- ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
}
return ret;
}
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 392f9eff5fb7..5bcc896a48c3 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -78,7 +78,7 @@ config MTD_PHYSMAP_OF_VERSATILE
bool "Support ARM Versatile physmap OF"
depends on MTD_PHYSMAP_OF
depends on MFD_SYSCON
- default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || REALVIEW_DT)
+ default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || ARCH_REALVIEW)
help
This provides some extra DT physmap parsing for the ARM Versatile
platforms, basically to add a VPP (write protection) callback so
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index e3936b847c6b..4f270482cfd0 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -376,6 +376,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
}
/**
+ * mtd_wunit_to_pairing_info - get pairing information of a wunit
+ * @mtd: pointer to new MTD device info structure
+ * @wunit: write unit we are interested in
+ * @info: returned pairing information
+ *
+ * Retrieve pairing information associated to the wunit.
+ * This is mainly useful when dealing with MLC/TLC NANDs where pages can be
+ * paired together, and where programming a page may influence the page it is
+ * paired with.
+ * The notion of page is replaced by the term wunit (write-unit) to stay
+ * consistent with the ->writesize field.
+ *
+ * The @wunit argument can be extracted from an absolute offset using
+ * mtd_offset_to_wunit(). @info is filled with the pairing information attached
+ * to @wunit.
+ *
+ * From the pairing info the MTD user can find all the wunits paired with
+ * @wunit using the following loop:
+ *
+ * for (i = 0; i < mtd_pairing_groups(mtd); i++) {
+ * info.pair = i;
+ * mtd_pairing_info_to_wunit(mtd, &info);
+ * ...
+ * }
+ */
+int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
+ struct mtd_pairing_info *info)
+{
+ int npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
+
+ if (wunit < 0 || wunit >= npairs)
+ return -EINVAL;
+
+ if (mtd->pairing && mtd->pairing->get_info)
+ return mtd->pairing->get_info(mtd, wunit, info);
+
+ info->group = 0;
+ info->pair = wunit;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_wunit_to_pairing_info);
+
+/**
+ * mtd_wunit_to_pairing_info - get wunit from pairing information
+ * @mtd: pointer to new MTD device info structure
+ * @info: pairing information struct
+ *
+ * Returns a positive number representing the wunit associated to the info
+ * struct, or a negative error code.
+ *
+ * This is the reverse of mtd_wunit_to_pairing_info(), and can help one to
+ * iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info()
+ * doc).
+ *
+ * It can also be used to only program the first page of each pair (i.e.
+ * page attached to group 0), which allows one to use an MLC NAND in
+ * software-emulated SLC mode:
+ *
+ * info.group = 0;
+ * npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
+ * for (info.pair = 0; info.pair < npairs; info.pair++) {
+ * wunit = mtd_pairing_info_to_wunit(mtd, &info);
+ * mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit),
+ * mtd->writesize, &retlen, buf + (i * mtd->writesize));
+ * }
+ */
+int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
+ const struct mtd_pairing_info *info)
+{
+ int ngroups = mtd_pairing_groups(mtd);
+ int npairs = mtd_wunit_per_eb(mtd) / ngroups;
+
+ if (!info || info->pair < 0 || info->pair >= npairs ||
+ info->group < 0 || info->group >= ngroups)
+ return -EINVAL;
+
+ if (mtd->pairing && mtd->pairing->get_wunit)
+ return mtd->pairing->get_wunit(mtd, info);
+
+ return info->pair;
+}
+EXPORT_SYMBOL_GPL(mtd_pairing_info_to_wunit);
+
+/**
+ * mtd_pairing_groups - get the number of pairing groups
+ * @mtd: pointer to new MTD device info structure
+ *
+ * Returns the number of pairing groups.
+ *
+ * This number is usually equal to the number of bits exposed by a single
+ * cell, and can be used in conjunction with mtd_pairing_info_to_wunit()
+ * to iterate over all pages of a given pair.
+ */
+int mtd_pairing_groups(struct mtd_info *mtd)
+{
+ if (!mtd->pairing || !mtd->pairing->ngroups)
+ return 1;
+
+ return mtd->pairing->ngroups;
+}
+EXPORT_SYMBOL_GPL(mtd_pairing_groups);
+
+/**
* add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure
*
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 1f13e32556f8..c1f34f04e338 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -317,6 +317,18 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
return res;
}
+static int part_get_device(struct mtd_info *mtd)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_get_device(part->master);
+}
+
+static void part_put_device(struct mtd_info *mtd)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+ part->master->_put_device(part->master);
+}
+
static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@@ -397,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
+ slave->mtd.pairing = master->pairing;
slave->mtd.name = name;
slave->mtd.owner = master->owner;
@@ -463,6 +476,12 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd._block_isbad = part_block_isbad;
if (master->_block_markbad)
slave->mtd._block_markbad = part_block_markbad;
+
+ if (master->_get_device)
+ slave->mtd._get_device = part_get_device;
+ if (master->_put_device)
+ slave->mtd._put_device = part_put_device;
+
slave->mtd._erase = part_erase;
slave->master = master;
slave->offset = part->offset;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 21ff58099f3b..7b7a887b4709 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -88,11 +88,11 @@ config MTD_NAND_AMS_DELTA
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2
- tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
- depends on ARCH_OMAP2PLUS
+ tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
+ depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
help
- Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
- platforms.
+ Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
+ and Keystone platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
@@ -428,7 +428,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
- depends on PPC
+ depends on FSL_SOC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
- depends on MTD_NAND && (FSL_SOC || ARCH_LAYERSCAPE)
+ depends on FSL_SOC || ARCH_LAYERSCAPE
select FSL_IFC
select MEMORY
help
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 37da4236ab90..3962f55bd034 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
- spin_lock_init(&info->controller.lock);
- init_waitqueue_head(&info->controller.wq);
+ nand_hw_control_init(&info->controller);
info->device = &pdev->dev;
info->platform = plat;
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 8eb2c64df38c..9d2424bfdbf5 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
u32 *flash_cache = (u32 *)ctrl->flash_cache;
int i;
- brcmnand_soc_data_bus_prepare(ctrl->soc);
+ brcmnand_soc_data_bus_prepare(ctrl->soc, true);
/*
* Must cache the FLASH_CACHE now, since changes in
@@ -1349,7 +1349,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
*/
flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
- brcmnand_soc_data_bus_unprepare(ctrl->soc);
+ brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
if (host->hwcfg.sector_size_1k)
@@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
brcmnand_waitfunc(mtd, chip);
if (likely(buf)) {
- brcmnand_soc_data_bus_prepare(ctrl->soc);
+ brcmnand_soc_data_bus_prepare(ctrl->soc, false);
for (j = 0; j < FC_WORDS; j++, buf++)
*buf = brcmnand_read_fc(ctrl, j);
- brcmnand_soc_data_bus_unprepare(ctrl->soc);
+ brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
}
if (oob)
@@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
if (buf) {
- brcmnand_soc_data_bus_prepare(ctrl->soc);
+ brcmnand_soc_data_bus_prepare(ctrl->soc, false);
for (j = 0; j < FC_WORDS; j++, buf++)
brcmnand_write_fc(ctrl, j, *buf);
- brcmnand_soc_data_bus_unprepare(ctrl->soc);
+ brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
} else if (oob) {
for (j = 0; j < FC_WORDS; j++)
brcmnand_write_fc(ctrl, j, 0xffffffff);
@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
init_completion(&ctrl->done);
init_completion(&ctrl->dma_done);
- spin_lock_init(&ctrl->controller.lock);
- init_waitqueue_head(&ctrl->controller.wq);
+ nand_hw_control_init(&ctrl->controller);
INIT_LIST_HEAD(&ctrl->host_list);
/* NAND register range */
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h
index ef5eabba88e5..5c44cd4aba87 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.h
+++ b/drivers/mtd/nand/brcmnand/brcmnand.h
@@ -23,19 +23,22 @@ struct dev_pm_ops;
struct brcmnand_soc {
bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
- void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
+ void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
+ bool is_param);
};
-static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc)
+static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
+ bool is_param)
{
if (soc && soc->prepare_data_bus)
- soc->prepare_data_bus(soc, true);
+ soc->prepare_data_bus(soc, true, is_param);
}
-static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc)
+static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
+ bool is_param)
{
if (soc && soc->prepare_data_bus)
- soc->prepare_data_bus(soc, false);
+ soc->prepare_data_bus(soc, false, is_param);
}
static inline u32 brcmnand_readl(void __iomem *addr)
diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/brcmnand/iproc_nand.c
index 585596c549b2..4c6ae113664d 100644
--- a/drivers/mtd/nand/brcmnand/iproc_nand.c
+++ b/drivers/mtd/nand/brcmnand/iproc_nand.c
@@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
spin_unlock_irqrestore(&priv->idm_lock, flags);
}
-static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
+static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
+ bool is_param)
{
struct iproc_nand_soc *priv =
container_of(soc, struct iproc_nand_soc, soc);
@@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
val = brcmnand_readl(mmio);
- if (prepare)
- val |= IPROC_NAND_APB_LE_MODE;
- else
+ /*
+ * In the case of BE or when dealing with NAND data, alway configure
+ * the APB bus to LE mode before accessing the FIFO and back to BE mode
+ * after the access is done
+ */
+ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
+ if (prepare)
+ val |= IPROC_NAND_APB_LE_MODE;
+ else
+ val &= ~IPROC_NAND_APB_LE_MODE;
+ } else { /* when in LE accessing the parameter page, keep APB in BE */
val &= ~IPROC_NAND_APB_LE_MODE;
+ }
brcmnand_writel(val, mmio);
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 47316998017f..7af2a3cd949e 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol;
- spin_lock_init(&nand->controller->lock);
- init_waitqueue_head(&nand->controller->wq);
+ nand_hw_control_init(nand->controller);
/* methods */
nand->cmdfunc = docg4_command;
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 60a88f24c6b3..113f76e59937 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
}
elbc_fcm_ctrl->counter++;
- spin_lock_init(&elbc_fcm_ctrl->controller.lock);
- init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
+ nand_hw_control_init(&elbc_fcm_ctrl->controller);
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
} else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 4e9e5fd8faf3..0a177b1bfe3e 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
ifc_nand_ctrl->addr = NULL;
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
- spin_lock_init(&ifc_nand_ctrl->controller.lock);
- init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+ nand_hw_control_init(&ifc_nand_ctrl->controller);
} else {
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
}
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 6e461560c6a8..6c062b8251d2 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -318,7 +318,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
return -EINVAL;
}
- geo->page_size = mtd->writesize + mtd->oobsize;
+ geo->page_size = mtd->writesize + geo->metadata_size +
+ (geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
geo->payload_size = mtd->writesize;
/*
diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
index 175f67da25af..a39bb70175ee 100644
--- a/drivers/mtd/nand/jz4780_nand.c
+++ b/drivers/mtd/nand/jz4780_nand.c
@@ -368,9 +368,8 @@ static int jz4780_nand_probe(struct platform_device *pdev)
nfc->dev = dev;
nfc->num_banks = num_banks;
- spin_lock_init(&nfc->controller.lock);
+ nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
- init_waitqueue_head(&nfc->controller.wq);
ret = jz4780_nand_init_chips(nfc, pdev);
if (ret) {
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 57cbe2b83849..d7f724b24fd7 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data {
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc);
+ int (*setup_data_interface)(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only);
/*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
+static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ int tRC_min_ns, tRC_ps, ret;
+ unsigned long rate, rate_round;
+ const struct nand_sdr_timings *timings;
+ u16 config1;
+
+ timings = nand_get_sdr_timings(conf);
+ if (IS_ERR(timings))
+ return -ENOTSUPP;
+
+ config1 = readw(NFC_V1_V2_CONFIG1);
+
+ tRC_min_ns = timings->tRC_min / 1000;
+ rate = 1000000000 / tRC_min_ns;
+
+ /*
+ * For tRC < 30ns we have to use EDO mode. In this case the controller
+ * does one access per clock cycle. Otherwise the controller does one
+ * access in two clock cycles, thus we have to double the rate to the
+ * controller.
+ */
+ if (tRC_min_ns < 30) {
+ rate_round = clk_round_rate(host->clk, rate);
+ config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
+ tRC_ps = 1000000000 / (rate_round / 1000);
+ } else {
+ rate *= 2;
+ rate_round = clk_round_rate(host->clk, rate);
+ config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
+ tRC_ps = 1000000000 / (rate_round / 1000 / 2);
+ }
+
+ /*
+ * The timing values compared against are from the i.MX25 Automotive
+ * datasheet, Table 50. NFC Timing Parameters
+ */
+ if (timings->tCLS_min > tRC_ps - 1000 ||
+ timings->tCLH_min > tRC_ps - 2000 ||
+ timings->tCS_min > tRC_ps - 1000 ||
+ timings->tCH_min > tRC_ps - 2000 ||
+ timings->tWP_min > tRC_ps - 1500 ||
+ timings->tALS_min > tRC_ps ||
+ timings->tALH_min > tRC_ps - 3000 ||
+ timings->tDS_min > tRC_ps ||
+ timings->tDH_min > tRC_ps - 5000 ||
+ timings->tWC_min > 2 * tRC_ps ||
+ timings->tWH_min > tRC_ps - 2500 ||
+ timings->tRR_min > 6 * tRC_ps ||
+ timings->tRP_min > 3 * tRC_ps / 2 ||
+ timings->tRC_min > 2 * tRC_ps ||
+ timings->tREH_min > (tRC_ps / 2) - 2500) {
+ dev_dbg(host->dev, "Timing out of bounds\n");
+ return -EINVAL;
+ }
+
+ if (check_only)
+ return 0;
+
+ ret = clk_set_rate(host->clk, rate);
+ if (ret)
+ return ret;
+
+ writew(config1, NFC_V1_V2_CONFIG1);
+
+ dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
+ config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
+ "normal");
+
+ return 0;
+}
+
static void preset_v2(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
@@ -1239,6 +1318,57 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
+static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
+ struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ int i;
+
+ if (!chip->onfi_version ||
+ !(le16_to_cpu(chip->onfi_params.opt_cmd)
+ & ONFI_OPT_CMD_SET_GET_FEATURES))
+ return -EINVAL;
+
+ host->buf_start = 0;
+
+ for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+ chip->write_byte(mtd, subfeature_param[i]);
+
+ memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
+ host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
+ mxc_do_addr_cycle(mtd, addr, -1);
+ host->devtype_data->send_page(mtd, NFC_INPUT);
+
+ return 0;
+}
+
+static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
+ struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ int i;
+
+ if (!chip->onfi_version ||
+ !(le16_to_cpu(chip->onfi_params.opt_cmd)
+ & ONFI_OPT_CMD_SET_GET_FEATURES))
+ return -EINVAL;
+
+ host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
+ mxc_do_addr_cycle(mtd, addr, -1);
+ host->devtype_data->send_page(mtd, NFC_OUTPUT);
+ memcpy32_fromio(host->data_buf, host->main_area0, 512);
+ host->buf_start = 0;
+
+ for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+ *subfeature_param++ = chip->read_byte(mtd);
+
+ return 0;
+}
+
/*
* The generic flash bbt decriptors overlap with our ecc
* hardware, so define some i.MX specific ones.
@@ -1327,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3,
+ .setup_data_interface = mxc_nand_v2_setup_data_interface,
.irqpending_quirk = 0,
.needs_ip = 0,
.regs_offset = 0x1e00,
@@ -1434,7 +1565,7 @@ static const struct platform_device_id mxcnd_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
-#ifdef CONFIG_OF_MTD
+#ifdef CONFIG_OF
static const struct of_device_id mxcnd_dt_ids[] = {
{
.compatible = "fsl,imx21-nand",
@@ -1513,6 +1644,8 @@ static int mxcnd_probe(struct platform_device *pdev)
this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf;
+ this->onfi_set_features = mxc_nand_onfi_set_features;
+ this->onfi_get_features = mxc_nand_onfi_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
@@ -1533,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err < 0)
return err;
+ this->setup_data_interface = host->devtype_data->setup_data_interface;
+
if (host->devtype_data->needs_ip) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77533f7f2429..e5718e5ecf92 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -745,7 +745,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
column >>= 1;
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
+
+ /* Only output a single addr cycle for 8bits opcodes. */
+ if (!nand_opcode_8bits(command))
+ chip->cmd_ctrl(mtd, column >> 8, ctrl);
}
if (page_addr != -1) {
chip->cmd_ctrl(mtd, page_addr, ctrl);
@@ -948,6 +951,172 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
}
/**
+ * nand_reset_data_interface - Reset data interface and timings
+ * @chip: The NAND chip
+ *
+ * Reset the Data interface and timings to ONFI mode 0.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_reset_data_interface(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ const struct nand_data_interface *conf;
+ int ret;
+
+ if (!chip->setup_data_interface)
+ return 0;
+
+ /*
+ * The ONFI specification says:
+ * "
+ * To transition from NV-DDR or NV-DDR2 to the SDR data
+ * interface, the host shall use the Reset (FFh) command
+ * using SDR timing mode 0. A device in any timing mode is
+ * required to recognize Reset (FFh) command issued in SDR
+ * timing mode 0.
+ * "
+ *
+ * Configure the data interface in SDR mode and set the
+ * timings to timing mode 0.
+ */
+
+ conf = nand_get_default_data_interface();
+ ret = chip->setup_data_interface(mtd, conf, false);
+ if (ret)
+ pr_err("Failed to configure data interface to SDR timing mode 0\n");
+
+ return ret;
+}
+
+/**
+ * nand_setup_data_interface - Setup the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find and configure the best data interface and NAND timings supported by
+ * the chip and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_setup_data_interface(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret;
+
+ if (!chip->setup_data_interface || !chip->data_interface)
+ return 0;
+
+ /*
+ * Ensure the timing mode has been changed on the chip side
+ * before changing timings on the controller side.
+ */
+ if (chip->onfi_version) {
+ u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
+ chip->onfi_timing_mode_default,
+ };
+
+ ret = chip->onfi_set_features(mtd, chip,
+ ONFI_FEATURE_ADDR_TIMING_MODE,
+ tmode_param);
+ if (ret)
+ goto err;
+ }
+
+ ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+err:
+ return ret;
+}
+
+/**
+ * nand_init_data_interface - find the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find the best data interface and NAND timings supported by the chip
+ * and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table. After this
+ * function nand_chip->data_interface is initialized with the best timing mode
+ * available.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_init_data_interface(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int modes, mode, ret;
+
+ if (!chip->setup_data_interface)
+ return 0;
+
+ /*
+ * First try to identify the best timings from ONFI parameters and
+ * if the NAND does not support ONFI, fallback to the default ONFI
+ * timing mode.
+ */
+ modes = onfi_get_async_timing_mode(chip);
+ if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+ if (!chip->onfi_timing_mode_default)
+ return 0;
+
+ modes = GENMASK(chip->onfi_timing_mode_default, 0);
+ }
+
+ chip->data_interface = kzalloc(sizeof(*chip->data_interface),
+ GFP_KERNEL);
+ if (!chip->data_interface)
+ return -ENOMEM;
+
+ for (mode = fls(modes) - 1; mode >= 0; mode--) {
+ ret = onfi_init_data_interface(chip, chip->data_interface,
+ NAND_SDR_IFACE, mode);
+ if (ret)
+ continue;
+
+ ret = chip->setup_data_interface(mtd, chip->data_interface,
+ true);
+ if (!ret) {
+ chip->onfi_timing_mode_default = mode;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void nand_release_data_interface(struct nand_chip *chip)
+{
+ kfree(chip->data_interface);
+}
+
+/**
+ * nand_reset - Reset and initialize a NAND device
+ * @chip: The NAND chip
+ *
+ * Returns 0 for success or negative error code otherwise
+ */
+int nand_reset(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret;
+
+ ret = nand_reset_data_interface(chip);
+ if (ret)
+ return ret;
+
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+ ret = nand_setup_data_interface(chip);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/**
* __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
* @mtd: mtd info
* @ofs: offset to start unlock from
@@ -1025,7 +1194,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ nand_reset(chip);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -1084,7 +1253,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ nand_reset(chip);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -2162,7 +2331,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
- int ret = -ENOTSUPP;
+ int ret;
ops->retlen = 0;
@@ -2173,24 +2342,18 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
return -EINVAL;
}
- nand_get_device(mtd, FL_READING);
-
- switch (ops->mode) {
- case MTD_OPS_PLACE_OOB:
- case MTD_OPS_AUTO_OOB:
- case MTD_OPS_RAW:
- break;
+ if (ops->mode != MTD_OPS_PLACE_OOB &&
+ ops->mode != MTD_OPS_AUTO_OOB &&
+ ops->mode != MTD_OPS_RAW)
+ return -ENOTSUPP;
- default:
- goto out;
- }
+ nand_get_device(mtd, FL_READING);
if (!ops->datbuf)
ret = nand_do_read_oob(mtd, from, ops);
else
ret = nand_do_read_ops(mtd, from, ops);
-out:
nand_release_device(mtd);
return ret;
}
@@ -2788,7 +2951,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
* if we don't do this. I have no clue why, but I seem to have 'fixed'
* it in the doc2000 driver in August 1999. dwmw2.
*/
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ nand_reset(chip);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -3191,8 +3354,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
- spin_lock_init(&chip->controller->lock);
- init_waitqueue_head(&chip->controller->wq);
+ nand_hw_control_init(chip->controller);
}
}
@@ -3829,7 +3991,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up.
*/
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ nand_reset(chip);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -4113,6 +4275,9 @@ static int nand_dt_init(struct nand_chip *chip)
if (ecc_step > 0)
chip->ecc.size = ecc_step;
+ if (of_property_read_bool(dn, "nand-ecc-maximize"))
+ chip->ecc.options |= NAND_ECC_MAXIMIZE;
+
return 0;
}
@@ -4141,6 +4306,15 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (!mtd->name && mtd->dev.parent)
mtd->name = dev_name(mtd->dev.parent);
+ if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
+ /*
+ * Default functions assigned for chip_select() and
+ * cmdfunc() both expect cmd_ctrl() to be populated,
+ * so we need to check that that's the case
+ */
+ pr_err("chip.cmd_ctrl() callback is not provided");
+ return -EINVAL;
+ }
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
@@ -4155,13 +4329,17 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return PTR_ERR(type);
}
+ ret = nand_init_data_interface(chip);
+ if (ret)
+ return ret;
+
chip->select_chip(mtd, -1);
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ nand_reset(chip);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
@@ -4221,6 +4399,7 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
ecc->write_page_raw = nand_write_page_raw;
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
+
/*
* Board driver should supply ecc.size and ecc.strength
* values to select how many bits are correctable.
@@ -4243,6 +4422,25 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
}
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+
+ }
+
+ /*
+ * We can only maximize ECC config when the default layout is
+ * used, otherwise we don't know how many bytes can really be
+ * used.
+ */
+ if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
+ ecc->options & NAND_ECC_MAXIMIZE) {
+ int steps, bytes;
+
+ /* Always prefer 1k blocks over 512bytes ones */
+ ecc->size = 1024;
+ steps = mtd->writesize / ecc->size;
+
+ /* Reserve 2 bytes for the BBM */
+ bytes = (mtd->oobsize - 2) / steps;
+ ecc->strength = bytes * 8 / fls(8 * ecc->size);
}
/* See nand_bch_init() for details. */
@@ -4601,18 +4799,16 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
EXPORT_SYMBOL(nand_scan);
/**
- * nand_release - [NAND Interface] Free resources held by the NAND device
- * @mtd: MTD device structure
+ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+ * @chip: NAND chip object
*/
-void nand_release(struct mtd_info *mtd)
+void nand_cleanup(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if (chip->ecc.mode == NAND_ECC_SOFT &&
chip->ecc.algo == NAND_ECC_BCH)
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
- mtd_device_unregister(mtd);
+ nand_release_data_interface(chip);
/* Free bad block table memory */
kfree(chip->bbt);
@@ -4624,6 +4820,18 @@ void nand_release(struct mtd_info *mtd)
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
}
+EXPORT_SYMBOL_GPL(nand_cleanup);
+
+/**
+ * nand_release - [NAND Interface] Unregister the MTD device and free resources
+ * held by the NAND device
+ * @mtd: MTD device structure
+ */
+void nand_release(struct mtd_info *mtd)
+{
+ mtd_device_unregister(mtd);
+ nand_cleanup(mtd_to_nand(mtd));
+}
EXPORT_SYMBOL_GPL(nand_release);
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 2fbb523df066..7695efea65f2 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -605,6 +605,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
}
/**
+ * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
+ * @this: the NAND device
+ * @td: the BBT description
+ * @md: the mirror BBT descriptor
+ * @chip: the CHIP selector
+ *
+ * This functions returns a positive block number pointing a valid eraseblock
+ * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
+ * all blocks are already used of marked bad. If td->pages[chip] was already
+ * pointing to a valid block we re-use it, otherwise we search for the next
+ * valid one.
+ */
+static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
+ struct nand_bbt_descr *md, int chip)
+{
+ int startblock, dir, page, numblocks, i;
+
+ /*
+ * There was already a version of the table, reuse the page. This
+ * applies for absolute placement too, as we have the page number in
+ * td->pages.
+ */
+ if (td->pages[chip] != -1)
+ return td->pages[chip] >>
+ (this->bbt_erase_shift - this->page_shift);
+
+ numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+ if (!(td->options & NAND_BBT_PERCHIP))
+ numblocks *= this->numchips;
+
+ /*
+ * Automatic placement of the bad block table. Search direction
+ * top -> down?
+ */
+ if (td->options & NAND_BBT_LASTBLOCK) {
+ startblock = numblocks * (chip + 1) - 1;
+ dir = -1;
+ } else {
+ startblock = chip * numblocks;
+ dir = 1;
+ }
+
+ for (i = 0; i < td->maxblocks; i++) {
+ int block = startblock + dir * i;
+
+ /* Check, if the block is bad */
+ switch (bbt_get_entry(this, block)) {
+ case BBT_BLOCK_WORN:
+ case BBT_BLOCK_FACTORY_BAD:
+ continue;
+ }
+
+ page = block << (this->bbt_erase_shift - this->page_shift);
+
+ /* Check, if the block is used by the mirror table */
+ if (!md || md->pages[chip] != page)
+ return block;
+ }
+
+ return -ENOSPC;
+}
+
+/**
+ * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
+ * @this: the NAND device
+ * @td: the BBT description
+ * @chip: the CHIP selector
+ * @block: the BBT block to mark
+ *
+ * Blocks reserved for BBT can become bad. This functions is an helper to mark
+ * such blocks as bad. It takes care of updating the in-memory BBT, marking the
+ * block as bad using a bad block marker and invalidating the associated
+ * td->pages[] entry.
+ */
+static void mark_bbt_block_bad(struct nand_chip *this,
+ struct nand_bbt_descr *td,
+ int chip, int block)
+{
+ struct mtd_info *mtd = nand_to_mtd(this);
+ loff_t to;
+ int res;
+
+ bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+ to = (loff_t)block << this->bbt_erase_shift;
+ res = this->block_markbad(mtd, to);
+ if (res)
+ pr_warn("nand_bbt: error %d while marking block %d bad\n",
+ res, block);
+
+ td->pages[chip] = -1;
+}
+
+/**
* write_bbt - [GENERIC] (Re)write the bad block table
* @mtd: MTD device structure
* @buf: temporary buffer
@@ -621,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_chip *this = mtd_to_nand(mtd);
struct erase_info einfo;
int i, res, chip = 0;
- int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
+ int bits, page, offs, numblocks, sft, sftmsk;
int nrchips, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
@@ -652,46 +746,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
}
/* Loop through the chips */
- for (; chip < nrchips; chip++) {
- /*
- * There was already a version of the table, reuse the page
- * This applies for absolute placement too, as we have the
- * page nr. in td->pages.
- */
- if (td->pages[chip] != -1) {
- page = td->pages[chip];
- goto write;
+ while (chip < nrchips) {
+ int block;
+
+ block = get_bbt_block(this, td, md, chip);
+ if (block < 0) {
+ pr_err("No space left to write bad block table\n");
+ res = block;
+ goto outerr;
}
/*
- * Automatic placement of the bad block table. Search direction
- * top -> down?
+ * get_bbt_block() returns a block number, shift the value to
+ * get a page number.
*/
- if (td->options & NAND_BBT_LASTBLOCK) {
- startblock = numblocks * (chip + 1) - 1;
- dir = -1;
- } else {
- startblock = chip * numblocks;
- dir = 1;
- }
-
- for (i = 0; i < td->maxblocks; i++) {
- int block = startblock + dir * i;
- /* Check, if the block is bad */
- switch (bbt_get_entry(this, block)) {
- case BBT_BLOCK_WORN:
- case BBT_BLOCK_FACTORY_BAD:
- continue;
- }
- page = block <<
- (this->bbt_erase_shift - this->page_shift);
- /* Check, if the block is used by the mirror table */
- if (!md || md->pages[chip] != page)
- goto write;
- }
- pr_err("No space left to write bad block table\n");
- return -ENOSPC;
- write:
+ page = block << (this->bbt_erase_shift - this->page_shift);
/* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -787,20 +856,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
- if (res < 0)
- goto outerr;
+ if (res < 0) {
+ pr_warn("nand_bbt: error while erasing BBT block %d\n",
+ res);
+ mark_bbt_block_bad(this, td, chip, block);
+ continue;
+ }
res = scan_write_bbt(mtd, to, len, buf,
td->options & NAND_BBT_NO_OOB ? NULL :
&buf[len]);
- if (res < 0)
- goto outerr;
+ if (res < 0) {
+ pr_warn("nand_bbt: error while writing BBT block %d\n",
+ res);
+ mark_bbt_block_bad(this, td, chip, block);
+ continue;
+ }
pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
(unsigned long long)to, td->version[chip]);
/* Mark it as used */
- td->pages[chip] = page;
+ td->pages[chip++] = page;
}
return 0;
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index e81470a8ac67..13a587407be3 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -13,228 +13,246 @@
#include <linux/export.h>
#include <linux/mtd/nand.h>
-static const struct nand_sdr_timings onfi_sdr_timings[] = {
+static const struct nand_data_interface onfi_sdr_timings[] = {
/* Mode 0 */
{
- .tADL_min = 200000,
- .tALH_min = 20000,
- .tALS_min = 50000,
- .tAR_min = 25000,
- .tCEA_max = 100000,
- .tCEH_min = 20000,
- .tCH_min = 20000,
- .tCHZ_max = 100000,
- .tCLH_min = 20000,
- .tCLR_min = 20000,
- .tCLS_min = 50000,
- .tCOH_min = 0,
- .tCS_min = 70000,
- .tDH_min = 20000,
- .tDS_min = 40000,
- .tFEAT_max = 1000000,
- .tIR_min = 10000,
- .tITC_max = 1000000,
- .tRC_min = 100000,
- .tREA_max = 40000,
- .tREH_min = 30000,
- .tRHOH_min = 0,
- .tRHW_min = 200000,
- .tRHZ_max = 200000,
- .tRLOH_min = 0,
- .tRP_min = 50000,
- .tRST_max = 250000000000ULL,
- .tWB_max = 200000,
- .tRR_min = 40000,
- .tWC_min = 100000,
- .tWH_min = 30000,
- .tWHR_min = 120000,
- .tWP_min = 50000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 400000,
+ .tALH_min = 20000,
+ .tALS_min = 50000,
+ .tAR_min = 25000,
+ .tCEA_max = 100000,
+ .tCEH_min = 20000,
+ .tCH_min = 20000,
+ .tCHZ_max = 100000,
+ .tCLH_min = 20000,
+ .tCLR_min = 20000,
+ .tCLS_min = 50000,
+ .tCOH_min = 0,
+ .tCS_min = 70000,
+ .tDH_min = 20000,
+ .tDS_min = 40000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 10000,
+ .tITC_max = 1000000,
+ .tRC_min = 100000,
+ .tREA_max = 40000,
+ .tREH_min = 30000,
+ .tRHOH_min = 0,
+ .tRHW_min = 200000,
+ .tRHZ_max = 200000,
+ .tRLOH_min = 0,
+ .tRP_min = 50000,
+ .tRR_min = 40000,
+ .tRST_max = 250000000000ULL,
+ .tWB_max = 200000,
+ .tWC_min = 100000,
+ .tWH_min = 30000,
+ .tWHR_min = 120000,
+ .tWP_min = 50000,
+ .tWW_min = 100000,
+ },
},
/* Mode 1 */
{
- .tADL_min = 100000,
- .tALH_min = 10000,
- .tALS_min = 25000,
- .tAR_min = 10000,
- .tCEA_max = 45000,
- .tCEH_min = 20000,
- .tCH_min = 10000,
- .tCHZ_max = 50000,
- .tCLH_min = 10000,
- .tCLR_min = 10000,
- .tCLS_min = 25000,
- .tCOH_min = 15000,
- .tCS_min = 35000,
- .tDH_min = 10000,
- .tDS_min = 20000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 50000,
- .tREA_max = 30000,
- .tREH_min = 15000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 0,
- .tRP_min = 25000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 45000,
- .tWH_min = 15000,
- .tWHR_min = 80000,
- .tWP_min = 25000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 400000,
+ .tALH_min = 10000,
+ .tALS_min = 25000,
+ .tAR_min = 10000,
+ .tCEA_max = 45000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 10000,
+ .tCLR_min = 10000,
+ .tCLS_min = 25000,
+ .tCOH_min = 15000,
+ .tCS_min = 35000,
+ .tDH_min = 10000,
+ .tDS_min = 20000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 50000,
+ .tREA_max = 30000,
+ .tREH_min = 15000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRP_min = 25000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 45000,
+ .tWH_min = 15000,
+ .tWHR_min = 80000,
+ .tWP_min = 25000,
+ .tWW_min = 100000,
+ },
},
/* Mode 2 */
{
- .tADL_min = 100000,
- .tALH_min = 10000,
- .tALS_min = 15000,
- .tAR_min = 10000,
- .tCEA_max = 30000,
- .tCEH_min = 20000,
- .tCH_min = 10000,
- .tCHZ_max = 50000,
- .tCLH_min = 10000,
- .tCLR_min = 10000,
- .tCLS_min = 15000,
- .tCOH_min = 15000,
- .tCS_min = 25000,
- .tDH_min = 5000,
- .tDS_min = 15000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 35000,
- .tREA_max = 25000,
- .tREH_min = 15000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 0,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tRP_min = 17000,
- .tWC_min = 35000,
- .tWH_min = 15000,
- .tWHR_min = 80000,
- .tWP_min = 17000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 400000,
+ .tALH_min = 10000,
+ .tALS_min = 15000,
+ .tAR_min = 10000,
+ .tCEA_max = 30000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 10000,
+ .tCLR_min = 10000,
+ .tCLS_min = 15000,
+ .tCOH_min = 15000,
+ .tCS_min = 25000,
+ .tDH_min = 5000,
+ .tDS_min = 15000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 35000,
+ .tREA_max = 25000,
+ .tREH_min = 15000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tRP_min = 17000,
+ .tWC_min = 35000,
+ .tWH_min = 15000,
+ .tWHR_min = 80000,
+ .tWP_min = 17000,
+ .tWW_min = 100000,
+ },
},
/* Mode 3 */
{
- .tADL_min = 100000,
- .tALH_min = 5000,
- .tALS_min = 10000,
- .tAR_min = 10000,
- .tCEA_max = 25000,
- .tCEH_min = 20000,
- .tCH_min = 5000,
- .tCHZ_max = 50000,
- .tCLH_min = 5000,
- .tCLR_min = 10000,
- .tCLS_min = 10000,
- .tCOH_min = 15000,
- .tCS_min = 25000,
- .tDH_min = 5000,
- .tDS_min = 10000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 30000,
- .tREA_max = 20000,
- .tREH_min = 10000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 0,
- .tRP_min = 15000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 30000,
- .tWH_min = 10000,
- .tWHR_min = 80000,
- .tWP_min = 15000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 400000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 25000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 30000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 0,
+ .tRP_min = 15000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 30000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 15000,
+ .tWW_min = 100000,
+ },
},
/* Mode 4 */
{
- .tADL_min = 70000,
- .tALH_min = 5000,
- .tALS_min = 10000,
- .tAR_min = 10000,
- .tCEA_max = 25000,
- .tCEH_min = 20000,
- .tCH_min = 5000,
- .tCHZ_max = 30000,
- .tCLH_min = 5000,
- .tCLR_min = 10000,
- .tCLS_min = 10000,
- .tCOH_min = 15000,
- .tCS_min = 20000,
- .tDH_min = 5000,
- .tDS_min = 10000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 25000,
- .tREA_max = 20000,
- .tREH_min = 10000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 5000,
- .tRP_min = 12000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 25000,
- .tWH_min = 10000,
- .tWHR_min = 80000,
- .tWP_min = 12000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 400000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 30000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 20000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 25000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 12000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 25000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 12000,
+ .tWW_min = 100000,
+ },
},
/* Mode 5 */
{
- .tADL_min = 70000,
- .tALH_min = 5000,
- .tALS_min = 10000,
- .tAR_min = 10000,
- .tCEA_max = 25000,
- .tCEH_min = 20000,
- .tCH_min = 5000,
- .tCHZ_max = 30000,
- .tCLH_min = 5000,
- .tCLR_min = 10000,
- .tCLS_min = 10000,
- .tCOH_min = 15000,
- .tCS_min = 15000,
- .tDH_min = 5000,
- .tDS_min = 7000,
- .tFEAT_max = 1000000,
- .tIR_min = 0,
- .tITC_max = 1000000,
- .tRC_min = 20000,
- .tREA_max = 16000,
- .tREH_min = 7000,
- .tRHOH_min = 15000,
- .tRHW_min = 100000,
- .tRHZ_max = 100000,
- .tRLOH_min = 5000,
- .tRP_min = 10000,
- .tRR_min = 20000,
- .tRST_max = 500000000,
- .tWB_max = 100000,
- .tWC_min = 20000,
- .tWH_min = 7000,
- .tWHR_min = 80000,
- .tWP_min = 10000,
- .tWW_min = 100000,
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tADL_min = 400000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 30000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 15000,
+ .tDH_min = 5000,
+ .tDS_min = 7000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 20000,
+ .tREA_max = 16000,
+ .tREH_min = 7000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 10000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 20000,
+ .tWH_min = 7000,
+ .tWHR_min = 80000,
+ .tWP_min = 10000,
+ .tWW_min = 100000,
+ },
},
};
@@ -248,6 +266,46 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
return ERR_PTR(-EINVAL);
- return &onfi_sdr_timings[mode];
+ return &onfi_sdr_timings[mode].timings.sdr;
}
EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
+
+/**
+ * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
+ * given ONFI mode
+ * @iface: The data interface to be initialized
+ * @mode: The ONFI timing mode
+ */
+int onfi_init_data_interface(struct nand_chip *chip,
+ struct nand_data_interface *iface,
+ enum nand_data_interface_type type,
+ int timing_mode)
+{
+ if (type != NAND_SDR_IFACE)
+ return -EINVAL;
+
+ if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+ return -EINVAL;
+
+ *iface = onfi_sdr_timings[timing_mode];
+
+ /*
+ * TODO: initialize timings that cannot be deduced from timing mode:
+ * tR, tPROG, tCCS, ...
+ * These information are part of the ONFI parameter page.
+ */
+
+ return 0;
+}
+EXPORT_SYMBOL(onfi_init_data_interface);
+
+/**
+ * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
+ * data interface for mode 0. This is used as default timing after
+ * reset.
+ */
+const struct nand_data_interface *nand_get_default_data_interface(void)
+{
+ return &onfi_sdr_timings[0];
+}
+EXPORT_SYMBOL(nand_get_default_data_interface);
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 218c789ca7ab..28e6118362f7 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
ndfc = &ndfc_ctrl[cs];
ndfc->chip_select = cs;
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ nand_hw_control_init(&ndfc->ndfc_control);
ndfc->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, ndfc);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 436dd6dc11f4..b121bf4ed73a 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->cmdfunc = nand_cmdfunc;
}
- spin_lock_init(&chip->controller->lock);
- init_waitqueue_head(&chip->controller->wq);
+ nand_hw_control_init(chip->controller);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get nand clock\n");
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index de7d28e62d4e..57d483ac5765 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -1957,8 +1957,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
INIT_LIST_HEAD(&nandc->desc_list);
INIT_LIST_HEAD(&nandc->host_list);
- spin_lock_init(&nandc->controller.lock);
- init_waitqueue_head(&nandc->controller.wq);
+ nand_hw_control_init(&nandc->controller);
return 0;
}
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d9309cf0ce2e..d459c19d78de 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -180,7 +180,7 @@ struct s3c2410_nand_info {
enum s3c_cpu_type cpu_type;
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
struct notifier_block freq_transition;
#endif
};
@@ -701,7 +701,7 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
/* cpufreq driver support */
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data)
@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
- spin_lock_init(&info->controller.lock);
- init_waitqueue_head(&info->controller.wq);
+ nand_hw_control_init(&info->controller);
/* get the clock source and enable it */
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index 6fa3bcd59769..442ce619b3b6 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -397,7 +397,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
struct dma_chan *chan;
enum dma_transfer_direction tr_dir;
dma_addr_t dma_addr;
- dma_cookie_t cookie = -EINVAL;
+ dma_cookie_t cookie;
uint32_t reg;
int ret;
@@ -423,6 +423,12 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
desc->callback = flctl_dma_complete;
desc->callback_param = flctl;
cookie = dmaengine_submit(desc);
+ if (dma_submit_error(cookie)) {
+ ret = dma_submit_error(cookie);
+ dev_warn(&flctl->pdev->dev,
+ "DMA submit failed, falling back to PIO\n");
+ goto out;
+ }
dma_async_issue_pending(chan);
} else {
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index e414b31b71c1..8b8470c4e6d0 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1572,14 +1572,22 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
- const struct nand_sdr_timings *timings)
+static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
+ const struct nand_sdr_timings *timings;
u32 min_clk_period = 0;
s32 tWB, tADL, tWHR, tRHW, tCAD;
long real_clk_rate;
+ timings = nand_get_sdr_timings(conf);
+ if (IS_ERR(timings))
+ return -ENOTSUPP;
+
/* T1 <=> tCLS */
if (timings->tCLS_min > min_clk_period)
min_clk_period = timings->tCLS_min;
@@ -1679,6 +1687,9 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return tRHW;
}
+ if (check_only)
+ return 0;
+
/*
* TODO: according to ONFI specs this value only applies for DDR NAND,
* but Allwinner seems to set this to 0x7. Mimic them for now.
@@ -1712,44 +1723,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return 0;
}
-static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
- struct device_node *np)
-{
- struct mtd_info *mtd = nand_to_mtd(&chip->nand);
- const struct nand_sdr_timings *timings;
- int ret;
- int mode;
-
- mode = onfi_get_async_timing_mode(&chip->nand);
- if (mode == ONFI_TIMING_MODE_UNKNOWN) {
- mode = chip->nand.onfi_timing_mode_default;
- } else {
- uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
- int i;
-
- mode = fls(mode) - 1;
- if (mode < 0)
- mode = 0;
-
- feature[0] = mode;
- for (i = 0; i < chip->nsels; i++) {
- chip->nand.select_chip(mtd, i);
- ret = chip->nand.onfi_set_features(mtd, &chip->nand,
- ONFI_FEATURE_ADDR_TIMING_MODE,
- feature);
- chip->nand.select_chip(mtd, -1);
- if (ret)
- return ret;
- }
- }
-
- timings = onfi_async_timing_mode_to_sdr_timings(mode);
- if (IS_ERR(timings))
- return PTR_ERR(timings);
-
- return sunxi_nand_chip_set_timings(chip, timings);
-}
-
static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@@ -1814,6 +1787,35 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
int ret;
int i;
+ if (ecc->options & NAND_ECC_MAXIMIZE) {
+ int bytes;
+
+ ecc->size = 1024;
+ nsectors = mtd->writesize / ecc->size;
+
+ /* Reserve 2 bytes for the BBM */
+ bytes = (mtd->oobsize - 2) / nsectors;
+
+ /* 4 non-ECC bytes are added before each ECC bytes section */
+ bytes -= 4;
+
+ /* and bytes has to be even. */
+ if (bytes % 2)
+ bytes--;
+
+ ecc->strength = bytes * 8 / fls(8 * ecc->size);
+
+ for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+ if (strengths[i] > ecc->strength)
+ break;
+ }
+
+ if (!i)
+ ecc->strength = 0;
+ else
+ ecc->strength = strengths[i - 1];
+ }
+
if (ecc->size != 512 && ecc->size != 1024)
return -EINVAL;
@@ -1975,7 +1977,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
- const struct nand_sdr_timings *timings;
struct sunxi_nand_chip *chip;
struct mtd_info *mtd;
struct nand_chip *nand;
@@ -2065,25 +2066,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->read_buf = sunxi_nfc_read_buf;
nand->write_buf = sunxi_nfc_write_buf;
nand->read_byte = sunxi_nfc_read_byte;
+ nand->setup_data_interface = sunxi_nfc_setup_data_interface;
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
- timings = onfi_async_timing_mode_to_sdr_timings(0);
- if (IS_ERR(timings)) {
- ret = PTR_ERR(timings);
- dev_err(dev,
- "could not retrieve timings for ONFI mode 0: %d\n",
- ret);
- return ret;
- }
-
- ret = sunxi_nand_chip_set_timings(chip, timings);
- if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
- return ret;
- }
-
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
return ret;
@@ -2096,12 +2083,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->options |= NAND_SUBPAGE_READ;
- ret = sunxi_nand_chip_init_timings(chip, np);
- if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
- return ret;
- }
-
ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret);
@@ -2175,8 +2156,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
return -ENOMEM;
nfc->dev = dev;
- spin_lock_init(&nfc->controller.lock);
- init_waitqueue_head(&nfc->controller.wq);
+ nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 04d63f56baa4..0a14fda2e41b 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
(gbusclk + 500000) / 1000000, hold, spw);
- spin_lock_init(&drvdata->hw_control.lock);
- init_waitqueue_head(&drvdata->hw_control.wq);
+ nand_hw_control_init(&drvdata->hw_control);
platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev);
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index ebf46ad2d513..d1e6931c132f 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -351,7 +351,6 @@ static int ubiblock_init_request(void *data, struct request *req,
static struct blk_mq_ops ubiblock_mq_ops = {
.queue_rq = ubiblock_queue_rq,
.init_request = ubiblock_init_request,
- .map_queue = blk_mq_map_queue,
};
static DEFINE_IDR(ubiblock_minor_idr);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 28e653e9c856..2125903043fb 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -350,6 +350,7 @@ struct adapter_params {
unsigned int nsched_cls; /* number of traffic classes */
unsigned int max_ordird_qp; /* Max read depth per RDMA QP */
unsigned int max_ird_adapter; /* Max read depth per adapter */
+ bool fr_nsmr_tpte_wr_support; /* FW support for FR_NSMR_TPTE_WR */
};
/* State needed to monitor the forward progress of SGE Ingress DMA activities
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index cf147ca419a8..f320497368f4 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3668,6 +3668,12 @@ static int adap_init0(struct adapter *adap)
adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0);
}
+ /* See if FW supports FW_RI_FR_NSMR_TPTE_WR work request */
+ params[0] = FW_PARAM_DEV(RI_FR_NSMR_TPTE_WR);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
+ 1, params, val);
+ adap->params.fr_nsmr_tpte_wr_support = (ret == 0 && val[0] != 0);
+
/*
* Get device capabilities so we can determine what resources we need
* to manage.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
index b4b2d20aab3c..0945fa49a5dd 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -550,6 +550,7 @@ static void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld)
lld->max_ird_adapter = adap->params.max_ird_adapter;
lld->ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl;
lld->nodeid = dev_to_node(adap->pdev_dev);
+ lld->fr_nsmr_tpte_wr_support = adap->params.fr_nsmr_tpte_wr_support;
}
static void uld_attach(struct adapter *adap, unsigned int uld)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 47bd14f602db..2996793b1aaa 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -308,6 +308,7 @@ struct cxgb4_lld_info {
unsigned int iscsi_llimit; /* chip's iscsi region llimit */
void **iscsi_ppm; /* iscsi page pod manager */
int nodeid; /* device numa node id */
+ bool fr_nsmr_tpte_wr_support; /* FW supports FR_NSMR_TPTE_WR */
};
struct cxgb4_uld_info {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 4b58b32105f7..8d9e4b7a8e84 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -100,6 +100,7 @@ enum fw_wr_opcodes {
FW_RI_RECV_WR = 0x17,
FW_RI_BIND_MW_WR = 0x18,
FW_RI_FR_NSMR_WR = 0x19,
+ FW_RI_FR_NSMR_TPTE_WR = 0x20,
FW_RI_INV_LSTAG_WR = 0x1a,
FW_ISCSI_TX_DATA_WR = 0x45,
FW_CRYPTO_LOOKASIDE_WR = 0X6d,
@@ -1121,6 +1122,7 @@ enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */
FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17,
FW_PARAMS_PARAM_DEV_FWCACHE = 0x18,
+ FW_PARAMS_PARAM_DEV_RI_FR_NSMR_TPTE_WR = 0x1C,
};
/*
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 751c1264c811..22e141005cd9 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -644,21 +644,6 @@ hns_mac_phy_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
return addr;
}
-static int hns_mac_phydev_match(struct device *dev, void *fwnode)
-{
- return dev->fwnode == fwnode;
-}
-
-static struct
-platform_device *hns_mac_find_platform_device(struct fwnode_handle *fwnode)
-{
- struct device *dev;
-
- dev = bus_find_device(&platform_bus_type, NULL,
- fwnode, hns_mac_phydev_match);
- return dev ? to_platform_device(dev) : NULL;
-}
-
static int
hns_mac_register_phydev(struct mii_bus *mdio, struct hns_mac_cb *mac_cb,
u32 addr)
@@ -724,7 +709,7 @@ static void hns_mac_register_phy(struct hns_mac_cb *mac_cb)
return;
/* dev address in adev */
- pdev = hns_mac_find_platform_device(acpi_fwnode_handle(args.adev));
+ pdev = hns_dsaf_find_platform_device(acpi_fwnode_handle(args.adev));
mii_bus = platform_get_drvdata(pdev);
rc = hns_mac_register_phydev(mii_bus, mac_cb, addr);
if (!rc)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index eb448dff7564..8e5b3f51b47b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -2780,7 +2780,7 @@ module_platform_driver(g_dsaf_driver);
* @enable: false - request reset , true - drop reset
* retuen 0 - success , negative -fail
*/
-int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool enable)
+int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset)
{
struct dsaf_device *dsaf_dev;
struct platform_device *pdev;
@@ -2809,24 +2809,44 @@ int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool enable)
{DSAF_ROCE_SL_1, DSAF_ROCE_SL_1, DSAF_ROCE_SL_3},
};
- if (!is_of_node(dsaf_fwnode)) {
- pr_err("hisi_dsaf: Only support DT node!\n");
+ /* find the platform device corresponding to fwnode */
+ if (is_of_node(dsaf_fwnode)) {
+ pdev = of_find_device_by_node(to_of_node(dsaf_fwnode));
+ } else if (is_acpi_device_node(dsaf_fwnode)) {
+ pdev = hns_dsaf_find_platform_device(dsaf_fwnode);
+ } else {
+ pr_err("fwnode is neither OF or ACPI type\n");
return -EINVAL;
}
- pdev = of_find_device_by_node(to_of_node(dsaf_fwnode));
+
+ /* check if we were a success in fetching pdev */
+ if (!pdev) {
+ pr_err("couldn't find platform device for node\n");
+ return -ENODEV;
+ }
+
+ /* retrieve the dsaf_device from the driver data */
dsaf_dev = dev_get_drvdata(&pdev->dev);
+ if (!dsaf_dev) {
+ dev_err(&pdev->dev, "dsaf_dev is NULL\n");
+ return -ENODEV;
+ }
+
+ /* now, make sure we are running on compatible SoC */
if (AE_IS_VER1(dsaf_dev->dsaf_ver)) {
dev_err(dsaf_dev->dev, "%s v1 chip doesn't support RoCE!\n",
dsaf_dev->ae_dev.name);
return -ENODEV;
}
- if (!enable) {
- /* Reset rocee-channels in dsaf and rocee */
- hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK, false);
- hns_dsaf_roce_srst(dsaf_dev, false);
+ /* do reset or de-reset according to the flag */
+ if (!dereset) {
+ /* reset rocee-channels in dsaf and rocee */
+ dsaf_dev->misc_op->hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK,
+ false);
+ dsaf_dev->misc_op->hns_dsaf_roce_srst(dsaf_dev, false);
} else {
- /* Configure dsaf tx roce correspond to port map and sl map */
+ /* configure dsaf tx roce correspond to port map and sl map */
mp = dsaf_read_dev(dsaf_dev, DSAF_ROCE_PORT_MAP_REG);
for (i = 0; i < DSAF_ROCE_CREDIT_CHN; i++)
dsaf_set_field(mp, 7 << i * 3, i * 3,
@@ -2840,12 +2860,13 @@ int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool enable)
sl_map[i][DSAF_ROCE_6PORT_MODE]);
dsaf_write_dev(dsaf_dev, DSAF_ROCE_SL_MAP_REG, sl);
- /* De-reset rocee-channels in dsaf and rocee */
- hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK, true);
+ /* de-reset rocee-channels in dsaf and rocee */
+ dsaf_dev->misc_op->hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK,
+ true);
msleep(SRST_TIME_INTERVAL);
- hns_dsaf_roce_srst(dsaf_dev, true);
+ dsaf_dev->misc_op->hns_dsaf_roce_srst(dsaf_dev, true);
- /* Eanble dsaf channel rocee credit */
+ /* enable dsaf channel rocee credit */
credit = dsaf_read_dev(dsaf_dev, DSAF_SBM_ROCEE_CFG_REG_REG);
dsaf_set_bit(credit, DSAF_SBM_ROCEE_CFG_CRD_EN_B, 0);
dsaf_write_dev(dsaf_dev, DSAF_SBM_ROCEE_CFG_REG_REG, credit);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
index f3681d566ae6..35df187e66f1 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
@@ -305,7 +305,7 @@ struct dsaf_misc_op {
void (*cpld_reset_led)(struct hns_mac_cb *mac_cb);
int (*cpld_set_led_id)(struct hns_mac_cb *mac_cb,
enum hnae_led_state status);
- /* reset seris function, it will be reset if the dereseet is 0 */
+ /* reset series function, it will be reset if the dereset is 0 */
void (*dsaf_reset)(struct dsaf_device *dsaf_dev, bool dereset);
void (*xge_srst)(struct dsaf_device *dsaf_dev, u32 port, bool dereset);
void (*xge_core_srst)(struct dsaf_device *dsaf_dev, u32 port,
@@ -313,6 +313,9 @@ struct dsaf_misc_op {
void (*ge_srst)(struct dsaf_device *dsaf_dev, u32 port, bool dereset);
void (*ppe_srst)(struct dsaf_device *dsaf_dev, u32 port, bool dereset);
void (*ppe_comm_srst)(struct dsaf_device *dsaf_dev, bool dereset);
+ void (*hns_dsaf_srst_chns)(struct dsaf_device *dsaf_dev, u32 msk,
+ bool dereset);
+ void (*hns_dsaf_roce_srst)(struct dsaf_device *dsaf_dev, bool dereset);
phy_interface_t (*get_phy_if)(struct hns_mac_cb *mac_cb);
int (*get_sfp_prsnt)(struct hns_mac_cb *mac_cb, int *sfp_prsnt);
@@ -445,10 +448,6 @@ int hns_dsaf_get_mac_entry_by_index(
void hns_dsaf_fix_mac_mode(struct hns_mac_cb *mac_cb);
-void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool enable);
-
-void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool enable);
-
int hns_dsaf_ae_init(struct dsaf_device *dsaf_dev);
void hns_dsaf_ae_uninit(struct dsaf_device *dsaf_dev);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
index 36b9f791cf2f..67accce1d33d 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -26,6 +26,8 @@ enum _dsm_rst_type {
HNS_XGE_CORE_RESET_FUNC = 0x3,
HNS_XGE_RESET_FUNC = 0x4,
HNS_GE_RESET_FUNC = 0x5,
+ HNS_DSAF_CHN_RESET_FUNC = 0x6,
+ HNS_ROCE_RESET_FUNC = 0x7,
};
const u8 hns_dsaf_acpi_dsm_uuid[] = {
@@ -241,11 +243,11 @@ static void hns_dsaf_xge_core_srst_by_port(struct dsaf_device *dsaf_dev,
* bit18-19 for com/dfx
* @enable: false - request reset , true - drop reset
*/
-void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool enable)
+void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
{
u32 reg_addr;
- if (!enable)
+ if (!dereset)
reg_addr = DSAF_SUB_SC_DSAF_RESET_REQ_REG;
else
reg_addr = DSAF_SUB_SC_DSAF_RESET_DREQ_REG;
@@ -253,9 +255,27 @@ void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool enable)
dsaf_write_sub(dsaf_dev, reg_addr, msk);
}
-void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool enable)
+/**
+ * hns_dsaf_srst_chns - reset dsaf channels
+ * @dsaf_dev: dsaf device struct pointer
+ * @msk: xbar channels mask value:
+ * bit0-5 for xge0-5
+ * bit6-11 for ppe0-5
+ * bit12-17 for roce0-5
+ * bit18-19 for com/dfx
+ * @enable: false - request reset , true - drop reset
+ */
+void
+hns_dsaf_srst_chns_acpi(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
{
- if (!enable) {
+ hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC,
+ HNS_DSAF_CHN_RESET_FUNC,
+ msk, dereset);
+}
+
+void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool dereset)
+{
+ if (!dereset) {
dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_ROCEE_RESET_REQ_REG, 1);
} else {
dsaf_write_sub(dsaf_dev,
@@ -267,6 +287,12 @@ void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool enable)
}
}
+void hns_dsaf_roce_srst_acpi(struct dsaf_device *dsaf_dev, bool dereset)
+{
+ hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC,
+ HNS_ROCE_RESET_FUNC, 0, dereset);
+}
+
static void
hns_dsaf_xge_core_srst_by_port_acpi(struct dsaf_device *dsaf_dev,
u32 port, bool dereset)
@@ -575,6 +601,8 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
misc_op->ge_srst = hns_dsaf_ge_srst_by_port;
misc_op->ppe_srst = hns_ppe_srst_by_port;
misc_op->ppe_comm_srst = hns_ppe_com_srst;
+ misc_op->hns_dsaf_srst_chns = hns_dsaf_srst_chns;
+ misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst;
misc_op->get_phy_if = hns_mac_get_phy_if;
misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt;
@@ -591,6 +619,8 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
misc_op->ge_srst = hns_dsaf_ge_srst_by_port_acpi;
misc_op->ppe_srst = hns_ppe_srst_by_port_acpi;
misc_op->ppe_comm_srst = hns_ppe_com_srst;
+ misc_op->hns_dsaf_srst_chns = hns_dsaf_srst_chns_acpi;
+ misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst_acpi;
misc_op->get_phy_if = hns_mac_get_phy_if_acpi;
misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt;
@@ -603,3 +633,18 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
return (void *)misc_op;
}
+
+static int hns_dsaf_dev_match(struct device *dev, void *fwnode)
+{
+ return dev->fwnode == fwnode;
+}
+
+struct
+platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&platform_bus_type, NULL,
+ fwnode, hns_dsaf_dev_match);
+ return dev ? to_platform_device(dev) : NULL;
+}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h
index f06bb03d47a6..310e80261366 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h
@@ -34,5 +34,6 @@
#define DSAF_LED_ANCHOR_B 5
struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev);
-
+struct
+platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index 13c16ab7be48..4b8b803822d1 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -78,10 +78,10 @@
#define DSAF_SUB_SC_RCB_PPE_COM_RESET_REQ_REG 0xA88
#define DSAF_SUB_SC_RCB_PPE_COM_RESET_DREQ_REG 0xA8C
#define DSAF_SUB_SC_DSAF_RESET_REQ_REG 0xAA8
-#define DSAF_SUB_SC_ROCEE_RESET_REQ_REG 0xA50
#define DSAF_SUB_SC_DSAF_RESET_DREQ_REG 0xAAC
-#define DSAF_SUB_SC_ROCEE_CLK_DIS_REG 0x32C
+#define DSAF_SUB_SC_ROCEE_RESET_REQ_REG 0xA50
#define DSAF_SUB_SC_ROCEE_RESET_DREQ_REG 0xA54
+#define DSAF_SUB_SC_ROCEE_CLK_DIS_REG 0x32C
#define DSAF_SUB_SC_ROCEE_CLK_EN_REG 0x328
#define DSAF_SUB_SC_LIGHT_MODULE_DETECT_EN_REG 0x2060
#define DSAF_SUB_SC_TCAM_MBIST_EN_REG 0x2300
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index f9cbc67f1694..c41ab31a39f8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -160,6 +160,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[33] = "RoCEv2 support",
[34] = "DMFS Sniffer support (UC & MC)",
[35] = "QinQ VST mode support",
+ [36] = "sl to vl mapping table change event support"
};
int i;
@@ -789,6 +790,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET 0x74
#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76
#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77
+#define QUERY_DEV_CAP_SL2VL_EVENT_OFFSET 0x78
#define QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE 0x7a
#define QUERY_DEV_CAP_ECN_QCN_VER_OFFSET 0x7b
#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80
@@ -904,6 +906,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB;
MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET);
dev_cap->fs_max_num_qp_per_entry = field;
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_SL2VL_EVENT_OFFSET);
+ if (field & (1 << 5))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT;
MLX4_GET(field, outbox, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
if (field & 0x1)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QCN;
@@ -2783,7 +2788,6 @@ static int mlx4_check_smp_firewall_active(struct mlx4_dev *dev,
int mlx4_config_mad_demux(struct mlx4_dev *dev)
{
struct mlx4_cmd_mailbox *mailbox;
- int secure_host_active;
int err;
/* Check if mad_demux is supported */
@@ -2806,7 +2810,8 @@ int mlx4_config_mad_demux(struct mlx4_dev *dev)
goto out;
}
- secure_host_active = mlx4_check_smp_firewall_active(dev, mailbox);
+ if (mlx4_check_smp_firewall_active(dev, mailbox))
+ dev->flags |= MLX4_FLAG_SECURE_HOST;
/* Config mad_demux to handle all MADs returned by the query above */
err = mlx4_cmd(dev, mailbox->dma, 0x01 /* subn mgmt class */,
@@ -2817,7 +2822,7 @@ int mlx4_config_mad_demux(struct mlx4_dev *dev)
goto out;
}
- if (secure_host_active)
+ if (dev->flags & MLX4_FLAG_SECURE_HOST)
mlx4_warn(dev, "HCA operating in secure-host mode. SMP firewall activated.\n");
out:
mlx4_free_cmd_mailbox(dev, mailbox);
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index c732b8ce2528..3818c5e06eba 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -61,13 +61,13 @@ config DWMAC_LPC18XX
config DWMAC_MESON
tristate "Amlogic Meson dwmac support"
default ARCH_MESON
- depends on OF && (ARCH_MESON || COMPILE_TEST)
+ depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
help
Support for Ethernet controller on Amlogic Meson SoCs.
This selects the Amlogic Meson SoC glue layer support for
- the stmmac device driver. This driver is used for Meson6 and
- Meson8 SoCs.
+ the stmmac device driver. This driver is used for Meson6,
+ Meson8, Meson8b and GXBB SoCs.
config DWMAC_ROCKCHIP
tristate "Rockchip dwmac support"
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index f0c9396fa28e..5d6ece5919b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -9,7 +9,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
-obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
+obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index c1bac1912b37..309d99536a2c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -1,5 +1,5 @@
/*
- * Amlogic Meson DWMAC glue layer
+ * Amlogic Meson6 and Meson8 DWMAC glue layer
*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
*
@@ -96,5 +96,5 @@ static struct platform_driver meson6_dwmac_driver = {
module_platform_driver(meson6_dwmac_driver);
MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
-MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer");
+MODULE_DESCRIPTION("Amlogic Meson6 and Meson8 DWMAC glue layer");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
new file mode 100644
index 000000000000..250e4ceafc8d
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -0,0 +1,324 @@
+/*
+ * Amlogic Meson8b and GXBB DWMAC glue layer
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/ethtool.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+#define PRG_ETH0 0x0
+
+#define PRG_ETH0_RGMII_MODE BIT(0)
+
+/* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */
+#define PRG_ETH0_CLK_M250_SEL_SHIFT 4
+#define PRG_ETH0_CLK_M250_SEL_MASK GENMASK(4, 4)
+
+#define PRG_ETH0_TXDLY_SHIFT 5
+#define PRG_ETH0_TXDLY_MASK GENMASK(6, 5)
+#define PRG_ETH0_TXDLY_OFF (0x0 << PRG_ETH0_TXDLY_SHIFT)
+#define PRG_ETH0_TXDLY_QUARTER (0x1 << PRG_ETH0_TXDLY_SHIFT)
+#define PRG_ETH0_TXDLY_HALF (0x2 << PRG_ETH0_TXDLY_SHIFT)
+#define PRG_ETH0_TXDLY_THREE_QUARTERS (0x3 << PRG_ETH0_TXDLY_SHIFT)
+
+/* divider for the result of m250_sel */
+#define PRG_ETH0_CLK_M250_DIV_SHIFT 7
+#define PRG_ETH0_CLK_M250_DIV_WIDTH 3
+
+/* divides the result of m25_sel by either 5 (bit unset) or 10 (bit set) */
+#define PRG_ETH0_CLK_M25_DIV_SHIFT 10
+#define PRG_ETH0_CLK_M25_DIV_WIDTH 1
+
+#define PRG_ETH0_INVERTED_RMII_CLK BIT(11)
+#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12)
+
+#define MUX_CLK_NUM_PARENTS 2
+
+struct meson8b_dwmac {
+ struct platform_device *pdev;
+
+ void __iomem *regs;
+
+ phy_interface_t phy_mode;
+
+ struct clk_mux m250_mux;
+ struct clk *m250_mux_clk;
+ struct clk *m250_mux_parent[MUX_CLK_NUM_PARENTS];
+
+ struct clk_divider m250_div;
+ struct clk *m250_div_clk;
+
+ struct clk_divider m25_div;
+ struct clk *m25_div_clk;
+};
+
+static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
+ u32 mask, u32 value)
+{
+ u32 data;
+
+ data = readl(dwmac->regs + reg);
+ data &= ~mask;
+ data |= (value & mask);
+
+ writel(data, dwmac->regs + reg);
+}
+
+static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
+{
+ struct clk_init_data init;
+ int i, ret;
+ struct device *dev = &dwmac->pdev->dev;
+ char clk_name[32];
+ const char *clk_div_parents[1];
+ const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
+ static struct clk_div_table clk_25m_div_table[] = {
+ { .val = 0, .div = 5 },
+ { .val = 1, .div = 10 },
+ { /* sentinel */ },
+ };
+
+ /* get the mux parents from DT */
+ for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
+ char name[16];
+
+ snprintf(name, sizeof(name), "clkin%d", i);
+ dwmac->m250_mux_parent[i] = devm_clk_get(dev, name);
+ if (IS_ERR(dwmac->m250_mux_parent[i])) {
+ ret = PTR_ERR(dwmac->m250_mux_parent[i]);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Missing clock %s\n", name);
+ return ret;
+ }
+
+ mux_parent_names[i] =
+ __clk_get_name(dwmac->m250_mux_parent[i]);
+ }
+
+ /* create the m250_mux */
+ snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev));
+ init.name = clk_name;
+ init.ops = &clk_mux_ops;
+ init.flags = 0;
+ init.parent_names = mux_parent_names;
+ init.num_parents = MUX_CLK_NUM_PARENTS;
+
+ dwmac->m250_mux.reg = dwmac->regs + PRG_ETH0;
+ dwmac->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
+ dwmac->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
+ dwmac->m250_mux.flags = 0;
+ dwmac->m250_mux.table = NULL;
+ dwmac->m250_mux.hw.init = &init;
+
+ dwmac->m250_mux_clk = devm_clk_register(dev, &dwmac->m250_mux.hw);
+ if (WARN_ON(IS_ERR(dwmac->m250_mux_clk)))
+ return PTR_ERR(dwmac->m250_mux_clk);
+
+ /* create the m250_div */
+ snprintf(clk_name, sizeof(clk_name), "%s#m250_div", dev_name(dev));
+ init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
+ init.ops = &clk_divider_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ clk_div_parents[0] = __clk_get_name(dwmac->m250_mux_clk);
+ init.parent_names = clk_div_parents;
+ init.num_parents = ARRAY_SIZE(clk_div_parents);
+
+ dwmac->m250_div.reg = dwmac->regs + PRG_ETH0;
+ dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
+ dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
+ dwmac->m250_div.hw.init = &init;
+ dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
+
+ dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw);
+ if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
+ return PTR_ERR(dwmac->m250_div_clk);
+
+ /* create the m25_div */
+ snprintf(clk_name, sizeof(clk_name), "%s#m25_div", dev_name(dev));
+ init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
+ init.ops = &clk_divider_ops;
+ init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+ clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
+ init.parent_names = clk_div_parents;
+ init.num_parents = ARRAY_SIZE(clk_div_parents);
+
+ dwmac->m25_div.reg = dwmac->regs + PRG_ETH0;
+ dwmac->m25_div.shift = PRG_ETH0_CLK_M25_DIV_SHIFT;
+ dwmac->m25_div.width = PRG_ETH0_CLK_M25_DIV_WIDTH;
+ dwmac->m25_div.table = clk_25m_div_table;
+ dwmac->m25_div.hw.init = &init;
+ dwmac->m25_div.flags = CLK_DIVIDER_ALLOW_ZERO;
+
+ dwmac->m25_div_clk = devm_clk_register(dev, &dwmac->m25_div.hw);
+ if (WARN_ON(IS_ERR(dwmac->m25_div_clk)))
+ return PTR_ERR(dwmac->m25_div_clk);
+
+ return 0;
+}
+
+static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
+{
+ int ret;
+ unsigned long clk_rate;
+
+ switch (dwmac->phy_mode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ /* Generate a 25MHz clock for the PHY */
+ clk_rate = 25 * 1000 * 1000;
+
+ /* enable RGMII mode */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
+ PRG_ETH0_RGMII_MODE);
+
+ /* only relevant for RMII mode -> disable in RGMII mode */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
+ PRG_ETH0_INVERTED_RMII_CLK, 0);
+
+ /* TX clock delay - all known boards use a 1/4 cycle delay */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
+ PRG_ETH0_TXDLY_QUARTER);
+ break;
+
+ case PHY_INTERFACE_MODE_RMII:
+ /* Use the rate of the mux clock for the internal RMII PHY */
+ clk_rate = clk_get_rate(dwmac->m250_mux_clk);
+
+ /* disable RGMII mode -> enables RMII mode */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
+ 0);
+
+ /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
+ PRG_ETH0_INVERTED_RMII_CLK,
+ PRG_ETH0_INVERTED_RMII_CLK);
+
+ /* TX clock delay cannot be configured in RMII mode */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
+ 0);
+
+ break;
+
+ default:
+ dev_err(&dwmac->pdev->dev, "unsupported phy-mode %s\n",
+ phy_modes(dwmac->phy_mode));
+ return -EINVAL;
+ }
+
+ ret = clk_prepare_enable(dwmac->m25_div_clk);
+ if (ret) {
+ dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(dwmac->m25_div_clk, clk_rate);
+ if (ret) {
+ clk_disable_unprepare(dwmac->m25_div_clk);
+
+ dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n");
+ return ret;
+ }
+
+ /* enable TX_CLK and PHY_REF_CLK generator */
+ meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
+ PRG_ETH0_TX_AND_PHY_REF_CLK);
+
+ return 0;
+}
+
+static int meson8b_dwmac_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct resource *res;
+ struct meson8b_dwmac *dwmac;
+ int ret;
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return ret;
+
+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+ if (IS_ERR(plat_dat))
+ return PTR_ERR(plat_dat);
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dwmac->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dwmac->regs))
+ return PTR_ERR(dwmac->regs);
+
+ dwmac->pdev = pdev;
+ dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
+ if (dwmac->phy_mode < 0) {
+ dev_err(&pdev->dev, "missing phy-mode property\n");
+ return -EINVAL;
+ }
+
+ ret = meson8b_init_clk(dwmac);
+ if (ret)
+ return ret;
+
+ ret = meson8b_init_prg_eth(dwmac);
+ if (ret)
+ return ret;
+
+ plat_dat->bsp_priv = dwmac;
+
+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+}
+
+static int meson8b_dwmac_remove(struct platform_device *pdev)
+{
+ struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
+
+ clk_disable_unprepare(dwmac->m25_div_clk);
+
+ return stmmac_pltfr_remove(pdev);
+}
+
+static const struct of_device_id meson8b_dwmac_match[] = {
+ { .compatible = "amlogic,meson8b-dwmac" },
+ { .compatible = "amlogic,meson-gxbb-dwmac" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
+
+static struct platform_driver meson8b_dwmac_driver = {
+ .probe = meson8b_dwmac_probe,
+ .remove = meson8b_dwmac_remove,
+ .driver = {
+ .name = "meson8b-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = meson8b_dwmac_match,
+ },
+};
+module_platform_driver(meson8b_dwmac_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Amlogic Meson8b and GXBB DWMAC glue layer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index ffeb8d9e2b2e..64e147f53a9c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -30,4 +30,12 @@ int stmmac_get_platform_resources(struct platform_device *pdev,
int stmmac_pltfr_remove(struct platform_device *pdev);
extern const struct dev_pm_ops stmmac_pltfr_pm_ops;
+static inline void *get_stmmac_bsp_priv(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
+
+ return priv->plat->bsp_priv;
+}
+
#endif /* __STMMAC_PLATFORM_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
index f6591c83d636..affe760c8c22 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
@@ -2422,14 +2422,12 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
*/
if (priv->mac80211_registered) {
char buf[100];
- struct dentry *mac80211_dir, *dev_dir, *root_dir;
+ struct dentry *mac80211_dir, *dev_dir;
dev_dir = dbgfs_dir->d_parent;
- root_dir = dev_dir->d_parent;
mac80211_dir = priv->hw->wiphy->debugfsdir;
- snprintf(buf, 100, "../../%s/%s", root_dir->d_name.name,
- dev_dir->d_name.name);
+ snprintf(buf, 100, "../../%pd2", dev_dir);
if (!debugfs_create_symlink("iwlwifi", mac80211_dir, buf))
goto err;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 2d6f44fbaf62..f4d75ffe3d8a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -1571,8 +1571,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
if (!mvmvif->dbgfs_dir) {
- IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
- dbgfs_dir->d_name.name);
+ IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
+ dbgfs_dir);
return;
}
@@ -1627,17 +1627,15 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* find
* netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
*/
- snprintf(buf, 100, "../../../%s/%s/%s/%s",
- dbgfs_dir->d_parent->d_parent->d_name.name,
- dbgfs_dir->d_parent->d_name.name,
- dbgfs_dir->d_name.name,
- mvmvif->dbgfs_dir->d_name.name);
+ snprintf(buf, 100, "../../../%pd3/%pd",
+ dbgfs_dir,
+ mvmvif->dbgfs_dir);
mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
mvm->debugfs_dir, buf);
if (!mvmvif->dbgfs_slink)
- IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
- dbgfs_dir->d_name.name);
+ IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
+ dbgfs_dir);
return;
err:
IWL_ERR(mvm, "Can't create debugfs entity\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 539d718df797..07da4efe8458 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1748,9 +1748,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
* Create a symlink with mac80211. It will be removed when mac80211
* exists (before the opmode exists which removes the target.)
*/
- snprintf(buf, 100, "../../%s/%s",
- dbgfs_dir->d_parent->d_parent->d_name.name,
- dbgfs_dir->d_parent->d_name.name);
+ snprintf(buf, 100, "../../%pd2", dbgfs_dir->d_parent);
if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
goto err;
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index d5c5894f252e..8601c10acf74 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -102,13 +102,16 @@ struct ntb_queue_entry {
void *buf;
unsigned int len;
unsigned int flags;
+ int retries;
+ int errors;
+ unsigned int tx_index;
+ unsigned int rx_index;
struct ntb_transport_qp *qp;
union {
struct ntb_payload_header __iomem *tx_hdr;
struct ntb_payload_header *rx_hdr;
};
- unsigned int index;
};
struct ntb_rx_info {
@@ -259,6 +262,12 @@ enum {
static void ntb_transport_rxc_db(unsigned long data);
static const struct ntb_ctx_ops ntb_transport_ops;
static struct ntb_client ntb_transport_client;
+static int ntb_async_tx_submit(struct ntb_transport_qp *qp,
+ struct ntb_queue_entry *entry);
+static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset);
+static int ntb_async_rx_submit(struct ntb_queue_entry *entry, void *offset);
+static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset);
+
static int ntb_transport_bus_match(struct device *dev,
struct device_driver *drv)
@@ -1229,7 +1238,7 @@ static void ntb_complete_rxc(struct ntb_transport_qp *qp)
break;
entry->rx_hdr->flags = 0;
- iowrite32(entry->index, &qp->rx_info->entry);
+ iowrite32(entry->rx_index, &qp->rx_info->entry);
cb_data = entry->cb_data;
len = entry->len;
@@ -1247,10 +1256,36 @@ static void ntb_complete_rxc(struct ntb_transport_qp *qp)
spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
}
-static void ntb_rx_copy_callback(void *data)
+static void ntb_rx_copy_callback(void *data,
+ const struct dmaengine_result *res)
{
struct ntb_queue_entry *entry = data;
+ /* we need to check DMA results if we are using DMA */
+ if (res) {
+ enum dmaengine_tx_result dma_err = res->result;
+
+ switch (dma_err) {
+ case DMA_TRANS_READ_FAILED:
+ case DMA_TRANS_WRITE_FAILED:
+ entry->errors++;
+ case DMA_TRANS_ABORTED:
+ {
+ struct ntb_transport_qp *qp = entry->qp;
+ void *offset = qp->rx_buff + qp->rx_max_frame *
+ qp->rx_index;
+
+ ntb_memcpy_rx(entry, offset);
+ qp->rx_memcpy++;
+ return;
+ }
+
+ case DMA_TRANS_NOERROR:
+ default:
+ break;
+ }
+ }
+
entry->flags |= DESC_DONE_FLAG;
ntb_complete_rxc(entry->qp);
@@ -1266,10 +1301,10 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
/* Ensure that the data is fully copied out before clearing the flag */
wmb();
- ntb_rx_copy_callback(entry);
+ ntb_rx_copy_callback(entry, NULL);
}
-static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
+static int ntb_async_rx_submit(struct ntb_queue_entry *entry, void *offset)
{
struct dma_async_tx_descriptor *txd;
struct ntb_transport_qp *qp = entry->qp;
@@ -1282,13 +1317,6 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
int retries = 0;
len = entry->len;
-
- if (!chan)
- goto err;
-
- if (len < copy_bytes)
- goto err;
-
device = chan->device;
pay_off = (size_t)offset & ~PAGE_MASK;
buff_off = (size_t)buf & ~PAGE_MASK;
@@ -1316,7 +1344,8 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
unmap->from_cnt = 1;
for (retries = 0; retries < DMA_RETRIES; retries++) {
- txd = device->device_prep_dma_memcpy(chan, unmap->addr[1],
+ txd = device->device_prep_dma_memcpy(chan,
+ unmap->addr[1],
unmap->addr[0], len,
DMA_PREP_INTERRUPT);
if (txd)
@@ -1331,7 +1360,7 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
goto err_get_unmap;
}
- txd->callback = ntb_rx_copy_callback;
+ txd->callback_result = ntb_rx_copy_callback;
txd->callback_param = entry;
dma_set_unmap(txd, unmap);
@@ -1345,13 +1374,38 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
qp->rx_async++;
- return;
+ return 0;
err_set_unmap:
dmaengine_unmap_put(unmap);
err_get_unmap:
dmaengine_unmap_put(unmap);
err:
+ return -ENXIO;
+}
+
+static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
+{
+ struct ntb_transport_qp *qp = entry->qp;
+ struct dma_chan *chan = qp->rx_dma_chan;
+ int res;
+
+ if (!chan)
+ goto err;
+
+ if (entry->len < copy_bytes)
+ goto err;
+
+ res = ntb_async_rx_submit(entry, offset);
+ if (res < 0)
+ goto err;
+
+ if (!entry->retries)
+ qp->rx_async++;
+
+ return;
+
+err:
ntb_memcpy_rx(entry, offset);
qp->rx_memcpy++;
}
@@ -1397,7 +1451,7 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
}
entry->rx_hdr = hdr;
- entry->index = qp->rx_index;
+ entry->rx_index = qp->rx_index;
if (hdr->len > entry->len) {
dev_dbg(&qp->ndev->pdev->dev,
@@ -1467,12 +1521,39 @@ static void ntb_transport_rxc_db(unsigned long data)
}
}
-static void ntb_tx_copy_callback(void *data)
+static void ntb_tx_copy_callback(void *data,
+ const struct dmaengine_result *res)
{
struct ntb_queue_entry *entry = data;
struct ntb_transport_qp *qp = entry->qp;
struct ntb_payload_header __iomem *hdr = entry->tx_hdr;
+ /* we need to check DMA results if we are using DMA */
+ if (res) {
+ enum dmaengine_tx_result dma_err = res->result;
+
+ switch (dma_err) {
+ case DMA_TRANS_READ_FAILED:
+ case DMA_TRANS_WRITE_FAILED:
+ entry->errors++;
+ case DMA_TRANS_ABORTED:
+ {
+ void __iomem *offset =
+ qp->tx_mw + qp->tx_max_frame *
+ entry->tx_index;
+
+ /* resubmit via CPU */
+ ntb_memcpy_tx(entry, offset);
+ qp->tx_memcpy++;
+ return;
+ }
+
+ case DMA_TRANS_NOERROR:
+ default:
+ break;
+ }
+ }
+
iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags);
ntb_peer_db_set(qp->ndev, BIT_ULL(qp->qp_num));
@@ -1507,40 +1588,25 @@ static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset)
/* Ensure that the data is fully copied out before setting the flags */
wmb();
- ntb_tx_copy_callback(entry);
+ ntb_tx_copy_callback(entry, NULL);
}
-static void ntb_async_tx(struct ntb_transport_qp *qp,
- struct ntb_queue_entry *entry)
+static int ntb_async_tx_submit(struct ntb_transport_qp *qp,
+ struct ntb_queue_entry *entry)
{
- struct ntb_payload_header __iomem *hdr;
struct dma_async_tx_descriptor *txd;
struct dma_chan *chan = qp->tx_dma_chan;
struct dma_device *device;
+ size_t len = entry->len;
+ void *buf = entry->buf;
size_t dest_off, buff_off;
struct dmaengine_unmap_data *unmap;
dma_addr_t dest;
dma_cookie_t cookie;
- void __iomem *offset;
- size_t len = entry->len;
- void *buf = entry->buf;
int retries = 0;
- offset = qp->tx_mw + qp->tx_max_frame * qp->tx_index;
- hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header);
- entry->tx_hdr = hdr;
-
- iowrite32(entry->len, &hdr->len);
- iowrite32((u32)qp->tx_pkts, &hdr->ver);
-
- if (!chan)
- goto err;
-
- if (len < copy_bytes)
- goto err;
-
device = chan->device;
- dest = qp->tx_mw_phys + qp->tx_max_frame * qp->tx_index;
+ dest = qp->tx_mw_phys + qp->tx_max_frame * entry->tx_index;
buff_off = (size_t)buf & ~PAGE_MASK;
dest_off = (size_t)dest & ~PAGE_MASK;
@@ -1560,8 +1626,9 @@ static void ntb_async_tx(struct ntb_transport_qp *qp,
unmap->to_cnt = 1;
for (retries = 0; retries < DMA_RETRIES; retries++) {
- txd = device->device_prep_dma_memcpy(chan, dest, unmap->addr[0],
- len, DMA_PREP_INTERRUPT);
+ txd = device->device_prep_dma_memcpy(chan, dest,
+ unmap->addr[0], len,
+ DMA_PREP_INTERRUPT);
if (txd)
break;
@@ -1574,7 +1641,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp,
goto err_get_unmap;
}
- txd->callback = ntb_tx_copy_callback;
+ txd->callback_result = ntb_tx_copy_callback;
txd->callback_param = entry;
dma_set_unmap(txd, unmap);
@@ -1585,14 +1652,48 @@ static void ntb_async_tx(struct ntb_transport_qp *qp,
dmaengine_unmap_put(unmap);
dma_async_issue_pending(chan);
- qp->tx_async++;
- return;
+ return 0;
err_set_unmap:
dmaengine_unmap_put(unmap);
err_get_unmap:
dmaengine_unmap_put(unmap);
err:
+ return -ENXIO;
+}
+
+static void ntb_async_tx(struct ntb_transport_qp *qp,
+ struct ntb_queue_entry *entry)
+{
+ struct ntb_payload_header __iomem *hdr;
+ struct dma_chan *chan = qp->tx_dma_chan;
+ void __iomem *offset;
+ int res;
+
+ entry->tx_index = qp->tx_index;
+ offset = qp->tx_mw + qp->tx_max_frame * entry->tx_index;
+ hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header);
+ entry->tx_hdr = hdr;
+
+ iowrite32(entry->len, &hdr->len);
+ iowrite32((u32)qp->tx_pkts, &hdr->ver);
+
+ if (!chan)
+ goto err;
+
+ if (entry->len < copy_bytes)
+ goto err;
+
+ res = ntb_async_tx_submit(qp, entry);
+ if (res < 0)
+ goto err;
+
+ if (!entry->retries)
+ qp->tx_async++;
+
+ return;
+
+err:
ntb_memcpy_tx(entry, offset);
qp->tx_memcpy++;
}
@@ -1928,6 +2029,9 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
entry->buf = data;
entry->len = len;
entry->flags = 0;
+ entry->retries = 0;
+ entry->errors = 0;
+ entry->rx_index = 0;
ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q);
@@ -1970,6 +2074,9 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
entry->buf = data;
entry->len = len;
entry->flags = 0;
+ entry->errors = 0;
+ entry->retries = 0;
+ entry->tx_index = 0;
rc = ntb_process_tx(qp, entry);
if (rc)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 2feacc70bf61..329381a28edf 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -156,12 +156,14 @@ static void nvme_free_ns(struct kref *kref)
{
struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
- if (ns->type == NVME_NS_LIGHTNVM)
- nvme_nvm_unregister(ns->queue, ns->disk->disk_name);
+ if (ns->ndev)
+ nvme_nvm_unregister(ns);
- spin_lock(&dev_list_lock);
- ns->disk->private_data = NULL;
- spin_unlock(&dev_list_lock);
+ if (ns->disk) {
+ spin_lock(&dev_list_lock);
+ ns->disk->private_data = NULL;
+ spin_unlock(&dev_list_lock);
+ }
put_disk(ns->disk);
ida_simple_remove(&ns->ctrl->ns_ida, ns->instance);
@@ -597,7 +599,7 @@ int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
}
int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
- dma_addr_t dma_addr, u32 *result)
+ void *buffer, size_t buflen, u32 *result)
{
struct nvme_command c;
struct nvme_completion cqe;
@@ -606,10 +608,9 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
memset(&c, 0, sizeof(c));
c.features.opcode = nvme_admin_get_features;
c.features.nsid = cpu_to_le32(nsid);
- c.features.dptr.prp1 = cpu_to_le64(dma_addr);
c.features.fid = cpu_to_le32(fid);
- ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0,
+ ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, buffer, buflen, 0,
NVME_QID_ANY, 0, 0);
if (ret >= 0 && result)
*result = le32_to_cpu(cqe.result);
@@ -617,7 +618,7 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
}
int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
- dma_addr_t dma_addr, u32 *result)
+ void *buffer, size_t buflen, u32 *result)
{
struct nvme_command c;
struct nvme_completion cqe;
@@ -625,12 +626,11 @@ int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
memset(&c, 0, sizeof(c));
c.features.opcode = nvme_admin_set_features;
- c.features.dptr.prp1 = cpu_to_le64(dma_addr);
c.features.fid = cpu_to_le32(fid);
c.features.dword11 = cpu_to_le32(dword11);
- ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0,
- NVME_QID_ANY, 0, 0);
+ ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe,
+ buffer, buflen, 0, NVME_QID_ANY, 0, 0);
if (ret >= 0 && result)
*result = le32_to_cpu(cqe.result);
return ret;
@@ -664,7 +664,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
u32 result;
int status, nr_io_queues;
- status = nvme_set_features(ctrl, NVME_FEAT_NUM_QUEUES, q_count, 0,
+ status = nvme_set_features(ctrl, NVME_FEAT_NUM_QUEUES, q_count, NULL, 0,
&result);
if (status < 0)
return status;
@@ -888,42 +888,32 @@ static void nvme_config_discard(struct nvme_ns *ns)
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
}
-static int nvme_revalidate_disk(struct gendisk *disk)
+static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
{
- struct nvme_ns *ns = disk->private_data;
- struct nvme_id_ns *id;
- u8 lbaf, pi_type;
- u16 old_ms;
- unsigned short bs;
-
- if (test_bit(NVME_NS_DEAD, &ns->flags)) {
- set_capacity(disk, 0);
- return -ENODEV;
- }
- if (nvme_identify_ns(ns->ctrl, ns->ns_id, &id)) {
- dev_warn(disk_to_dev(ns->disk), "%s: Identify failure\n",
- __func__);
- return -ENODEV;
- }
- if (id->ncap == 0) {
- kfree(id);
+ if (nvme_identify_ns(ns->ctrl, ns->ns_id, id)) {
+ dev_warn(ns->ctrl->dev, "%s: Identify failure\n", __func__);
return -ENODEV;
}
- if (nvme_nvm_ns_supported(ns, id) && ns->type != NVME_NS_LIGHTNVM) {
- if (nvme_nvm_register(ns->queue, disk->disk_name)) {
- dev_warn(disk_to_dev(ns->disk),
- "%s: LightNVM init failure\n", __func__);
- kfree(id);
- return -ENODEV;
- }
- ns->type = NVME_NS_LIGHTNVM;
+ if ((*id)->ncap == 0) {
+ kfree(*id);
+ return -ENODEV;
}
if (ns->ctrl->vs >= NVME_VS(1, 1))
- memcpy(ns->eui, id->eui64, sizeof(ns->eui));
+ memcpy(ns->eui, (*id)->eui64, sizeof(ns->eui));
if (ns->ctrl->vs >= NVME_VS(1, 2))
- memcpy(ns->uuid, id->nguid, sizeof(ns->uuid));
+ memcpy(ns->uuid, (*id)->nguid, sizeof(ns->uuid));
+
+ return 0;
+}
+
+static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
+{
+ struct nvme_ns *ns = disk->private_data;
+ u8 lbaf, pi_type;
+ u16 old_ms;
+ unsigned short bs;
old_ms = ns->ms;
lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
@@ -962,8 +952,26 @@ static int nvme_revalidate_disk(struct gendisk *disk)
if (ns->ctrl->oncs & NVME_CTRL_ONCS_DSM)
nvme_config_discard(ns);
blk_mq_unfreeze_queue(disk->queue);
+}
+
+static int nvme_revalidate_disk(struct gendisk *disk)
+{
+ struct nvme_ns *ns = disk->private_data;
+ struct nvme_id_ns *id = NULL;
+ int ret;
+
+ if (test_bit(NVME_NS_DEAD, &ns->flags)) {
+ set_capacity(disk, 0);
+ return -ENODEV;
+ }
+
+ ret = nvme_revalidate_ns(ns, &id);
+ if (ret)
+ return ret;
+ __nvme_revalidate_disk(disk, id);
kfree(id);
+
return 0;
}
@@ -1425,7 +1433,7 @@ static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan);
static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
struct nvme_ctrl *ctrl = ns->ctrl;
int serial_len = sizeof(ctrl->serial);
int model_len = sizeof(ctrl->model);
@@ -1449,7 +1457,7 @@ static DEVICE_ATTR(wwid, S_IRUGO, wwid_show, NULL);
static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
return sprintf(buf, "%pU\n", ns->uuid);
}
static DEVICE_ATTR(uuid, S_IRUGO, uuid_show, NULL);
@@ -1457,7 +1465,7 @@ static DEVICE_ATTR(uuid, S_IRUGO, uuid_show, NULL);
static ssize_t eui_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
return sprintf(buf, "%8phd\n", ns->eui);
}
static DEVICE_ATTR(eui, S_IRUGO, eui_show, NULL);
@@ -1465,7 +1473,7 @@ static DEVICE_ATTR(eui, S_IRUGO, eui_show, NULL);
static ssize_t nsid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
return sprintf(buf, "%d\n", ns->ns_id);
}
static DEVICE_ATTR(nsid, S_IRUGO, nsid_show, NULL);
@@ -1482,7 +1490,7 @@ static umode_t nvme_ns_attrs_are_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
if (a == &dev_attr_uuid.attr) {
if (!memchr_inv(ns->uuid, 0, sizeof(ns->uuid)))
@@ -1642,6 +1650,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
{
struct nvme_ns *ns;
struct gendisk *disk;
+ struct nvme_id_ns *id;
+ char disk_name[DISK_NAME_LEN];
int node = dev_to_node(ctrl->dev);
ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
@@ -1659,34 +1669,49 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
ns->queue->queuedata = ns;
ns->ctrl = ctrl;
- disk = alloc_disk_node(0, node);
- if (!disk)
- goto out_free_queue;
-
kref_init(&ns->kref);
ns->ns_id = nsid;
- ns->disk = disk;
ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
-
blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
nvme_set_queue_limits(ctrl, ns->queue);
- disk->fops = &nvme_fops;
- disk->private_data = ns;
- disk->queue = ns->queue;
- disk->flags = GENHD_FL_EXT_DEVT;
- sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
+ sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
+
+ if (nvme_revalidate_ns(ns, &id))
+ goto out_free_queue;
+
+ if (nvme_nvm_ns_supported(ns, id)) {
+ if (nvme_nvm_register(ns, disk_name, node,
+ &nvme_ns_attr_group)) {
+ dev_warn(ctrl->dev, "%s: LightNVM init failure\n",
+ __func__);
+ goto out_free_id;
+ }
+ } else {
+ disk = alloc_disk_node(0, node);
+ if (!disk)
+ goto out_free_id;
+
+ disk->fops = &nvme_fops;
+ disk->private_data = ns;
+ disk->queue = ns->queue;
+ disk->flags = GENHD_FL_EXT_DEVT;
+ memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
+ ns->disk = disk;
- if (nvme_revalidate_disk(ns->disk))
- goto out_free_disk;
+ __nvme_revalidate_disk(disk, id);
+ }
mutex_lock(&ctrl->namespaces_mutex);
list_add_tail(&ns->list, &ctrl->namespaces);
mutex_unlock(&ctrl->namespaces_mutex);
kref_get(&ctrl->kref);
- if (ns->type == NVME_NS_LIGHTNVM)
+
+ kfree(id);
+
+ if (ns->ndev)
return;
device_add_disk(ctrl->device, ns->disk);
@@ -1695,8 +1720,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
pr_warn("%s: failed to create sysfs group for identification\n",
ns->disk->disk_name);
return;
- out_free_disk:
- kfree(disk);
+ out_free_id:
+ kfree(id);
out_free_queue:
blk_cleanup_queue(ns->queue);
out_release_instance:
@@ -1710,7 +1735,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
return;
- if (ns->disk->flags & GENHD_FL_UP) {
+ if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
if (blk_get_integrity(ns->disk))
blk_integrity_unregister(ns->disk);
sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
@@ -1733,7 +1758,7 @@ static void nvme_validate_ns(struct nvme_ctrl *ctrl, unsigned nsid)
ns = nvme_find_get_ns(ctrl, nsid);
if (ns) {
- if (revalidate_disk(ns->disk))
+ if (ns->disk && revalidate_disk(ns->disk))
nvme_ns_remove(ns);
nvme_put_ns(ns);
} else
@@ -1826,9 +1851,6 @@ static void nvme_scan_work(struct work_struct *work)
list_sort(NULL, &ctrl->namespaces, ns_cmp);
mutex_unlock(&ctrl->namespaces_mutex);
kfree(id);
-
- if (ctrl->ops->post_scan)
- ctrl->ops->post_scan(ctrl);
}
void nvme_queue_scan(struct nvme_ctrl *ctrl)
@@ -2038,7 +2060,7 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
* Revalidating a dead namespace sets capacity to 0. This will
* end buffered writers dirtying pages that can't be synced.
*/
- if (!test_and_set_bit(NVME_NS_DEAD, &ns->flags))
+ if (ns->disk && !test_and_set_bit(NVME_NS_DEAD, &ns->flags))
revalidate_disk(ns->disk);
blk_set_queue_dying(ns->queue);
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 4eff49174466..5a3f008d3480 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -111,8 +111,19 @@ static void nvmf_host_put(struct nvmf_host *host)
*/
int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
{
- return snprintf(buf, size, "traddr=%s,trsvcid=%s\n",
- ctrl->opts->traddr, ctrl->opts->trsvcid);
+ int len = 0;
+
+ if (ctrl->opts->mask & NVMF_OPT_TRADDR)
+ len += snprintf(buf, size, "traddr=%s", ctrl->opts->traddr);
+ if (ctrl->opts->mask & NVMF_OPT_TRSVCID)
+ len += snprintf(buf + len, size - len, "%strsvcid=%s",
+ (len) ? "," : "", ctrl->opts->trsvcid);
+ if (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)
+ len += snprintf(buf + len, size - len, "%shost_traddr=%s",
+ (len) ? "," : "", ctrl->opts->host_traddr);
+ len += snprintf(buf + len, size - len, "\n");
+
+ return len;
}
EXPORT_SYMBOL_GPL(nvmf_get_address);
@@ -519,6 +530,7 @@ static const match_table_t opt_tokens = {
{ NVMF_OPT_RECONNECT_DELAY, "reconnect_delay=%d" },
{ NVMF_OPT_KATO, "keep_alive_tmo=%d" },
{ NVMF_OPT_HOSTNQN, "hostnqn=%s" },
+ { NVMF_OPT_HOST_TRADDR, "host_traddr=%s" },
{ NVMF_OPT_ERR, NULL }
};
@@ -675,6 +687,14 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
}
opts->reconnect_delay = token;
break;
+ case NVMF_OPT_HOST_TRADDR:
+ p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ opts->host_traddr = p;
+ break;
default:
pr_warn("unknown parameter or missing value '%s' in ctrl creation request\n",
p);
@@ -741,6 +761,7 @@ void nvmf_free_options(struct nvmf_ctrl_options *opts)
kfree(opts->traddr);
kfree(opts->trsvcid);
kfree(opts->subsysnqn);
+ kfree(opts->host_traddr);
kfree(opts);
}
EXPORT_SYMBOL_GPL(nvmf_free_options);
diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h
index 46e460aee52d..924145c979f1 100644
--- a/drivers/nvme/host/fabrics.h
+++ b/drivers/nvme/host/fabrics.h
@@ -52,6 +52,7 @@ enum {
NVMF_OPT_KATO = 1 << 7,
NVMF_OPT_HOSTNQN = 1 << 8,
NVMF_OPT_RECONNECT_DELAY = 1 << 9,
+ NVMF_OPT_HOST_TRADDR = 1 << 10,
};
/**
@@ -64,9 +65,12 @@ enum {
* being added.
* @subsysnqn: Hold the fully qualified NQN subystem name (format defined
* in the NVMe specification, "NVMe Qualified Names").
- * @traddr: network address that will be used by the host to communicate
- * to the added NVMe controller.
- * @trsvcid: network port used for host-controller communication.
+ * @traddr: The transport-specific TRADDR field for a port on the
+ * subsystem which is adding a controller.
+ * @trsvcid: The transport-specific TRSVCID field for a port on the
+ * subsystem which is adding a controller.
+ * @host_traddr: A transport-specific field identifying the NVME host port
+ * to use for the connection to the controller.
* @queue_size: Number of IO queue elements.
* @nr_io_queues: Number of controller IO queues that will be established.
* @reconnect_delay: Time between two consecutive reconnect attempts.
@@ -80,6 +84,7 @@ struct nvmf_ctrl_options {
char *subsysnqn;
char *traddr;
char *trsvcid;
+ char *host_traddr;
size_t queue_size;
unsigned int nr_io_queues;
unsigned int reconnect_delay;
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 63f483daf930..f5e3011e31fc 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -475,7 +475,7 @@ static inline void nvme_nvm_rqtocmd(struct request *rq, struct nvm_rq *rqd,
if (rqd->opcode == NVM_OP_HBWRITE || rqd->opcode == NVM_OP_HBREAD)
c->hb_rw.slba = cpu_to_le64(nvme_block_nr(ns,
- rqd->bio->bi_iter.bi_sector));
+ rqd->bio->bi_iter.bi_sector));
}
static void nvme_nvm_end_io(struct request *rq, int error)
@@ -592,14 +592,37 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
.max_phys_sect = 64,
};
-int nvme_nvm_register(struct request_queue *q, char *disk_name)
+int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node,
+ const struct attribute_group *attrs)
{
- return nvm_register(q, disk_name, &nvme_nvm_dev_ops);
+ struct request_queue *q = ns->queue;
+ struct nvm_dev *dev;
+ int ret;
+
+ dev = nvm_alloc_dev(node);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->q = q;
+ memcpy(dev->name, disk_name, DISK_NAME_LEN);
+ dev->ops = &nvme_nvm_dev_ops;
+ dev->parent_dev = ns->ctrl->device;
+ dev->private_data = ns;
+ ns->ndev = dev;
+
+ ret = nvm_register(dev);
+
+ ns->lba_shift = ilog2(dev->sec_size) - 9;
+
+ if (sysfs_create_group(&dev->dev.kobj, attrs))
+ pr_warn("%s: failed to create sysfs group for identification\n",
+ disk_name);
+ return ret;
}
-void nvme_nvm_unregister(struct request_queue *q, char *disk_name)
+void nvme_nvm_unregister(struct nvme_ns *ns)
{
- nvm_unregister(disk_name);
+ nvm_unregister(ns->ndev);
}
/* move to shared place when used in multiple places. */
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ab18b78102bf..d47f5a5d18c7 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/kref.h>
#include <linux/blk-mq.h>
+#include <linux/lightnvm.h>
enum {
/*
@@ -154,6 +155,7 @@ struct nvme_ns {
struct nvme_ctrl *ctrl;
struct request_queue *queue;
struct gendisk *disk;
+ struct nvm_dev *ndev;
struct kref kref;
int instance;
@@ -165,7 +167,6 @@ struct nvme_ns {
u16 ms;
bool ext;
u8 pi_type;
- int type;
unsigned long flags;
#define NVME_NS_REMOVING 0
@@ -184,7 +185,6 @@ struct nvme_ctrl_ops {
int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
int (*reset_ctrl)(struct nvme_ctrl *ctrl);
void (*free_ctrl)(struct nvme_ctrl *ctrl);
- void (*post_scan)(struct nvme_ctrl *ctrl);
void (*submit_async_event)(struct nvme_ctrl *ctrl, int aer_idx);
int (*delete_ctrl)(struct nvme_ctrl *ctrl);
const char *(*get_subsysnqn)(struct nvme_ctrl *ctrl);
@@ -292,9 +292,9 @@ int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
struct nvme_id_ns **id);
int nvme_get_log_page(struct nvme_ctrl *dev, struct nvme_smart_log **log);
int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
- dma_addr_t dma_addr, u32 *result);
+ void *buffer, size_t buflen, u32 *result);
int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
- dma_addr_t dma_addr, u32 *result);
+ void *buffer, size_t buflen, u32 *result);
int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count);
void nvme_start_keep_alive(struct nvme_ctrl *ctrl);
void nvme_stop_keep_alive(struct nvme_ctrl *ctrl);
@@ -307,20 +307,35 @@ int nvme_sg_get_version_num(int __user *ip);
#ifdef CONFIG_NVM
int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id);
-int nvme_nvm_register(struct request_queue *q, char *disk_name);
-void nvme_nvm_unregister(struct request_queue *q, char *disk_name);
+int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node,
+ const struct attribute_group *attrs);
+void nvme_nvm_unregister(struct nvme_ns *ns);
+
+static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
+{
+ if (dev->type->devnode)
+ return dev_to_disk(dev)->private_data;
+
+ return (container_of(dev, struct nvm_dev, dev))->private_data;
+}
#else
-static inline int nvme_nvm_register(struct request_queue *q, char *disk_name)
+static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name,
+ int node,
+ const struct attribute_group *attrs)
{
return 0;
}
-static inline void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {};
+static inline void nvme_nvm_unregister(struct nvme_ns *ns) {};
static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
{
return 0;
}
+static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
+{
+ return dev_to_disk(dev)->private_data;
+}
#endif /* CONFIG_NVM */
int __init nvme_core_init(void);
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 60f7eab11865..68ef1875e8a8 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -16,6 +16,7 @@
#include <linux/bitops.h>
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
+#include <linux/blk-mq-pci.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -88,7 +89,6 @@ struct nvme_dev {
unsigned max_qid;
int q_depth;
u32 db_stride;
- struct msix_entry *entry;
void __iomem *bar;
struct work_struct reset_work;
struct work_struct remove_work;
@@ -201,6 +201,11 @@ static unsigned int nvme_cmd_size(struct nvme_dev *dev)
nvme_iod_alloc_size(dev, NVME_INT_BYTES(dev), NVME_INT_PAGES);
}
+static int nvmeq_irq(struct nvme_queue *nvmeq)
+{
+ return pci_irq_vector(to_pci_dev(nvmeq->dev->dev), nvmeq->cq_vector);
+}
+
static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
unsigned int hctx_idx)
{
@@ -263,6 +268,13 @@ static int nvme_init_request(void *data, struct request *req,
return 0;
}
+static int nvme_pci_map_queues(struct blk_mq_tag_set *set)
+{
+ struct nvme_dev *dev = set->driver_data;
+
+ return blk_mq_pci_map_queues(set, to_pci_dev(dev->dev));
+}
+
/**
* __nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
* @nvmeq: The queue to use
@@ -960,7 +972,7 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq)
spin_unlock_irq(&nvmeq->q_lock);
return 1;
}
- vector = nvmeq->dev->entry[nvmeq->cq_vector].vector;
+ vector = nvmeq_irq(nvmeq);
nvmeq->dev->online_queues--;
nvmeq->cq_vector = -1;
spin_unlock_irq(&nvmeq->q_lock);
@@ -968,7 +980,6 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq)
if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q)
blk_mq_stop_hw_queues(nvmeq->dev->ctrl.admin_q);
- irq_set_affinity_hint(vector, NULL);
free_irq(vector, nvmeq);
return 0;
@@ -1075,15 +1086,14 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
return NULL;
}
-static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq,
- const char *name)
+static int queue_request_irq(struct nvme_queue *nvmeq)
{
if (use_threaded_interrupts)
- return request_threaded_irq(dev->entry[nvmeq->cq_vector].vector,
- nvme_irq_check, nvme_irq, IRQF_SHARED,
- name, nvmeq);
- return request_irq(dev->entry[nvmeq->cq_vector].vector, nvme_irq,
- IRQF_SHARED, name, nvmeq);
+ return request_threaded_irq(nvmeq_irq(nvmeq), nvme_irq_check,
+ nvme_irq, IRQF_SHARED, nvmeq->irqname, nvmeq);
+ else
+ return request_irq(nvmeq_irq(nvmeq), nvme_irq, IRQF_SHARED,
+ nvmeq->irqname, nvmeq);
}
static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid)
@@ -1114,7 +1124,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
if (result < 0)
goto release_cq;
- result = queue_request_irq(dev, nvmeq, nvmeq->irqname);
+ result = queue_request_irq(nvmeq);
if (result < 0)
goto release_sq;
@@ -1131,7 +1141,6 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
static struct blk_mq_ops nvme_mq_admin_ops = {
.queue_rq = nvme_queue_rq,
.complete = nvme_complete_rq,
- .map_queue = blk_mq_map_queue,
.init_hctx = nvme_admin_init_hctx,
.exit_hctx = nvme_admin_exit_hctx,
.init_request = nvme_admin_init_request,
@@ -1141,9 +1150,9 @@ static struct blk_mq_ops nvme_mq_admin_ops = {
static struct blk_mq_ops nvme_mq_ops = {
.queue_rq = nvme_queue_rq,
.complete = nvme_complete_rq,
- .map_queue = blk_mq_map_queue,
.init_hctx = nvme_init_hctx,
.init_request = nvme_init_request,
+ .map_queues = nvme_pci_map_queues,
.timeout = nvme_timeout,
.poll = nvme_poll,
};
@@ -1234,7 +1243,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
goto free_nvmeq;
nvmeq->cq_vector = 0;
- result = queue_request_irq(dev, nvmeq, nvmeq->irqname);
+ result = queue_request_irq(nvmeq);
if (result) {
nvmeq->cq_vector = -1;
goto free_nvmeq;
@@ -1382,7 +1391,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
{
struct nvme_queue *adminq = dev->queues[0];
struct pci_dev *pdev = to_pci_dev(dev->dev);
- int result, i, vecs, nr_io_queues, size;
+ int result, nr_io_queues, size;
nr_io_queues = num_online_cpus();
result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues);
@@ -1417,29 +1426,18 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
}
/* Deregister the admin queue's interrupt */
- free_irq(dev->entry[0].vector, adminq);
+ free_irq(pci_irq_vector(pdev, 0), adminq);
/*
* If we enable msix early due to not intx, disable it again before
* setting up the full range we need.
*/
- if (pdev->msi_enabled)
- pci_disable_msi(pdev);
- else if (pdev->msix_enabled)
- pci_disable_msix(pdev);
-
- for (i = 0; i < nr_io_queues; i++)
- dev->entry[i].entry = i;
- vecs = pci_enable_msix_range(pdev, dev->entry, 1, nr_io_queues);
- if (vecs < 0) {
- vecs = pci_enable_msi_range(pdev, 1, min(nr_io_queues, 32));
- if (vecs < 0) {
- vecs = 1;
- } else {
- for (i = 0; i < vecs; i++)
- dev->entry[i].vector = i + pdev->irq;
- }
- }
+ pci_free_irq_vectors(pdev);
+ nr_io_queues = pci_alloc_irq_vectors(pdev, 1, nr_io_queues,
+ PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY);
+ if (nr_io_queues <= 0)
+ return -EIO;
+ dev->max_qid = nr_io_queues;
/*
* Should investigate if there's a performance win from allocating
@@ -1447,10 +1445,8 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
* path to scale better, even if the receive path is limited by the
* number of interrupts.
*/
- nr_io_queues = vecs;
- dev->max_qid = nr_io_queues;
- result = queue_request_irq(dev, adminq, adminq->irqname);
+ result = queue_request_irq(adminq);
if (result) {
adminq->cq_vector = -1;
goto free_queues;
@@ -1462,23 +1458,6 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
return result;
}
-static void nvme_pci_post_scan(struct nvme_ctrl *ctrl)
-{
- struct nvme_dev *dev = to_nvme_dev(ctrl);
- struct nvme_queue *nvmeq;
- int i;
-
- for (i = 0; i < dev->online_queues; i++) {
- nvmeq = dev->queues[i];
-
- if (!nvmeq->tags || !(*nvmeq->tags))
- continue;
-
- irq_set_affinity_hint(dev->entry[nvmeq->cq_vector].vector,
- blk_mq_tags_cpumask(*nvmeq->tags));
- }
-}
-
static void nvme_del_queue_end(struct request *req, int error)
{
struct nvme_queue *nvmeq = req->end_io_data;
@@ -1615,15 +1594,9 @@ static int nvme_pci_enable(struct nvme_dev *dev)
* interrupts. Pre-enable a single MSIX or MSI vec for setup. We'll
* adjust this later.
*/
- if (pci_enable_msix(pdev, dev->entry, 1)) {
- pci_enable_msi(pdev);
- dev->entry[0].vector = pdev->irq;
- }
-
- if (!dev->entry[0].vector) {
- result = -ENODEV;
- goto disable;
- }
+ result = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (result < 0)
+ return result;
cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
@@ -1665,10 +1638,7 @@ static void nvme_pci_disable(struct nvme_dev *dev)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
- if (pdev->msi_enabled)
- pci_disable_msi(pdev);
- else if (pdev->msix_enabled)
- pci_disable_msix(pdev);
+ pci_free_irq_vectors(pdev);
if (pci_is_enabled(pdev)) {
pci_disable_pcie_error_reporting(pdev);
@@ -1743,7 +1713,6 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
if (dev->ctrl.admin_q)
blk_put_queue(dev->ctrl.admin_q);
kfree(dev->queues);
- kfree(dev->entry);
kfree(dev);
}
@@ -1887,7 +1856,6 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
.reg_read64 = nvme_pci_reg_read64,
.reset_ctrl = nvme_pci_reset_ctrl,
.free_ctrl = nvme_pci_free_ctrl,
- .post_scan = nvme_pci_post_scan,
.submit_async_event = nvme_pci_submit_async_event,
};
@@ -1920,10 +1888,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node);
if (!dev)
return -ENOMEM;
- dev->entry = kzalloc_node(num_possible_cpus() * sizeof(*dev->entry),
- GFP_KERNEL, node);
- if (!dev->entry)
- goto free;
dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(void *),
GFP_KERNEL, node);
if (!dev->queues)
@@ -1964,7 +1928,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
nvme_dev_unmap(dev);
free:
kfree(dev->queues);
- kfree(dev->entry);
kfree(dev);
return result;
}
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index fbdb2267e460..5a8388177959 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -54,7 +54,6 @@
struct nvme_rdma_device {
struct ib_device *dev;
struct ib_pd *pd;
- struct ib_mr *mr;
struct kref ref;
struct list_head entry;
};
@@ -408,10 +407,7 @@ static void nvme_rdma_free_dev(struct kref *ref)
list_del(&ndev->entry);
mutex_unlock(&device_list_mutex);
- if (!register_always)
- ib_dereg_mr(ndev->mr);
ib_dealloc_pd(ndev->pd);
-
kfree(ndev);
}
@@ -444,24 +440,16 @@ nvme_rdma_find_get_device(struct rdma_cm_id *cm_id)
ndev->dev = cm_id->device;
kref_init(&ndev->ref);
- ndev->pd = ib_alloc_pd(ndev->dev);
+ ndev->pd = ib_alloc_pd(ndev->dev,
+ register_always ? 0 : IB_PD_UNSAFE_GLOBAL_RKEY);
if (IS_ERR(ndev->pd))
goto out_free_dev;
- if (!register_always) {
- ndev->mr = ib_get_dma_mr(ndev->pd,
- IB_ACCESS_LOCAL_WRITE |
- IB_ACCESS_REMOTE_READ |
- IB_ACCESS_REMOTE_WRITE);
- if (IS_ERR(ndev->mr))
- goto out_free_pd;
- }
-
if (!(ndev->dev->attrs.device_cap_flags &
IB_DEVICE_MEM_MGT_EXTENSIONS)) {
dev_err(&ndev->dev->dev,
"Memory registrations not supported.\n");
- goto out_free_mr;
+ goto out_free_pd;
}
list_add(&ndev->entry, &device_list);
@@ -469,9 +457,6 @@ out_unlock:
mutex_unlock(&device_list_mutex);
return ndev;
-out_free_mr:
- if (!register_always)
- ib_dereg_mr(ndev->mr);
out_free_pd:
ib_dealloc_pd(ndev->pd);
out_free_dev:
@@ -915,7 +900,7 @@ static int nvme_rdma_map_sg_single(struct nvme_rdma_queue *queue,
sg->addr = cpu_to_le64(sg_dma_address(req->sg_table.sgl));
put_unaligned_le24(sg_dma_len(req->sg_table.sgl), sg->length);
- put_unaligned_le32(queue->device->mr->rkey, sg->key);
+ put_unaligned_le32(queue->device->pd->unsafe_global_rkey, sg->key);
sg->type = NVME_KEY_SGL_FMT_DATA_DESC << 4;
return 0;
}
@@ -1000,7 +985,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
nvme_rdma_queue_idx(queue))
return nvme_rdma_map_sg_inline(queue, req, c);
- if (!register_always)
+ if (dev->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)
return nvme_rdma_map_sg_single(queue, req, c);
}
@@ -1495,7 +1480,6 @@ static void nvme_rdma_complete_rq(struct request *rq)
static struct blk_mq_ops nvme_rdma_mq_ops = {
.queue_rq = nvme_rdma_queue_rq,
.complete = nvme_rdma_complete_rq,
- .map_queue = blk_mq_map_queue,
.init_request = nvme_rdma_init_request,
.exit_request = nvme_rdma_exit_request,
.reinit_request = nvme_rdma_reinit_request,
@@ -1507,7 +1491,6 @@ static struct blk_mq_ops nvme_rdma_mq_ops = {
static struct blk_mq_ops nvme_rdma_admin_mq_ops = {
.queue_rq = nvme_rdma_queue_rq,
.complete = nvme_rdma_complete_rq,
- .map_queue = blk_mq_map_queue,
.init_request = nvme_rdma_init_admin_request,
.exit_request = nvme_rdma_exit_admin_request,
.reinit_request = nvme_rdma_reinit_request,
diff --git a/drivers/nvme/host/scsi.c b/drivers/nvme/host/scsi.c
index e947e298a737..c2a0a1c7d05d 100644
--- a/drivers/nvme/host/scsi.c
+++ b/drivers/nvme/host/scsi.c
@@ -72,15 +72,6 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define ALL_LUNS_RETURNED 0x02
#define ALL_WELL_KNOWN_LUNS_RETURNED 0x01
#define RESTRICTED_LUNS_RETURNED 0x00
-#define NVME_POWER_STATE_START_VALID 0x00
-#define NVME_POWER_STATE_ACTIVE 0x01
-#define NVME_POWER_STATE_IDLE 0x02
-#define NVME_POWER_STATE_STANDBY 0x03
-#define NVME_POWER_STATE_LU_CONTROL 0x07
-#define POWER_STATE_0 0
-#define POWER_STATE_1 1
-#define POWER_STATE_2 2
-#define POWER_STATE_3 3
#define DOWNLOAD_SAVE_ACTIVATE 0x05
#define DOWNLOAD_SAVE_DEFER_ACTIVATE 0x0E
#define ACTIVATE_DEFERRED_MICROCODE 0x0F
@@ -915,7 +906,7 @@ static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr,
kfree(smart_log);
/* Get Features for Temp Threshold */
- res = nvme_get_features(ns->ctrl, NVME_FEAT_TEMP_THRESH, 0, 0,
+ res = nvme_get_features(ns->ctrl, NVME_FEAT_TEMP_THRESH, 0, NULL, 0,
&feature_resp);
if (res != NVME_SC_SUCCESS)
temp_c_thresh = LOG_TEMP_UNKNOWN;
@@ -1048,7 +1039,7 @@ static int nvme_trans_fill_caching_page(struct nvme_ns *ns,
if (len < MODE_PAGE_CACHING_LEN)
return -EINVAL;
- nvme_sc = nvme_get_features(ns->ctrl, NVME_FEAT_VOLATILE_WC, 0, 0,
+ nvme_sc = nvme_get_features(ns->ctrl, NVME_FEAT_VOLATILE_WC, 0, NULL, 0,
&feature_resp);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
@@ -1229,64 +1220,6 @@ static void nvme_trans_fill_read_cap(u8 *response, struct nvme_id_ns *id_ns,
/* Start Stop Unit Helper Functions */
-static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
- u8 pc, u8 pcmod, u8 start)
-{
- int res;
- int nvme_sc;
- struct nvme_id_ctrl *id_ctrl;
- int lowest_pow_st; /* max npss = lowest power consumption */
- unsigned ps_desired = 0;
-
- nvme_sc = nvme_identify_ctrl(ns->ctrl, &id_ctrl);
- res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- return res;
-
- lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1));
- kfree(id_ctrl);
-
- switch (pc) {
- case NVME_POWER_STATE_START_VALID:
- /* Action unspecified if POWER CONDITION MODIFIER != 0 */
- if (pcmod == 0 && start == 0x1)
- ps_desired = POWER_STATE_0;
- if (pcmod == 0 && start == 0x0)
- ps_desired = lowest_pow_st;
- break;
- case NVME_POWER_STATE_ACTIVE:
- /* Action unspecified if POWER CONDITION MODIFIER != 0 */
- if (pcmod == 0)
- ps_desired = POWER_STATE_0;
- break;
- case NVME_POWER_STATE_IDLE:
- /* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */
- if (pcmod == 0x0)
- ps_desired = POWER_STATE_1;
- else if (pcmod == 0x1)
- ps_desired = POWER_STATE_2;
- else if (pcmod == 0x2)
- ps_desired = POWER_STATE_3;
- break;
- case NVME_POWER_STATE_STANDBY:
- /* Action unspecified if POWER CONDITION MODIFIER != [0,1] */
- if (pcmod == 0x0)
- ps_desired = max(POWER_STATE_0, (lowest_pow_st - 2));
- else if (pcmod == 0x1)
- ps_desired = max(POWER_STATE_0, (lowest_pow_st - 1));
- break;
- case NVME_POWER_STATE_LU_CONTROL:
- default:
- res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
- ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
- SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- break;
- }
- nvme_sc = nvme_set_features(ns->ctrl, NVME_FEAT_POWER_MGMT, ps_desired, 0,
- NULL);
- return nvme_trans_status_code(hdr, nvme_sc);
-}
-
static int nvme_trans_send_activate_fw_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 buffer_id)
{
@@ -1395,7 +1328,7 @@ static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
case MODE_PAGE_CACHING:
dword11 = ((mode_page[2] & CACHING_MODE_PAGE_WCE_MASK) ? 1 : 0);
nvme_sc = nvme_set_features(ns->ctrl, NVME_FEAT_VOLATILE_WC,
- dword11, 0, NULL);
+ dword11, NULL, 0, NULL);
res = nvme_trans_status_code(hdr, nvme_sc);
break;
case MODE_PAGE_CONTROL:
@@ -2235,11 +2168,10 @@ static int nvme_trans_synchronize_cache(struct nvme_ns *ns,
static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- u8 immed, pcmod, pc, no_flush, start;
+ u8 immed, pcmod, no_flush, start;
immed = cmd[1] & 0x01;
pcmod = cmd[3] & 0x0f;
- pc = (cmd[4] & 0xf0) >> 4;
no_flush = cmd[4] & 0x04;
start = cmd[4] & 0x01;
@@ -2254,8 +2186,8 @@ static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr,
if (res)
return res;
}
- /* Setup the expected power state transition */
- return nvme_trans_power_state(ns, hdr, pc, pcmod, start);
+
+ return 0;
}
}
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 47c564b5a289..7ab9c9381b98 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <generated/utsrelease.h>
+#include <asm/unaligned.h>
#include "nvmet.h"
u32 nvmet_get_log_page_len(struct nvme_command *cmd)
@@ -29,8 +30,84 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd)
return len;
}
+static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
+ struct nvme_smart_log *slog)
+{
+ u16 status;
+ struct nvmet_ns *ns;
+ u64 host_reads, host_writes, data_units_read, data_units_written;
+
+ status = NVME_SC_SUCCESS;
+ ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->get_log_page.nsid);
+ if (!ns) {
+ status = NVME_SC_INVALID_NS;
+ pr_err("nvmet : Counld not find namespace id : %d\n",
+ le32_to_cpu(req->cmd->get_log_page.nsid));
+ goto out;
+ }
+
+ host_reads = part_stat_read(ns->bdev->bd_part, ios[READ]);
+ data_units_read = part_stat_read(ns->bdev->bd_part, sectors[READ]);
+ host_writes = part_stat_read(ns->bdev->bd_part, ios[WRITE]);
+ data_units_written = part_stat_read(ns->bdev->bd_part, sectors[WRITE]);
+
+ put_unaligned_le64(host_reads, &slog->host_reads[0]);
+ put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
+ put_unaligned_le64(host_writes, &slog->host_writes[0]);
+ put_unaligned_le64(data_units_written, &slog->data_units_written[0]);
+ nvmet_put_namespace(ns);
+out:
+ return status;
+}
+
+static u16 nvmet_get_smart_log_all(struct nvmet_req *req,
+ struct nvme_smart_log *slog)
+{
+ u16 status;
+ u64 host_reads = 0, host_writes = 0;
+ u64 data_units_read = 0, data_units_written = 0;
+ struct nvmet_ns *ns;
+ struct nvmet_ctrl *ctrl;
+
+ status = NVME_SC_SUCCESS;
+ ctrl = req->sq->ctrl;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) {
+ host_reads += part_stat_read(ns->bdev->bd_part, ios[READ]);
+ data_units_read +=
+ part_stat_read(ns->bdev->bd_part, sectors[READ]);
+ host_writes += part_stat_read(ns->bdev->bd_part, ios[WRITE]);
+ data_units_written +=
+ part_stat_read(ns->bdev->bd_part, sectors[WRITE]);
+
+ }
+ rcu_read_unlock();
+
+ put_unaligned_le64(host_reads, &slog->host_reads[0]);
+ put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
+ put_unaligned_le64(host_writes, &slog->host_writes[0]);
+ put_unaligned_le64(data_units_written, &slog->data_units_written[0]);
+
+ return status;
+}
+
+static u16 nvmet_get_smart_log(struct nvmet_req *req,
+ struct nvme_smart_log *slog)
+{
+ u16 status;
+
+ WARN_ON(req == NULL || slog == NULL);
+ if (req->cmd->get_log_page.nsid == 0xFFFFFFFF)
+ status = nvmet_get_smart_log_all(req, slog);
+ else
+ status = nvmet_get_smart_log_nsid(req, slog);
+ return status;
+}
+
static void nvmet_execute_get_log_page(struct nvmet_req *req)
{
+ struct nvme_smart_log *smart_log;
size_t data_len = nvmet_get_log_page_len(req->cmd);
void *buf;
u16 status = 0;
@@ -59,6 +136,16 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
* available (e.g. units or commands read/written) those aren't
* persistent over power loss.
*/
+ if (data_len != sizeof(*smart_log)) {
+ status = NVME_SC_INTERNAL;
+ goto err;
+ }
+ smart_log = buf;
+ status = nvmet_get_smart_log(req, smart_log);
+ if (status) {
+ memset(buf, '\0', data_len);
+ goto err;
+ }
break;
case 0x03:
/*
@@ -73,6 +160,7 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
status = nvmet_copy_to_sgl(req, 0, buf, data_len);
+err:
kfree(buf);
out:
nvmet_req_complete(req, status);
diff --git a/drivers/nvme/target/io-cmd.c b/drivers/nvme/target/io-cmd.c
index 2cd069b691ae..4a96c2049b7b 100644
--- a/drivers/nvme/target/io-cmd.c
+++ b/drivers/nvme/target/io-cmd.c
@@ -58,6 +58,7 @@ static void nvmet_execute_rw(struct nvmet_req *req)
if (req->cmd->rw.opcode == nvme_cmd_write) {
op = REQ_OP_WRITE;
+ op_flags = WRITE_ODIRECT;
if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
op_flags |= REQ_FUA;
} else {
@@ -205,7 +206,7 @@ int nvmet_parse_io_cmd(struct nvmet_req *req)
return 0;
case nvme_cmd_dsm:
req->execute = nvmet_execute_dsm;
- req->data_len = le32_to_cpu(cmd->dsm.nr) *
+ req->data_len = le32_to_cpu(cmd->dsm.nr + 1) *
sizeof(struct nvme_dsm_range);
return 0;
default:
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index 395e60dad835..d5df77d686b2 100644
--- a/drivers/nvme/target/loop.c
+++ b/drivers/nvme/target/loop.c
@@ -273,7 +273,6 @@ static int nvme_loop_init_admin_hctx(struct blk_mq_hw_ctx *hctx, void *data,
static struct blk_mq_ops nvme_loop_mq_ops = {
.queue_rq = nvme_loop_queue_rq,
.complete = nvme_loop_complete_rq,
- .map_queue = blk_mq_map_queue,
.init_request = nvme_loop_init_request,
.init_hctx = nvme_loop_init_hctx,
.timeout = nvme_loop_timeout,
@@ -282,7 +281,6 @@ static struct blk_mq_ops nvme_loop_mq_ops = {
static struct blk_mq_ops nvme_loop_admin_mq_ops = {
.queue_rq = nvme_loop_queue_rq,
.complete = nvme_loop_complete_rq,
- .map_queue = blk_mq_map_queue,
.init_request = nvme_loop_init_admin_request,
.init_hctx = nvme_loop_init_admin_hctx,
.timeout = nvme_loop_timeout,
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 1cbe6e053b5b..f8d23999e0f2 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -848,7 +848,7 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
ndev->device = cm_id->device;
kref_init(&ndev->ref);
- ndev->pd = ib_alloc_pd(ndev->device);
+ ndev->pd = ib_alloc_pd(ndev->device, 0);
if (IS_ERR(ndev->pd))
goto out_free_dev;
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index f550c4596a7a..ba140eaee5c8 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -101,4 +101,14 @@ config NVMEM_VF610_OCOTP
This driver can also be build as a module. If so, the module will
be called nvmem-vf610-ocotp.
+config MESON_EFUSE
+ tristate "Amlogic eFuse Support"
+ depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM
+ help
+ This is a driver to retrieve specific values from the eFuse found on
+ the Amlogic Meson SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem_meson_efuse.
+
endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 45ab1ae08fa9..8f942a0cdaec 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -22,3 +22,5 @@ obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
nvmem_sunxi_sid-y := sunxi_sid.o
obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o
nvmem-vf610-ocotp-y := vf610-ocotp.o
+obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o
+nvmem_meson_efuse-y := meson-efuse.o
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c
new file mode 100644
index 000000000000..f207c3b10482
--- /dev/null
+++ b/drivers/nvmem/meson-efuse.c
@@ -0,0 +1,93 @@
+/*
+ * Amlogic eFuse Driver
+ *
+ * Copyright (c) 2016 Endless Computers, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <linux/firmware/meson/meson_sm.h>
+
+static int meson_efuse_read(void *context, unsigned int offset,
+ void *val, size_t bytes)
+{
+ u8 *buf = val;
+ int ret;
+
+ ret = meson_sm_call_read(buf, SM_EFUSE_READ, offset,
+ bytes, 0, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct nvmem_config econfig = {
+ .name = "meson-efuse",
+ .owner = THIS_MODULE,
+ .stride = 1,
+ .word_size = 1,
+ .read_only = true,
+};
+
+static const struct of_device_id meson_efuse_match[] = {
+ { .compatible = "amlogic,meson-gxbb-efuse", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, meson_efuse_match);
+
+static int meson_efuse_probe(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem;
+ unsigned int size;
+
+ if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0)
+ return -EINVAL;
+
+ econfig.dev = &pdev->dev;
+ econfig.reg_read = meson_efuse_read;
+ econfig.size = size;
+
+ nvmem = nvmem_register(&econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+static int meson_efuse_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static struct platform_driver meson_efuse_driver = {
+ .probe = meson_efuse_probe,
+ .remove = meson_efuse_remove,
+ .driver = {
+ .name = "meson-efuse",
+ .of_match_table = meson_efuse_match,
+ },
+};
+
+module_platform_driver(meson_efuse_driver);
+
+MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
+MODULE_DESCRIPTION("Amlogic Meson NVMEM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index bc07ad30c9bf..ba7b034b2b91 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -90,10 +90,6 @@ config OF_PCI_IRQ
help
OpenFirmware PCI IRQ routing helpers
-config OF_MTD
- depends on MTD
- def_bool y
-
config OF_RESERVED_MEM
depends on OF_EARLY_FLATTREE
bool
diff --git a/drivers/of/base.c b/drivers/of/base.c
index a0bccb54a9bd..d687e6de24a0 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2077,6 +2077,8 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
name = of_get_property(of_aliases, "stdout", NULL);
if (name)
of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
+ if (of_stdout)
+ console_set_by_of();
}
if (!of_aliases)
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index a0e5260bd006..134398e0231b 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -30,7 +30,7 @@ static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
if (inode) {
inode->i_ino = get_next_ino();
inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
}
return inode;
}
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 67f9916ff14d..6555eb78d91c 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -25,7 +25,7 @@ config PCI_MSI
If you don't know what to do here, say Y.
config PCI_MSI_IRQ_DOMAIN
- def_bool ARM || ARM64 || X86
+ def_bool ARC || ARM || ARM64 || X86
depends on PCI_MSI
select GENERIC_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 9b485d873b0d..d7e7c0a827c3 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -274,4 +274,31 @@ config PCIE_ARTPEC6
Say Y here to enable PCIe controller support on Axis ARTPEC-6
SoCs. This PCIe controller uses the DesignWare core.
+config PCIE_ROCKCHIP
+ bool "Rockchip PCIe controller"
+ depends on ARCH_ROCKCHIP
+ depends on OF
+ depends on PCI_MSI_IRQ_DOMAIN
+ select MFD_SYSCON
+ help
+ Say Y here if you want internal PCI support on Rockchip SoC.
+ There is 1 internal PCIe port available to support GEN2 with
+ 4 slots.
+
+config VMD
+ depends on PCI_MSI && X86_64
+ tristate "Intel Volume Management Device Driver"
+ default N
+ ---help---
+ Adds support for the Intel Volume Management Device (VMD). VMD is a
+ secondary PCI host bridge that allows PCI Express root ports,
+ and devices attached to them, to be removed from the default
+ PCI domain and placed within the VMD domain. This provides
+ more bus resources than are otherwise possible with a
+ single domain. If you know your system provides one of these and
+ has devices attached to it, say Y; if you are not sure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vmd.
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 88434101e4c4..084cb4983645 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -31,3 +31,5 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
+obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
+obj-$(CONFIG_VMD) += vmd.o
diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c
index ef9893fa3176..e4a5b7ee90cf 100644
--- a/drivers/pci/host/pci-aardvark.c
+++ b/drivers/pci/host/pci-aardvark.c
@@ -848,7 +848,7 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
int err, res_valid = 0;
struct device *dev = &pcie->pdev->dev;
struct device_node *np = dev->of_node;
- struct resource_entry *win;
+ struct resource_entry *win, *tmp;
resource_size_t iobase;
INIT_LIST_HEAD(&pcie->resources);
@@ -862,7 +862,7 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
if (err)
goto out_release_res;
- resource_list_for_each_entry(win, &pcie->resources) {
+ resource_list_for_each_entry_safe(win, tmp, &pcie->resources) {
struct resource *res = win->res;
switch (resource_type(res)) {
@@ -874,9 +874,11 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
lower_32_bits(res->start),
OB_PCIE_IO);
err = pci_remap_iospace(res, iobase);
- if (err)
+ if (err) {
dev_warn(dev, "error %d: failed to map resource %pR\n",
err, res);
+ resource_list_destroy_entry(win);
+ }
break;
case IORESOURCE_MEM:
advk_pcie_set_ob_win(pcie, 0,
@@ -925,10 +927,8 @@ static int advk_pcie_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pcie->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(pcie->base)) {
- dev_err(&pdev->dev, "Failed to map registers\n");
+ if (IS_ERR(pcie->base))
return PTR_ERR(pcie->base);
- }
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, irq, advk_pcie_irq_handler,
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
index 81b3949a26db..19223ed2e619 100644
--- a/drivers/pci/host/pci-dra7xx.c
+++ b/drivers/pci/host/pci-dra7xx.c
@@ -15,7 +15,7 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_gpio.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
@@ -443,25 +443,6 @@ err_phy:
return ret;
}
-static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
-{
- struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev);
- struct pcie_port *pp = &dra7xx->pp;
- struct device *dev = &pdev->dev;
- int count = dra7xx->phy_count;
-
- if (pp->irq_domain)
- irq_domain_remove(pp->irq_domain);
- pm_runtime_put(dev);
- pm_runtime_disable(dev);
- while (count--) {
- phy_power_off(dra7xx->phy[count]);
- phy_exit(dra7xx->phy[count]);
- }
-
- return 0;
-}
-
#ifdef CONFIG_PM_SLEEP
static int dra7xx_pcie_suspend(struct device *dev)
{
@@ -545,19 +526,13 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
{ .compatible = "ti,dra7-pcie", },
{},
};
-MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match);
static struct platform_driver dra7xx_pcie_driver = {
- .remove = __exit_p(dra7xx_pcie_remove),
.driver = {
.name = "dra7-pcie",
.of_match_table = of_dra7xx_pcie_match,
+ .suppress_bind_attrs = true,
.pm = &dra7xx_pcie_pm_ops,
},
};
-
-module_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe);
-
-MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
-MODULE_DESCRIPTION("TI PCIe controller driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe);
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index 219976103efc..2e2d7f00b9e8 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -16,7 +16,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_gpio.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
@@ -425,12 +425,15 @@ static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
exynos_pcie_msi_init(pp);
}
-static inline void exynos_pcie_readl_rc(struct pcie_port *pp,
- void __iomem *dbi_base, u32 *val)
+static inline u32 exynos_pcie_readl_rc(struct pcie_port *pp,
+ void __iomem *dbi_base)
{
+ u32 val;
+
exynos_pcie_sideband_dbi_r_mode(pp, true);
- *val = readl(dbi_base);
+ val = readl(dbi_base);
exynos_pcie_sideband_dbi_r_mode(pp, false);
+ return val;
}
static inline void exynos_pcie_writel_rc(struct pcie_port *pp,
@@ -624,7 +627,6 @@ static const struct of_device_id exynos_pcie_of_match[] = {
{ .compatible = "samsung,exynos5440-pcie", },
{},
};
-MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
static struct platform_driver exynos_pcie_driver = {
.remove = __exit_p(exynos_pcie_remove),
@@ -641,7 +643,3 @@ static int __init exynos_pcie_init(void)
return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
}
subsys_initcall(exynos_pcie_init);
-
-MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
-MODULE_DESCRIPTION("Samsung PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
index 9d9d34e959b6..e3c48b5deb93 100644
--- a/drivers/pci/host/pci-host-common.c
+++ b/drivers/pci/host/pci-host-common.c
@@ -1,4 +1,6 @@
/*
+ * Generic PCI host driver common code
+ *
* 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.
@@ -17,7 +19,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/pci-ecam.h>
@@ -29,7 +30,7 @@ static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
int err, res_valid = 0;
struct device_node *np = dev->of_node;
resource_size_t iobase;
- struct resource_entry *win;
+ struct resource_entry *win, *tmp;
err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
if (err)
@@ -39,15 +40,17 @@ static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
if (err)
return err;
- resource_list_for_each_entry(win, resources) {
+ resource_list_for_each_entry_safe(win, tmp, resources) {
struct resource *res = win->res;
switch (resource_type(res)) {
case IORESOURCE_IO:
err = pci_remap_iospace(res, iobase);
- if (err)
+ if (err) {
dev_warn(dev, "error %d: failed to map resource %pR\n",
err, res);
+ resource_list_destroy_entry(win);
+ }
break;
case IORESOURCE_MEM:
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
@@ -162,7 +165,3 @@ int pci_host_common_probe(struct platform_device *pdev,
pci_bus_add_devices(bus);
return 0;
}
-
-MODULE_DESCRIPTION("Generic PCI host driver common code");
-MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c
index 6955ffdb89f3..763ff8745828 100644
--- a/drivers/pci/host/pci-hyperv.c
+++ b/drivers/pci/host/pci-hyperv.c
@@ -200,11 +200,11 @@ struct tran_int_desc {
*/
struct pci_message {
- u32 message_type;
+ u32 type;
} __packed;
struct pci_child_message {
- u32 message_type;
+ struct pci_message message_type;
union win_slot_encoding wslot;
} __packed;
@@ -222,7 +222,8 @@ struct pci_packet {
void (*completion_func)(void *context, struct pci_response *resp,
int resp_packet_size);
void *compl_ctxt;
- struct pci_message message;
+
+ struct pci_message message[0];
};
/*
@@ -258,7 +259,7 @@ struct pci_bus_d0_entry {
struct pci_bus_relations {
struct pci_incoming_message incoming;
u32 device_count;
- struct pci_function_description func[1];
+ struct pci_function_description func[0];
} __packed;
struct pci_q_res_req_response {
@@ -314,7 +315,7 @@ struct pci_dev_incoming {
} __packed;
struct pci_eject_response {
- u32 message_type;
+ struct pci_message message_type;
union win_slot_encoding wslot;
u32 status;
} __packed;
@@ -373,7 +374,6 @@ struct hv_pcibus_device {
struct list_head children;
struct list_head dr_list;
- struct work_struct wrk;
struct msi_domain_info msi_info;
struct msi_controller msi_chip;
@@ -393,7 +393,7 @@ struct hv_dr_work {
struct hv_dr_state {
struct list_head list_entry;
u32 device_count;
- struct pci_function_description func[1];
+ struct pci_function_description func[0];
};
enum hv_pcichild_state {
@@ -447,15 +447,16 @@ struct hv_pci_compl {
* for any message for which the completion packet contains a
* status and nothing else.
*/
-static
-void
-hv_pci_generic_compl(void *context, struct pci_response *resp,
- int resp_packet_size)
+static void hv_pci_generic_compl(void *context, struct pci_response *resp,
+ int resp_packet_size)
{
struct hv_pci_compl *comp_pkt = context;
if (resp_packet_size >= offsetofend(struct pci_response, status))
comp_pkt->completion_status = resp->status;
+ else
+ comp_pkt->completion_status = -1;
+
complete(&comp_pkt->host_event);
}
@@ -694,13 +695,12 @@ static void hv_int_desc_free(struct hv_pci_dev *hpdev,
struct pci_delete_interrupt *int_pkt;
struct {
struct pci_packet pkt;
- u8 buffer[sizeof(struct pci_delete_interrupt) -
- sizeof(struct pci_message)];
+ u8 buffer[sizeof(struct pci_delete_interrupt)];
} ctxt;
memset(&ctxt, 0, sizeof(ctxt));
int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message;
- int_pkt->message_type.message_type =
+ int_pkt->message_type.type =
PCI_DELETE_INTERRUPT_MESSAGE;
int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
int_pkt->int_desc = *int_desc;
@@ -847,8 +847,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct cpumask *affinity;
struct {
struct pci_packet pkt;
- u8 buffer[sizeof(struct pci_create_interrupt) -
- sizeof(struct pci_message)];
+ u8 buffer[sizeof(struct pci_create_interrupt)];
} ctxt;
int cpu;
int ret;
@@ -876,7 +875,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
ctxt.pkt.completion_func = hv_pci_compose_compl;
ctxt.pkt.compl_ctxt = &comp;
int_pkt = (struct pci_create_interrupt *)&ctxt.pkt.message;
- int_pkt->message_type.message_type = PCI_CREATE_INTERRUPT_MESSAGE;
+ int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
int_pkt->int_desc.vector = cfg->vector;
int_pkt->int_desc.vector_count = 1;
@@ -897,8 +896,10 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
sizeof(*int_pkt), (unsigned long)&ctxt.pkt,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (!ret)
- wait_for_completion(&comp.comp_pkt.host_event);
+ if (ret)
+ goto free_int_desc;
+
+ wait_for_completion(&comp.comp_pkt.host_event);
if (comp.comp_pkt.completion_status < 0) {
dev_err(&hbus->hdev->device,
@@ -1289,7 +1290,7 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
pkt.init_packet.compl_ctxt = &comp_pkt;
pkt.init_packet.completion_func = q_resource_requirements;
res_req = (struct pci_child_message *)&pkt.init_packet.message;
- res_req->message_type = PCI_QUERY_RESOURCE_REQUIREMENTS;
+ res_req->message_type.type = PCI_QUERY_RESOURCE_REQUIREMENTS;
res_req->wslot.slot = desc->win_slot.slot;
ret = vmbus_sendpacket(hbus->hdev->channel, res_req,
@@ -1466,8 +1467,7 @@ static void pci_devices_present_work(struct work_struct *work)
if (hpdev->reported_missing) {
found = true;
put_pcichild(hpdev, hv_pcidev_ref_childlist);
- list_del(&hpdev->list_entry);
- list_add_tail(&hpdev->list_entry, &removed);
+ list_move_tail(&hpdev->list_entry, &removed);
break;
}
}
@@ -1558,8 +1558,7 @@ static void hv_eject_device_work(struct work_struct *work)
int wslot;
struct {
struct pci_packet pkt;
- u8 buffer[sizeof(struct pci_eject_response) -
- sizeof(struct pci_message)];
+ u8 buffer[sizeof(struct pci_eject_response)];
} ctxt;
hpdev = container_of(work, struct hv_pci_dev, wrk);
@@ -1585,7 +1584,7 @@ static void hv_eject_device_work(struct work_struct *work)
memset(&ctxt, 0, sizeof(ctxt));
ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
- ejct_pkt->message_type = PCI_EJECTION_COMPLETE;
+ ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
ejct_pkt->wslot.slot = hpdev->desc.win_slot.slot;
vmbus_sendpacket(hpdev->hbus->hdev->channel, ejct_pkt,
sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
@@ -1688,7 +1687,7 @@ static void hv_pci_onchannelcallback(void *context)
case VM_PKT_DATA_INBAND:
new_message = (struct pci_incoming_message *)buffer;
- switch (new_message->message_type.message_type) {
+ switch (new_message->message_type.type) {
case PCI_BUS_RELATIONS:
bus_rel = (struct pci_bus_relations *)buffer;
@@ -1719,7 +1718,7 @@ static void hv_pci_onchannelcallback(void *context)
default:
dev_warn(&hbus->hdev->device,
"Unimplemented protocol message %x\n",
- new_message->message_type.message_type);
+ new_message->message_type.type);
break;
}
break;
@@ -1772,7 +1771,7 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev)
pkt->completion_func = hv_pci_generic_compl;
pkt->compl_ctxt = &comp_pkt;
version_req = (struct pci_version_request *)&pkt->message;
- version_req->message_type.message_type = PCI_QUERY_PROTOCOL_VERSION;
+ version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION;
version_req->protocol_version = PCI_PROTOCOL_VERSION_CURRENT;
ret = vmbus_sendpacket(hdev->channel, version_req,
@@ -1973,7 +1972,7 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
pkt->completion_func = hv_pci_generic_compl;
pkt->compl_ctxt = &comp_pkt;
d0_entry = (struct pci_bus_d0_entry *)&pkt->message;
- d0_entry->message_type.message_type = PCI_BUS_D0ENTRY;
+ d0_entry->message_type.type = PCI_BUS_D0ENTRY;
d0_entry->mmio_base = hbus->mem_config->start;
ret = vmbus_sendpacket(hdev->channel, d0_entry, sizeof(*d0_entry),
@@ -2019,7 +2018,7 @@ static int hv_pci_query_relations(struct hv_device *hdev)
return -ENOTEMPTY;
memset(&message, 0, sizeof(message));
- message.message_type = PCI_QUERY_BUS_RELATIONS;
+ message.type = PCI_QUERY_BUS_RELATIONS;
ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message),
0, VM_PKT_DATA_INBAND, 0);
@@ -2072,8 +2071,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
init_completion(&comp_pkt.host_event);
pkt->completion_func = hv_pci_generic_compl;
pkt->compl_ctxt = &comp_pkt;
- pkt->message.message_type = PCI_RESOURCES_ASSIGNED;
res_assigned = (struct pci_resources_assigned *)&pkt->message;
+ res_assigned->message_type.type = PCI_RESOURCES_ASSIGNED;
res_assigned->wslot.slot = hpdev->desc.win_slot.slot;
put_pcichild(hpdev, hv_pcidev_ref_by_slot);
@@ -2123,7 +2122,7 @@ static int hv_send_resources_released(struct hv_device *hdev)
continue;
memset(&pkt, 0, sizeof(pkt));
- pkt.message_type = PCI_RESOURCES_RELEASED;
+ pkt.message_type.type = PCI_RESOURCES_RELEASED;
pkt.wslot.slot = hpdev->desc.win_slot.slot;
put_pcichild(hpdev, hv_pcidev_ref_by_slot);
@@ -2290,7 +2289,7 @@ static int hv_pci_remove(struct hv_device *hdev)
init_completion(&comp_pkt.host_event);
pkt.teardown_packet.completion_func = hv_pci_generic_compl;
pkt.teardown_packet.compl_ctxt = &comp_pkt;
- pkt.teardown_packet.message.message_type = PCI_BUS_D0EXIT;
+ pkt.teardown_packet.message[0].type = PCI_BUS_D0EXIT;
ret = vmbus_sendpacket(hdev->channel, &pkt.teardown_packet.message,
sizeof(struct pci_message),
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index b741a36a67f3..ead4a5c3480b 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -739,7 +739,6 @@ static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
{},
};
-MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
static struct platform_driver imx6_pcie_driver = {
.driver = {
@@ -749,14 +748,8 @@ static struct platform_driver imx6_pcie_driver = {
.shutdown = imx6_pcie_shutdown,
};
-/* Freescale PCIe driver does not allow module unload */
-
static int __init imx6_pcie_init(void)
{
return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
}
-module_init(imx6_pcie_init);
-
-MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
-MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
+device_initcall(imx6_pcie_init);
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 8ba28834d470..82b461b5b08a 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -334,8 +334,9 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
if (ks_pcie->error_irq <= 0)
dev_info(&pdev->dev, "no error IRQ defined\n");
else {
- if (request_irq(ks_pcie->error_irq, pcie_err_irq_handler,
- IRQF_SHARED, "pcie-error-irq", ks_pcie) < 0) {
+ ret = request_irq(ks_pcie->error_irq, pcie_err_irq_handler,
+ IRQF_SHARED, "pcie-error-irq", ks_pcie);
+ if (ret < 0) {
dev_err(&pdev->dev, "failed to request error IRQ %d\n",
ks_pcie->error_irq);
return ret;
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 6de0757b11e4..e2a8e4cab22e 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -240,7 +240,7 @@ struct tegra_msi {
};
/* used to differentiate between Tegra SoC generations */
-struct tegra_pcie_soc_data {
+struct tegra_pcie_soc {
unsigned int num_ports;
unsigned int msi_base_shift;
u32 pads_pll_ctl;
@@ -300,7 +300,7 @@ struct tegra_pcie {
struct regulator_bulk_data *supplies;
unsigned int num_supplies;
- const struct tegra_pcie_soc_data *soc_data;
+ const struct tegra_pcie_soc *soc;
struct dentry *debugfs;
};
@@ -542,8 +542,8 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
{
- const struct tegra_pcie_soc_data *soc = port->pcie->soc_data;
unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ const struct tegra_pcie_soc *soc = port->pcie->soc;
unsigned long value;
/* enable reference clock */
@@ -562,8 +562,8 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
{
- const struct tegra_pcie_soc_data *soc = port->pcie->soc_data;
unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
+ const struct tegra_pcie_soc *soc = port->pcie->soc;
unsigned long value;
/* assert port reset */
@@ -621,7 +621,11 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
if (err < 0)
return err;
- pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset);
+ err = pci_remap_iospace(&pcie->pio, pcie->io.start);
+ if (!err)
+ pci_add_resource_offset(&sys->resources, &pcie->pio,
+ sys->io_offset);
+
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource_offset(&sys->resources, &pcie->prefetch,
sys->mem_offset);
@@ -631,7 +635,6 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
if (err < 0)
return err;
- pci_remap_iospace(&pcie->pio, pcie->io.start);
return 1;
}
@@ -774,7 +777,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
u32 value;
timeout = jiffies + msecs_to_jiffies(timeout);
@@ -790,7 +793,7 @@ static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
u32 value;
int err;
@@ -845,7 +848,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
static int tegra_pcie_phy_disable(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
u32 value;
/* disable TX/RX data */
@@ -906,7 +909,7 @@ static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port)
static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_pcie_port *port;
int err;
@@ -974,7 +977,7 @@ static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie)
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_pcie_port *port;
unsigned long value;
int err;
@@ -1067,7 +1070,7 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
static int tegra_pcie_power_on(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
int err;
reset_control_assert(pcie->pcie_xrst);
@@ -1117,7 +1120,7 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
pcie->pex_clk = devm_clk_get(pcie->dev, "pex");
if (IS_ERR(pcie->pex_clk))
@@ -1234,7 +1237,7 @@ static int tegra_pcie_port_get_phys(struct tegra_pcie_port *port)
static int tegra_pcie_phys_get(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
struct device_node *np = pcie->dev->of_node;
struct tegra_pcie_port *port;
int err;
@@ -1486,7 +1489,7 @@ static const struct irq_domain_ops msi_domain_ops = {
static int tegra_pcie_enable_msi(struct tegra_pcie *pcie)
{
struct platform_device *pdev = to_platform_device(pcie->dev);
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
+ const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_msi *msi = &pcie->msi;
unsigned long base;
int err;
@@ -1799,8 +1802,8 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
{
- const struct tegra_pcie_soc_data *soc = pcie->soc_data;
struct device_node *np = pcie->dev->of_node, *port;
+ const struct tegra_pcie_soc *soc = pcie->soc;
struct of_pci_range_parser parser;
struct of_pci_range range;
u32 lanes = 0, mask = 0;
@@ -2043,7 +2046,7 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie)
return 0;
}
-static const struct tegra_pcie_soc_data tegra20_pcie_data = {
+static const struct tegra_pcie_soc tegra20_pcie = {
.num_ports = 2,
.msi_base_shift = 0,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
@@ -2056,7 +2059,7 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = {
.has_gen2 = false,
};
-static const struct tegra_pcie_soc_data tegra30_pcie_data = {
+static const struct tegra_pcie_soc tegra30_pcie = {
.num_ports = 3,
.msi_base_shift = 8,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
@@ -2070,7 +2073,7 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = {
.has_gen2 = false,
};
-static const struct tegra_pcie_soc_data tegra124_pcie_data = {
+static const struct tegra_pcie_soc tegra124_pcie = {
.num_ports = 2,
.msi_base_shift = 8,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
@@ -2084,9 +2087,9 @@ static const struct tegra_pcie_soc_data tegra124_pcie_data = {
};
static const struct of_device_id tegra_pcie_of_match[] = {
- { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie_data },
- { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie_data },
- { .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie_data },
+ { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
+ { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },
+ { .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie },
{ },
};
@@ -2201,21 +2204,16 @@ remove:
static int tegra_pcie_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
struct tegra_pcie *pcie;
int err;
- match = of_match_device(tegra_pcie_of_match, &pdev->dev);
- if (!match)
- return -ENODEV;
-
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
return -ENOMEM;
+ pcie->soc = of_device_get_match_data(&pdev->dev);
INIT_LIST_HEAD(&pcie->buses);
INIT_LIST_HEAD(&pcie->ports);
- pcie->soc_data = match->data;
pcie->dev = &pdev->dev;
err = tegra_pcie_parse_dt(pcie);
diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c
index f234405770ab..b7dc07002f13 100644
--- a/drivers/pci/host/pci-versatile.c
+++ b/drivers/pci/host/pci-versatile.c
@@ -74,7 +74,7 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
int err, mem = 1, res_valid = 0;
struct device_node *np = dev->of_node;
resource_size_t iobase;
- struct resource_entry *win;
+ struct resource_entry *win, *tmp;
err = of_pci_get_host_bridge_resources(np, 0, 0xff, res, &iobase);
if (err)
@@ -84,15 +84,17 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
if (err)
goto out_release_res;
- resource_list_for_each_entry(win, res) {
+ resource_list_for_each_entry_safe(win, tmp, res) {
struct resource *res = win->res;
switch (resource_type(res)) {
case IORESOURCE_IO:
err = pci_remap_iospace(res, iobase);
- if (err)
+ if (err) {
dev_warn(dev, "error %d: failed to map resource %pR\n",
err, res);
+ resource_list_destroy_entry(win);
+ }
break;
case IORESOURCE_MEM:
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
diff --git a/drivers/pci/host/pcie-altera-msi.c b/drivers/pci/host/pcie-altera-msi.c
index 99177f4ccde2..4e5d628e8cd4 100644
--- a/drivers/pci/host/pcie-altera-msi.c
+++ b/drivers/pci/host/pcie-altera-msi.c
@@ -1,4 +1,8 @@
/*
+ * Altera PCIe MSI support
+ *
+ * Author: Ley Foon Tan <lftan@altera.com>
+ *
* Copyright Altera Corporation (C) 2013-2015. All rights reserved
*
* This program is free software; you can redistribute it and/or modify it
@@ -16,7 +20,7 @@
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -237,11 +241,6 @@ static int altera_msi_probe(struct platform_device *pdev)
msi->pdev = pdev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
- if (!res) {
- dev_err(&pdev->dev, "no csr memory resource defined\n");
- return -ENODEV;
- }
-
msi->csr_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msi->csr_base)) {
dev_err(&pdev->dev, "failed to map csr memory\n");
@@ -250,11 +249,6 @@ static int altera_msi_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"vector_slave");
- if (!res) {
- dev_err(&pdev->dev, "no vector_slave memory resource defined\n");
- return -ENODEV;
- }
-
msi->vector_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msi->vector_base)) {
dev_err(&pdev->dev, "failed to map vector_slave memory\n");
@@ -308,7 +302,3 @@ static int __init altera_msi_init(void)
return platform_driver_register(&altera_msi_driver);
}
subsys_initcall(altera_msi_init);
-
-MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
-MODULE_DESCRIPTION("Altera PCIe MSI support");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c
index 2b7837650db8..c24e96559cbb 100644
--- a/drivers/pci/host/pcie-altera.c
+++ b/drivers/pci/host/pcie-altera.c
@@ -1,6 +1,9 @@
/*
* Copyright Altera Corporation (C) 2013-2015. All rights reserved
*
+ * Author: Ley Foon Tan <lftan@altera.com>
+ * Description: Altera PCIe host controller driver
+ *
* 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.
@@ -17,7 +20,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
@@ -43,6 +46,7 @@
#define RP_LTSSM_MASK 0x1f
#define LTSSM_L0 0xf
+#define PCIE_CAP_OFFSET 0x80
/* TLP configuration type 0 and 1 */
#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */
#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */
@@ -61,7 +65,8 @@
#define TLP_LOOP 500
#define RP_DEVFN 0
-#define LINK_UP_TIMEOUT 5000
+#define LINK_UP_TIMEOUT HZ
+#define LINK_RETRAIN_TIMEOUT HZ
#define INTX_NUM 4
@@ -99,38 +104,6 @@ static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
}
-static void altera_pcie_retrain(struct pci_dev *dev)
-{
- u16 linkcap, linkstat;
- struct altera_pcie *pcie = dev->bus->sysdata;
- int timeout = 0;
-
- if (!altera_pcie_link_is_up(pcie))
- return;
-
- /*
- * Set the retrain bit if the PCIe rootport support > 2.5GB/s, but
- * current speed is 2.5 GB/s.
- */
- pcie_capability_read_word(dev, PCI_EXP_LNKCAP, &linkcap);
-
- if ((linkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
- return;
-
- pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &linkstat);
- if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
- pcie_capability_set_word(dev, PCI_EXP_LNKCTL,
- PCI_EXP_LNKCTL_RL);
- while (!altera_pcie_link_is_up(pcie)) {
- timeout++;
- if (timeout > LINK_UP_TIMEOUT)
- break;
- udelay(5);
- }
- }
-}
-DECLARE_PCI_FIXUP_EARLY(0x1172, PCI_ANY_ID, altera_pcie_retrain);
-
/*
* Altera PCIe port uses BAR0 of RC's configuration space as the translation
* from PCI bus to native BUS. Entire DDR region is mapped into PCIe space
@@ -171,13 +144,6 @@ static bool altera_pcie_valid_config(struct altera_pcie *pcie,
if (bus->number == pcie->root_bus_nr && dev > 0)
return false;
- /*
- * Do not read more than one device on the bus directly attached
- * to root port, root port can only attach to one downstream port.
- */
- if (bus->primary == pcie->root_bus_nr && dev > 0)
- return false;
-
return true;
}
@@ -301,22 +267,14 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn,
return PCIBIOS_SUCCESSFUL;
}
-static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *value)
+static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno,
+ unsigned int devfn, int where, int size,
+ u32 *value)
{
- struct altera_pcie *pcie = bus->sysdata;
int ret;
u32 data;
u8 byte_en;
- if (altera_pcie_hide_rc_bar(bus, devfn, where))
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) {
- *value = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
switch (size) {
case 1:
byte_en = 1 << (where & 3);
@@ -329,7 +287,7 @@ static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
break;
}
- ret = tlp_cfg_dword_read(pcie, bus->number, devfn,
+ ret = tlp_cfg_dword_read(pcie, busno, devfn,
(where & ~DWORD_MASK), byte_en, &data);
if (ret != PCIBIOS_SUCCESSFUL)
return ret;
@@ -349,20 +307,14 @@ static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
}
-static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 value)
+static int _altera_pcie_cfg_write(struct altera_pcie *pcie, u8 busno,
+ unsigned int devfn, int where, int size,
+ u32 value)
{
- struct altera_pcie *pcie = bus->sysdata;
u32 data32;
u32 shift = 8 * (where & 3);
u8 byte_en;
- if (altera_pcie_hide_rc_bar(bus, devfn, where))
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn)))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
switch (size) {
case 1:
data32 = (value & 0xff) << shift;
@@ -378,8 +330,40 @@ static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn,
break;
}
- return tlp_cfg_dword_write(pcie, bus->number, devfn,
- (where & ~DWORD_MASK), byte_en, data32);
+ return tlp_cfg_dword_write(pcie, busno, devfn, (where & ~DWORD_MASK),
+ byte_en, data32);
+}
+
+static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ struct altera_pcie *pcie = bus->sysdata;
+
+ if (altera_pcie_hide_rc_bar(bus, devfn, where))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) {
+ *value = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return _altera_pcie_cfg_read(pcie, bus->number, devfn, where, size,
+ value);
+}
+
+static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct altera_pcie *pcie = bus->sysdata;
+
+ if (altera_pcie_hide_rc_bar(bus, devfn, where))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return _altera_pcie_cfg_write(pcie, bus->number, devfn, where, size,
+ value);
}
static struct pci_ops altera_pcie_ops = {
@@ -387,6 +371,90 @@ static struct pci_ops altera_pcie_ops = {
.write = altera_pcie_cfg_write,
};
+static int altera_read_cap_word(struct altera_pcie *pcie, u8 busno,
+ unsigned int devfn, int offset, u16 *value)
+{
+ u32 data;
+ int ret;
+
+ ret = _altera_pcie_cfg_read(pcie, busno, devfn,
+ PCIE_CAP_OFFSET + offset, sizeof(*value),
+ &data);
+ *value = data;
+ return ret;
+}
+
+static int altera_write_cap_word(struct altera_pcie *pcie, u8 busno,
+ unsigned int devfn, int offset, u16 value)
+{
+ return _altera_pcie_cfg_write(pcie, busno, devfn,
+ PCIE_CAP_OFFSET + offset, sizeof(value),
+ value);
+}
+
+static void altera_wait_link_retrain(struct altera_pcie *pcie)
+{
+ u16 reg16;
+ unsigned long start_jiffies;
+
+ /* Wait for link training end. */
+ start_jiffies = jiffies;
+ for (;;) {
+ altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN,
+ PCI_EXP_LNKSTA, &reg16);
+ if (!(reg16 & PCI_EXP_LNKSTA_LT))
+ break;
+
+ if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) {
+ dev_err(&pcie->pdev->dev, "link retrain timeout\n");
+ break;
+ }
+ udelay(100);
+ }
+
+ /* Wait for link is up */
+ start_jiffies = jiffies;
+ for (;;) {
+ if (altera_pcie_link_is_up(pcie))
+ break;
+
+ if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) {
+ dev_err(&pcie->pdev->dev, "link up timeout\n");
+ break;
+ }
+ udelay(100);
+ }
+}
+
+static void altera_pcie_retrain(struct altera_pcie *pcie)
+{
+ u16 linkcap, linkstat, linkctl;
+
+ if (!altera_pcie_link_is_up(pcie))
+ return;
+
+ /*
+ * Set the retrain bit if the PCIe rootport support > 2.5GB/s, but
+ * current speed is 2.5 GB/s.
+ */
+ altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN, PCI_EXP_LNKCAP,
+ &linkcap);
+ if ((linkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+ return;
+
+ altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN, PCI_EXP_LNKSTA,
+ &linkstat);
+ if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+ altera_read_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN,
+ PCI_EXP_LNKCTL, &linkctl);
+ linkctl |= PCI_EXP_LNKCTL_RL;
+ altera_write_cap_word(pcie, pcie->root_bus_nr, RP_DEVFN,
+ PCI_EXP_LNKCTL, linkctl);
+
+ altera_wait_link_retrain(pcie);
+ }
+}
+
static int altera_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
@@ -508,6 +576,11 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
return 0;
}
+static void altera_pcie_host_init(struct altera_pcie *pcie)
+{
+ altera_pcie_retrain(pcie);
+}
+
static int altera_pcie_probe(struct platform_device *pdev)
{
struct altera_pcie *pcie;
@@ -545,6 +618,7 @@ static int altera_pcie_probe(struct platform_device *pdev)
cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
/* enable all interrupts */
cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
+ altera_pcie_host_init(pcie);
bus = pci_scan_root_bus(&pdev->dev, pcie->root_bus_nr, &altera_pcie_ops,
pcie, &pcie->resources);
@@ -568,7 +642,6 @@ static const struct of_device_id altera_pcie_of_match[] = {
{ .compatible = "altr,pcie-root-port-1.0", },
{},
};
-MODULE_DEVICE_TABLE(of, altera_pcie_of_match);
static struct platform_driver altera_pcie_driver = {
.probe = altera_pcie_probe,
@@ -583,8 +656,4 @@ static int altera_pcie_init(void)
{
return platform_driver_register(&altera_pcie_driver);
}
-module_init(altera_pcie_init);
-
-MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
-MODULE_DESCRIPTION("Altera PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
+device_initcall(altera_pcie_init);
diff --git a/drivers/pci/host/pcie-artpec6.c b/drivers/pci/host/pcie-artpec6.c
index 16ba70b7ec65..39bf1a6df463 100644
--- a/drivers/pci/host/pcie-artpec6.c
+++ b/drivers/pci/host/pcie-artpec6.c
@@ -191,8 +191,8 @@ static irqreturn_t artpec6_pcie_msi_handler(int irq, void *arg)
return dw_handle_msi_irq(pp);
}
-static int __init artpec6_add_pcie_port(struct pcie_port *pp,
- struct platform_device *pdev)
+static int artpec6_add_pcie_port(struct pcie_port *pp,
+ struct platform_device *pdev)
{
int ret;
diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/host/pcie-designware-plat.c
index c8079dc81c10..17da005497a5 100644
--- a/drivers/pci/host/pcie-designware-plat.c
+++ b/drivers/pci/host/pcie-designware-plat.c
@@ -100,9 +100,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
pp->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
dw_plat_pcie->mem_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dw_plat_pcie->mem_base))
return PTR_ERR(dw_plat_pcie->mem_base);
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 12afce19890b..74da71ea544a 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -14,7 +14,6 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
@@ -26,7 +25,17 @@
#include "pcie-designware.h"
-/* Synopsis specific PCIE configuration registers */
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_USLEEP_MIN 90000
+#define LINK_WAIT_USLEEP_MAX 100000
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES 5
+#define LINK_WAIT_IATU_MIN 9000
+#define LINK_WAIT_IATU_MAX 10000
+
+/* Synopsys-specific PCIe configuration registers */
#define PCIE_PORT_LINK_CONTROL 0x710
#define PORT_LINK_MODE_MASK (0x3f << 16)
#define PORT_LINK_MODE_1_LANES (0x1 << 16)
@@ -51,6 +60,7 @@
#define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX2 (0x2 << 0)
#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
#define PCIE_ATU_CR1 0x904
@@ -70,10 +80,26 @@
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
#define PCIE_ATU_UPPER_TARGET 0x91C
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll
+ */
+#define PCIE_ATU_UNR_REGION_CTRL1 0x00
+#define PCIE_ATU_UNR_REGION_CTRL2 0x04
+#define PCIE_ATU_UNR_LOWER_BASE 0x08
+#define PCIE_ATU_UNR_UPPER_BASE 0x0C
+#define PCIE_ATU_UNR_LIMIT 0x10
+#define PCIE_ATU_UNR_LOWER_TARGET 0x14
+#define PCIE_ATU_UNR_UPPER_TARGET 0x18
+
+/* Register address builder */
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((0x3 << 20) | (region << 9))
+
/* PCIe Port Logic registers */
#define PLR_OFFSET 0x700
#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
-#define PCIE_PHY_DEBUG_R1_LINK_UP 0x00000010
+#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4)
+#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
static struct pci_ops dw_pcie_ops;
@@ -115,12 +141,12 @@ int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
return PCIBIOS_SUCCESSFUL;
}
-static inline void dw_pcie_readl_rc(struct pcie_port *pp, u32 reg, u32 *val)
+static inline u32 dw_pcie_readl_rc(struct pcie_port *pp, u32 reg)
{
if (pp->ops->readl_rc)
- pp->ops->readl_rc(pp, pp->dbi_base + reg, val);
- else
- *val = readl(pp->dbi_base + reg);
+ return pp->ops->readl_rc(pp, pp->dbi_base + reg);
+
+ return readl(pp->dbi_base + reg);
}
static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
@@ -131,6 +157,27 @@ static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
writel(val, pp->dbi_base + reg);
}
+static inline u32 dw_pcie_readl_unroll(struct pcie_port *pp, u32 index, u32 reg)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+ if (pp->ops->readl_rc)
+ return pp->ops->readl_rc(pp, pp->dbi_base + offset + reg);
+
+ return readl(pp->dbi_base + offset + reg);
+}
+
+static inline void dw_pcie_writel_unroll(struct pcie_port *pp, u32 index,
+ u32 val, u32 reg)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+ if (pp->ops->writel_rc)
+ pp->ops->writel_rc(pp, val, pp->dbi_base + offset + reg);
+ else
+ writel(val, pp->dbi_base + offset + reg);
+}
+
static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
u32 *val)
{
@@ -152,24 +199,57 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
int type, u64 cpu_addr, u64 pci_addr, u32 size)
{
- u32 val;
-
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET);
- dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+ u32 retries, val;
+
+ if (pp->iatu_unroll_enabled) {
+ dw_pcie_writel_unroll(pp, index,
+ lower_32_bits(cpu_addr), PCIE_ATU_UNR_LOWER_BASE);
+ dw_pcie_writel_unroll(pp, index,
+ upper_32_bits(cpu_addr), PCIE_ATU_UNR_UPPER_BASE);
+ dw_pcie_writel_unroll(pp, index,
+ lower_32_bits(cpu_addr + size - 1), PCIE_ATU_UNR_LIMIT);
+ dw_pcie_writel_unroll(pp, index,
+ lower_32_bits(pci_addr), PCIE_ATU_UNR_LOWER_TARGET);
+ dw_pcie_writel_unroll(pp, index,
+ upper_32_bits(pci_addr), PCIE_ATU_UNR_UPPER_TARGET);
+ dw_pcie_writel_unroll(pp, index,
+ type, PCIE_ATU_UNR_REGION_CTRL1);
+ dw_pcie_writel_unroll(pp, index,
+ PCIE_ATU_ENABLE, PCIE_ATU_UNR_REGION_CTRL2);
+ } else {
+ dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,
+ PCIE_ATU_VIEWPORT);
+ dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr),
+ PCIE_ATU_LOWER_BASE);
+ dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr),
+ PCIE_ATU_UPPER_BASE);
+ dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),
+ PCIE_ATU_LIMIT);
+ dw_pcie_writel_rc(pp, lower_32_bits(pci_addr),
+ PCIE_ATU_LOWER_TARGET);
+ dw_pcie_writel_rc(pp, upper_32_bits(pci_addr),
+ PCIE_ATU_UPPER_TARGET);
+ dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);
+ dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+ }
/*
* Make sure ATU enable takes effect before any subsequent config
* and I/O accesses.
*/
- dw_pcie_readl_rc(pp, PCIE_ATU_CR2, &val);
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ if (pp->iatu_unroll_enabled)
+ val = dw_pcie_readl_unroll(pp, index,
+ PCIE_ATU_UNR_REGION_CTRL2);
+ else
+ val = dw_pcie_readl_rc(pp, PCIE_ATU_CR2);
+
+ if (val == PCIE_ATU_ENABLE)
+ return;
+
+ usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX);
+ }
+ dev_err(pp->dev, "iATU is not being enabled\n");
}
static struct irq_chip dw_msi_irq_chip = {
@@ -412,7 +492,8 @@ int dw_pcie_link_up(struct pcie_port *pp)
return pp->ops->link_up(pp);
val = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
- return val & PCIE_PHY_DEBUG_R1_LINK_UP;
+ return ((val & PCIE_PHY_DEBUG_R1_LINK_UP) &&
+ (!(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING)));
}
static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
@@ -428,6 +509,17 @@ static const struct irq_domain_ops msi_domain_ops = {
.map = dw_pcie_msi_map,
};
+static u8 dw_pcie_iatu_unroll_enabled(struct pcie_port *pp)
+{
+ u32 val;
+
+ val = dw_pcie_readl_rc(pp, PCIE_ATU_VIEWPORT);
+ if (val == 0xffffffff)
+ return 1;
+
+ return 0;
+}
+
int dw_pcie_host_init(struct pcie_port *pp)
{
struct device_node *np = pp->dev->of_node;
@@ -436,7 +528,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
struct resource *cfg_res;
int i, ret;
LIST_HEAD(res);
- struct resource_entry *win;
+ struct resource_entry *win, *tmp;
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (cfg_res) {
@@ -457,17 +549,20 @@ int dw_pcie_host_init(struct pcie_port *pp)
goto error;
/* Get the I/O and memory ranges from DT */
- resource_list_for_each_entry(win, &res) {
+ resource_list_for_each_entry_safe(win, tmp, &res) {
switch (resource_type(win->res)) {
case IORESOURCE_IO:
- pp->io = win->res;
- pp->io->name = "I/O";
- pp->io_size = resource_size(pp->io);
- pp->io_bus_addr = pp->io->start - win->offset;
- ret = pci_remap_iospace(pp->io, pp->io_base);
- if (ret)
+ ret = pci_remap_iospace(win->res, pp->io_base);
+ if (ret) {
dev_warn(pp->dev, "error %d: failed to map resource %pR\n",
- ret, pp->io);
+ ret, win->res);
+ resource_list_destroy_entry(win);
+ } else {
+ pp->io = win->res;
+ pp->io->name = "I/O";
+ pp->io_size = resource_size(pp->io);
+ pp->io_bus_addr = pp->io->start - win->offset;
+ }
break;
case IORESOURCE_MEM:
pp->mem = win->res;
@@ -524,6 +619,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (ret)
pp->lanes = 0;
+ ret = of_property_read_u32(np, "num-viewport", &pp->num_viewport);
+ if (ret)
+ pp->num_viewport = 2;
+
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (!pp->ops->msi_host_init) {
pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
@@ -544,6 +643,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
}
}
+ pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp);
+
if (pp->ops->host_init)
pp->ops->host_init(pp);
@@ -609,13 +710,14 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
va_cfg_base = pp->va_cfg1_base;
}
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
type, cpu_addr,
busdev, cfg_size);
ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_IO, pp->io_base,
- pp->io_bus_addr, pp->io_size);
+ if (pp->num_viewport <= 2)
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pp->io_base,
+ pp->io_bus_addr, pp->io_size);
return ret;
}
@@ -646,13 +748,14 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
va_cfg_base = pp->va_cfg1_base;
}
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
type, cpu_addr,
busdev, cfg_size);
ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_IO, pp->io_base,
- pp->io_bus_addr, pp->io_size);
+ if (pp->num_viewport <= 2)
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pp->io_base,
+ pp->io_bus_addr, pp->io_size);
return ret;
}
@@ -670,13 +773,6 @@ static int dw_pcie_valid_config(struct pcie_port *pp,
if (bus->number == pp->root_bus_nr && dev > 0)
return 0;
- /*
- * do not read more than one device on the bus directly attached
- * to RC's (Virtual Bridge's) DS side.
- */
- if (bus->primary == pp->root_bus_nr && dev > 0)
- return 0;
-
return 1;
}
@@ -720,7 +816,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
u32 val;
/* set the number of lanes */
- dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
+ val = dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL);
val &= ~PORT_LINK_MODE_MASK;
switch (pp->lanes) {
case 1:
@@ -742,7 +838,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
/* set link width speed control register */
- dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, &val);
+ val = dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL);
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
switch (pp->lanes) {
case 1:
@@ -765,19 +861,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
/* setup interrupt pins */
- dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
+ val = dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE);
val &= 0xffff00ff;
val |= 0x00000100;
dw_pcie_writel_rc(pp, val, PCI_INTERRUPT_LINE);
/* setup bus numbers */
- dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
+ val = dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS);
val &= 0xff000000;
val |= 0x00010100;
dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
/* setup command register */
- dw_pcie_readl_rc(pp, PCI_COMMAND, &val);
+ val = dw_pcie_readl_rc(pp, PCI_COMMAND);
val &= 0xffff0000;
val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
@@ -788,10 +884,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
* uses its own address translation component rather than ATU, so
* we should not program the ATU here.
*/
- if (!pp->ops->rd_other_conf)
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
+ if (!pp->ops->rd_other_conf) {
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM, pp->mem_base,
pp->mem_bus_addr, pp->mem_size);
+ if (pp->num_viewport > 2)
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX2,
+ PCIE_ATU_TYPE_IO, pp->io_base,
+ pp->io_bus_addr, pp->io_size);
+ }
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
@@ -802,7 +903,3 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
val |= PORT_LOGIC_SPEED_CHANGE;
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
}
-
-MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
-MODULE_DESCRIPTION("Designware PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index f437f9b5be04..c8e5bc647f49 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -22,11 +22,6 @@
#define MAX_MSI_IRQS 32
#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
-/* Parameters for the waiting for link up routine */
-#define LINK_WAIT_MAX_RETRIES 10
-#define LINK_WAIT_USLEEP_MIN 90000
-#define LINK_WAIT_USLEEP_MAX 100000
-
struct pcie_port {
struct device *dev;
u8 root_bus_nr;
@@ -49,16 +44,17 @@ struct pcie_port {
struct resource *busn;
int irq;
u32 lanes;
+ u32 num_viewport;
struct pcie_host_ops *ops;
int msi_irq;
struct irq_domain *irq_domain;
unsigned long msi_data;
+ u8 iatu_unroll_enabled;
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
};
struct pcie_host_ops {
- void (*readl_rc)(struct pcie_port *pp,
- void __iomem *dbi_base, u32 *val);
+ u32 (*readl_rc)(struct pcie_port *pp, void __iomem *dbi_base);
void (*writel_rc)(struct pcie_port *pp,
u32 val, void __iomem *dbi_base);
int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c
index f2f90c50f75d..5ec2d440a6b7 100644
--- a/drivers/pci/host/pcie-qcom.c
+++ b/drivers/pci/host/pcie-qcom.c
@@ -1,7 +1,11 @@
/*
+ * Qualcomm PCIe root complex driver
+ *
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
* Copyright 2015 Linaro Limited.
*
+ * Author: Stanimir Varbanov <svarbanov@mm-sol.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 and
* only version 2 as published by the Free Software Foundation.
@@ -19,7 +23,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pci.h>
@@ -570,37 +574,19 @@ static int qcom_pcie_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_pcie_remove(struct platform_device *pdev)
-{
- struct qcom_pcie *pcie = platform_get_drvdata(pdev);
-
- qcom_ep_reset_assert(pcie);
- phy_power_off(pcie->phy);
- phy_exit(pcie->phy);
- pcie->ops->deinit(pcie);
-
- return 0;
-}
-
static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-ipq8064", .data = &ops_v0 },
{ .compatible = "qcom,pcie-apq8064", .data = &ops_v0 },
{ .compatible = "qcom,pcie-apq8084", .data = &ops_v1 },
{ }
};
-MODULE_DEVICE_TABLE(of, qcom_pcie_match);
static struct platform_driver qcom_pcie_driver = {
.probe = qcom_pcie_probe,
- .remove = qcom_pcie_remove,
.driver = {
.name = "qcom-pcie",
+ .suppress_bind_attrs = true,
.of_match_table = qcom_pcie_match,
},
};
-
-module_platform_driver(qcom_pcie_driver);
-
-MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
-MODULE_DESCRIPTION("Qualcomm PCIe root complex driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(qcom_pcie_driver);
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 65db7a221509..e06b1d3b4dea 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -84,8 +84,18 @@
#define IDSETR1 0x011004
#define TLCTLR 0x011048
#define MACSR 0x011054
+#define SPCHGFIN (1 << 4)
+#define SPCHGFAIL (1 << 6)
+#define SPCHGSUC (1 << 7)
+#define LINK_SPEED (0xf << 16)
+#define LINK_SPEED_2_5GTS (1 << 16)
+#define LINK_SPEED_5_0GTS (2 << 16)
#define MACCTLR 0x011058
+#define SPEED_CHANGE (1 << 24)
#define SCRAMBLE_DISABLE (1 << 27)
+#define MACS2R 0x011078
+#define MACCGSPSETR 0x011084
+#define SPCNGRSN (1 << 31)
/* R-Car H1 PHY */
#define H1_PCIEPHYADRR 0x04000c
@@ -385,11 +395,67 @@ static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci)
return 1;
}
+static void rcar_pcie_force_speedup(struct rcar_pcie *pcie)
+{
+ unsigned int timeout = 1000;
+ u32 macsr;
+
+ if ((rcar_pci_read_reg(pcie, MACS2R) & LINK_SPEED) != LINK_SPEED_5_0GTS)
+ return;
+
+ if (rcar_pci_read_reg(pcie, MACCTLR) & SPEED_CHANGE) {
+ dev_err(pcie->dev, "Speed change already in progress\n");
+ return;
+ }
+
+ macsr = rcar_pci_read_reg(pcie, MACSR);
+ if ((macsr & LINK_SPEED) == LINK_SPEED_5_0GTS)
+ goto done;
+
+ /* Set target link speed to 5.0 GT/s */
+ rcar_rmw32(pcie, EXPCAP(12), PCI_EXP_LNKSTA_CLS,
+ PCI_EXP_LNKSTA_CLS_5_0GB);
+
+ /* Set speed change reason as intentional factor */
+ rcar_rmw32(pcie, MACCGSPSETR, SPCNGRSN, 0);
+
+ /* Clear SPCHGFIN, SPCHGSUC, and SPCHGFAIL */
+ if (macsr & (SPCHGFIN | SPCHGSUC | SPCHGFAIL))
+ rcar_pci_write_reg(pcie, macsr, MACSR);
+
+ /* Start link speed change */
+ rcar_rmw32(pcie, MACCTLR, SPEED_CHANGE, SPEED_CHANGE);
+
+ while (timeout--) {
+ macsr = rcar_pci_read_reg(pcie, MACSR);
+ if (macsr & SPCHGFIN) {
+ /* Clear the interrupt bits */
+ rcar_pci_write_reg(pcie, macsr, MACSR);
+
+ if (macsr & SPCHGFAIL)
+ dev_err(pcie->dev, "Speed change failed\n");
+
+ goto done;
+ }
+
+ msleep(1);
+ };
+
+ dev_err(pcie->dev, "Speed change timed out\n");
+
+done:
+ dev_info(pcie->dev, "Current link speed is %s GT/s\n",
+ (macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5");
+}
+
static int rcar_pcie_enable(struct rcar_pcie *pcie)
{
struct pci_bus *bus, *child;
LIST_HEAD(res);
+ /* Try setting 5 GT/s link speed */
+ rcar_pcie_force_speedup(pcie);
+
rcar_pcie_setup(&res, pcie);
pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
@@ -608,6 +674,18 @@ static int rcar_msi_alloc(struct rcar_msi *chip)
return msi;
}
+static int rcar_msi_alloc_region(struct rcar_msi *chip, int no_irqs)
+{
+ int msi;
+
+ mutex_lock(&chip->lock);
+ msi = bitmap_find_free_region(chip->used, INT_PCI_MSI_NR,
+ order_base_2(no_irqs));
+ mutex_unlock(&chip->lock);
+
+ return msi;
+}
+
static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq)
{
mutex_lock(&chip->lock);
@@ -665,7 +743,7 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
if (hwirq < 0)
return hwirq;
- irq = irq_create_mapping(msi->domain, hwirq);
+ irq = irq_find_mapping(msi->domain, hwirq);
if (!irq) {
rcar_msi_free(msi, hwirq);
return -EINVAL;
@@ -682,6 +760,58 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
return 0;
}
+static int rcar_msi_setup_irqs(struct msi_controller *chip,
+ struct pci_dev *pdev, int nvec, int type)
+{
+ struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip);
+ struct rcar_msi *msi = to_rcar_msi(chip);
+ struct msi_desc *desc;
+ struct msi_msg msg;
+ unsigned int irq;
+ int hwirq;
+ int i;
+
+ /* MSI-X interrupts are not supported */
+ if (type == PCI_CAP_ID_MSIX)
+ return -EINVAL;
+
+ WARN_ON(!list_is_singular(&pdev->dev.msi_list));
+ desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
+
+ hwirq = rcar_msi_alloc_region(msi, nvec);
+ if (hwirq < 0)
+ return -ENOSPC;
+
+ irq = irq_find_mapping(msi->domain, hwirq);
+ if (!irq)
+ return -ENOSPC;
+
+ for (i = 0; i < nvec; i++) {
+ /*
+ * irq_create_mapping() called from rcar_pcie_probe() pre-
+ * allocates descs, so there is no need to allocate descs here.
+ * We can therefore assume that if irq_find_mapping() above
+ * returns non-zero, then the descs are also successfully
+ * allocated.
+ */
+ if (irq_set_msi_desc_off(irq, i, desc)) {
+ /* TODO: clear */
+ return -EINVAL;
+ }
+ }
+
+ desc->nvec_used = nvec;
+ desc->msi_attrib.multiple = order_base_2(nvec);
+
+ msg.address_lo = rcar_pci_read_reg(pcie, PCIEMSIALR) & ~MSIFE;
+ msg.address_hi = rcar_pci_read_reg(pcie, PCIEMSIAUR);
+ msg.data = hwirq;
+
+ pci_write_msi_msg(irq, &msg);
+
+ return 0;
+}
+
static void rcar_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
{
struct rcar_msi *msi = to_rcar_msi(chip);
@@ -716,12 +846,13 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
struct platform_device *pdev = to_platform_device(pcie->dev);
struct rcar_msi *msi = &pcie->msi;
unsigned long base;
- int err;
+ int err, i;
mutex_init(&msi->lock);
msi->chip.dev = pcie->dev;
msi->chip.setup_irq = rcar_msi_setup_irq;
+ msi->chip.setup_irqs = rcar_msi_setup_irqs;
msi->chip.teardown_irq = rcar_msi_teardown_irq;
msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR,
@@ -731,6 +862,9 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
return -ENOMEM;
}
+ for (i = 0; i < INT_PCI_MSI_NR; i++)
+ irq_create_mapping(msi->domain, i);
+
/* Two irqs are for MSI, but they are also used for non-MSI irqs */
err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq,
IRQF_SHARED | IRQF_NO_THREAD,
@@ -775,6 +909,10 @@ static int rcar_pcie_get_resources(struct platform_device *pdev,
if (err)
return err;
+ pcie->base = devm_ioremap_resource(&pdev->dev, &res);
+ if (IS_ERR(pcie->base))
+ return PTR_ERR(pcie->base);
+
pcie->clk = devm_clk_get(&pdev->dev, "pcie");
if (IS_ERR(pcie->clk)) {
dev_err(pcie->dev, "cannot get platform clock\n");
@@ -782,7 +920,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev,
}
err = clk_prepare_enable(pcie->clk);
if (err)
- goto fail_clk;
+ return err;
pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
if (IS_ERR(pcie->bus_clk)) {
@@ -792,7 +930,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev,
}
err = clk_prepare_enable(pcie->bus_clk);
if (err)
- goto err_map_reg;
+ goto fail_clk;
i = irq_of_parse_and_map(pdev->dev.of_node, 0);
if (!i) {
@@ -810,12 +948,6 @@ static int rcar_pcie_get_resources(struct platform_device *pdev,
}
pcie->msi.irq2 = i;
- pcie->base = devm_ioremap_resource(&pdev->dev, &res);
- if (IS_ERR(pcie->base)) {
- err = PTR_ERR(pcie->base);
- goto err_map_reg;
- }
-
return 0;
err_map_reg:
@@ -865,12 +997,16 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
* Set up 64-bit inbound regions as the range parser doesn't
* distinguish between 32 and 64-bit types.
*/
- rcar_pci_write_reg(pcie, lower_32_bits(pci_addr), PCIEPRAR(idx));
+ rcar_pci_write_reg(pcie, lower_32_bits(pci_addr),
+ PCIEPRAR(idx));
rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
- rcar_pci_write_reg(pcie, lower_32_bits(mask) | flags, PCIELAMR(idx));
+ rcar_pci_write_reg(pcie, lower_32_bits(mask) | flags,
+ PCIELAMR(idx));
- rcar_pci_write_reg(pcie, upper_32_bits(pci_addr), PCIEPRAR(idx+1));
- rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx+1));
+ rcar_pci_write_reg(pcie, upper_32_bits(pci_addr),
+ PCIEPRAR(idx + 1));
+ rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr),
+ PCIELAR(idx + 1));
rcar_pci_write_reg(pcie, 0, PCIELAMR(idx + 1));
pci_addr += size;
@@ -919,6 +1055,7 @@ static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
/* Get the dma-ranges from DT */
for_each_of_pci_range(&parser, &range) {
u64 end = range.cpu_addr + range.size - 1;
+
dev_dbg(pcie->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
range.flags, range.cpu_addr, end, range.pci_addr);
@@ -932,9 +1069,12 @@ static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie,
static const struct of_device_id rcar_pcie_of_match[] = {
{ .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 },
- { .compatible = "renesas,pcie-rcar-gen2", .data = rcar_pcie_hw_init_gen2 },
- { .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init_gen2 },
- { .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init_gen2 },
+ { .compatible = "renesas,pcie-rcar-gen2",
+ .data = rcar_pcie_hw_init_gen2 },
+ { .compatible = "renesas,pcie-r8a7790",
+ .data = rcar_pcie_hw_init_gen2 },
+ { .compatible = "renesas,pcie-r8a7791",
+ .data = rcar_pcie_hw_init_gen2 },
{ .compatible = "renesas,pcie-r8a7795", .data = rcar_pcie_hw_init },
{},
};
@@ -945,9 +1085,10 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
struct device *dev = pci->dev;
struct device_node *np = dev->of_node;
resource_size_t iobase;
- struct resource_entry *win;
+ struct resource_entry *win, *tmp;
- err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, &iobase);
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
+ &iobase);
if (err)
return err;
@@ -955,14 +1096,17 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
if (err)
goto out_release_res;
- resource_list_for_each_entry(win, &pci->resources) {
+ resource_list_for_each_entry_safe(win, tmp, &pci->resources) {
struct resource *res = win->res;
if (resource_type(res) == IORESOURCE_IO) {
err = pci_remap_iospace(res, iobase);
- if (err)
+ if (err) {
dev_warn(dev, "error %d: failed to map resource %pR\n",
err, res);
+
+ resource_list_destroy_entry(win);
+ }
}
}
@@ -998,8 +1142,8 @@ static int rcar_pcie_probe(struct platform_device *pdev)
return err;
}
- err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node);
- if (err)
+ err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node);
+ if (err)
return err;
of_id = of_match_device(rcar_pcie_of_match, pcie->dev);
diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
new file mode 100644
index 000000000000..b8c82fc812dc
--- /dev/null
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -0,0 +1,1229 @@
+/*
+ * Rockchip AXI PCIe host controller driver
+ *
+ * Copyright (c) 2016 Rockchip, Inc.
+ *
+ * Author: Shawn Lin <shawn.lin@rock-chips.com>
+ * Wenrui Li <wenrui.li@rock-chips.com>
+ *
+ * Bits taken from Synopsys Designware Host controller driver and
+ * ARM PCI Host generic driver.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+/*
+ * The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16
+ * bits. This allows atomic updates of the register without locking.
+ */
+#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
+#define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val)
+
+#define ENCODE_LANES(x) ((((x) >> 1) & 3) << 4)
+
+#define PCIE_CLIENT_BASE 0x0
+#define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00)
+#define PCIE_CLIENT_CONF_ENABLE HIWORD_UPDATE_BIT(0x0001)
+#define PCIE_CLIENT_LINK_TRAIN_ENABLE HIWORD_UPDATE_BIT(0x0002)
+#define PCIE_CLIENT_ARI_ENABLE HIWORD_UPDATE_BIT(0x0008)
+#define PCIE_CLIENT_CONF_LANE_NUM(x) HIWORD_UPDATE(0x0030, ENCODE_LANES(x))
+#define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040)
+#define PCIE_CLIENT_GEN_SEL_2 HIWORD_UPDATE_BIT(0x0080)
+#define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48)
+#define PCIE_CLIENT_LINK_STATUS_UP 0x00300000
+#define PCIE_CLIENT_LINK_STATUS_MASK 0x00300000
+#define PCIE_CLIENT_INT_MASK (PCIE_CLIENT_BASE + 0x4c)
+#define PCIE_CLIENT_INT_STATUS (PCIE_CLIENT_BASE + 0x50)
+#define PCIE_CLIENT_INTR_MASK GENMASK(8, 5)
+#define PCIE_CLIENT_INTR_SHIFT 5
+#define PCIE_CLIENT_INT_LEGACY_DONE BIT(15)
+#define PCIE_CLIENT_INT_MSG BIT(14)
+#define PCIE_CLIENT_INT_HOT_RST BIT(13)
+#define PCIE_CLIENT_INT_DPA BIT(12)
+#define PCIE_CLIENT_INT_FATAL_ERR BIT(11)
+#define PCIE_CLIENT_INT_NFATAL_ERR BIT(10)
+#define PCIE_CLIENT_INT_CORR_ERR BIT(9)
+#define PCIE_CLIENT_INT_INTD BIT(8)
+#define PCIE_CLIENT_INT_INTC BIT(7)
+#define PCIE_CLIENT_INT_INTB BIT(6)
+#define PCIE_CLIENT_INT_INTA BIT(5)
+#define PCIE_CLIENT_INT_LOCAL BIT(4)
+#define PCIE_CLIENT_INT_UDMA BIT(3)
+#define PCIE_CLIENT_INT_PHY BIT(2)
+#define PCIE_CLIENT_INT_HOT_PLUG BIT(1)
+#define PCIE_CLIENT_INT_PWR_STCG BIT(0)
+
+#define PCIE_CLIENT_INT_LEGACY \
+ (PCIE_CLIENT_INT_INTA | PCIE_CLIENT_INT_INTB | \
+ PCIE_CLIENT_INT_INTC | PCIE_CLIENT_INT_INTD)
+
+#define PCIE_CLIENT_INT_CLI \
+ (PCIE_CLIENT_INT_CORR_ERR | PCIE_CLIENT_INT_NFATAL_ERR | \
+ PCIE_CLIENT_INT_FATAL_ERR | PCIE_CLIENT_INT_DPA | \
+ PCIE_CLIENT_INT_HOT_RST | PCIE_CLIENT_INT_MSG | \
+ PCIE_CLIENT_INT_LEGACY_DONE | PCIE_CLIENT_INT_LEGACY | \
+ PCIE_CLIENT_INT_PHY)
+
+#define PCIE_CORE_CTRL_MGMT_BASE 0x900000
+#define PCIE_CORE_CTRL (PCIE_CORE_CTRL_MGMT_BASE + 0x000)
+#define PCIE_CORE_PL_CONF_SPEED_5G 0x00000008
+#define PCIE_CORE_PL_CONF_SPEED_MASK 0x00000018
+#define PCIE_CORE_PL_CONF_LANE_MASK 0x00000006
+#define PCIE_CORE_PL_CONF_LANE_SHIFT 1
+#define PCIE_CORE_CTRL_PLC1 (PCIE_CORE_CTRL_MGMT_BASE + 0x004)
+#define PCIE_CORE_CTRL_PLC1_FTS_MASK GENMASK(23, 8)
+#define PCIE_CORE_CTRL_PLC1_FTS_SHIFT 8
+#define PCIE_CORE_CTRL_PLC1_FTS_CNT 0xffff
+#define PCIE_CORE_TXCREDIT_CFG1 (PCIE_CORE_CTRL_MGMT_BASE + 0x020)
+#define PCIE_CORE_TXCREDIT_CFG1_MUI_MASK 0xFFFF0000
+#define PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT 16
+#define PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(x) \
+ (((x) >> 3) << PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT)
+#define PCIE_CORE_INT_STATUS (PCIE_CORE_CTRL_MGMT_BASE + 0x20c)
+#define PCIE_CORE_INT_PRFPE BIT(0)
+#define PCIE_CORE_INT_CRFPE BIT(1)
+#define PCIE_CORE_INT_RRPE BIT(2)
+#define PCIE_CORE_INT_PRFO BIT(3)
+#define PCIE_CORE_INT_CRFO BIT(4)
+#define PCIE_CORE_INT_RT BIT(5)
+#define PCIE_CORE_INT_RTR BIT(6)
+#define PCIE_CORE_INT_PE BIT(7)
+#define PCIE_CORE_INT_MTR BIT(8)
+#define PCIE_CORE_INT_UCR BIT(9)
+#define PCIE_CORE_INT_FCE BIT(10)
+#define PCIE_CORE_INT_CT BIT(11)
+#define PCIE_CORE_INT_UTC BIT(18)
+#define PCIE_CORE_INT_MMVC BIT(19)
+#define PCIE_CORE_INT_MASK (PCIE_CORE_CTRL_MGMT_BASE + 0x210)
+#define PCIE_RC_BAR_CONF (PCIE_CORE_CTRL_MGMT_BASE + 0x300)
+
+#define PCIE_CORE_INT \
+ (PCIE_CORE_INT_PRFPE | PCIE_CORE_INT_CRFPE | \
+ PCIE_CORE_INT_RRPE | PCIE_CORE_INT_CRFO | \
+ PCIE_CORE_INT_RT | PCIE_CORE_INT_RTR | \
+ PCIE_CORE_INT_PE | PCIE_CORE_INT_MTR | \
+ PCIE_CORE_INT_UCR | PCIE_CORE_INT_FCE | \
+ PCIE_CORE_INT_CT | PCIE_CORE_INT_UTC | \
+ PCIE_CORE_INT_MMVC)
+
+#define PCIE_RC_CONFIG_BASE 0xa00000
+#define PCIE_RC_CONFIG_VENDOR (PCIE_RC_CONFIG_BASE + 0x00)
+#define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08)
+#define PCIE_RC_CONFIG_SCC_SHIFT 16
+#define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0)
+#define PCIE_RC_CONFIG_LCS_RETRAIN_LINK BIT(5)
+#define PCIE_RC_CONFIG_LCS_LBMIE BIT(10)
+#define PCIE_RC_CONFIG_LCS_LABIE BIT(11)
+#define PCIE_RC_CONFIG_LCS_LBMS BIT(30)
+#define PCIE_RC_CONFIG_LCS_LAMS BIT(31)
+#define PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 (PCIE_RC_CONFIG_BASE + 0x90c)
+
+#define PCIE_CORE_AXI_CONF_BASE 0xc00000
+#define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0)
+#define PCIE_CORE_OB_REGION_ADDR0_NUM_BITS 0x3f
+#define PCIE_CORE_OB_REGION_ADDR0_LO_ADDR 0xffffff00
+#define PCIE_CORE_OB_REGION_ADDR1 (PCIE_CORE_AXI_CONF_BASE + 0x4)
+#define PCIE_CORE_OB_REGION_DESC0 (PCIE_CORE_AXI_CONF_BASE + 0x8)
+#define PCIE_CORE_OB_REGION_DESC1 (PCIE_CORE_AXI_CONF_BASE + 0xc)
+
+#define PCIE_CORE_AXI_INBOUND_BASE 0xc00800
+#define PCIE_RP_IB_ADDR0 (PCIE_CORE_AXI_INBOUND_BASE + 0x0)
+#define PCIE_CORE_IB_REGION_ADDR0_NUM_BITS 0x3f
+#define PCIE_CORE_IB_REGION_ADDR0_LO_ADDR 0xffffff00
+#define PCIE_RP_IB_ADDR1 (PCIE_CORE_AXI_INBOUND_BASE + 0x4)
+
+/* Size of one AXI Region (not Region 0) */
+#define AXI_REGION_SIZE BIT(20)
+/* Size of Region 0, equal to sum of sizes of other regions */
+#define AXI_REGION_0_SIZE (32 * (0x1 << 20))
+#define OB_REG_SIZE_SHIFT 5
+#define IB_ROOT_PORT_REG_SIZE_SHIFT 3
+#define AXI_WRAPPER_IO_WRITE 0x6
+#define AXI_WRAPPER_MEM_WRITE 0x2
+
+#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3
+#define MIN_AXI_ADDR_BITS_PASSED 8
+#define ROCKCHIP_VENDOR_ID 0x1d87
+#define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20)
+#define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15)
+#define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12)
+#define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0)
+#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
+ (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
+ PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
+
+#define RC_REGION_0_ADDR_TRANS_H 0x00000000
+#define RC_REGION_0_ADDR_TRANS_L 0x00000000
+#define RC_REGION_0_PASS_BITS (25 - 1)
+#define MAX_AXI_WRAPPER_REGION_NUM 33
+
+struct rockchip_pcie {
+ void __iomem *reg_base; /* DT axi-base */
+ void __iomem *apb_base; /* DT apb-base */
+ struct phy *phy;
+ struct reset_control *core_rst;
+ struct reset_control *mgmt_rst;
+ struct reset_control *mgmt_sticky_rst;
+ struct reset_control *pipe_rst;
+ struct clk *aclk_pcie;
+ struct clk *aclk_perf_pcie;
+ struct clk *hclk_pcie;
+ struct clk *clk_pcie_pm;
+ struct regulator *vpcie3v3; /* 3.3V power supply */
+ struct regulator *vpcie1v8; /* 1.8V power supply */
+ struct regulator *vpcie0v9; /* 0.9V power supply */
+ struct gpio_desc *ep_gpio;
+ u32 lanes;
+ u8 root_bus_nr;
+ struct device *dev;
+ struct irq_domain *irq_domain;
+};
+
+static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg)
+{
+ return readl(rockchip->apb_base + reg);
+}
+
+static void rockchip_pcie_write(struct rockchip_pcie *rockchip, u32 val,
+ u32 reg)
+{
+ writel(val, rockchip->apb_base + reg);
+}
+
+static void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rockchip)
+{
+ u32 status;
+
+ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
+ status |= (PCIE_RC_CONFIG_LCS_LBMIE | PCIE_RC_CONFIG_LCS_LABIE);
+ rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
+}
+
+static void rockchip_pcie_clr_bw_int(struct rockchip_pcie *rockchip)
+{
+ u32 status;
+
+ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
+ status |= (PCIE_RC_CONFIG_LCS_LBMS | PCIE_RC_CONFIG_LCS_LAMS);
+ rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
+}
+
+static void rockchip_pcie_update_txcredit_mui(struct rockchip_pcie *rockchip)
+{
+ u32 val;
+
+ /* Update Tx credit maximum update interval */
+ val = rockchip_pcie_read(rockchip, PCIE_CORE_TXCREDIT_CFG1);
+ val &= ~PCIE_CORE_TXCREDIT_CFG1_MUI_MASK;
+ val |= PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(24000); /* ns */
+ rockchip_pcie_write(rockchip, val, PCIE_CORE_TXCREDIT_CFG1);
+}
+
+static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip,
+ struct pci_bus *bus, int dev)
+{
+ /* access only one slot on each root port */
+ if (bus->number == rockchip->root_bus_nr && dev > 0)
+ return 0;
+
+ /*
+ * do not read more than one device on the bus directly attached
+ * to RC's downstream side.
+ */
+ if (bus->primary == rockchip->root_bus_nr && dev > 0)
+ return 0;
+
+ return 1;
+}
+
+static int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip,
+ int where, int size, u32 *val)
+{
+ void __iomem *addr = rockchip->apb_base + PCIE_RC_CONFIG_BASE + where;
+
+ if (!IS_ALIGNED((uintptr_t)addr, size)) {
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (size == 4) {
+ *val = readl(addr);
+ } else if (size == 2) {
+ *val = readw(addr);
+ } else if (size == 1) {
+ *val = readb(addr);
+ } else {
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_wr_own_conf(struct rockchip_pcie *rockchip,
+ int where, int size, u32 val)
+{
+ u32 mask, tmp, offset;
+
+ offset = where & ~0x3;
+
+ if (size == 4) {
+ writel(val, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
+
+ /*
+ * N.B. This read/modify/write isn't safe in general because it can
+ * corrupt RW1C bits in adjacent registers. But the hardware
+ * doesn't support smaller writes.
+ */
+ tmp = readl(rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset) & mask;
+ tmp |= val << ((where & 0x3) * 8);
+ writel(tmp, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
+ struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 *val)
+{
+ u32 busdev;
+
+ busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where);
+
+ if (!IS_ALIGNED(busdev, size)) {
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (size == 4) {
+ *val = readl(rockchip->reg_base + busdev);
+ } else if (size == 2) {
+ *val = readw(rockchip->reg_base + busdev);
+ } else if (size == 1) {
+ *val = readb(rockchip->reg_base + busdev);
+ } else {
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
+ struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ u32 busdev;
+
+ busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where);
+ if (!IS_ALIGNED(busdev, size))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (size == 4)
+ writel(val, rockchip->reg_base + busdev);
+ else if (size == 2)
+ writew(val, rockchip->reg_base + busdev);
+ else if (size == 1)
+ writeb(val, rockchip->reg_base + busdev);
+ else
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ struct rockchip_pcie *rockchip = bus->sysdata;
+
+ if (!rockchip_pcie_valid_device(rockchip, bus, PCI_SLOT(devfn))) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (bus->number == rockchip->root_bus_nr)
+ return rockchip_pcie_rd_own_conf(rockchip, where, size, val);
+
+ return rockchip_pcie_rd_other_conf(rockchip, bus, devfn, where, size, val);
+}
+
+static int rockchip_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ struct rockchip_pcie *rockchip = bus->sysdata;
+
+ if (!rockchip_pcie_valid_device(rockchip, bus, PCI_SLOT(devfn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (bus->number == rockchip->root_bus_nr)
+ return rockchip_pcie_wr_own_conf(rockchip, where, size, val);
+
+ return rockchip_pcie_wr_other_conf(rockchip, bus, devfn, where, size, val);
+}
+
+static struct pci_ops rockchip_pcie_ops = {
+ .read = rockchip_pcie_rd_conf,
+ .write = rockchip_pcie_wr_conf,
+};
+
+/**
+ * rockchip_pcie_init_port - Initialize hardware
+ * @rockchip: PCIe port information
+ */
+static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
+{
+ struct device *dev = rockchip->dev;
+ int err;
+ u32 status;
+ unsigned long timeout;
+
+ gpiod_set_value(rockchip->ep_gpio, 0);
+
+ err = phy_init(rockchip->phy);
+ if (err < 0) {
+ dev_err(dev, "fail to init phy, err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_assert(rockchip->core_rst);
+ if (err) {
+ dev_err(dev, "assert core_rst err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_assert(rockchip->mgmt_rst);
+ if (err) {
+ dev_err(dev, "assert mgmt_rst err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_assert(rockchip->mgmt_sticky_rst);
+ if (err) {
+ dev_err(dev, "assert mgmt_sticky_rst err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_assert(rockchip->pipe_rst);
+ if (err) {
+ dev_err(dev, "assert pipe_rst err %d\n", err);
+ return err;
+ }
+
+ rockchip_pcie_write(rockchip,
+ PCIE_CLIENT_CONF_ENABLE |
+ PCIE_CLIENT_LINK_TRAIN_ENABLE |
+ PCIE_CLIENT_ARI_ENABLE |
+ PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes) |
+ PCIE_CLIENT_MODE_RC |
+ PCIE_CLIENT_GEN_SEL_2,
+ PCIE_CLIENT_CONFIG);
+
+ err = phy_power_on(rockchip->phy);
+ if (err) {
+ dev_err(dev, "fail to power on phy, err %d\n", err);
+ return err;
+ }
+
+ /*
+ * Please don't reorder the deassert sequence of the following
+ * four reset pins.
+ */
+ err = reset_control_deassert(rockchip->mgmt_sticky_rst);
+ if (err) {
+ dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_deassert(rockchip->core_rst);
+ if (err) {
+ dev_err(dev, "deassert core_rst err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_deassert(rockchip->mgmt_rst);
+ if (err) {
+ dev_err(dev, "deassert mgmt_rst err %d\n", err);
+ return err;
+ }
+
+ err = reset_control_deassert(rockchip->pipe_rst);
+ if (err) {
+ dev_err(dev, "deassert pipe_rst err %d\n", err);
+ return err;
+ }
+
+ /*
+ * We need to read/write PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 before
+ * enabling ASPM. Otherwise L1PwrOnSc and L1PwrOnVal isn't
+ * reliable and enabling ASPM doesn't work. This is a controller
+ * bug we need to work around.
+ */
+ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2);
+ rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2);
+
+ /* Fix the transmitted FTS count desired to exit from L0s. */
+ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL_PLC1);
+ status = (status & PCIE_CORE_CTRL_PLC1_FTS_MASK) |
+ (PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT);
+ rockchip_pcie_write(rockchip, status, PCIE_CORE_CTRL_PLC1);
+
+ /* Enable Gen1 training */
+ rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE,
+ PCIE_CLIENT_CONFIG);
+
+ gpiod_set_value(rockchip->ep_gpio, 1);
+
+ /* 500ms timeout value should be enough for Gen1/2 training */
+ timeout = jiffies + msecs_to_jiffies(500);
+
+ for (;;) {
+ status = rockchip_pcie_read(rockchip,
+ PCIE_CLIENT_BASIC_STATUS1);
+ if ((status & PCIE_CLIENT_LINK_STATUS_MASK) ==
+ PCIE_CLIENT_LINK_STATUS_UP) {
+ dev_dbg(dev, "PCIe link training gen1 pass!\n");
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(dev, "PCIe link training gen1 timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ msleep(20);
+ }
+
+ /*
+ * Enable retrain for gen2. This should be configured only after
+ * gen1 finished.
+ */
+ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
+ status |= PCIE_RC_CONFIG_LCS_RETRAIN_LINK;
+ rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
+
+ timeout = jiffies + msecs_to_jiffies(500);
+ for (;;) {
+ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
+ if ((status & PCIE_CORE_PL_CONF_SPEED_MASK) ==
+ PCIE_CORE_PL_CONF_SPEED_5G) {
+ dev_dbg(dev, "PCIe link training gen2 pass!\n");
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
+ break;
+ }
+
+ msleep(20);
+ }
+
+ /* Check the final link width from negotiated lane counter from MGMT */
+ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
+ status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>
+ PCIE_CORE_PL_CONF_LANE_MASK);
+ dev_dbg(dev, "current link width is x%d\n", status);
+
+ rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID,
+ PCIE_RC_CONFIG_VENDOR);
+ rockchip_pcie_write(rockchip,
+ PCI_CLASS_BRIDGE_PCI << PCIE_RC_CONFIG_SCC_SHIFT,
+ PCIE_RC_CONFIG_RID_CCR);
+ rockchip_pcie_write(rockchip, 0x0, PCIE_RC_BAR_CONF);
+
+ rockchip_pcie_write(rockchip,
+ (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS),
+ PCIE_CORE_OB_REGION_ADDR0);
+ rockchip_pcie_write(rockchip, RC_REGION_0_ADDR_TRANS_H,
+ PCIE_CORE_OB_REGION_ADDR1);
+ rockchip_pcie_write(rockchip, 0x0080000a, PCIE_CORE_OB_REGION_DESC0);
+ rockchip_pcie_write(rockchip, 0x0, PCIE_CORE_OB_REGION_DESC1);
+
+ return 0;
+}
+
+static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
+{
+ struct rockchip_pcie *rockchip = arg;
+ struct device *dev = rockchip->dev;
+ u32 reg;
+ u32 sub_reg;
+
+ reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS);
+ if (reg & PCIE_CLIENT_INT_LOCAL) {
+ dev_dbg(dev, "local interrupt received\n");
+ sub_reg = rockchip_pcie_read(rockchip, PCIE_CORE_INT_STATUS);
+ if (sub_reg & PCIE_CORE_INT_PRFPE)
+ dev_dbg(dev, "parity error detected while reading from the PNP receive FIFO RAM\n");
+
+ if (sub_reg & PCIE_CORE_INT_CRFPE)
+ dev_dbg(dev, "parity error detected while reading from the Completion Receive FIFO RAM\n");
+
+ if (sub_reg & PCIE_CORE_INT_RRPE)
+ dev_dbg(dev, "parity error detected while reading from replay buffer RAM\n");
+
+ if (sub_reg & PCIE_CORE_INT_PRFO)
+ dev_dbg(dev, "overflow occurred in the PNP receive FIFO\n");
+
+ if (sub_reg & PCIE_CORE_INT_CRFO)
+ dev_dbg(dev, "overflow occurred in the completion receive FIFO\n");
+
+ if (sub_reg & PCIE_CORE_INT_RT)
+ dev_dbg(dev, "replay timer timed out\n");
+
+ if (sub_reg & PCIE_CORE_INT_RTR)
+ dev_dbg(dev, "replay timer rolled over after 4 transmissions of the same TLP\n");
+
+ if (sub_reg & PCIE_CORE_INT_PE)
+ dev_dbg(dev, "phy error detected on receive side\n");
+
+ if (sub_reg & PCIE_CORE_INT_MTR)
+ dev_dbg(dev, "malformed TLP received from the link\n");
+
+ if (sub_reg & PCIE_CORE_INT_UCR)
+ dev_dbg(dev, "malformed TLP received from the link\n");
+
+ if (sub_reg & PCIE_CORE_INT_FCE)
+ dev_dbg(dev, "an error was observed in the flow control advertisements from the other side\n");
+
+ if (sub_reg & PCIE_CORE_INT_CT)
+ dev_dbg(dev, "a request timed out waiting for completion\n");
+
+ if (sub_reg & PCIE_CORE_INT_UTC)
+ dev_dbg(dev, "unmapped TC error\n");
+
+ if (sub_reg & PCIE_CORE_INT_MMVC)
+ dev_dbg(dev, "MSI mask register changes\n");
+
+ rockchip_pcie_write(rockchip, sub_reg, PCIE_CORE_INT_STATUS);
+ } else if (reg & PCIE_CLIENT_INT_PHY) {
+ dev_dbg(dev, "phy link changes\n");
+ rockchip_pcie_update_txcredit_mui(rockchip);
+ rockchip_pcie_clr_bw_int(rockchip);
+ }
+
+ rockchip_pcie_write(rockchip, reg & PCIE_CLIENT_INT_LOCAL,
+ PCIE_CLIENT_INT_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_pcie_client_irq_handler(int irq, void *arg)
+{
+ struct rockchip_pcie *rockchip = arg;
+ struct device *dev = rockchip->dev;
+ u32 reg;
+
+ reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS);
+ if (reg & PCIE_CLIENT_INT_LEGACY_DONE)
+ dev_dbg(dev, "legacy done interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_MSG)
+ dev_dbg(dev, "message done interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_HOT_RST)
+ dev_dbg(dev, "hot reset interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_DPA)
+ dev_dbg(dev, "dpa interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_FATAL_ERR)
+ dev_dbg(dev, "fatal error interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_NFATAL_ERR)
+ dev_dbg(dev, "no fatal error interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_CORR_ERR)
+ dev_dbg(dev, "correctable error interrupt received\n");
+
+ if (reg & PCIE_CLIENT_INT_PHY)
+ dev_dbg(dev, "phy interrupt received\n");
+
+ rockchip_pcie_write(rockchip, reg & (PCIE_CLIENT_INT_LEGACY_DONE |
+ PCIE_CLIENT_INT_MSG | PCIE_CLIENT_INT_HOT_RST |
+ PCIE_CLIENT_INT_DPA | PCIE_CLIENT_INT_FATAL_ERR |
+ PCIE_CLIENT_INT_NFATAL_ERR |
+ PCIE_CLIENT_INT_CORR_ERR |
+ PCIE_CLIENT_INT_PHY),
+ PCIE_CLIENT_INT_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc);
+ struct device *dev = rockchip->dev;
+ u32 reg;
+ u32 hwirq;
+ u32 virq;
+
+ chained_irq_enter(chip, desc);
+
+ reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS);
+ reg = (reg & PCIE_CLIENT_INTR_MASK) >> PCIE_CLIENT_INTR_SHIFT;
+
+ while (reg) {
+ hwirq = ffs(reg) - 1;
+ reg &= ~BIT(hwirq);
+
+ virq = irq_find_mapping(rockchip->irq_domain, hwirq);
+ if (virq)
+ generic_handle_irq(virq);
+ else
+ dev_err(dev, "unexpected IRQ, INT%d\n", hwirq);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+
+/**
+ * rockchip_pcie_parse_dt - Parse Device Tree
+ * @rockchip: PCIe port information
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
+{
+ struct device *dev = rockchip->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *node = dev->of_node;
+ struct resource *regs;
+ int irq;
+ int err;
+
+ regs = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ "axi-base");
+ rockchip->reg_base = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(rockchip->reg_base))
+ return PTR_ERR(rockchip->reg_base);
+
+ regs = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ "apb-base");
+ rockchip->apb_base = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(rockchip->apb_base))
+ return PTR_ERR(rockchip->apb_base);
+
+ rockchip->phy = devm_phy_get(dev, "pcie-phy");
+ if (IS_ERR(rockchip->phy)) {
+ if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER)
+ dev_err(dev, "missing phy\n");
+ return PTR_ERR(rockchip->phy);
+ }
+
+ rockchip->lanes = 1;
+ err = of_property_read_u32(node, "num-lanes", &rockchip->lanes);
+ if (!err && (rockchip->lanes == 0 ||
+ rockchip->lanes == 3 ||
+ rockchip->lanes > 4)) {
+ dev_warn(dev, "invalid num-lanes, default to use one lane\n");
+ rockchip->lanes = 1;
+ }
+
+ rockchip->core_rst = devm_reset_control_get(dev, "core");
+ if (IS_ERR(rockchip->core_rst)) {
+ if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER)
+ dev_err(dev, "missing core reset property in node\n");
+ return PTR_ERR(rockchip->core_rst);
+ }
+
+ rockchip->mgmt_rst = devm_reset_control_get(dev, "mgmt");
+ if (IS_ERR(rockchip->mgmt_rst)) {
+ if (PTR_ERR(rockchip->mgmt_rst) != -EPROBE_DEFER)
+ dev_err(dev, "missing mgmt reset property in node\n");
+ return PTR_ERR(rockchip->mgmt_rst);
+ }
+
+ rockchip->mgmt_sticky_rst = devm_reset_control_get(dev, "mgmt-sticky");
+ if (IS_ERR(rockchip->mgmt_sticky_rst)) {
+ if (PTR_ERR(rockchip->mgmt_sticky_rst) != -EPROBE_DEFER)
+ dev_err(dev, "missing mgmt-sticky reset property in node\n");
+ return PTR_ERR(rockchip->mgmt_sticky_rst);
+ }
+
+ rockchip->pipe_rst = devm_reset_control_get(dev, "pipe");
+ if (IS_ERR(rockchip->pipe_rst)) {
+ if (PTR_ERR(rockchip->pipe_rst) != -EPROBE_DEFER)
+ dev_err(dev, "missing pipe reset property in node\n");
+ return PTR_ERR(rockchip->pipe_rst);
+ }
+
+ rockchip->ep_gpio = devm_gpiod_get(dev, "ep", GPIOD_OUT_HIGH);
+ if (IS_ERR(rockchip->ep_gpio)) {
+ dev_err(dev, "missing ep-gpios property in node\n");
+ return PTR_ERR(rockchip->ep_gpio);
+ }
+
+ rockchip->aclk_pcie = devm_clk_get(dev, "aclk");
+ if (IS_ERR(rockchip->aclk_pcie)) {
+ dev_err(dev, "aclk clock not found\n");
+ return PTR_ERR(rockchip->aclk_pcie);
+ }
+
+ rockchip->aclk_perf_pcie = devm_clk_get(dev, "aclk-perf");
+ if (IS_ERR(rockchip->aclk_perf_pcie)) {
+ dev_err(dev, "aclk_perf clock not found\n");
+ return PTR_ERR(rockchip->aclk_perf_pcie);
+ }
+
+ rockchip->hclk_pcie = devm_clk_get(dev, "hclk");
+ if (IS_ERR(rockchip->hclk_pcie)) {
+ dev_err(dev, "hclk clock not found\n");
+ return PTR_ERR(rockchip->hclk_pcie);
+ }
+
+ rockchip->clk_pcie_pm = devm_clk_get(dev, "pm");
+ if (IS_ERR(rockchip->clk_pcie_pm)) {
+ dev_err(dev, "pm clock not found\n");
+ return PTR_ERR(rockchip->clk_pcie_pm);
+ }
+
+ irq = platform_get_irq_byname(pdev, "sys");
+ if (irq < 0) {
+ dev_err(dev, "missing sys IRQ resource\n");
+ return -EINVAL;
+ }
+
+ err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
+ IRQF_SHARED, "pcie-sys", rockchip);
+ if (err) {
+ dev_err(dev, "failed to request PCIe subsystem IRQ\n");
+ return err;
+ }
+
+ irq = platform_get_irq_byname(pdev, "legacy");
+ if (irq < 0) {
+ dev_err(dev, "missing legacy IRQ resource\n");
+ return -EINVAL;
+ }
+
+ irq_set_chained_handler_and_data(irq,
+ rockchip_pcie_legacy_int_handler,
+ rockchip);
+
+ irq = platform_get_irq_byname(pdev, "client");
+ if (irq < 0) {
+ dev_err(dev, "missing client IRQ resource\n");
+ return -EINVAL;
+ }
+
+ err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
+ IRQF_SHARED, "pcie-client", rockchip);
+ if (err) {
+ dev_err(dev, "failed to request PCIe client IRQ\n");
+ return err;
+ }
+
+ rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3");
+ if (IS_ERR(rockchip->vpcie3v3)) {
+ if (PTR_ERR(rockchip->vpcie3v3) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(dev, "no vpcie3v3 regulator found\n");
+ }
+
+ rockchip->vpcie1v8 = devm_regulator_get_optional(dev, "vpcie1v8");
+ if (IS_ERR(rockchip->vpcie1v8)) {
+ if (PTR_ERR(rockchip->vpcie1v8) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(dev, "no vpcie1v8 regulator found\n");
+ }
+
+ rockchip->vpcie0v9 = devm_regulator_get_optional(dev, "vpcie0v9");
+ if (IS_ERR(rockchip->vpcie0v9)) {
+ if (PTR_ERR(rockchip->vpcie0v9) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(dev, "no vpcie0v9 regulator found\n");
+ }
+
+ return 0;
+}
+
+static int rockchip_pcie_set_vpcie(struct rockchip_pcie *rockchip)
+{
+ struct device *dev = rockchip->dev;
+ int err;
+
+ if (!IS_ERR(rockchip->vpcie3v3)) {
+ err = regulator_enable(rockchip->vpcie3v3);
+ if (err) {
+ dev_err(dev, "fail to enable vpcie3v3 regulator\n");
+ goto err_out;
+ }
+ }
+
+ if (!IS_ERR(rockchip->vpcie1v8)) {
+ err = regulator_enable(rockchip->vpcie1v8);
+ if (err) {
+ dev_err(dev, "fail to enable vpcie1v8 regulator\n");
+ goto err_disable_3v3;
+ }
+ }
+
+ if (!IS_ERR(rockchip->vpcie0v9)) {
+ err = regulator_enable(rockchip->vpcie0v9);
+ if (err) {
+ dev_err(dev, "fail to enable vpcie0v9 regulator\n");
+ goto err_disable_1v8;
+ }
+ }
+
+ return 0;
+
+err_disable_1v8:
+ if (!IS_ERR(rockchip->vpcie1v8))
+ regulator_disable(rockchip->vpcie1v8);
+err_disable_3v3:
+ if (!IS_ERR(rockchip->vpcie3v3))
+ regulator_disable(rockchip->vpcie3v3);
+err_out:
+ return err;
+}
+
+static void rockchip_pcie_enable_interrupts(struct rockchip_pcie *rockchip)
+{
+ rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) &
+ (~PCIE_CLIENT_INT_CLI), PCIE_CLIENT_INT_MASK);
+ rockchip_pcie_write(rockchip, (u32)(~PCIE_CORE_INT),
+ PCIE_CORE_INT_MASK);
+
+ rockchip_pcie_enable_bw_int(rockchip);
+}
+
+static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+ irq_set_chip_data(irq, domain->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+ .map = rockchip_pcie_intx_map,
+};
+
+static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
+{
+ struct device *dev = rockchip->dev;
+ struct device_node *intc = of_get_next_child(dev->of_node, NULL);
+
+ if (!intc) {
+ dev_err(dev, "missing child interrupt-controller node\n");
+ return -EINVAL;
+ }
+
+ rockchip->irq_domain = irq_domain_add_linear(intc, 4,
+ &intx_domain_ops, rockchip);
+ if (!rockchip->irq_domain) {
+ dev_err(dev, "failed to get a INTx IRQ domain\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rockchip_pcie_prog_ob_atu(struct rockchip_pcie *rockchip,
+ int region_no, int type, u8 num_pass_bits,
+ u32 lower_addr, u32 upper_addr)
+{
+ u32 ob_addr_0;
+ u32 ob_addr_1;
+ u32 ob_desc_0;
+ u32 aw_offset;
+
+ if (region_no >= MAX_AXI_WRAPPER_REGION_NUM)
+ return -EINVAL;
+ if (num_pass_bits + 1 < 8)
+ return -EINVAL;
+ if (num_pass_bits > 63)
+ return -EINVAL;
+ if (region_no == 0) {
+ if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits))
+ return -EINVAL;
+ }
+ if (region_no != 0) {
+ if (AXI_REGION_SIZE < (2ULL << num_pass_bits))
+ return -EINVAL;
+ }
+
+ aw_offset = (region_no << OB_REG_SIZE_SHIFT);
+
+ ob_addr_0 = num_pass_bits & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS;
+ ob_addr_0 |= lower_addr & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR;
+ ob_addr_1 = upper_addr;
+ ob_desc_0 = (1 << 23 | type);
+
+ rockchip_pcie_write(rockchip, ob_addr_0,
+ PCIE_CORE_OB_REGION_ADDR0 + aw_offset);
+ rockchip_pcie_write(rockchip, ob_addr_1,
+ PCIE_CORE_OB_REGION_ADDR1 + aw_offset);
+ rockchip_pcie_write(rockchip, ob_desc_0,
+ PCIE_CORE_OB_REGION_DESC0 + aw_offset);
+ rockchip_pcie_write(rockchip, 0,
+ PCIE_CORE_OB_REGION_DESC1 + aw_offset);
+
+ return 0;
+}
+
+static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie *rockchip,
+ int region_no, u8 num_pass_bits,
+ u32 lower_addr, u32 upper_addr)
+{
+ u32 ib_addr_0;
+ u32 ib_addr_1;
+ u32 aw_offset;
+
+ if (region_no > MAX_AXI_IB_ROOTPORT_REGION_NUM)
+ return -EINVAL;
+ if (num_pass_bits + 1 < MIN_AXI_ADDR_BITS_PASSED)
+ return -EINVAL;
+ if (num_pass_bits > 63)
+ return -EINVAL;
+
+ aw_offset = (region_no << IB_ROOT_PORT_REG_SIZE_SHIFT);
+
+ ib_addr_0 = num_pass_bits & PCIE_CORE_IB_REGION_ADDR0_NUM_BITS;
+ ib_addr_0 |= (lower_addr << 8) & PCIE_CORE_IB_REGION_ADDR0_LO_ADDR;
+ ib_addr_1 = upper_addr;
+
+ rockchip_pcie_write(rockchip, ib_addr_0, PCIE_RP_IB_ADDR0 + aw_offset);
+ rockchip_pcie_write(rockchip, ib_addr_1, PCIE_RP_IB_ADDR1 + aw_offset);
+
+ return 0;
+}
+
+static int rockchip_pcie_probe(struct platform_device *pdev)
+{
+ struct rockchip_pcie *rockchip;
+ struct device *dev = &pdev->dev;
+ struct pci_bus *bus, *child;
+ struct resource_entry *win;
+ resource_size_t io_base;
+ struct resource *mem;
+ struct resource *io;
+ phys_addr_t io_bus_addr = 0;
+ u32 io_size;
+ phys_addr_t mem_bus_addr = 0;
+ u32 mem_size = 0;
+ int reg_no;
+ int err;
+ int offset;
+
+ LIST_HEAD(res);
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
+ if (!rockchip)
+ return -ENOMEM;
+
+ rockchip->dev = dev;
+
+ err = rockchip_pcie_parse_dt(rockchip);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(rockchip->aclk_pcie);
+ if (err) {
+ dev_err(dev, "unable to enable aclk_pcie clock\n");
+ goto err_aclk_pcie;
+ }
+
+ err = clk_prepare_enable(rockchip->aclk_perf_pcie);
+ if (err) {
+ dev_err(dev, "unable to enable aclk_perf_pcie clock\n");
+ goto err_aclk_perf_pcie;
+ }
+
+ err = clk_prepare_enable(rockchip->hclk_pcie);
+ if (err) {
+ dev_err(dev, "unable to enable hclk_pcie clock\n");
+ goto err_hclk_pcie;
+ }
+
+ err = clk_prepare_enable(rockchip->clk_pcie_pm);
+ if (err) {
+ dev_err(dev, "unable to enable hclk_pcie clock\n");
+ goto err_pcie_pm;
+ }
+
+ err = rockchip_pcie_set_vpcie(rockchip);
+ if (err) {
+ dev_err(dev, "failed to set vpcie regulator\n");
+ goto err_set_vpcie;
+ }
+
+ err = rockchip_pcie_init_port(rockchip);
+ if (err)
+ goto err_vpcie;
+
+ platform_set_drvdata(pdev, rockchip);
+
+ rockchip_pcie_enable_interrupts(rockchip);
+
+ err = rockchip_pcie_init_irq_domain(rockchip);
+ if (err < 0)
+ goto err_vpcie;
+
+ err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
+ &res, &io_base);
+ if (err)
+ goto err_vpcie;
+
+ err = devm_request_pci_bus_resources(dev, &res);
+ if (err)
+ goto err_vpcie;
+
+ /* Get the I/O and memory ranges from DT */
+ io_size = 0;
+ resource_list_for_each_entry(win, &res) {
+ switch (resource_type(win->res)) {
+ case IORESOURCE_IO:
+ io = win->res;
+ io->name = "I/O";
+ io_size = resource_size(io);
+ io_bus_addr = io->start - win->offset;
+ err = pci_remap_iospace(io, io_base);
+ if (err) {
+ dev_warn(dev, "error %d: failed to map resource %pR\n",
+ err, io);
+ continue;
+ }
+ break;
+ case IORESOURCE_MEM:
+ mem = win->res;
+ mem->name = "MEM";
+ mem_size = resource_size(mem);
+ mem_bus_addr = mem->start - win->offset;
+ break;
+ case IORESOURCE_BUS:
+ rockchip->root_bus_nr = win->res->start;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ if (mem_size) {
+ for (reg_no = 0; reg_no < (mem_size >> 20); reg_no++) {
+ err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1,
+ AXI_WRAPPER_MEM_WRITE,
+ 20 - 1,
+ mem_bus_addr +
+ (reg_no << 20),
+ 0);
+ if (err) {
+ dev_err(dev, "program RC mem outbound ATU failed\n");
+ goto err_vpcie;
+ }
+ }
+ }
+
+ err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0);
+ if (err) {
+ dev_err(dev, "program RC mem inbound ATU failed\n");
+ goto err_vpcie;
+ }
+
+ offset = mem_size >> 20;
+
+ if (io_size) {
+ for (reg_no = 0; reg_no < (io_size >> 20); reg_no++) {
+ err = rockchip_pcie_prog_ob_atu(rockchip,
+ reg_no + 1 + offset,
+ AXI_WRAPPER_IO_WRITE,
+ 20 - 1,
+ io_bus_addr +
+ (reg_no << 20),
+ 0);
+ if (err) {
+ dev_err(dev, "program RC io outbound ATU failed\n");
+ goto err_vpcie;
+ }
+ }
+ }
+
+ bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res);
+ if (!bus) {
+ err = -ENOMEM;
+ goto err_vpcie;
+ }
+
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+
+ pci_bus_add_devices(bus);
+
+ dev_warn(dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n");
+
+ return err;
+
+err_vpcie:
+ if (!IS_ERR(rockchip->vpcie3v3))
+ regulator_disable(rockchip->vpcie3v3);
+ if (!IS_ERR(rockchip->vpcie1v8))
+ regulator_disable(rockchip->vpcie1v8);
+ if (!IS_ERR(rockchip->vpcie0v9))
+ regulator_disable(rockchip->vpcie0v9);
+err_set_vpcie:
+ clk_disable_unprepare(rockchip->clk_pcie_pm);
+err_pcie_pm:
+ clk_disable_unprepare(rockchip->hclk_pcie);
+err_hclk_pcie:
+ clk_disable_unprepare(rockchip->aclk_perf_pcie);
+err_aclk_perf_pcie:
+ clk_disable_unprepare(rockchip->aclk_pcie);
+err_aclk_pcie:
+ return err;
+}
+
+static const struct of_device_id rockchip_pcie_of_match[] = {
+ { .compatible = "rockchip,rk3399-pcie", },
+ {}
+};
+
+static struct platform_driver rockchip_pcie_driver = {
+ .driver = {
+ .name = "rockchip-pcie",
+ .of_match_table = rockchip_pcie_of_match,
+ },
+ .probe = rockchip_pcie_probe,
+
+};
+builtin_platform_driver(rockchip_pcie_driver);
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index a4060b85ab23..09aed85f275a 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -15,7 +15,7 @@
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
@@ -355,7 +355,6 @@ static const struct of_device_id spear13xx_pcie_of_match[] = {
{ .compatible = "st,spear1340-pcie", },
{},
};
-MODULE_DEVICE_TABLE(of, spear13xx_pcie_of_match);
static struct platform_driver spear13xx_pcie_driver = {
.probe = spear13xx_pcie_probe,
@@ -365,14 +364,8 @@ static struct platform_driver spear13xx_pcie_driver = {
},
};
-/* SPEAr13xx PCIe driver does not allow module unload */
-
static int __init spear13xx_pcie_init(void)
{
return platform_driver_register(&spear13xx_pcie_driver);
}
-module_init(spear13xx_pcie_init);
-
-MODULE_DESCRIPTION("ST Microelectronics SPEAr13xx PCIe host controller driver");
-MODULE_AUTHOR("Pratyush Anand <pratyush.anand@gmail.com>");
-MODULE_LICENSE("GPL v2");
+device_initcall(spear13xx_pcie_init);
diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/host/pcie-xilinx-nwl.c
index 0b597d9190b4..67eae4179290 100644
--- a/drivers/pci/host/pcie-xilinx-nwl.c
+++ b/drivers/pci/host/pcie-xilinx-nwl.c
@@ -15,7 +15,7 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
@@ -85,10 +85,15 @@
#define MSGF_MISC_SR_MASTER_ERR BIT(5)
#define MSGF_MISC_SR_I_ADDR_ERR BIT(6)
#define MSGF_MISC_SR_E_ADDR_ERR BIT(7)
-#define MSGF_MISC_SR_UR_DETECT BIT(20)
-
-#define MSGF_MISC_SR_PCIE_CORE GENMASK(18, 16)
-#define MSGF_MISC_SR_PCIE_CORE_ERR GENMASK(31, 22)
+#define MSGF_MISC_SR_FATAL_AER BIT(16)
+#define MSGF_MISC_SR_NON_FATAL_AER BIT(17)
+#define MSGF_MISC_SR_CORR_AER BIT(18)
+#define MSGF_MISC_SR_UR_DETECT BIT(20)
+#define MSGF_MISC_SR_NON_FATAL_DEV BIT(22)
+#define MSGF_MISC_SR_FATAL_DEV BIT(23)
+#define MSGF_MISC_SR_LINK_DOWN BIT(24)
+#define MSGF_MSIC_SR_LINK_AUTO_BWIDTH BIT(25)
+#define MSGF_MSIC_SR_LINK_BWIDTH BIT(26)
#define MSGF_MISC_SR_MASKALL (MSGF_MISC_SR_RXMSG_AVAIL | \
MSGF_MISC_SR_RXMSG_OVER | \
@@ -96,9 +101,15 @@
MSGF_MISC_SR_MASTER_ERR | \
MSGF_MISC_SR_I_ADDR_ERR | \
MSGF_MISC_SR_E_ADDR_ERR | \
+ MSGF_MISC_SR_FATAL_AER | \
+ MSGF_MISC_SR_NON_FATAL_AER | \
+ MSGF_MISC_SR_CORR_AER | \
MSGF_MISC_SR_UR_DETECT | \
- MSGF_MISC_SR_PCIE_CORE | \
- MSGF_MISC_SR_PCIE_CORE_ERR)
+ MSGF_MISC_SR_NON_FATAL_DEV | \
+ MSGF_MISC_SR_FATAL_DEV | \
+ MSGF_MISC_SR_LINK_DOWN | \
+ MSGF_MSIC_SR_LINK_AUTO_BWIDTH | \
+ MSGF_MSIC_SR_LINK_BWIDTH)
/* Legacy interrupt status mask bits */
#define MSGF_LEG_SR_INTA BIT(0)
@@ -109,8 +120,8 @@
MSGF_LEG_SR_INTC | MSGF_LEG_SR_INTD)
/* MSI interrupt status mask bits */
-#define MSGF_MSI_SR_LO_MASK BIT(0)
-#define MSGF_MSI_SR_HI_MASK BIT(0)
+#define MSGF_MSI_SR_LO_MASK GENMASK(31, 0)
+#define MSGF_MSI_SR_HI_MASK GENMASK(31, 0)
#define MSII_PRESENT BIT(0)
#define MSII_ENABLE BIT(0)
@@ -291,8 +302,29 @@ static irqreturn_t nwl_pcie_misc_handler(int irq, void *data)
dev_err(pcie->dev,
"In Misc Egress address translation error\n");
- if (misc_stat & MSGF_MISC_SR_PCIE_CORE_ERR)
- dev_err(pcie->dev, "PCIe Core error\n");
+ if (misc_stat & MSGF_MISC_SR_FATAL_AER)
+ dev_err(pcie->dev, "Fatal Error in AER Capability\n");
+
+ if (misc_stat & MSGF_MISC_SR_NON_FATAL_AER)
+ dev_err(pcie->dev, "Non-Fatal Error in AER Capability\n");
+
+ if (misc_stat & MSGF_MISC_SR_CORR_AER)
+ dev_err(pcie->dev, "Correctable Error in AER Capability\n");
+
+ if (misc_stat & MSGF_MISC_SR_UR_DETECT)
+ dev_err(pcie->dev, "Unsupported request Detected\n");
+
+ if (misc_stat & MSGF_MISC_SR_NON_FATAL_DEV)
+ dev_err(pcie->dev, "Non-Fatal Error Detected\n");
+
+ if (misc_stat & MSGF_MISC_SR_FATAL_DEV)
+ dev_err(pcie->dev, "Fatal Error Detected\n");
+
+ if (misc_stat & MSGF_MSIC_SR_LINK_AUTO_BWIDTH)
+ dev_info(pcie->dev, "Link Autonomous Bandwidth Management Status bit set\n");
+
+ if (misc_stat & MSGF_MSIC_SR_LINK_BWIDTH)
+ dev_info(pcie->dev, "Link Bandwidth Management Status bit set\n");
/* Clear misc interrupt status */
nwl_bridge_writel(pcie, misc_stat, MSGF_MISC_STATUS);
@@ -459,40 +491,6 @@ static const struct irq_domain_ops dev_msi_domain_ops = {
.free = nwl_irq_domain_free,
};
-static void nwl_msi_free_irq_domain(struct nwl_pcie *pcie)
-{
- struct nwl_msi *msi = &pcie->msi;
-
- if (msi->irq_msi0)
- irq_set_chained_handler_and_data(msi->irq_msi0, NULL, NULL);
- if (msi->irq_msi1)
- irq_set_chained_handler_and_data(msi->irq_msi1, NULL, NULL);
-
- if (msi->msi_domain)
- irq_domain_remove(msi->msi_domain);
- if (msi->dev_domain)
- irq_domain_remove(msi->dev_domain);
-
- kfree(msi->bitmap);
- msi->bitmap = NULL;
-}
-
-static void nwl_pcie_free_irq_domain(struct nwl_pcie *pcie)
-{
- int i;
- u32 irq;
-
- for (i = 0; i < INTX_NUM; i++) {
- irq = irq_find_mapping(pcie->legacy_irq_domain, i + 1);
- if (irq > 0)
- irq_dispose_mapping(irq);
- }
- if (pcie->legacy_irq_domain)
- irq_domain_remove(pcie->legacy_irq_domain);
-
- nwl_msi_free_irq_domain(pcie);
-}
-
static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie)
{
#ifdef CONFIG_PCI_MSI
@@ -867,25 +865,12 @@ error:
return err;
}
-static int nwl_pcie_remove(struct platform_device *pdev)
-{
- struct nwl_pcie *pcie = platform_get_drvdata(pdev);
-
- nwl_pcie_free_irq_domain(pcie);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
static struct platform_driver nwl_pcie_driver = {
.driver = {
.name = "nwl-pcie",
+ .suppress_bind_attrs = true,
.of_match_table = nwl_pcie_of_match,
},
.probe = nwl_pcie_probe,
- .remove = nwl_pcie_remove,
};
-module_platform_driver(nwl_pcie_driver);
-
-MODULE_AUTHOR("Xilinx, Inc");
-MODULE_DESCRIPTION("NWL PCIe driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(nwl_pcie_driver);
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index a30e01639557..be568039d9d0 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -18,7 +18,7 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
@@ -101,7 +101,8 @@
* @msi_pages: MSI pages
* @root_busno: Root Bus number
* @dev: Device pointer
- * @irq_domain: IRQ domain pointer
+ * @msi_domain: MSI IRQ domain pointer
+ * @leg_domain: Legacy IRQ domain pointer
* @resources: Bus Resources
*/
struct xilinx_pcie_port {
@@ -110,7 +111,8 @@ struct xilinx_pcie_port {
unsigned long msi_pages;
u8 root_busno;
struct device *dev;
- struct irq_domain *irq_domain;
+ struct irq_domain *msi_domain;
+ struct irq_domain *leg_domain;
struct list_head resources;
};
@@ -168,13 +170,6 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
if (bus->number == port->root_busno && devfn > 0)
return false;
- /*
- * Do not read more than one device on the bus directly attached
- * to RC.
- */
- if (bus->primary == port->root_busno && devfn > 0)
- return false;
-
return true;
}
@@ -219,13 +214,15 @@ static void xilinx_pcie_destroy_msi(unsigned int irq)
{
struct msi_desc *msi;
struct xilinx_pcie_port *port;
+ struct irq_data *d = irq_get_irq_data(irq);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
- if (!test_bit(irq, msi_irq_in_use)) {
+ if (!test_bit(hwirq, msi_irq_in_use)) {
msi = irq_get_msi_desc(irq);
port = msi_desc_to_pci_sysdata(msi);
dev_err(port->dev, "Trying to free unused MSI#%d\n", irq);
} else {
- clear_bit(irq, msi_irq_in_use);
+ clear_bit(hwirq, msi_irq_in_use);
}
}
@@ -257,6 +254,7 @@ static void xilinx_msi_teardown_irq(struct msi_controller *chip,
unsigned int irq)
{
xilinx_pcie_destroy_msi(irq);
+ irq_dispose_mapping(irq);
}
/**
@@ -281,7 +279,7 @@ static int xilinx_pcie_msi_setup_irq(struct msi_controller *chip,
if (hwirq < 0)
return hwirq;
- irq = irq_create_mapping(port->irq_domain, hwirq);
+ irq = irq_create_mapping(port->msi_domain, hwirq);
if (!irq)
return -EINVAL;
@@ -432,7 +430,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
/* Check whether interrupt valid */
if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) {
dev_warn(port->dev, "RP Intr FIFO1 read error\n");
- return IRQ_HANDLED;
+ goto error;
}
if (!(val & XILINX_PCIE_RPIFR1_MSI_INTR)) {
@@ -443,7 +441,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
/* Handle INTx Interrupt */
val = ((val & XILINX_PCIE_RPIFR1_INTR_MASK) >>
XILINX_PCIE_RPIFR1_INTR_SHIFT) + 1;
- generic_handle_irq(irq_find_mapping(port->irq_domain,
+ generic_handle_irq(irq_find_mapping(port->leg_domain,
val));
}
}
@@ -454,7 +452,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) {
dev_warn(port->dev, "RP Intr FIFO1 read error\n");
- return IRQ_HANDLED;
+ goto error;
}
if (val & XILINX_PCIE_RPIFR1_MSI_INTR) {
@@ -499,6 +497,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
if (status & XILINX_PCIE_INTR_MST_ERRP)
dev_warn(port->dev, "Master error poison\n");
+error:
/* Clear the Interrupt Decode register */
pcie_write(port, status, XILINX_PCIE_REG_IDR);
@@ -506,35 +505,6 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data)
}
/**
- * xilinx_pcie_free_irq_domain - Free IRQ domain
- * @port: PCIe port information
- */
-static void xilinx_pcie_free_irq_domain(struct xilinx_pcie_port *port)
-{
- int i;
- u32 irq, num_irqs;
-
- /* Free IRQ Domain */
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
-
- free_pages(port->msi_pages, 0);
-
- num_irqs = XILINX_NUM_MSI_IRQS;
- } else {
- /* INTx */
- num_irqs = 4;
- }
-
- for (i = 0; i < num_irqs; i++) {
- irq = irq_find_mapping(port->irq_domain, i);
- if (irq > 0)
- irq_dispose_mapping(irq);
- }
-
- irq_domain_remove(port->irq_domain);
-}
-
-/**
* xilinx_pcie_init_irq_domain - Initialize IRQ domain
* @port: PCIe port information
*
@@ -553,21 +523,21 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
return -ENODEV;
}
- port->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
+ port->leg_domain = irq_domain_add_linear(pcie_intc_node, 4,
&intx_domain_ops,
port);
- if (!port->irq_domain) {
+ if (!port->leg_domain) {
dev_err(dev, "Failed to get a INTx IRQ domain\n");
return -ENODEV;
}
/* Setup MSI */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
- port->irq_domain = irq_domain_add_linear(node,
+ port->msi_domain = irq_domain_add_linear(node,
XILINX_NUM_MSI_IRQS,
&msi_domain_ops,
&xilinx_pcie_msi_chip);
- if (!port->irq_domain) {
+ if (!port->msi_domain) {
dev_err(dev, "Failed to get a MSI IRQ domain\n");
return -ENODEV;
}
@@ -724,21 +694,6 @@ error:
return err;
}
-/**
- * xilinx_pcie_remove - Remove function
- * @pdev: Platform device pointer
- *
- * Return: '0' always
- */
-static int xilinx_pcie_remove(struct platform_device *pdev)
-{
- struct xilinx_pcie_port *port = platform_get_drvdata(pdev);
-
- xilinx_pcie_free_irq_domain(port);
-
- return 0;
-}
-
static struct of_device_id xilinx_pcie_of_match[] = {
{ .compatible = "xlnx,axi-pcie-host-1.00.a", },
{}
@@ -751,10 +706,5 @@ static struct platform_driver xilinx_pcie_driver = {
.suppress_bind_attrs = true,
},
.probe = xilinx_pcie_probe,
- .remove = xilinx_pcie_remove,
};
-module_platform_driver(xilinx_pcie_driver);
-
-MODULE_AUTHOR("Xilinx Inc");
-MODULE_DESCRIPTION("Xilinx AXI PCIe driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(xilinx_pcie_driver);
diff --git a/arch/x86/pci/vmd.c b/drivers/pci/host/vmd.c
index 7948be342ee9..37e29b580be3 100644
--- a/arch/x86/pci/vmd.c
+++ b/drivers/pci/host/vmd.c
@@ -58,16 +58,11 @@ struct vmd_irq {
/**
* struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector
* @irq_list: the list of irq's the VMD one demuxes to.
- * @vmd_vector: the h/w IRQ assigned to the VMD.
- * @index: index into the VMD MSI-X table; used for message routing.
* @count: number of child IRQs assigned to this vector; used to track
* sharing.
*/
struct vmd_irq_list {
struct list_head irq_list;
- struct vmd_dev *vmd;
- unsigned int vmd_vector;
- unsigned int index;
unsigned int count;
};
@@ -78,7 +73,6 @@ struct vmd_dev {
char __iomem *cfgbar;
int msix_count;
- struct msix_entry *msix_entries;
struct vmd_irq_list *irqs;
struct pci_sysdata sysdata;
@@ -97,6 +91,12 @@ static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
return container_of(bus->sysdata, struct vmd_dev, sysdata);
}
+static inline unsigned int index_from_irqs(struct vmd_dev *vmd,
+ struct vmd_irq_list *irqs)
+{
+ return irqs - vmd->irqs;
+}
+
/*
* Drivers managing a device in a VMD domain allocate their own IRQs as before,
* but the MSI entry for the hardware it's driving will be programmed with a
@@ -109,9 +109,11 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct vmd_irq *vmdirq = data->chip_data;
struct vmd_irq_list *irq = vmdirq->irq;
+ struct vmd_dev *vmd = irq_data_get_irq_handler_data(data);
msg->address_hi = MSI_ADDR_BASE_HI;
- msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_DEST_ID(irq->index);
+ msg->address_lo = MSI_ADDR_BASE_LO |
+ MSI_ADDR_DEST_ID(index_from_irqs(vmd, irq));
msg->data = 0;
}
@@ -200,6 +202,7 @@ static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
struct msi_desc *desc = arg->desc;
struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(desc)->bus);
struct vmd_irq *vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
+ unsigned int index, vector;
if (!vmdirq)
return -ENOMEM;
@@ -207,9 +210,11 @@ static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
INIT_LIST_HEAD(&vmdirq->node);
vmdirq->irq = vmd_next_irq(vmd, desc);
vmdirq->virq = virq;
+ index = index_from_irqs(vmd, vmdirq->irq);
+ vector = pci_irq_vector(vmd->dev, index);
- irq_domain_set_info(domain, virq, vmdirq->irq->vmd_vector, info->chip,
- vmdirq, handle_untracked_irq, vmd, NULL);
+ irq_domain_set_info(domain, virq, vector, info->chip, vmdirq,
+ handle_untracked_irq, vmd, NULL);
return 0;
}
@@ -219,6 +224,8 @@ static void vmd_msi_free(struct irq_domain *domain,
struct vmd_irq *vmdirq = irq_get_chip_data(virq);
unsigned long flags;
+ synchronize_rcu();
+
/* XXX: Potential optimization to rebalance */
raw_spin_lock_irqsave(&list_lock, flags);
vmdirq->irq->count--;
@@ -602,6 +609,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd)
.parent = res,
};
+ sd->vmd_domain = true;
sd->domain = vmd_find_free_domain();
if (sd->domain < 0)
return sd->domain;
@@ -677,30 +685,19 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (vmd->msix_count < 0)
return -ENODEV;
+ vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
+ PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
+ if (vmd->msix_count < 0)
+ return vmd->msix_count;
+
vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),
GFP_KERNEL);
if (!vmd->irqs)
return -ENOMEM;
- vmd->msix_entries = devm_kcalloc(&dev->dev, vmd->msix_count,
- sizeof(*vmd->msix_entries),
- GFP_KERNEL);
- if (!vmd->msix_entries)
- return -ENOMEM;
- for (i = 0; i < vmd->msix_count; i++)
- vmd->msix_entries[i].entry = i;
-
- vmd->msix_count = pci_enable_msix_range(vmd->dev, vmd->msix_entries, 1,
- vmd->msix_count);
- if (vmd->msix_count < 0)
- return vmd->msix_count;
-
for (i = 0; i < vmd->msix_count; i++) {
INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
- vmd->irqs[i].vmd_vector = vmd->msix_entries[i].vector;
- vmd->irqs[i].index = i;
-
- err = devm_request_irq(&dev->dev, vmd->irqs[i].vmd_vector,
+ err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
vmd_irq, 0, "vmd", &vmd->irqs[i]);
if (err)
return err;
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index 555bcde3b196..60e66e027ebc 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -101,10 +101,8 @@ int cpci_unconfigure_slot(struct slot *slot);
#ifdef CONFIG_HOTPLUG_PCI_CPCI
int cpci_hotplug_init(int debug);
-void cpci_hotplug_exit(void);
#else
static inline int cpci_hotplug_init(int debug) { return 0; }
-static inline void cpci_hotplug_exit(void) { }
#endif
#endif /* _CPCI_HOTPLUG_H */
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index 7d3866c47312..7ec8a8f72c69 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -719,13 +719,3 @@ cpci_hotplug_init(int debug)
cpci_debug = debug;
return 0;
}
-
-void __exit
-cpci_hotplug_exit(void)
-{
- /*
- * Clean everything up.
- */
- cpci_hp_stop();
- cpci_hp_unregister_controller(controller);
-}
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 9acd1997c6fe..fea0b8b33589 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -25,7 +25,7 @@
*
*/
-#include <linux/module.h>
+#include <linux/module.h> /* try_module_get & module_put */
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -537,17 +537,11 @@ static int __init pci_hotplug_init(void)
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
return result;
}
+device_initcall(pci_hotplug_init);
-static void __exit pci_hotplug_exit(void)
-{
- cpci_hotplug_exit();
-}
-
-module_init(pci_hotplug_init);
-module_exit(pci_hotplug_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index e764918641ae..37d70b5ad22f 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -152,6 +152,9 @@ bool pciehp_check_link_active(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
int pciehp_reset_slot(struct slot *slot, int probe);
+int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
+int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
+
static inline const char *slot_name(struct slot *slot)
{
return hotplug_slot_name(slot->hotplug_slot);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index ac531e674a05..7d32fa33dcef 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -47,10 +46,10 @@ static bool pciehp_force;
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
#define DRIVER_DESC "PCI Express Hot Plug Controller Driver"
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
module_param(pciehp_debug, bool, 0644);
module_param(pciehp_poll_mode, bool, 0644);
module_param(pciehp_poll_time, int, 0644);
@@ -114,6 +113,9 @@ static int init_slot(struct controller *ctrl)
if (ATTN_LED(ctrl)) {
ops->get_attention_status = get_attention_status;
ops->set_attention_status = set_attention_status;
+ } else if (ctrl->pcie->port->hotplug_user_indicators) {
+ ops->get_attention_status = pciehp_get_raw_indicator_status;
+ ops->set_attention_status = pciehp_set_raw_indicator_status;
}
/* register this slot with the hotplug pci core */
@@ -337,13 +339,4 @@ static int __init pcied_init(void)
return retval;
}
-
-static void __exit pcied_cleanup(void)
-{
- dbg("unload_pciehpd()\n");
- pcie_port_service_unregister(&hpdriver_portdrv);
- info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
-}
-
-module_init(pcied_init);
-module_exit(pcied_cleanup);
+device_initcall(pcied_init);
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 880978b6d534..efe69e879455 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -106,7 +106,7 @@ static int board_added(struct slot *p_slot)
/* Check for a power fault */
if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
- ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
+ ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(p_slot));
retval = -EIO;
goto err_exit;
}
@@ -120,6 +120,7 @@ static int board_added(struct slot *p_slot)
}
pciehp_green_led_on(p_slot);
+ pciehp_set_attention_status(p_slot, 0);
return 0;
err_exit:
@@ -253,11 +254,11 @@ static void handle_button_press_event(struct slot *p_slot)
pciehp_get_power_status(p_slot, &getstatus);
if (getstatus) {
p_slot->state = BLINKINGOFF_STATE;
- ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n",
+ ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
slot_name(p_slot));
} else {
p_slot->state = BLINKINGON_STATE;
- ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n",
+ ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
slot_name(p_slot));
}
/* blink green LED and turn off amber */
@@ -272,14 +273,14 @@ static void handle_button_press_event(struct slot *p_slot)
* press the attention again before the 5 sec. limit
* expires to cancel hot-add or hot-remove
*/
- ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
+ ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(p_slot));
cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE)
pciehp_green_led_on(p_slot);
else
pciehp_green_led_off(p_slot);
pciehp_set_attention_status(p_slot, 0);
- ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n",
+ ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
slot_name(p_slot));
p_slot->state = STATIC_STATE;
break;
@@ -290,10 +291,12 @@ static void handle_button_press_event(struct slot *p_slot)
* this means that the previous attention button action
* to hot-add or hot-remove is undergoing
*/
- ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot));
+ ctrl_info(ctrl, "Slot(%s): Button ignored\n",
+ slot_name(p_slot));
break;
default:
- ctrl_warn(ctrl, "ignoring invalid state %#x\n", p_slot->state);
+ ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
+ slot_name(p_slot), p_slot->state);
break;
}
}
@@ -301,20 +304,6 @@ static void handle_button_press_event(struct slot *p_slot)
/*
* Note: This function must be called with slot->lock held
*/
-static void handle_surprise_event(struct slot *p_slot)
-{
- u8 getstatus;
-
- pciehp_get_adapter_status(p_slot, &getstatus);
- if (!getstatus)
- pciehp_queue_power_work(p_slot, DISABLE_REQ);
- else
- pciehp_queue_power_work(p_slot, ENABLE_REQ);
-}
-
-/*
- * Note: This function must be called with slot->lock held
- */
static void handle_link_event(struct slot *p_slot, u32 event)
{
struct controller *ctrl = p_slot->ctrl;
@@ -330,31 +319,27 @@ static void handle_link_event(struct slot *p_slot, u32 event)
break;
case POWERON_STATE:
if (event == INT_LINK_UP) {
- ctrl_info(ctrl,
- "Link Up event ignored on slot(%s): already powering on\n",
+ ctrl_info(ctrl, "Slot(%s): Link Up event ignored; already powering on\n",
slot_name(p_slot));
} else {
- ctrl_info(ctrl,
- "Link Down event queued on slot(%s): currently getting powered on\n",
+ ctrl_info(ctrl, "Slot(%s): Link Down event queued; currently getting powered on\n",
slot_name(p_slot));
pciehp_queue_power_work(p_slot, DISABLE_REQ);
}
break;
case POWEROFF_STATE:
if (event == INT_LINK_UP) {
- ctrl_info(ctrl,
- "Link Up event queued on slot(%s): currently getting powered off\n",
+ ctrl_info(ctrl, "Slot(%s): Link Up event queued; currently getting powered off\n",
slot_name(p_slot));
pciehp_queue_power_work(p_slot, ENABLE_REQ);
} else {
- ctrl_info(ctrl,
- "Link Down event ignored on slot(%s): already powering off\n",
+ ctrl_info(ctrl, "Slot(%s): Link Down event ignored; already powering off\n",
slot_name(p_slot));
}
break;
default:
- ctrl_err(ctrl, "ignoring invalid state %#x on slot(%s)\n",
- p_slot->state, slot_name(p_slot));
+ ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
+ slot_name(p_slot), p_slot->state);
break;
}
}
@@ -377,14 +362,14 @@ static void interrupt_event_handler(struct work_struct *work)
pciehp_green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
- handle_surprise_event(p_slot);
+ pciehp_queue_power_work(p_slot, ENABLE_REQ);
break;
case INT_PRESENCE_OFF:
/*
* Regardless of surprise capability, we need to
* definitely remove a card that has been pulled out!
*/
- handle_surprise_event(p_slot);
+ pciehp_queue_power_work(p_slot, DISABLE_REQ);
break;
case INT_LINK_UP:
case INT_LINK_DOWN:
@@ -404,18 +389,17 @@ static void interrupt_event_handler(struct work_struct *work)
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
- int rc;
struct controller *ctrl = p_slot->ctrl;
pciehp_get_adapter_status(p_slot, &getstatus);
if (!getstatus) {
- ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
+ ctrl_info(ctrl, "Slot(%s): No adapter\n", slot_name(p_slot));
return -ENODEV;
}
if (MRL_SENS(p_slot->ctrl)) {
pciehp_get_latch_status(p_slot, &getstatus);
if (getstatus) {
- ctrl_info(ctrl, "Latch open on slot(%s)\n",
+ ctrl_info(ctrl, "Slot(%s): Latch open\n",
slot_name(p_slot));
return -ENODEV;
}
@@ -424,19 +408,13 @@ int pciehp_enable_slot(struct slot *p_slot)
if (POWER_CTRL(p_slot->ctrl)) {
pciehp_get_power_status(p_slot, &getstatus);
if (getstatus) {
- ctrl_info(ctrl, "Already enabled on slot(%s)\n",
+ ctrl_info(ctrl, "Slot(%s): Already enabled\n",
slot_name(p_slot));
return -EINVAL;
}
}
- pciehp_get_latch_status(p_slot, &getstatus);
-
- rc = board_added(p_slot);
- if (rc)
- pciehp_get_latch_status(p_slot, &getstatus);
-
- return rc;
+ return board_added(p_slot);
}
/*
@@ -453,7 +431,7 @@ int pciehp_disable_slot(struct slot *p_slot)
if (POWER_CTRL(p_slot->ctrl)) {
pciehp_get_power_status(p_slot, &getstatus);
if (!getstatus) {
- ctrl_info(ctrl, "Already disabled on slot(%s)\n",
+ ctrl_info(ctrl, "Slot(%s): Already disabled\n",
slot_name(p_slot));
return -EINVAL;
}
@@ -481,17 +459,17 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
p_slot->state = STATIC_STATE;
break;
case POWERON_STATE:
- ctrl_info(ctrl, "Slot %s is already in powering on state\n",
+ ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
slot_name(p_slot));
break;
case BLINKINGOFF_STATE:
case POWEROFF_STATE:
- ctrl_info(ctrl, "Already enabled on slot %s\n",
+ ctrl_info(ctrl, "Slot(%s): Already enabled\n",
slot_name(p_slot));
break;
default:
- ctrl_err(ctrl, "invalid state %#x on slot %s\n",
- p_slot->state, slot_name(p_slot));
+ ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
+ slot_name(p_slot), p_slot->state);
break;
}
mutex_unlock(&p_slot->lock);
@@ -518,17 +496,17 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot)
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
- ctrl_info(ctrl, "Slot %s is already in powering off state\n",
+ ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
slot_name(p_slot));
break;
case BLINKINGON_STATE:
case POWERON_STATE:
- ctrl_info(ctrl, "Already disabled on slot %s\n",
+ ctrl_info(ctrl, "Slot(%s): Already disabled\n",
slot_name(p_slot));
break;
default:
- ctrl_err(ctrl, "invalid state %#x on slot %s\n",
- p_slot->state, slot_name(p_slot));
+ ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
+ slot_name(p_slot), p_slot->state);
break;
}
mutex_unlock(&p_slot->lock);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 08e84d61874e..b57fc6d6e28a 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -355,6 +355,18 @@ static int pciehp_link_enable(struct controller *ctrl)
return __pciehp_link_set(ctrl, true);
}
+int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot,
+ u8 *status)
+{
+ struct slot *slot = hotplug_slot->private;
+ struct pci_dev *pdev = ctrl_dev(slot->ctrl);
+ u16 slot_ctrl;
+
+ pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
+ *status = (slot_ctrl & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
+ return 0;
+}
+
void pciehp_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
@@ -431,6 +443,17 @@ int pciehp_query_power_fault(struct slot *slot)
return !!(slot_status & PCI_EXP_SLTSTA_PFD);
}
+int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
+ u8 status)
+{
+ struct slot *slot = hotplug_slot->private;
+ struct controller *ctrl = slot->ctrl;
+
+ pcie_write_cmd_nowait(ctrl, status << 6,
+ PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC);
+ return 0;
+}
+
void pciehp_set_attention_status(struct slot *slot, u8 value)
{
struct controller *ctrl = slot->ctrl;
@@ -535,14 +558,14 @@ void pciehp_power_off_slot(struct slot *slot)
PCI_EXP_SLTCTL_PWR_OFF);
}
-static irqreturn_t pcie_isr(int irq, void *dev_id)
+static irqreturn_t pciehp_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
struct pci_dev *pdev = ctrl_dev(ctrl);
struct pci_bus *subordinate = pdev->subordinate;
struct pci_dev *dev;
struct slot *slot = ctrl->slot;
- u16 detected, intr_loc;
+ u16 status, events;
u8 present;
bool link;
@@ -550,36 +573,31 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
if (pdev->current_state == PCI_D3cold)
return IRQ_NONE;
+ pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status);
+ if (status == (u16) ~0) {
+ ctrl_info(ctrl, "%s: no response from device\n", __func__);
+ return IRQ_NONE;
+ }
+
/*
- * In order to guarantee that all interrupt events are
- * serviced, we need to re-inspect Slot Status register after
- * clearing what is presumed to be the last pending interrupt.
+ * Slot Status contains plain status bits as well as event
+ * notification bits; right now we only want the event bits.
*/
- intr_loc = 0;
- do {
- pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected);
- if (detected == (u16) ~0) {
- ctrl_info(ctrl, "%s: no response from device\n",
- __func__);
- return IRQ_HANDLED;
- }
+ events = status & (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
+ PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC |
+ PCI_EXP_SLTSTA_DLLSC);
+ if (!events)
+ return IRQ_NONE;
- detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
- PCI_EXP_SLTSTA_PDC |
- PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
- detected &= ~intr_loc;
- intr_loc |= detected;
- if (!intr_loc)
- return IRQ_NONE;
- if (detected)
- pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
- intr_loc);
- } while (detected);
+ /* Capture link status before clearing interrupts */
+ if (events & PCI_EXP_SLTSTA_DLLSC)
+ link = pciehp_check_link_active(ctrl);
- ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", intr_loc);
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events);
+ ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events);
/* Check Command Complete Interrupt Pending */
- if (intr_loc & PCI_EXP_SLTSTA_CC) {
+ if (events & PCI_EXP_SLTSTA_CC) {
ctrl->cmd_busy = 0;
smp_mb();
wake_up(&ctrl->queue);
@@ -589,42 +607,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
list_for_each_entry(dev, &subordinate->devices, bus_list) {
if (dev->ignore_hotplug) {
ctrl_dbg(ctrl, "ignoring hotplug event %#06x (%s requested no hotplug)\n",
- intr_loc, pci_name(dev));
+ events, pci_name(dev));
return IRQ_HANDLED;
}
}
}
- if (!(intr_loc & ~PCI_EXP_SLTSTA_CC))
- return IRQ_HANDLED;
-
/* Check Attention Button Pressed */
- if (intr_loc & PCI_EXP_SLTSTA_ABP) {
- ctrl_info(ctrl, "Button pressed on Slot(%s)\n",
+ if (events & PCI_EXP_SLTSTA_ABP) {
+ ctrl_info(ctrl, "Slot(%s): Attention button pressed\n",
slot_name(slot));
pciehp_queue_interrupt_event(slot, INT_BUTTON_PRESS);
}
/* Check Presence Detect Changed */
- if (intr_loc & PCI_EXP_SLTSTA_PDC) {
- pciehp_get_adapter_status(slot, &present);
- ctrl_info(ctrl, "Card %spresent on Slot(%s)\n",
- present ? "" : "not ", slot_name(slot));
+ if (events & PCI_EXP_SLTSTA_PDC) {
+ present = !!(status & PCI_EXP_SLTSTA_PDS);
+ ctrl_info(ctrl, "Slot(%s): Card %spresent\n", slot_name(slot),
+ present ? "" : "not ");
pciehp_queue_interrupt_event(slot, present ? INT_PRESENCE_ON :
INT_PRESENCE_OFF);
}
/* Check Power Fault Detected */
- if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
+ if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
ctrl->power_fault_detected = 1;
- ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(slot));
+ ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(slot));
pciehp_queue_interrupt_event(slot, INT_POWER_FAULT);
}
- if (intr_loc & PCI_EXP_SLTSTA_DLLSC) {
- link = pciehp_check_link_active(ctrl);
- ctrl_info(ctrl, "slot(%s): Link %s event\n",
- slot_name(slot), link ? "Up" : "Down");
+ if (events & PCI_EXP_SLTSTA_DLLSC) {
+ ctrl_info(ctrl, "Slot(%s): Link %s\n", slot_name(slot),
+ link ? "Up" : "Down");
pciehp_queue_interrupt_event(slot, link ? INT_LINK_UP :
INT_LINK_DOWN);
}
@@ -632,6 +646,25 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t pcie_isr(int irq, void *dev_id)
+{
+ irqreturn_t rc, handled = IRQ_NONE;
+
+ /*
+ * To guarantee that all interrupt events are serviced, we need to
+ * re-inspect Slot Status register after clearing what is presumed
+ * to be the last pending interrupt.
+ */
+ do {
+ rc = pciehp_isr(irq, dev_id);
+ if (rc == IRQ_HANDLED)
+ handled = IRQ_HANDLED;
+ } while (rc == IRQ_HANDLED);
+
+ /* Return IRQ_HANDLED if we handled one or more events */
+ return handled;
+}
+
void pcie_enable_notification(struct controller *ctrl)
{
u16 cmd, mask;
@@ -804,6 +837,10 @@ struct controller *pcie_init(struct pcie_device *dev)
}
ctrl->pcie = dev;
pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
+
+ if (pdev->hotplug_user_indicators)
+ slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP);
+
ctrl->slot_cap = slot_cap;
mutex_init(&ctrl->ctrl_lock);
init_waitqueue_head(&ctrl->queue);
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index e6245b03f0a1..56efaf72d08e 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -22,6 +22,12 @@
#define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
#define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver"
+struct pnv_php_event {
+ bool added;
+ struct pnv_php_slot *php_slot;
+ struct work_struct work;
+};
+
static LIST_HEAD(pnv_php_slot_list);
static DEFINE_SPINLOCK(pnv_php_lock);
@@ -29,12 +35,40 @@ static void pnv_php_register(struct device_node *dn);
static void pnv_php_unregister_one(struct device_node *dn);
static void pnv_php_unregister(struct device_node *dn);
+static void pnv_php_disable_irq(struct pnv_php_slot *php_slot)
+{
+ struct pci_dev *pdev = php_slot->pdev;
+ u16 ctrl;
+
+ if (php_slot->irq > 0) {
+ pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
+ ctrl &= ~(PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_PDCE |
+ PCI_EXP_SLTCTL_DLLSCE);
+ pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
+
+ free_irq(php_slot->irq, php_slot);
+ php_slot->irq = 0;
+ }
+
+ if (php_slot->wq) {
+ destroy_workqueue(php_slot->wq);
+ php_slot->wq = NULL;
+ }
+
+ if (pdev->msix_enabled)
+ pci_disable_msix(pdev);
+ else if (pdev->msi_enabled)
+ pci_disable_msi(pdev);
+}
+
static void pnv_php_free_slot(struct kref *kref)
{
struct pnv_php_slot *php_slot = container_of(kref,
struct pnv_php_slot, kref);
WARN_ON(!list_empty(&php_slot->children));
+ pnv_php_disable_irq(php_slot);
kfree(php_slot->name);
kfree(php_slot);
}
@@ -122,7 +156,7 @@ static void pnv_php_detach_device_nodes(struct device_node *parent)
of_node_put(dn);
refcount = atomic_read(&dn->kobj.kref.refcount);
- if (unlikely(refcount != 1))
+ if (refcount != 1)
pr_warn("Invalid refcount %d on <%s>\n",
refcount, of_node_full_name(dn));
@@ -184,11 +218,11 @@ static int pnv_php_populate_changeset(struct of_changeset *ocs,
for_each_child_of_node(dn, child) {
ret = of_changeset_attach_node(ocs, child);
- if (unlikely(ret))
+ if (ret)
break;
ret = pnv_php_populate_changeset(ocs, child);
- if (unlikely(ret))
+ if (ret)
break;
}
@@ -201,7 +235,7 @@ static void *pnv_php_add_one_pdn(struct device_node *dn, void *data)
struct pci_dn *pdn;
pdn = pci_add_device_node_info(hose, dn);
- if (unlikely(!pdn))
+ if (!pdn)
return ERR_PTR(-ENOMEM);
return NULL;
@@ -224,21 +258,21 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
* fits the real size.
*/
fdt1 = kzalloc(0x10000, GFP_KERNEL);
- if (unlikely(!fdt1)) {
+ if (!fdt1) {
ret = -ENOMEM;
dev_warn(&php_slot->pdev->dev, "Cannot alloc FDT blob\n");
goto out;
}
ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
- if (unlikely(ret)) {
+ if (ret) {
dev_warn(&php_slot->pdev->dev, "Error %d getting FDT blob\n",
ret);
goto free_fdt1;
}
fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL);
- if (unlikely(!fdt)) {
+ if (!fdt) {
ret = -ENOMEM;
dev_warn(&php_slot->pdev->dev, "Cannot %d bytes memory\n",
fdt_totalsize(fdt1));
@@ -248,7 +282,7 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
/* Unflatten device tree blob */
memcpy(fdt, fdt1, fdt_totalsize(fdt1));
dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
- if (unlikely(!dt)) {
+ if (!dt) {
ret = -EINVAL;
dev_warn(&php_slot->pdev->dev, "Cannot unflatten FDT\n");
goto free_fdt;
@@ -258,7 +292,7 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
of_changeset_init(&php_slot->ocs);
pnv_php_reverse_nodes(php_slot->dn);
ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
- if (unlikely(ret)) {
+ if (ret) {
pnv_php_reverse_nodes(php_slot->dn);
dev_warn(&php_slot->pdev->dev, "Error %d populating changeset\n",
ret);
@@ -267,7 +301,7 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
php_slot->dn->child = NULL;
ret = of_changeset_apply(&php_slot->ocs);
- if (unlikely(ret)) {
+ if (ret) {
dev_warn(&php_slot->pdev->dev, "Error %d applying changeset\n",
ret);
goto destroy_changeset;
@@ -301,7 +335,7 @@ int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
int ret;
ret = pnv_pci_set_power_state(php_slot->id, state, &msg);
- if (likely(ret > 0)) {
+ if (ret > 0) {
if (be64_to_cpu(msg.params[1]) != php_slot->dn->phandle ||
be64_to_cpu(msg.params[2]) != state ||
be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) {
@@ -311,7 +345,7 @@ int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
be64_to_cpu(msg.params[3]));
return -ENOMSG;
}
- } else if (unlikely(ret < 0)) {
+ } else if (ret < 0) {
dev_warn(&php_slot->pdev->dev, "Error %d powering %s\n",
ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off");
return ret;
@@ -338,7 +372,7 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
* be on.
*/
ret = pnv_pci_get_power_state(php_slot->id, &power_state);
- if (unlikely(ret)) {
+ if (ret) {
dev_warn(&php_slot->pdev->dev, "Error %d getting power status\n",
ret);
} else {
@@ -360,7 +394,7 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
* get that, it will fail back to be empty.
*/
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
- if (likely(ret >= 0)) {
+ if (ret >= 0) {
*state = presence;
slot->info->adapter_status = presence;
ret = 0;
@@ -393,7 +427,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
/* Retrieve slot presence status */
ret = pnv_php_get_adapter_state(slot, &presence);
- if (unlikely(ret))
+ if (ret)
return ret;
/* Proceed if there have nothing behind the slot */
@@ -414,7 +448,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
php_slot->power_state_check = true;
ret = pnv_php_get_power_state(slot, &power_status);
- if (unlikely(ret))
+ if (ret)
return ret;
if (power_status != OPAL_PCI_SLOT_POWER_ON)
@@ -423,7 +457,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
/* Check the power status. Scan the slot if it is already on */
ret = pnv_php_get_power_state(slot, &power_status);
- if (unlikely(ret))
+ if (ret)
return ret;
if (power_status == OPAL_PCI_SLOT_POWER_ON)
@@ -431,7 +465,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
/* Power is off, turn it on and then scan the slot */
ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
- if (unlikely(ret))
+ if (ret)
return ret;
scan:
@@ -513,29 +547,30 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
struct pci_bus *bus;
const char *label;
uint64_t id;
+ int ret;
- label = of_get_property(dn, "ibm,slot-label", NULL);
- if (unlikely(!label))
+ ret = of_property_read_string(dn, "ibm,slot-label", &label);
+ if (ret)
return NULL;
if (pnv_pci_get_slot_id(dn, &id))
return NULL;
bus = pci_find_bus_by_node(dn);
- if (unlikely(!bus))
+ if (!bus)
return NULL;
php_slot = kzalloc(sizeof(*php_slot), GFP_KERNEL);
- if (unlikely(!php_slot))
+ if (!php_slot)
return NULL;
php_slot->name = kstrdup(label, GFP_KERNEL);
- if (unlikely(!php_slot->name)) {
+ if (!php_slot->name) {
kfree(php_slot);
return NULL;
}
- if (likely(dn->child && PCI_DN(dn->child)))
+ if (dn->child && PCI_DN(dn->child))
php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
else
php_slot->slot_no = -1; /* Placeholder slot */
@@ -567,7 +602,7 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
/* Check if the slot is registered or not */
parent = pnv_php_find_slot(php_slot->dn);
- if (unlikely(parent)) {
+ if (parent) {
pnv_php_put_slot(parent);
return -EEXIST;
}
@@ -575,7 +610,7 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
/* Register PCI slot */
ret = pci_hp_register(&php_slot->slot, php_slot->bus,
php_slot->slot_no, php_slot->name);
- if (unlikely(ret)) {
+ if (ret) {
dev_warn(&php_slot->pdev->dev, "Error %d registering slot\n",
ret);
return ret;
@@ -609,33 +644,213 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
return 0;
}
+static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
+{
+ struct pci_dev *pdev = php_slot->pdev;
+ struct msix_entry entry;
+ int nr_entries, ret;
+ u16 pcie_flag;
+
+ /* Get total number of MSIx entries */
+ nr_entries = pci_msix_vec_count(pdev);
+ if (nr_entries < 0)
+ return nr_entries;
+
+ /* Check hotplug MSIx entry is in range */
+ pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
+ entry.entry = (pcie_flag & PCI_EXP_FLAGS_IRQ) >> 9;
+ if (entry.entry >= nr_entries)
+ return -ERANGE;
+
+ /* Enable MSIx */
+ ret = pci_enable_msix_exact(pdev, &entry, 1);
+ if (ret) {
+ dev_warn(&pdev->dev, "Error %d enabling MSIx\n", ret);
+ return ret;
+ }
+
+ return entry.vector;
+}
+
+static void pnv_php_event_handler(struct work_struct *work)
+{
+ struct pnv_php_event *event =
+ container_of(work, struct pnv_php_event, work);
+ struct pnv_php_slot *php_slot = event->php_slot;
+
+ if (event->added)
+ pnv_php_enable_slot(&php_slot->slot);
+ else
+ pnv_php_disable_slot(&php_slot->slot);
+
+ kfree(event);
+}
+
+static irqreturn_t pnv_php_interrupt(int irq, void *data)
+{
+ struct pnv_php_slot *php_slot = data;
+ struct pci_dev *pchild, *pdev = php_slot->pdev;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct pnv_php_event *event;
+ u16 sts, lsts;
+ u8 presence;
+ bool added;
+ unsigned long flags;
+ int ret;
+
+ pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
+ sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
+ if (sts & PCI_EXP_SLTSTA_DLLSC) {
+ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
+ added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
+ } else if (sts & PCI_EXP_SLTSTA_PDC) {
+ ret = pnv_pci_get_presence_state(php_slot->id, &presence);
+ if (!ret)
+ return IRQ_HANDLED;
+ added = !!(presence == OPAL_PCI_SLOT_PRESENT);
+ } else {
+ return IRQ_NONE;
+ }
+
+ /* Freeze the removed PE to avoid unexpected error reporting */
+ if (!added) {
+ pchild = list_first_entry_or_null(&php_slot->bus->devices,
+ struct pci_dev, bus_list);
+ edev = pchild ? pci_dev_to_eeh_dev(pchild) : NULL;
+ pe = edev ? edev->pe : NULL;
+ if (pe) {
+ eeh_serialize_lock(&flags);
+ eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+ eeh_serialize_unlock(flags);
+ eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE);
+ }
+ }
+
+ /*
+ * The PE is left in frozen state if the event is missed. It's
+ * fine as the PCI devices (PE) aren't functional any more.
+ */
+ event = kzalloc(sizeof(*event), GFP_ATOMIC);
+ if (!event) {
+ dev_warn(&pdev->dev, "PCI slot [%s] missed hotplug event 0x%04x\n",
+ php_slot->name, sts);
+ return IRQ_HANDLED;
+ }
+
+ dev_info(&pdev->dev, "PCI slot [%s] %s (IRQ: %d)\n",
+ php_slot->name, added ? "added" : "removed", irq);
+ INIT_WORK(&event->work, pnv_php_event_handler);
+ event->added = added;
+ event->php_slot = php_slot;
+ queue_work(php_slot->wq, &event->work);
+
+ return IRQ_HANDLED;
+}
+
+static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
+{
+ struct pci_dev *pdev = php_slot->pdev;
+ u16 sts, ctrl;
+ int ret;
+
+ /* Allocate workqueue */
+ php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
+ if (!php_slot->wq) {
+ dev_warn(&pdev->dev, "Cannot alloc workqueue\n");
+ pnv_php_disable_irq(php_slot);
+ return;
+ }
+
+ /* Clear pending interrupts */
+ pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
+ sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
+
+ /* Request the interrupt */
+ ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
+ php_slot->name, php_slot);
+ if (ret) {
+ pnv_php_disable_irq(php_slot);
+ dev_warn(&pdev->dev, "Error %d enabling IRQ %d\n", ret, irq);
+ return;
+ }
+
+ /* Enable the interrupts */
+ pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
+ ctrl |= (PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_PDCE |
+ PCI_EXP_SLTCTL_DLLSCE);
+ pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
+
+ /* The interrupt is initialized successfully when @irq is valid */
+ php_slot->irq = irq;
+}
+
+static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
+{
+ struct pci_dev *pdev = php_slot->pdev;
+ int irq, ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_warn(&pdev->dev, "Error %d enabling device\n", ret);
+ return;
+ }
+
+ pci_set_master(pdev);
+
+ /* Enable MSIx interrupt */
+ irq = pnv_php_enable_msix(php_slot);
+ if (irq > 0) {
+ pnv_php_init_irq(php_slot, irq);
+ return;
+ }
+
+ /*
+ * Use MSI if MSIx doesn't work. Fail back to legacy INTx
+ * if MSI doesn't work either
+ */
+ ret = pci_enable_msi(pdev);
+ if (!ret || pdev->irq) {
+ irq = pdev->irq;
+ pnv_php_init_irq(php_slot, irq);
+ }
+}
+
static int pnv_php_register_one(struct device_node *dn)
{
struct pnv_php_slot *php_slot;
- const __be32 *prop32;
+ u32 prop32;
int ret;
/* Check if it's hotpluggable slot */
- prop32 = of_get_property(dn, "ibm,slot-pluggable", NULL);
- if (!prop32 || !of_read_number(prop32, 1))
+ ret = of_property_read_u32(dn, "ibm,slot-pluggable", &prop32);
+ if (ret || !prop32)
return -ENXIO;
- prop32 = of_get_property(dn, "ibm,reset-by-firmware", NULL);
- if (!prop32 || !of_read_number(prop32, 1))
+ ret = of_property_read_u32(dn, "ibm,reset-by-firmware", &prop32);
+ if (ret || !prop32)
return -ENXIO;
php_slot = pnv_php_alloc_slot(dn);
- if (unlikely(!php_slot))
+ if (!php_slot)
return -ENODEV;
ret = pnv_php_register_slot(php_slot);
- if (unlikely(ret))
+ if (ret)
goto free_slot;
ret = pnv_php_enable(php_slot, false);
- if (unlikely(ret))
+ if (ret)
goto unregister_slot;
+ /* Enable interrupt if the slot supports surprise hotplug */
+ ret = of_property_read_u32(dn, "ibm,slot-surprise-pluggable", &prop32);
+ if (!ret && prop32)
+ pnv_php_enable_irq(php_slot);
+
return 0;
unregister_slot:
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 2194b447201d..e30f05c8517f 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -136,7 +136,10 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset)
virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
virtfn->vendor = dev->vendor;
pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
- pci_setup_device(virtfn);
+ rc = pci_setup_device(virtfn);
+ if (rc)
+ goto failed0;
+
virtfn->dev.parent = dev->dev.parent;
virtfn->physfn = pci_dev_get(dev);
virtfn->is_virtfn = 1;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 9a033e8ee9a4..d966d47c9e80 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -452,6 +452,27 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
return error;
}
+static pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
+ static const pci_power_t state_conv[] = {
+ [ACPI_STATE_D0] = PCI_D0,
+ [ACPI_STATE_D1] = PCI_D1,
+ [ACPI_STATE_D2] = PCI_D2,
+ [ACPI_STATE_D3_HOT] = PCI_D3hot,
+ [ACPI_STATE_D3_COLD] = PCI_D3cold,
+ };
+ int state;
+
+ if (!adev || !acpi_device_power_manageable(adev))
+ return PCI_UNKNOWN;
+
+ if (acpi_device_get_power(adev, &state) || state == ACPI_STATE_UNKNOWN)
+ return PCI_UNKNOWN;
+
+ return state_conv[state];
+}
+
static bool acpi_pci_can_wakeup(struct pci_dev *dev)
{
struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
@@ -534,6 +555,7 @@ static bool acpi_pci_need_resume(struct pci_dev *dev)
static const struct pci_platform_pm_ops acpi_pci_platform_pm = {
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
+ .get_state = acpi_pci_get_power_state,
.choose_state = acpi_pci_choose_state,
.sleep_wake = acpi_pci_sleep_wake,
.run_wake = acpi_pci_run_wake,
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e39a67c8ef39..1ccce1cd6aca 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -466,7 +466,6 @@ static void pci_device_shutdown(struct device *dev)
pci_msi_shutdown(pci_dev);
pci_msix_shutdown(pci_dev);
-#ifdef CONFIG_KEXEC_CORE
/*
* If this is a kexec reboot, turn off Bus Master bit on the
* device to tell it to not continue to do DMA. Don't touch
@@ -476,7 +475,6 @@ static void pci_device_shutdown(struct device *dev)
*/
if (kexec_in_progress && (pci_dev->current_state <= PCI_D3hot))
pci_clear_master(pci_dev);
-#endif
}
#ifdef CONFIG_PM
@@ -684,8 +682,19 @@ static int pci_pm_prepare(struct device *dev)
static void pci_pm_complete(struct device *dev)
{
- pci_dev_complete_resume(to_pci_dev(dev));
- pm_complete_with_resume_check(dev);
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
+ pci_dev_complete_resume(pci_dev);
+ pm_generic_complete(dev);
+
+ /* Resume device if platform firmware has put it in reset-power-on */
+ if (dev->power.direct_complete && pm_resume_via_firmware()) {
+ pci_power_t pre_sleep_state = pci_dev->current_state;
+
+ pci_update_current_state(pci_dev, pci_dev->current_state);
+ if (pci_dev->current_state < pre_sleep_state)
+ pm_request_resume(dev);
+ }
}
#else /* !CONFIG_PM_SLEEP */
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 415956c5c593..ba34907538f6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -576,8 +576,9 @@ static const struct pci_platform_pm_ops *pci_platform_pm;
int pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
{
- if (!ops->is_manageable || !ops->set_state || !ops->choose_state ||
- !ops->sleep_wake || !ops->run_wake || !ops->need_resume)
+ if (!ops->is_manageable || !ops->set_state || !ops->get_state ||
+ !ops->choose_state || !ops->sleep_wake || !ops->run_wake ||
+ !ops->need_resume)
return -EINVAL;
pci_platform_pm = ops;
return 0;
@@ -594,6 +595,11 @@ static inline int platform_pci_set_power_state(struct pci_dev *dev,
return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS;
}
+static inline pci_power_t platform_pci_get_power_state(struct pci_dev *dev)
+{
+ return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN;
+}
+
static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
{
return pci_platform_pm ?
@@ -725,26 +731,25 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
}
/**
- * pci_update_current_state - Read PCI power state of given device from its
- * PCI PM registers and cache it
+ * pci_update_current_state - Read power state of given device and cache it
* @dev: PCI device to handle.
* @state: State to cache in case the device doesn't have the PM capability
+ *
+ * The power state is read from the PMCSR register, which however is
+ * inaccessible in D3cold. The platform firmware is therefore queried first
+ * to detect accessibility of the register. In case the platform firmware
+ * reports an incorrect state or the device isn't power manageable by the
+ * platform at all, we try to detect D3cold by testing accessibility of the
+ * vendor ID in config space.
*/
void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
{
- if (dev->pm_cap) {
+ if (platform_pci_get_power_state(dev) == PCI_D3cold ||
+ !pci_device_is_present(dev)) {
+ dev->current_state = PCI_D3cold;
+ } else if (dev->pm_cap) {
u16 pmcsr;
- /*
- * Configuration space is not accessible for device in
- * D3cold, so just keep or set D3cold for safety
- */
- if (dev->current_state == PCI_D3cold)
- return;
- if (state == PCI_D3cold) {
- dev->current_state = PCI_D3cold;
- return;
- }
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
} else {
@@ -1983,9 +1988,22 @@ static pci_power_t pci_target_state(struct pci_dev *dev)
default:
target_state = state;
}
- } else if (!dev->pm_cap) {
+
+ return target_state;
+ }
+
+ if (!dev->pm_cap)
target_state = PCI_D0;
- } else if (device_may_wakeup(&dev->dev)) {
+
+ /*
+ * If the device is in D3cold even though it's not power-manageable by
+ * the platform, it may have been powered down by non-standard means.
+ * Best to let it slumber.
+ */
+ if (dev->current_state == PCI_D3cold)
+ target_state = PCI_D3cold;
+
+ if (device_may_wakeup(&dev->dev)) {
/*
* Find the deepest state from which the device can generate
* wake-up events, make it the target state and enable device
@@ -4983,6 +5001,13 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
spin_lock(&resource_alignment_lock);
p = resource_alignment_param;
+ if (!*p)
+ goto out;
+ if (pci_has_flag(PCI_PROBE_ONLY)) {
+ pr_info_once("PCI: Ignoring requested alignments (PCI_PROBE_ONLY)\n");
+ goto out;
+ }
+
while (*p) {
count = 0;
if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
@@ -5047,6 +5072,7 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
}
p++;
}
+out:
spin_unlock(&resource_alignment_lock);
return align;
}
@@ -5065,6 +5091,15 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
resource_size_t align, size;
u16 command;
+ /*
+ * VF BARs are read-only zero according to SR-IOV spec r1.1, sec
+ * 3.4.1.11. Their resources are allocated from the space
+ * described by the VF BARx register in the PF's SR-IOV capability.
+ * We can't influence their alignment here.
+ */
+ if (dev->is_virtfn)
+ return;
+
/* check if specified PCI is target device to reassign */
align = pci_specified_resource_alignment(dev);
if (!align)
@@ -5087,6 +5122,12 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM))
continue;
+ if (r->flags & IORESOURCE_PCI_FIXED) {
+ dev_info(&dev->dev, "Ignoring requested alignment for BAR%d: %pR\n",
+ i, r);
+ continue;
+ }
+
size = resource_size(r);
if (size < align) {
size = align;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9730c474b016..451856210e18 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -42,6 +42,8 @@ int pci_probe_reset_function(struct pci_dev *dev);
*
* @set_state: invokes the platform firmware to set the device's power state
*
+ * @get_state: queries the platform firmware for a device's current power state
+ *
* @choose_state: returns PCI power state of given device preferred by the
* platform; to be used during system-wide transitions from a
* sleeping state to the working state and vice versa
@@ -62,6 +64,7 @@ int pci_probe_reset_function(struct pci_dev *dev);
struct pci_platform_pm_ops {
bool (*is_manageable)(struct pci_dev *dev);
int (*set_state)(struct pci_dev *dev, pci_power_t state);
+ pci_power_t (*get_state)(struct pci_dev *dev);
pci_power_t (*choose_state)(struct pci_dev *dev);
int (*sleep_wake)(struct pci_dev *dev, bool enable);
int (*run_wake)(struct pci_dev *dev, bool enable);
@@ -332,6 +335,12 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
void pci_enable_acs(struct pci_dev *dev);
+#ifdef CONFIG_PCIE_PTM
+void pci_ptm_init(struct pci_dev *dev);
+#else
+static inline void pci_ptm_init(struct pci_dev *dev) { }
+#endif
+
struct pci_dev_reset_methods {
u16 vendor;
u16 device;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 7fcea75afa4c..7ce77635e5ad 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -92,3 +92,14 @@ config PCIE_DPC
will be handled by the DPC driver. If your system doesn't
have this capability or you do not want to use this feature,
it is safe to answer N.
+
+config PCIE_PTM
+ bool "PCIe Precision Time Measurement support"
+ default n
+ depends on PCIEPORTBUS
+ help
+ This enables PCI Express Precision Time Measurement (PTM)
+ support.
+
+ This is only useful if you have devices that support PTM, but it
+ is safe to enable even if you don't.
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index b24525b3dec1..36e35ea8fde7 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PCIEAER) += aer/
obj-$(CONFIG_PCIE_PME) += pme.o
obj-$(CONFIG_PCIE_DPC) += pcie-dpc.o
+obj-$(CONFIG_PCIE_PTM) += ptm.o
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 48d21e0edd56..139150b2bdfd 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -15,7 +15,6 @@
*
*/
-#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/sched.h>
@@ -37,9 +36,6 @@
#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
static int aer_probe(struct pcie_device *dev);
static void aer_remove(struct pcie_device *dev);
@@ -70,7 +66,7 @@ static int pcie_aer_disable;
void pci_no_aer(void)
{
- pcie_aer_disable = 1; /* has priority over 'forceload' */
+ pcie_aer_disable = 1;
}
bool pci_aer_available(void)
@@ -134,7 +130,7 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
SYSTEM_ERROR_INTR_ON_MESG_MASK);
- aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+ aer_pos = pdev->aer_cap;
/* Clear error status */
pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
@@ -173,7 +169,7 @@ static void aer_disable_rootport(struct aer_rpc *rpc)
*/
set_downstream_devices_error_reporting(pdev, false);
- pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+ pos = pdev->aer_cap;
/* Disable Root's interrupt in response to error messages */
pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
@@ -200,7 +196,7 @@ irqreturn_t aer_irq(int irq, void *context)
unsigned long flags;
int pos;
- pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
+ pos = pdev->port->aer_cap;
/*
* Must lock access to Root Error Status Reg, Root Error ID Reg,
* and Root error producer/consumer index
@@ -294,7 +290,6 @@ static void aer_remove(struct pcie_device *dev)
/**
* aer_probe - initialize resources
* @dev: pointer to the pcie_dev data structure
- * @id: pointer to the service id data structure
*
* Invoked when PCI Express bus loads AER service driver.
*/
@@ -304,11 +299,6 @@ static int aer_probe(struct pcie_device *dev)
struct aer_rpc *rpc;
struct device *device = &dev->device;
- /* Init */
- status = aer_init(dev);
- if (status)
- return status;
-
/* Alloc rpc data structure */
rpc = aer_alloc_rpc(dev);
if (!rpc) {
@@ -343,7 +333,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
u32 reg32;
int pos;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
/* Disable Root's interrupt in response to error messages */
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
@@ -396,7 +386,7 @@ static void aer_error_resume(struct pci_dev *dev)
pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16);
/* Clean AER Root Error Status */
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
if (dev->error_state == pci_channel_io_normal)
@@ -417,16 +407,4 @@ static int __init aer_service_init(void)
return -ENXIO;
return pcie_port_service_register(&aerdriver);
}
-
-/**
- * aer_service_exit - unregister AER root service driver
- *
- * Invoked when AER root service driver is unloaded.
- */
-static void __exit aer_service_exit(void)
-{
- pcie_port_service_unregister(&aerdriver);
-}
-
-module_init(aer_service_init);
-module_exit(aer_service_exit);
+device_initcall(aer_service_init);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 945c939a86c5..d51e4a57b190 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -60,6 +60,7 @@ struct aer_rpc {
struct pcie_device *rpd; /* Root Port device */
struct work_struct dpc_handler;
struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
+ struct aer_err_info e_info;
unsigned short prod_idx; /* Error Producer Index */
unsigned short cons_idx; /* Error Consumer Index */
int isr;
@@ -105,7 +106,6 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
}
extern struct bus_type pcie_port_bus_type;
-int aer_init(struct pcie_device *dev);
void aer_isr(struct work_struct *work);
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info);
@@ -121,11 +121,4 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
return 0;
}
#endif
-
-static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
- int enable)
-{
- pci_dev->__aer_firmware_first = !!enable;
- pci_dev->__aer_firmware_first_valid = 1;
-}
#endif /* _AERDRV_H_ */
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 521e39c1b66d..b1303b32053f 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -27,11 +27,6 @@
#include <linux/kfifo.h>
#include "aerdrv.h"
-static bool forceload;
-static bool nosourceid;
-module_param(forceload, bool, 0);
-module_param(nosourceid, bool, 0);
-
#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
@@ -40,7 +35,7 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev)
if (pcie_aer_get_firmware_first(dev))
return -EIO;
- if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+ if (!dev->aer_cap)
return -EIO;
return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
@@ -62,7 +57,7 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
int pos;
u32 status;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
if (!pos)
return -EIO;
@@ -83,7 +78,7 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
if (!pci_is_pcie(dev))
return -ENODEV;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
if (!pos)
return -EIO;
@@ -102,6 +97,12 @@ int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
return 0;
}
+int pci_aer_init(struct pci_dev *dev)
+{
+ dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ return pci_cleanup_aer_error_status_regs(dev);
+}
+
/**
* add_error_device - list device to be handled
* @e_info: pointer to error info
@@ -132,7 +133,8 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
* When bus id is equal to 0, it might be a bad id
* reported by root port.
*/
- if (!nosourceid && (PCI_BUS_NUM(e_info->id) != 0)) {
+ if ((PCI_BUS_NUM(e_info->id) != 0) &&
+ !(dev->bus->bus_flags & PCI_BUS_FLAGS_NO_AERSID)) {
/* Device ID match? */
if (e_info->id == ((dev->bus->number << 8) | dev->devfn))
return true;
@@ -144,10 +146,10 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
/*
* When either
- * 1) nosourceid==y;
- * 2) bus id is equal to 0. Some ports might lose the bus
+ * 1) bus id is equal to 0. Some ports might lose the bus
* id of error source id;
- * 3) There are multiple errors and prior id comparing fails;
+ * 2) bus flag PCI_BUS_FLAGS_NO_AERSID is set
+ * 3) There are multiple errors and prior ID comparing fails;
* We check AER status registers to find possible reporter.
*/
if (atomic_read(&dev->enable_cnt) == 0)
@@ -158,7 +160,7 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
if (!(reg16 & PCI_EXP_AER_FLAGS))
return false;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
if (!pos)
return false;
@@ -555,7 +557,7 @@ static void handle_error_source(struct pcie_device *aerdev,
* Correctable error does not need software intervention.
* No need to go through error recovery process.
*/
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
if (pos)
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
info->status);
@@ -647,7 +649,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
info->status = 0;
info->tlp_header_valid = 0;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ pos = dev->aer_cap;
/* The device might not support AER */
if (!pos)
@@ -715,15 +717,8 @@ static inline void aer_process_err_devices(struct pcie_device *p_device,
static void aer_isr_one_error(struct pcie_device *p_device,
struct aer_err_source *e_src)
{
- struct aer_err_info *e_info;
-
- /* struct aer_err_info might be big, so we allocate it with slab */
- e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL);
- if (!e_info) {
- dev_printk(KERN_DEBUG, &p_device->port->dev,
- "Can't allocate mem when processing AER errors\n");
- return;
- }
+ struct aer_rpc *rpc = get_service_data(p_device);
+ struct aer_err_info *e_info = &rpc->e_info;
/*
* There is a possibility that both correctable error and
@@ -762,8 +757,6 @@ static void aer_isr_one_error(struct pcie_device *p_device,
if (find_source_device(p_device->port, e_info))
aer_process_err_devices(p_device, e_info);
}
-
- kfree(e_info);
}
/**
@@ -812,19 +805,3 @@ void aer_isr(struct work_struct *work)
aer_isr_one_error(p_device, &e_src);
mutex_unlock(&rpc->rpc_mutex);
}
-
-/**
- * aer_init - provide AER initialization
- * @dev: pointer to AER pcie device
- *
- * Invoked when AER service driver is loaded.
- */
-int aer_init(struct pcie_device *dev)
-{
- if (forceload) {
- dev_printk(KERN_DEBUG, &dev->device,
- "aerdrv forceload requested.\n");
- pcie_aer_force_firmware_first(dev->port, 0);
- }
- return 0;
-}
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
index 167fe411ce2e..54c4b691e51f 100644
--- a/drivers/pci/pcie/aer/aerdrv_errprint.c
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -219,15 +219,13 @@ int cper_severity_to_aer(int cper_severity)
}
EXPORT_SYMBOL_GPL(cper_severity_to_aer);
-void cper_print_aer(struct pci_dev *dev, int cper_severity,
+void cper_print_aer(struct pci_dev *dev, int aer_severity,
struct aer_capability_regs *aer)
{
- int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
+ int layer, agent, status_strs_size, tlp_header_valid = 0;
u32 status, mask;
const char **status_strs;
- aer_severity = cper_severity_to_aer(cper_severity);
-
if (aer_severity == AER_CORRECTABLE) {
status = aer->cor_status;
mask = aer->cor_mask;
diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c
index 250f87861786..9811b14d9ad8 100644
--- a/drivers/pci/pcie/pcie-dpc.c
+++ b/drivers/pci/pcie/pcie-dpc.c
@@ -1,5 +1,7 @@
/*
* PCI Express Downstream Port Containment services driver
+ * Author: Keith Busch <keith.busch@intel.com>
+ *
* Copyright (C) 2016 Intel Corp.
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -9,7 +11,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pcieport_if.h>
@@ -143,16 +145,4 @@ static int __init dpc_service_init(void)
{
return pcie_port_service_register(&dpcdriver);
}
-
-static void __exit dpc_service_exit(void)
-{
- pcie_port_service_unregister(&dpcdriver);
-}
-
-MODULE_DESCRIPTION("PCI Express Downstream Port Containment driver");
-MODULE_AUTHOR("Keith Busch <keith.busch@intel.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
-
-module_init(dpc_service_init);
-module_exit(dpc_service_exit);
+device_initcall(dpc_service_init);
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 1ae4c73e7a3c..884bad5320f8 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -10,7 +10,6 @@
* for more details.
*/
-#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -449,17 +448,6 @@ static int pcie_pme_resume(struct pcie_device *srv)
return 0;
}
-/**
- * pcie_pme_remove - Prepare PCIe PME service device for removal.
- * @srv - PCIe service device to remove.
- */
-static void pcie_pme_remove(struct pcie_device *srv)
-{
- pcie_pme_suspend(srv);
- free_irq(srv->irq, srv);
- kfree(get_service_data(srv));
-}
-
static struct pcie_port_service_driver pcie_pme_driver = {
.name = "pcie_pme",
.port_type = PCI_EXP_TYPE_ROOT_PORT,
@@ -468,7 +456,6 @@ static struct pcie_port_service_driver pcie_pme_driver = {
.probe = pcie_pme_probe,
.suspend = pcie_pme_suspend,
.resume = pcie_pme_resume,
- .remove = pcie_pme_remove,
};
/**
@@ -478,5 +465,4 @@ static int __init pcie_pme_service_init(void)
{
return pcie_port_service_register(&pcie_pme_driver);
}
-
-module_init(pcie_pme_service_init);
+device_initcall(pcie_pme_service_init);
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 70d7ad8c6d17..79327cc14e7d 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -1,12 +1,13 @@
/*
* File: portdrv_pci.c
* Purpose: PCI Express Port Bus Driver
+ * Author: Tom Nguyen <tom.l.nguyen@intel.com>
+ * Version: v1.0
*
* Copyright (C) 2004 Intel
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
-#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -21,16 +22,6 @@
#include "portdrv.h"
#include "aer/aerdrv.h"
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0"
-#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
-#define DRIVER_DESC "PCIe Port Bus Driver"
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
/* If this switch is set, PCIe port native services should not be enabled. */
bool pcie_ports_disabled;
@@ -341,7 +332,6 @@ static const struct pci_device_id port_pci_ids[] = { {
PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
}, { /* end: all zeroes */ }
};
-MODULE_DEVICE_TABLE(pci, port_pci_ids);
static const struct pci_error_handlers pcie_portdrv_err_handler = {
.error_detected = pcie_portdrv_error_detected,
@@ -406,5 +396,4 @@ static int __init pcie_portdrv_init(void)
out:
return retval;
}
-
-module_init(pcie_portdrv_init);
+device_initcall(pcie_portdrv_init);
diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c
new file mode 100644
index 000000000000..bab8ac63c4f3
--- /dev/null
+++ b/drivers/pci/pcie/ptm.c
@@ -0,0 +1,142 @@
+/*
+ * PCI Express Precision Time Measurement
+ * Copyright (c) 2016, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include "../pci.h"
+
+static void pci_ptm_info(struct pci_dev *dev)
+{
+ char clock_desc[8];
+
+ switch (dev->ptm_granularity) {
+ case 0:
+ snprintf(clock_desc, sizeof(clock_desc), "unknown");
+ break;
+ case 255:
+ snprintf(clock_desc, sizeof(clock_desc), ">254ns");
+ break;
+ default:
+ snprintf(clock_desc, sizeof(clock_desc), "%udns",
+ dev->ptm_granularity);
+ break;
+ }
+ dev_info(&dev->dev, "PTM enabled%s, %s granularity\n",
+ dev->ptm_root ? " (root)" : "", clock_desc);
+}
+
+void pci_ptm_init(struct pci_dev *dev)
+{
+ int pos;
+ u32 cap, ctrl;
+ u8 local_clock;
+ struct pci_dev *ups;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
+ if (!pos)
+ return;
+
+ /*
+ * Enable PTM only on interior devices (root ports, switch ports,
+ * etc.) on the assumption that it causes no link traffic until an
+ * endpoint enables it.
+ */
+ if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT ||
+ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END))
+ return;
+
+ pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
+ local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
+
+ /*
+ * There's no point in enabling PTM unless it's enabled in the
+ * upstream device or this device can be a PTM Root itself. Per
+ * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
+ * furthest upstream Time Source as the PTM Root.
+ */
+ ups = pci_upstream_bridge(dev);
+ if (ups && ups->ptm_enabled) {
+ ctrl = PCI_PTM_CTRL_ENABLE;
+ if (ups->ptm_granularity == 0)
+ dev->ptm_granularity = 0;
+ else if (ups->ptm_granularity > local_clock)
+ dev->ptm_granularity = ups->ptm_granularity;
+ } else {
+ if (cap & PCI_PTM_CAP_ROOT) {
+ ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT;
+ dev->ptm_root = 1;
+ dev->ptm_granularity = local_clock;
+ } else
+ return;
+ }
+
+ ctrl |= dev->ptm_granularity << 8;
+ pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
+ dev->ptm_enabled = 1;
+
+ pci_ptm_info(dev);
+}
+
+int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
+{
+ int pos;
+ u32 cap, ctrl;
+ struct pci_dev *ups;
+
+ if (!pci_is_pcie(dev))
+ return -EINVAL;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
+ if (!pos)
+ return -EINVAL;
+
+ pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
+ if (!(cap & PCI_PTM_CAP_REQ))
+ return -EINVAL;
+
+ /*
+ * For a PCIe Endpoint, PTM is only useful if the endpoint can
+ * issue PTM requests to upstream devices that have PTM enabled.
+ *
+ * For Root Complex Integrated Endpoints, there is no upstream
+ * device, so there must be some implementation-specific way to
+ * associate the endpoint with a time source.
+ */
+ if (pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT) {
+ ups = pci_upstream_bridge(dev);
+ if (!ups || !ups->ptm_enabled)
+ return -EINVAL;
+
+ dev->ptm_granularity = ups->ptm_granularity;
+ } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
+ dev->ptm_granularity = 0;
+ } else
+ return -EINVAL;
+
+ ctrl = PCI_PTM_CTRL_ENABLE;
+ ctrl |= dev->ptm_granularity << 8;
+ pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
+ dev->ptm_enabled = 1;
+
+ pci_ptm_info(dev);
+
+ if (granularity)
+ *granularity = dev->ptm_granularity;
+ return 0;
+}
+EXPORT_SYMBOL(pci_enable_ptm);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 93f280df3428..ab002671fa60 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1666,7 +1666,11 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Enable ACS P2P upstream forwarding */
pci_enable_acs(dev);
- pci_cleanup_aer_error_status_regs(dev);
+ /* Precision Time Measurement */
+ pci_ptm_init(dev);
+
+ /* Advanced Error Reporting */
+ pci_aer_init(dev);
}
/*
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 44e0ff37480b..c232729f5b1b 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -834,6 +834,17 @@ static void quirk_amd_ioapic(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic);
#endif /* CONFIG_X86_IO_APIC */
+#if defined(CONFIG_ARM64) && defined(CONFIG_PCI_ATS)
+
+static void quirk_cavium_sriov_rnm_link(struct pci_dev *dev)
+{
+ /* Fix for improper SRIOV configuration on Cavium cn88xx RNM device */
+ if (dev->subsystem_device == 0xa118)
+ dev->sriov->link = dev->devfn;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CAVIUM, 0xa018, quirk_cavium_sriov_rnm_link);
+#endif
+
/*
* Some settings of MMRBC can lead to data corruption so block changes.
* See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide
@@ -3198,6 +3209,7 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
static void quirk_no_pm_reset(struct pci_dev *dev)
{
@@ -4431,3 +4443,20 @@ static void quirk_intel_qat_vf_cap(struct pci_dev *pdev)
}
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap);
+
+/*
+ * VMD-enabled root ports will change the source ID for all messages
+ * to the VMD device. Rather than doing device matching with the source
+ * ID, the AER driver should traverse the child device tree, reading
+ * AER registers to find the faulting device.
+ */
+static void quirk_no_aersid(struct pci_dev *pdev)
+{
+ /* VMD Domain */
+ if (pdev->bus->sysdata && pci_domain_nr(pdev->bus) >= 0x10000)
+ pdev->bus->bus_flags |= PCI_BUS_FLAGS_NO_AERSID;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2030, quirk_no_aersid);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2031, quirk_no_aersid);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2032, quirk_no_aersid);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2033, quirk_no_aersid);
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
index 44cfc4416e54..71ace6910d7e 100644
--- a/drivers/pcmcia/sa1100_assabet.c
+++ b/drivers/pcmcia/sa1100_assabet.c
@@ -31,13 +31,6 @@ static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
return 0;
}
-static void
-assabet_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
-{
- state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */
- state->vs_Xv = 0;
-}
-
static int
assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{
@@ -90,7 +83,7 @@ static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
static struct pcmcia_low_level assabet_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = assabet_pcmcia_hw_init,
- .socket_state = assabet_pcmcia_socket_state,
+ .socket_state = soc_common_cf_socket_state,
.configure_socket = assabet_pcmcia_configure_socket,
.socket_suspend = assabet_pcmcia_socket_suspend,
};
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index b3774e5d0396..c3f67363f6a1 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -45,13 +45,6 @@ static void cerf_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
gpio_free(CERF_GPIO_CF_RESET);
}
-static void
-cerf_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
-{
- state->vs_3v = 1;
- state->vs_Xv = 0;
-}
-
static int
cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
@@ -77,7 +70,7 @@ static struct pcmcia_low_level cerf_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = cerf_pcmcia_hw_init,
.hw_shutdown = cerf_pcmcia_hw_shutdown,
- .socket_state = cerf_pcmcia_socket_state,
+ .socket_state = soc_common_cf_socket_state,
.configure_socket = cerf_pcmcia_configure_socket,
};
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index d5ca760c4eb2..153f3122283d 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -33,6 +33,7 @@
#include <linux/cpufreq.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -42,6 +43,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
@@ -79,6 +81,41 @@ EXPORT_SYMBOL(soc_pcmcia_debug);
#define to_soc_pcmcia_socket(x) \
container_of(x, struct soc_pcmcia_socket, socket)
+int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
+ struct soc_pcmcia_regulator *r, int v)
+{
+ bool on;
+ int ret;
+
+ if (!r->reg)
+ return 0;
+
+ on = v != 0;
+ if (r->on == on)
+ return 0;
+
+ if (on) {
+ ret = regulator_set_voltage(r->reg, v * 100000, v * 100000);
+ if (ret) {
+ int vout = regulator_get_voltage(r->reg) / 100000;
+
+ dev_warn(&skt->socket.dev,
+ "CS requested %s=%u.%uV, applying %u.%uV\n",
+ r == &skt->vcc ? "Vcc" : "Vpp",
+ v / 10, v % 10, vout / 10, vout % 10);
+ }
+
+ ret = regulator_enable(r->reg);
+ } else {
+ regulator_disable(r->reg);
+ }
+ if (ret == 0)
+ r->on = on;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(soc_pcmcia_regulator_set);
+
static unsigned short
calc_speed(unsigned short *spds, int num, unsigned short dflt)
{
@@ -111,12 +148,9 @@ static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
{
unsigned int i;
- for (i = 0; i < nr; i++) {
+ for (i = 0; i < nr; i++)
if (skt->stat[i].irq)
free_irq(skt->stat[i].irq, skt);
- if (gpio_is_valid(skt->stat[i].gpio))
- gpio_free(skt->stat[i].gpio);
- }
if (skt->ops->hw_shutdown)
skt->ops->hw_shutdown(skt);
@@ -129,6 +163,30 @@ static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
__soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
}
+int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
+{
+ struct device *dev = skt->socket.dev.parent;
+ struct gpio_desc *desc;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
+ if (!skt->stat[i].name)
+ continue;
+
+ desc = devm_gpiod_get(dev, skt->stat[i].name, GPIOD_IN);
+ if (IS_ERR(desc)) {
+ dev_err(dev, "Failed to get GPIO for %s: %ld\n",
+ skt->stat[i].name, PTR_ERR(desc));
+ return PTR_ERR(desc);
+ }
+
+ skt->stat[i].desc = desc;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods);
+
static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
int ret = 0, i;
@@ -143,21 +201,32 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
if (gpio_is_valid(skt->stat[i].gpio)) {
- int irq;
+ unsigned long flags = GPIOF_IN;
- ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN,
- skt->stat[i].name);
+ /* CD is active low by default */
+ if (i == SOC_STAT_CD)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ ret = devm_gpio_request_one(skt->socket.dev.parent,
+ skt->stat[i].gpio, flags,
+ skt->stat[i].name);
if (ret) {
__soc_pcmcia_hw_shutdown(skt, i);
return ret;
}
- irq = gpio_to_irq(skt->stat[i].gpio);
+ skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
+ }
+
+ if (i < SOC_STAT_VS1 && skt->stat[i].desc) {
+ int irq = gpiod_to_irq(skt->stat[i].desc);
- if (i == SOC_STAT_RDY)
- skt->socket.pci_irq = irq;
- else
- skt->stat[i].irq = irq;
+ if (irq > 0) {
+ if (i == SOC_STAT_RDY)
+ skt->socket.pci_irq = irq;
+ else
+ skt->stat[i].irq = irq;
+ }
}
if (skt->stat[i].irq) {
@@ -166,8 +235,6 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
IRQF_TRIGGER_NONE,
skt->stat[i].name, skt);
if (ret) {
- if (gpio_is_valid(skt->stat[i].gpio))
- gpio_free(skt->stat[i].gpio);
__soc_pcmcia_hw_shutdown(skt, i);
return ret;
}
@@ -197,6 +264,18 @@ static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
}
+/*
+ * The CF 3.0 specification says that cards tie VS1 to ground and leave
+ * VS2 open. Many implementations do not wire up the VS signals, so we
+ * provide hard-coded values as per the CF 3.0 spec.
+ */
+void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ state->vs_3v = 1;
+}
+EXPORT_SYMBOL_GPL(soc_common_cf_socket_state);
+
static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
{
struct pcmcia_state state;
@@ -208,17 +287,18 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
state.bvd1 = 1;
state.bvd2 = 1;
- /* CD is active low by default */
- if (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio))
- state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio);
-
- /* RDY and BVD are active high by default */
- if (gpio_is_valid(skt->stat[SOC_STAT_RDY].gpio))
- state.ready = !!gpio_get_value(skt->stat[SOC_STAT_RDY].gpio);
- if (gpio_is_valid(skt->stat[SOC_STAT_BVD1].gpio))
- state.bvd1 = !!gpio_get_value(skt->stat[SOC_STAT_BVD1].gpio);
- if (gpio_is_valid(skt->stat[SOC_STAT_BVD2].gpio))
- state.bvd2 = !!gpio_get_value(skt->stat[SOC_STAT_BVD2].gpio);
+ if (skt->stat[SOC_STAT_CD].desc)
+ state.detect = !!gpiod_get_value(skt->stat[SOC_STAT_CD].desc);
+ if (skt->stat[SOC_STAT_RDY].desc)
+ state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
+ if (skt->stat[SOC_STAT_BVD1].desc)
+ state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
+ if (skt->stat[SOC_STAT_BVD2].desc)
+ state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
+ if (skt->stat[SOC_STAT_VS1].desc)
+ state.vs_3v = !!gpiod_get_value(skt->stat[SOC_STAT_VS1].desc);
+ if (skt->stat[SOC_STAT_VS2].desc)
+ state.vs_Xv = !!gpiod_get_value(skt->stat[SOC_STAT_VS2].desc);
skt->ops->socket_state(skt, &state);
@@ -257,7 +337,30 @@ static int soc_common_pcmcia_config_skt(
int ret;
ret = skt->ops->configure_socket(skt, state);
+ if (ret < 0) {
+ pr_err("soc_common_pcmcia: unable to configure socket %d\n",
+ skt->nr);
+ /* restore the previous state */
+ WARN_ON(skt->ops->configure_socket(skt, &skt->cs_state));
+ return ret;
+ }
+
if (ret == 0) {
+ struct gpio_desc *descs[2];
+ int values[2], n = 0;
+
+ if (skt->gpio_reset) {
+ descs[n] = skt->gpio_reset;
+ values[n++] = !!(state->flags & SS_RESET);
+ }
+ if (skt->gpio_bus_enable) {
+ descs[n] = skt->gpio_bus_enable;
+ values[n++] = !!(state->flags & SS_OUTPUT_ENA);
+ }
+
+ if (n)
+ gpiod_set_array_value_cansleep(n, descs, values);
+
/*
* This really needs a better solution. The IRQ
* may or may not be claimed by the driver.
@@ -274,10 +377,6 @@ static int soc_common_pcmcia_config_skt(
skt->cs_state = *state;
}
- if (ret < 0)
- printk(KERN_ERR "soc_common_pcmcia: unable to configure "
- "socket %d\n", skt->nr);
-
return ret;
}
@@ -637,54 +736,19 @@ static struct pccard_operations soc_common_pcmcia_operations = {
};
-static LIST_HEAD(soc_pcmcia_sockets);
-static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
-
#ifdef CONFIG_CPU_FREQ
-static int
-soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
+static int soc_common_pcmcia_cpufreq_nb(struct notifier_block *nb,
+ unsigned long val, void *data)
{
- struct soc_pcmcia_socket *skt;
+ struct soc_pcmcia_socket *skt = container_of(nb, struct soc_pcmcia_socket, cpufreq_nb);
struct cpufreq_freqs *freqs = data;
- int ret = 0;
-
- mutex_lock(&soc_pcmcia_sockets_lock);
- list_for_each_entry(skt, &soc_pcmcia_sockets, node)
- if (skt->ops->frequency_change)
- ret += skt->ops->frequency_change(skt, val, freqs);
- mutex_unlock(&soc_pcmcia_sockets_lock);
-
- return ret;
-}
-
-static struct notifier_block soc_pcmcia_notifier_block = {
- .notifier_call = soc_pcmcia_notifier
-};
-
-static int soc_pcmcia_cpufreq_register(void)
-{
- int ret;
- ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- if (ret < 0)
- printk(KERN_ERR "Unable to register CPU frequency change "
- "notifier for PCMCIA (%d)\n", ret);
- return ret;
+ return skt->ops->frequency_change(skt, val, freqs);
}
-fs_initcall(soc_pcmcia_cpufreq_register);
-
-static void soc_pcmcia_cpufreq_unregister(void)
-{
- cpufreq_unregister_notifier(&soc_pcmcia_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-module_exit(soc_pcmcia_cpufreq_unregister);
-
#endif
void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
- struct pcmcia_low_level *ops, struct device *dev)
+ const struct pcmcia_low_level *ops, struct device *dev)
{
int i;
@@ -700,19 +764,21 @@ EXPORT_SYMBOL(soc_pcmcia_init_one);
void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
{
- mutex_lock(&soc_pcmcia_sockets_lock);
del_timer_sync(&skt->poll_timer);
pcmcia_unregister_socket(&skt->socket);
+#ifdef CONFIG_CPU_FREQ
+ if (skt->ops->frequency_change)
+ cpufreq_unregister_notifier(&skt->cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
soc_pcmcia_hw_shutdown(skt);
/* should not be required; violates some lowlevel drivers */
soc_common_pcmcia_config_skt(skt, &dead_socket);
- list_del(&skt->node);
- mutex_unlock(&soc_pcmcia_sockets_lock);
-
iounmap(skt->virt_io);
skt->virt_io = NULL;
release_resource(&skt->res_attr);
@@ -726,6 +792,8 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
{
int ret;
+ skt->cs_state = dead_socket;
+
setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event,
(unsigned long)skt);
skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
@@ -752,10 +820,6 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
goto out_err_5;
}
- mutex_lock(&soc_pcmcia_sockets_lock);
-
- list_add(&skt->node, &soc_pcmcia_sockets);
-
/*
* We initialize default socket timing here, because
* we are not guaranteed to see a SetIOMap operation at
@@ -776,14 +840,23 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
skt->status = soc_common_pcmcia_skt_state(skt);
+#ifdef CONFIG_CPU_FREQ
+ if (skt->ops->frequency_change) {
+ skt->cpufreq_nb.notifier_call = soc_common_pcmcia_cpufreq_nb;
+
+ ret = cpufreq_register_notifier(&skt->cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (ret < 0)
+ dev_err(skt->socket.dev.parent,
+ "unable to register CPU frequency change notifier for PCMCIA (%d)\n",
+ ret);
+ }
+#endif
+
ret = pcmcia_register_socket(&skt->socket);
if (ret)
goto out_err_7;
- add_timer(&skt->poll_timer);
-
- mutex_unlock(&soc_pcmcia_sockets_lock);
-
ret = device_create_file(&skt->socket.dev, &dev_attr_status);
if (ret)
goto out_err_8;
@@ -791,15 +864,12 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
return ret;
out_err_8:
- mutex_lock(&soc_pcmcia_sockets_lock);
del_timer_sync(&skt->poll_timer);
pcmcia_unregister_socket(&skt->socket);
out_err_7:
soc_pcmcia_hw_shutdown(skt);
out_err_6:
- list_del(&skt->node);
- mutex_unlock(&soc_pcmcia_sockets_lock);
iounmap(skt->virt_io);
out_err_5:
release_resource(&skt->res_attr);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 94762a54d731..3f3625805353 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -17,7 +17,14 @@
struct device;
+struct gpio_desc;
struct pcmcia_low_level;
+struct regulator;
+
+struct soc_pcmcia_regulator {
+ struct regulator *reg;
+ bool on;
+};
/*
* This structure encapsulates per-socket state which we might need to
@@ -52,18 +59,30 @@ struct soc_pcmcia_socket {
struct {
int gpio;
+ struct gpio_desc *desc;
unsigned int irq;
const char *name;
- } stat[4];
+ } stat[6];
#define SOC_STAT_CD 0 /* Card detect */
#define SOC_STAT_BVD1 1 /* BATDEAD / IOSTSCHG */
#define SOC_STAT_BVD2 2 /* BATWARN / IOSPKR */
#define SOC_STAT_RDY 3 /* Ready / Interrupt */
+#define SOC_STAT_VS1 4 /* Voltage sense 1 */
+#define SOC_STAT_VS2 5 /* Voltage sense 2 */
+
+ struct gpio_desc *gpio_reset;
+ struct gpio_desc *gpio_bus_enable;
+ struct soc_pcmcia_regulator vcc;
+ struct soc_pcmcia_regulator vpp;
unsigned int irq_state;
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block cpufreq_nb;
+#endif
struct timer_list poll_timer;
struct list_head node;
+ void *driver_data;
};
struct skt_dev_info {
@@ -133,10 +152,16 @@ struct soc_pcmcia_timing {
extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
- struct pcmcia_low_level *ops, struct device *dev);
+ const struct pcmcia_low_level *ops, struct device *dev);
void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
+int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt);
+
+void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state);
+int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
+ struct soc_pcmcia_regulator *r, int v);
#ifdef CONFIG_PCMCIA_DEBUG
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 04e2653bb8c0..4d5c5f9f0dbd 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -12,4 +12,11 @@ config ARM_PMU
Say y if you want to use CPU performance monitors on ARM-based
systems.
+config XGENE_PMU
+ depends on PERF_EVENTS && ARCH_XGENE
+ bool "APM X-Gene SoC PMU"
+ default n
+ help
+ Say y if you want to use APM X-Gene SoC performance monitors.
+
endmenu
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index acd2397ded94..b116e982810b 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c
new file mode 100644
index 000000000000..c2ac7646b99f
--- /dev/null
+++ b/drivers/perf/xgene_pmu.c
@@ -0,0 +1,1398 @@
+/*
+ * APM X-Gene SoC PMU (Performance Monitor Unit)
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Author: Hoan Tran <hotran@apm.com>
+ * Tai Nguyen <ttnguyen@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define CSW_CSWCR 0x0000
+#define CSW_CSWCR_DUALMCB_MASK BIT(0)
+#define MCBADDRMR 0x0000
+#define MCBADDRMR_DUALMCU_MODE_MASK BIT(2)
+
+#define PCPPMU_INTSTATUS_REG 0x000
+#define PCPPMU_INTMASK_REG 0x004
+#define PCPPMU_INTMASK 0x0000000F
+#define PCPPMU_INTENMASK 0xFFFFFFFF
+#define PCPPMU_INTCLRMASK 0xFFFFFFF0
+#define PCPPMU_INT_MCU BIT(0)
+#define PCPPMU_INT_MCB BIT(1)
+#define PCPPMU_INT_L3C BIT(2)
+#define PCPPMU_INT_IOB BIT(3)
+
+#define PMU_MAX_COUNTERS 4
+#define PMU_CNT_MAX_PERIOD 0x100000000ULL
+#define PMU_OVERFLOW_MASK 0xF
+#define PMU_PMCR_E BIT(0)
+#define PMU_PMCR_P BIT(1)
+
+#define PMU_PMEVCNTR0 0x000
+#define PMU_PMEVCNTR1 0x004
+#define PMU_PMEVCNTR2 0x008
+#define PMU_PMEVCNTR3 0x00C
+#define PMU_PMEVTYPER0 0x400
+#define PMU_PMEVTYPER1 0x404
+#define PMU_PMEVTYPER2 0x408
+#define PMU_PMEVTYPER3 0x40C
+#define PMU_PMAMR0 0xA00
+#define PMU_PMAMR1 0xA04
+#define PMU_PMCNTENSET 0xC00
+#define PMU_PMCNTENCLR 0xC20
+#define PMU_PMINTENSET 0xC40
+#define PMU_PMINTENCLR 0xC60
+#define PMU_PMOVSR 0xC80
+#define PMU_PMCR 0xE04
+
+#define to_pmu_dev(p) container_of(p, struct xgene_pmu_dev, pmu)
+#define GET_CNTR(ev) (ev->hw.idx)
+#define GET_EVENTID(ev) (ev->hw.config & 0xFFULL)
+#define GET_AGENTID(ev) (ev->hw.config_base & 0xFFFFFFFFUL)
+#define GET_AGENT1ID(ev) ((ev->hw.config_base >> 32) & 0xFFFFFFFFUL)
+
+struct hw_pmu_info {
+ u32 type;
+ u32 enable_mask;
+ void __iomem *csr;
+};
+
+struct xgene_pmu_dev {
+ struct hw_pmu_info *inf;
+ struct xgene_pmu *parent;
+ struct pmu pmu;
+ u8 max_counters;
+ DECLARE_BITMAP(cntr_assign_mask, PMU_MAX_COUNTERS);
+ u64 max_period;
+ const struct attribute_group **attr_groups;
+ struct perf_event *pmu_counter_event[PMU_MAX_COUNTERS];
+};
+
+struct xgene_pmu {
+ struct device *dev;
+ int version;
+ void __iomem *pcppmu_csr;
+ u32 mcb_active_mask;
+ u32 mc_active_mask;
+ cpumask_t cpu;
+ raw_spinlock_t lock;
+ struct list_head l3cpmus;
+ struct list_head iobpmus;
+ struct list_head mcbpmus;
+ struct list_head mcpmus;
+};
+
+struct xgene_pmu_dev_ctx {
+ char *name;
+ struct list_head next;
+ struct xgene_pmu_dev *pmu_dev;
+ struct hw_pmu_info inf;
+};
+
+struct xgene_pmu_data {
+ int id;
+ u32 data;
+};
+
+enum xgene_pmu_version {
+ PCP_PMU_V1 = 1,
+ PCP_PMU_V2,
+};
+
+enum xgene_pmu_dev_type {
+ PMU_TYPE_L3C = 0,
+ PMU_TYPE_IOB,
+ PMU_TYPE_MCB,
+ PMU_TYPE_MC,
+};
+
+/*
+ * sysfs format attributes
+ */
+static ssize_t xgene_pmu_format_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr;
+
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
+ return sprintf(buf, "%s\n", (char *) eattr->var);
+}
+
+#define XGENE_PMU_FORMAT_ATTR(_name, _config) \
+ (&((struct dev_ext_attribute[]) { \
+ { .attr = __ATTR(_name, S_IRUGO, xgene_pmu_format_show, NULL), \
+ .var = (void *) _config, } \
+ })[0].attr.attr)
+
+static struct attribute *l3c_pmu_format_attrs[] = {
+ XGENE_PMU_FORMAT_ATTR(l3c_eventid, "config:0-7"),
+ XGENE_PMU_FORMAT_ATTR(l3c_agentid, "config1:0-9"),
+ NULL,
+};
+
+static struct attribute *iob_pmu_format_attrs[] = {
+ XGENE_PMU_FORMAT_ATTR(iob_eventid, "config:0-7"),
+ XGENE_PMU_FORMAT_ATTR(iob_agentid, "config1:0-63"),
+ NULL,
+};
+
+static struct attribute *mcb_pmu_format_attrs[] = {
+ XGENE_PMU_FORMAT_ATTR(mcb_eventid, "config:0-5"),
+ XGENE_PMU_FORMAT_ATTR(mcb_agentid, "config1:0-9"),
+ NULL,
+};
+
+static struct attribute *mc_pmu_format_attrs[] = {
+ XGENE_PMU_FORMAT_ATTR(mc_eventid, "config:0-28"),
+ NULL,
+};
+
+static const struct attribute_group l3c_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = l3c_pmu_format_attrs,
+};
+
+static const struct attribute_group iob_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = iob_pmu_format_attrs,
+};
+
+static const struct attribute_group mcb_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = mcb_pmu_format_attrs,
+};
+
+static const struct attribute_group mc_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = mc_pmu_format_attrs,
+};
+
+/*
+ * sysfs event attributes
+ */
+static ssize_t xgene_pmu_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr;
+
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
+ return sprintf(buf, "config=0x%lx\n", (unsigned long) eattr->var);
+}
+
+#define XGENE_PMU_EVENT_ATTR(_name, _config) \
+ (&((struct dev_ext_attribute[]) { \
+ { .attr = __ATTR(_name, S_IRUGO, xgene_pmu_event_show, NULL), \
+ .var = (void *) _config, } \
+ })[0].attr.attr)
+
+static struct attribute *l3c_pmu_events_attrs[] = {
+ XGENE_PMU_EVENT_ATTR(cycle-count, 0x00),
+ XGENE_PMU_EVENT_ATTR(cycle-count-div-64, 0x01),
+ XGENE_PMU_EVENT_ATTR(read-hit, 0x02),
+ XGENE_PMU_EVENT_ATTR(read-miss, 0x03),
+ XGENE_PMU_EVENT_ATTR(write-need-replacement, 0x06),
+ XGENE_PMU_EVENT_ATTR(write-not-need-replacement, 0x07),
+ XGENE_PMU_EVENT_ATTR(tq-full, 0x08),
+ XGENE_PMU_EVENT_ATTR(ackq-full, 0x09),
+ XGENE_PMU_EVENT_ATTR(wdb-full, 0x0a),
+ XGENE_PMU_EVENT_ATTR(bank-fifo-full, 0x0b),
+ XGENE_PMU_EVENT_ATTR(odb-full, 0x0c),
+ XGENE_PMU_EVENT_ATTR(wbq-full, 0x0d),
+ XGENE_PMU_EVENT_ATTR(bank-conflict-fifo-issue, 0x0e),
+ XGENE_PMU_EVENT_ATTR(bank-fifo-issue, 0x0f),
+ NULL,
+};
+
+static struct attribute *iob_pmu_events_attrs[] = {
+ XGENE_PMU_EVENT_ATTR(cycle-count, 0x00),
+ XGENE_PMU_EVENT_ATTR(cycle-count-div-64, 0x01),
+ XGENE_PMU_EVENT_ATTR(axi0-read, 0x02),
+ XGENE_PMU_EVENT_ATTR(axi0-read-partial, 0x03),
+ XGENE_PMU_EVENT_ATTR(axi1-read, 0x04),
+ XGENE_PMU_EVENT_ATTR(axi1-read-partial, 0x05),
+ XGENE_PMU_EVENT_ATTR(csw-read-block, 0x06),
+ XGENE_PMU_EVENT_ATTR(csw-read-partial, 0x07),
+ XGENE_PMU_EVENT_ATTR(axi0-write, 0x10),
+ XGENE_PMU_EVENT_ATTR(axi0-write-partial, 0x11),
+ XGENE_PMU_EVENT_ATTR(axi1-write, 0x13),
+ XGENE_PMU_EVENT_ATTR(axi1-write-partial, 0x14),
+ XGENE_PMU_EVENT_ATTR(csw-inbound-dirty, 0x16),
+ NULL,
+};
+
+static struct attribute *mcb_pmu_events_attrs[] = {
+ XGENE_PMU_EVENT_ATTR(cycle-count, 0x00),
+ XGENE_PMU_EVENT_ATTR(cycle-count-div-64, 0x01),
+ XGENE_PMU_EVENT_ATTR(csw-read, 0x02),
+ XGENE_PMU_EVENT_ATTR(csw-write-request, 0x03),
+ XGENE_PMU_EVENT_ATTR(mcb-csw-stall, 0x04),
+ XGENE_PMU_EVENT_ATTR(cancel-read-gack, 0x05),
+ NULL,
+};
+
+static struct attribute *mc_pmu_events_attrs[] = {
+ XGENE_PMU_EVENT_ATTR(cycle-count, 0x00),
+ XGENE_PMU_EVENT_ATTR(cycle-count-div-64, 0x01),
+ XGENE_PMU_EVENT_ATTR(act-cmd-sent, 0x02),
+ XGENE_PMU_EVENT_ATTR(pre-cmd-sent, 0x03),
+ XGENE_PMU_EVENT_ATTR(rd-cmd-sent, 0x04),
+ XGENE_PMU_EVENT_ATTR(rda-cmd-sent, 0x05),
+ XGENE_PMU_EVENT_ATTR(wr-cmd-sent, 0x06),
+ XGENE_PMU_EVENT_ATTR(wra-cmd-sent, 0x07),
+ XGENE_PMU_EVENT_ATTR(pde-cmd-sent, 0x08),
+ XGENE_PMU_EVENT_ATTR(sre-cmd-sent, 0x09),
+ XGENE_PMU_EVENT_ATTR(prea-cmd-sent, 0x0a),
+ XGENE_PMU_EVENT_ATTR(ref-cmd-sent, 0x0b),
+ XGENE_PMU_EVENT_ATTR(rd-rda-cmd-sent, 0x0c),
+ XGENE_PMU_EVENT_ATTR(wr-wra-cmd-sent, 0x0d),
+ XGENE_PMU_EVENT_ATTR(in-rd-collision, 0x0e),
+ XGENE_PMU_EVENT_ATTR(in-wr-collision, 0x0f),
+ XGENE_PMU_EVENT_ATTR(collision-queue-not-empty, 0x10),
+ XGENE_PMU_EVENT_ATTR(collision-queue-full, 0x11),
+ XGENE_PMU_EVENT_ATTR(mcu-request, 0x12),
+ XGENE_PMU_EVENT_ATTR(mcu-rd-request, 0x13),
+ XGENE_PMU_EVENT_ATTR(mcu-hp-rd-request, 0x14),
+ XGENE_PMU_EVENT_ATTR(mcu-wr-request, 0x15),
+ XGENE_PMU_EVENT_ATTR(mcu-rd-proceed-all, 0x16),
+ XGENE_PMU_EVENT_ATTR(mcu-rd-proceed-cancel, 0x17),
+ XGENE_PMU_EVENT_ATTR(mcu-rd-response, 0x18),
+ XGENE_PMU_EVENT_ATTR(mcu-rd-proceed-speculative-all, 0x19),
+ XGENE_PMU_EVENT_ATTR(mcu-rd-proceed-speculative-cancel, 0x1a),
+ XGENE_PMU_EVENT_ATTR(mcu-wr-proceed-all, 0x1b),
+ XGENE_PMU_EVENT_ATTR(mcu-wr-proceed-cancel, 0x1c),
+ NULL,
+};
+
+static const struct attribute_group l3c_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = l3c_pmu_events_attrs,
+};
+
+static const struct attribute_group iob_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = iob_pmu_events_attrs,
+};
+
+static const struct attribute_group mcb_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = mcb_pmu_events_attrs,
+};
+
+static const struct attribute_group mc_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = mc_pmu_events_attrs,
+};
+
+/*
+ * sysfs cpumask attributes
+ */
+static ssize_t xgene_pmu_cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(dev_get_drvdata(dev));
+
+ return cpumap_print_to_pagebuf(true, buf, &pmu_dev->parent->cpu);
+}
+
+static DEVICE_ATTR(cpumask, S_IRUGO, xgene_pmu_cpumask_show, NULL);
+
+static struct attribute *xgene_pmu_cpumask_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL,
+};
+
+static const struct attribute_group pmu_cpumask_attr_group = {
+ .attrs = xgene_pmu_cpumask_attrs,
+};
+
+/*
+ * Per PMU device attribute groups
+ */
+static const struct attribute_group *l3c_pmu_attr_groups[] = {
+ &l3c_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &l3c_pmu_events_attr_group,
+ NULL
+};
+
+static const struct attribute_group *iob_pmu_attr_groups[] = {
+ &iob_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &iob_pmu_events_attr_group,
+ NULL
+};
+
+static const struct attribute_group *mcb_pmu_attr_groups[] = {
+ &mcb_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &mcb_pmu_events_attr_group,
+ NULL
+};
+
+static const struct attribute_group *mc_pmu_attr_groups[] = {
+ &mc_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &mc_pmu_events_attr_group,
+ NULL
+};
+
+static int get_next_avail_cntr(struct xgene_pmu_dev *pmu_dev)
+{
+ int cntr;
+
+ cntr = find_first_zero_bit(pmu_dev->cntr_assign_mask,
+ pmu_dev->max_counters);
+ if (cntr == pmu_dev->max_counters)
+ return -ENOSPC;
+ set_bit(cntr, pmu_dev->cntr_assign_mask);
+
+ return cntr;
+}
+
+static void clear_avail_cntr(struct xgene_pmu_dev *pmu_dev, int cntr)
+{
+ clear_bit(cntr, pmu_dev->cntr_assign_mask);
+}
+
+static inline void xgene_pmu_mask_int(struct xgene_pmu *xgene_pmu)
+{
+ writel(PCPPMU_INTENMASK, xgene_pmu->pcppmu_csr + PCPPMU_INTMASK_REG);
+}
+
+static inline void xgene_pmu_unmask_int(struct xgene_pmu *xgene_pmu)
+{
+ writel(PCPPMU_INTCLRMASK, xgene_pmu->pcppmu_csr + PCPPMU_INTMASK_REG);
+}
+
+static inline u32 xgene_pmu_read_counter(struct xgene_pmu_dev *pmu_dev, int idx)
+{
+ return readl(pmu_dev->inf->csr + PMU_PMEVCNTR0 + (4 * idx));
+}
+
+static inline void
+xgene_pmu_write_counter(struct xgene_pmu_dev *pmu_dev, int idx, u32 val)
+{
+ writel(val, pmu_dev->inf->csr + PMU_PMEVCNTR0 + (4 * idx));
+}
+
+static inline void
+xgene_pmu_write_evttype(struct xgene_pmu_dev *pmu_dev, int idx, u32 val)
+{
+ writel(val, pmu_dev->inf->csr + PMU_PMEVTYPER0 + (4 * idx));
+}
+
+static inline void
+xgene_pmu_write_agentmsk(struct xgene_pmu_dev *pmu_dev, u32 val)
+{
+ writel(val, pmu_dev->inf->csr + PMU_PMAMR0);
+}
+
+static inline void
+xgene_pmu_write_agent1msk(struct xgene_pmu_dev *pmu_dev, u32 val)
+{
+ writel(val, pmu_dev->inf->csr + PMU_PMAMR1);
+}
+
+static inline void
+xgene_pmu_enable_counter(struct xgene_pmu_dev *pmu_dev, int idx)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMCNTENSET);
+ val |= 1 << idx;
+ writel(val, pmu_dev->inf->csr + PMU_PMCNTENSET);
+}
+
+static inline void
+xgene_pmu_disable_counter(struct xgene_pmu_dev *pmu_dev, int idx)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMCNTENCLR);
+ val |= 1 << idx;
+ writel(val, pmu_dev->inf->csr + PMU_PMCNTENCLR);
+}
+
+static inline void
+xgene_pmu_enable_counter_int(struct xgene_pmu_dev *pmu_dev, int idx)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMINTENSET);
+ val |= 1 << idx;
+ writel(val, pmu_dev->inf->csr + PMU_PMINTENSET);
+}
+
+static inline void
+xgene_pmu_disable_counter_int(struct xgene_pmu_dev *pmu_dev, int idx)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMINTENCLR);
+ val |= 1 << idx;
+ writel(val, pmu_dev->inf->csr + PMU_PMINTENCLR);
+}
+
+static inline void xgene_pmu_reset_counters(struct xgene_pmu_dev *pmu_dev)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMCR);
+ val |= PMU_PMCR_P;
+ writel(val, pmu_dev->inf->csr + PMU_PMCR);
+}
+
+static inline void xgene_pmu_start_counters(struct xgene_pmu_dev *pmu_dev)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMCR);
+ val |= PMU_PMCR_E;
+ writel(val, pmu_dev->inf->csr + PMU_PMCR);
+}
+
+static inline void xgene_pmu_stop_counters(struct xgene_pmu_dev *pmu_dev)
+{
+ u32 val;
+
+ val = readl(pmu_dev->inf->csr + PMU_PMCR);
+ val &= ~PMU_PMCR_E;
+ writel(val, pmu_dev->inf->csr + PMU_PMCR);
+}
+
+static void xgene_perf_pmu_enable(struct pmu *pmu)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(pmu);
+ int enabled = bitmap_weight(pmu_dev->cntr_assign_mask,
+ pmu_dev->max_counters);
+
+ if (!enabled)
+ return;
+
+ xgene_pmu_start_counters(pmu_dev);
+}
+
+static void xgene_perf_pmu_disable(struct pmu *pmu)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(pmu);
+
+ xgene_pmu_stop_counters(pmu_dev);
+}
+
+static int xgene_perf_event_init(struct perf_event *event)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+ struct perf_event *sibling;
+
+ /* Test the event attr type check for PMU enumeration */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /*
+ * SOC PMU counters are shared across all cores.
+ * Therefore, it does not support per-process mode.
+ * Also, it does not support event sampling mode.
+ */
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EINVAL;
+
+ /* SOC counters do not have usr/os/guest/host bits */
+ if (event->attr.exclude_user || event->attr.exclude_kernel ||
+ event->attr.exclude_host || event->attr.exclude_guest)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+ /*
+ * Many perf core operations (eg. events rotation) operate on a
+ * single CPU context. This is obvious for CPU PMUs, where one
+ * expects the same sets of events being observed on all CPUs,
+ * but can lead to issues for off-core PMUs, where each
+ * event could be theoretically assigned to a different CPU. To
+ * mitigate this, we enforce CPU assignment to one, selected
+ * processor (the one described in the "cpumask" attribute).
+ */
+ event->cpu = cpumask_first(&pmu_dev->parent->cpu);
+
+ hw->config = event->attr.config;
+ /*
+ * Each bit of the config1 field represents an agent from which the
+ * request of the event come. The event is counted only if it's caused
+ * by a request of an agent has the bit cleared.
+ * By default, the event is counted for all agents.
+ */
+ hw->config_base = event->attr.config1;
+
+ /*
+ * We must NOT create groups containing mixed PMUs, although software
+ * events are acceptable
+ */
+ if (event->group_leader->pmu != event->pmu &&
+ !is_software_event(event->group_leader))
+ return -EINVAL;
+
+ list_for_each_entry(sibling, &event->group_leader->sibling_list,
+ group_entry)
+ if (sibling->pmu != event->pmu &&
+ !is_software_event(sibling))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void xgene_perf_enable_event(struct perf_event *event)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+
+ xgene_pmu_write_evttype(pmu_dev, GET_CNTR(event), GET_EVENTID(event));
+ xgene_pmu_write_agentmsk(pmu_dev, ~((u32)GET_AGENTID(event)));
+ if (pmu_dev->inf->type == PMU_TYPE_IOB)
+ xgene_pmu_write_agent1msk(pmu_dev, ~((u32)GET_AGENT1ID(event)));
+
+ xgene_pmu_enable_counter(pmu_dev, GET_CNTR(event));
+ xgene_pmu_enable_counter_int(pmu_dev, GET_CNTR(event));
+}
+
+static void xgene_perf_disable_event(struct perf_event *event)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+
+ xgene_pmu_disable_counter(pmu_dev, GET_CNTR(event));
+ xgene_pmu_disable_counter_int(pmu_dev, GET_CNTR(event));
+}
+
+static void xgene_perf_event_set_period(struct perf_event *event)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+ /*
+ * The X-Gene PMU counters have a period of 2^32. To account for the
+ * possiblity of extreme interrupt latency we program for a period of
+ * half that. Hopefully we can handle the interrupt before another 2^31
+ * events occur and the counter overtakes its previous value.
+ */
+ u64 val = 1ULL << 31;
+
+ local64_set(&hw->prev_count, val);
+ xgene_pmu_write_counter(pmu_dev, hw->idx, (u32) val);
+}
+
+static void xgene_perf_event_update(struct perf_event *event)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+ u64 delta, prev_raw_count, new_raw_count;
+
+again:
+ prev_raw_count = local64_read(&hw->prev_count);
+ new_raw_count = xgene_pmu_read_counter(pmu_dev, GET_CNTR(event));
+
+ if (local64_cmpxchg(&hw->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count)
+ goto again;
+
+ delta = (new_raw_count - prev_raw_count) & pmu_dev->max_period;
+
+ local64_add(delta, &event->count);
+}
+
+static void xgene_perf_read(struct perf_event *event)
+{
+ xgene_perf_event_update(event);
+}
+
+static void xgene_perf_start(struct perf_event *event, int flags)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+
+ if (WARN_ON_ONCE(!(hw->state & PERF_HES_STOPPED)))
+ return;
+
+ WARN_ON_ONCE(!(hw->state & PERF_HES_UPTODATE));
+ hw->state = 0;
+
+ xgene_perf_event_set_period(event);
+
+ if (flags & PERF_EF_RELOAD) {
+ u64 prev_raw_count = local64_read(&hw->prev_count);
+
+ xgene_pmu_write_counter(pmu_dev, GET_CNTR(event),
+ (u32) prev_raw_count);
+ }
+
+ xgene_perf_enable_event(event);
+ perf_event_update_userpage(event);
+}
+
+static void xgene_perf_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hw = &event->hw;
+ u64 config;
+
+ if (hw->state & PERF_HES_UPTODATE)
+ return;
+
+ xgene_perf_disable_event(event);
+ WARN_ON_ONCE(hw->state & PERF_HES_STOPPED);
+ hw->state |= PERF_HES_STOPPED;
+
+ if (hw->state & PERF_HES_UPTODATE)
+ return;
+
+ config = hw->config;
+ xgene_perf_read(event);
+ hw->state |= PERF_HES_UPTODATE;
+}
+
+static int xgene_perf_add(struct perf_event *event, int flags)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+
+ hw->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ /* Allocate an event counter */
+ hw->idx = get_next_avail_cntr(pmu_dev);
+ if (hw->idx < 0)
+ return -EAGAIN;
+
+ /* Update counter event pointer for Interrupt handler */
+ pmu_dev->pmu_counter_event[hw->idx] = event;
+
+ if (flags & PERF_EF_START)
+ xgene_perf_start(event, PERF_EF_RELOAD);
+
+ return 0;
+}
+
+static void xgene_perf_del(struct perf_event *event, int flags)
+{
+ struct xgene_pmu_dev *pmu_dev = to_pmu_dev(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+
+ xgene_perf_stop(event, PERF_EF_UPDATE);
+
+ /* clear the assigned counter */
+ clear_avail_cntr(pmu_dev, GET_CNTR(event));
+
+ perf_event_update_userpage(event);
+ pmu_dev->pmu_counter_event[hw->idx] = NULL;
+}
+
+static int xgene_init_perf(struct xgene_pmu_dev *pmu_dev, char *name)
+{
+ struct xgene_pmu *xgene_pmu;
+
+ pmu_dev->max_period = PMU_CNT_MAX_PERIOD - 1;
+ /* First version PMU supports only single event counter */
+ xgene_pmu = pmu_dev->parent;
+ if (xgene_pmu->version == PCP_PMU_V1)
+ pmu_dev->max_counters = 1;
+ else
+ pmu_dev->max_counters = PMU_MAX_COUNTERS;
+
+ /* Perf driver registration */
+ pmu_dev->pmu = (struct pmu) {
+ .attr_groups = pmu_dev->attr_groups,
+ .task_ctx_nr = perf_invalid_context,
+ .pmu_enable = xgene_perf_pmu_enable,
+ .pmu_disable = xgene_perf_pmu_disable,
+ .event_init = xgene_perf_event_init,
+ .add = xgene_perf_add,
+ .del = xgene_perf_del,
+ .start = xgene_perf_start,
+ .stop = xgene_perf_stop,
+ .read = xgene_perf_read,
+ };
+
+ /* Hardware counter init */
+ xgene_pmu_stop_counters(pmu_dev);
+ xgene_pmu_reset_counters(pmu_dev);
+
+ return perf_pmu_register(&pmu_dev->pmu, name, -1);
+}
+
+static int
+xgene_pmu_dev_add(struct xgene_pmu *xgene_pmu, struct xgene_pmu_dev_ctx *ctx)
+{
+ struct device *dev = xgene_pmu->dev;
+ struct xgene_pmu_dev *pmu;
+ int rc;
+
+ pmu = devm_kzalloc(dev, sizeof(*pmu), GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+ pmu->parent = xgene_pmu;
+ pmu->inf = &ctx->inf;
+ ctx->pmu_dev = pmu;
+
+ switch (pmu->inf->type) {
+ case PMU_TYPE_L3C:
+ pmu->attr_groups = l3c_pmu_attr_groups;
+ break;
+ case PMU_TYPE_IOB:
+ pmu->attr_groups = iob_pmu_attr_groups;
+ break;
+ case PMU_TYPE_MCB:
+ if (!(xgene_pmu->mcb_active_mask & pmu->inf->enable_mask))
+ goto dev_err;
+ pmu->attr_groups = mcb_pmu_attr_groups;
+ break;
+ case PMU_TYPE_MC:
+ if (!(xgene_pmu->mc_active_mask & pmu->inf->enable_mask))
+ goto dev_err;
+ pmu->attr_groups = mc_pmu_attr_groups;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = xgene_init_perf(pmu, ctx->name);
+ if (rc) {
+ dev_err(dev, "%s PMU: Failed to init perf driver\n", ctx->name);
+ goto dev_err;
+ }
+
+ dev_info(dev, "%s PMU registered\n", ctx->name);
+
+ return rc;
+
+dev_err:
+ devm_kfree(dev, pmu);
+ return -ENODEV;
+}
+
+static void _xgene_pmu_isr(int irq, struct xgene_pmu_dev *pmu_dev)
+{
+ struct xgene_pmu *xgene_pmu = pmu_dev->parent;
+ u32 pmovsr;
+ int idx;
+
+ pmovsr = readl(pmu_dev->inf->csr + PMU_PMOVSR) & PMU_OVERFLOW_MASK;
+ if (!pmovsr)
+ return;
+
+ /* Clear interrupt flag */
+ if (xgene_pmu->version == PCP_PMU_V1)
+ writel(0x0, pmu_dev->inf->csr + PMU_PMOVSR);
+ else
+ writel(pmovsr, pmu_dev->inf->csr + PMU_PMOVSR);
+
+ for (idx = 0; idx < PMU_MAX_COUNTERS; idx++) {
+ struct perf_event *event = pmu_dev->pmu_counter_event[idx];
+ int overflowed = pmovsr & BIT(idx);
+
+ /* Ignore if we don't have an event. */
+ if (!event || !overflowed)
+ continue;
+ xgene_perf_event_update(event);
+ xgene_perf_event_set_period(event);
+ }
+}
+
+static irqreturn_t xgene_pmu_isr(int irq, void *dev_id)
+{
+ struct xgene_pmu_dev_ctx *ctx;
+ struct xgene_pmu *xgene_pmu = dev_id;
+ unsigned long flags;
+ u32 val;
+
+ raw_spin_lock_irqsave(&xgene_pmu->lock, flags);
+
+ /* Get Interrupt PMU source */
+ val = readl(xgene_pmu->pcppmu_csr + PCPPMU_INTSTATUS_REG);
+ if (val & PCPPMU_INT_MCU) {
+ list_for_each_entry(ctx, &xgene_pmu->mcpmus, next) {
+ _xgene_pmu_isr(irq, ctx->pmu_dev);
+ }
+ }
+ if (val & PCPPMU_INT_MCB) {
+ list_for_each_entry(ctx, &xgene_pmu->mcbpmus, next) {
+ _xgene_pmu_isr(irq, ctx->pmu_dev);
+ }
+ }
+ if (val & PCPPMU_INT_L3C) {
+ list_for_each_entry(ctx, &xgene_pmu->l3cpmus, next) {
+ _xgene_pmu_isr(irq, ctx->pmu_dev);
+ }
+ }
+ if (val & PCPPMU_INT_IOB) {
+ list_for_each_entry(ctx, &xgene_pmu->iobpmus, next) {
+ _xgene_pmu_isr(irq, ctx->pmu_dev);
+ }
+ }
+
+ raw_spin_unlock_irqrestore(&xgene_pmu->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int acpi_pmu_probe_active_mcb_mcu(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ void __iomem *csw_csr, *mcba_csr, *mcbb_csr;
+ struct resource *res;
+ unsigned int reg;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ csw_csr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(csw_csr)) {
+ dev_err(&pdev->dev, "ioremap failed for CSW CSR resource\n");
+ return PTR_ERR(csw_csr);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ mcba_csr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcba_csr)) {
+ dev_err(&pdev->dev, "ioremap failed for MCBA CSR resource\n");
+ return PTR_ERR(mcba_csr);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ mcbb_csr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcbb_csr)) {
+ dev_err(&pdev->dev, "ioremap failed for MCBB CSR resource\n");
+ return PTR_ERR(mcbb_csr);
+ }
+
+ reg = readl(csw_csr + CSW_CSWCR);
+ if (reg & CSW_CSWCR_DUALMCB_MASK) {
+ /* Dual MCB active */
+ xgene_pmu->mcb_active_mask = 0x3;
+ /* Probe all active MC(s) */
+ reg = readl(mcbb_csr + CSW_CSWCR);
+ xgene_pmu->mc_active_mask =
+ (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0xF : 0x5;
+ } else {
+ /* Single MCB active */
+ xgene_pmu->mcb_active_mask = 0x1;
+ /* Probe all active MC(s) */
+ reg = readl(mcba_csr + CSW_CSWCR);
+ xgene_pmu->mc_active_mask =
+ (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0x3 : 0x1;
+ }
+
+ return 0;
+}
+
+static int fdt_pmu_probe_active_mcb_mcu(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ struct regmap *csw_map, *mcba_map, *mcbb_map;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int reg;
+
+ csw_map = syscon_regmap_lookup_by_phandle(np, "regmap-csw");
+ if (IS_ERR(csw_map)) {
+ dev_err(&pdev->dev, "unable to get syscon regmap csw\n");
+ return PTR_ERR(csw_map);
+ }
+
+ mcba_map = syscon_regmap_lookup_by_phandle(np, "regmap-mcba");
+ if (IS_ERR(mcba_map)) {
+ dev_err(&pdev->dev, "unable to get syscon regmap mcba\n");
+ return PTR_ERR(mcba_map);
+ }
+
+ mcbb_map = syscon_regmap_lookup_by_phandle(np, "regmap-mcbb");
+ if (IS_ERR(mcbb_map)) {
+ dev_err(&pdev->dev, "unable to get syscon regmap mcbb\n");
+ return PTR_ERR(mcbb_map);
+ }
+
+ if (regmap_read(csw_map, CSW_CSWCR, &reg))
+ return -EINVAL;
+
+ if (reg & CSW_CSWCR_DUALMCB_MASK) {
+ /* Dual MCB active */
+ xgene_pmu->mcb_active_mask = 0x3;
+ /* Probe all active MC(s) */
+ if (regmap_read(mcbb_map, MCBADDRMR, &reg))
+ return 0;
+ xgene_pmu->mc_active_mask =
+ (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0xF : 0x5;
+ } else {
+ /* Single MCB active */
+ xgene_pmu->mcb_active_mask = 0x1;
+ /* Probe all active MC(s) */
+ if (regmap_read(mcba_map, MCBADDRMR, &reg))
+ return 0;
+ xgene_pmu->mc_active_mask =
+ (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0x3 : 0x1;
+ }
+
+ return 0;
+}
+
+static int xgene_pmu_probe_active_mcb_mcu(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ if (has_acpi_companion(&pdev->dev))
+ return acpi_pmu_probe_active_mcb_mcu(xgene_pmu, pdev);
+ return fdt_pmu_probe_active_mcb_mcu(xgene_pmu, pdev);
+}
+
+static char *xgene_pmu_dev_name(struct device *dev, u32 type, int id)
+{
+ switch (type) {
+ case PMU_TYPE_L3C:
+ return devm_kasprintf(dev, GFP_KERNEL, "l3c%d", id);
+ case PMU_TYPE_IOB:
+ return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id);
+ case PMU_TYPE_MCB:
+ return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id);
+ case PMU_TYPE_MC:
+ return devm_kasprintf(dev, GFP_KERNEL, "mc%d", id);
+ default:
+ return devm_kasprintf(dev, GFP_KERNEL, "unknown");
+ }
+}
+
+#if defined(CONFIG_ACPI)
+static int acpi_pmu_dev_add_resource(struct acpi_resource *ares, void *data)
+{
+ struct resource *res = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32)
+ acpi_dev_resource_memory(ares, res);
+
+ /* Always tell the ACPI core to skip this resource */
+ return 1;
+}
+
+static struct
+xgene_pmu_dev_ctx *acpi_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu,
+ struct acpi_device *adev, u32 type)
+{
+ struct device *dev = xgene_pmu->dev;
+ struct list_head resource_list;
+ struct xgene_pmu_dev_ctx *ctx;
+ const union acpi_object *obj;
+ struct hw_pmu_info *inf;
+ void __iomem *dev_csr;
+ struct resource res;
+ int enable_bit;
+ int rc;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ INIT_LIST_HEAD(&resource_list);
+ rc = acpi_dev_get_resources(adev, &resource_list,
+ acpi_pmu_dev_add_resource, &res);
+ acpi_dev_free_resource_list(&resource_list);
+ if (rc < 0 || IS_ERR(&res)) {
+ dev_err(dev, "PMU type %d: No resource address found\n", type);
+ goto err;
+ }
+
+ dev_csr = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(dev_csr)) {
+ dev_err(dev, "PMU type %d: Fail to map resource\n", type);
+ goto err;
+ }
+
+ /* A PMU device node without enable-bit-index is always enabled */
+ rc = acpi_dev_get_property(adev, "enable-bit-index",
+ ACPI_TYPE_INTEGER, &obj);
+ if (rc < 0)
+ enable_bit = 0;
+ else
+ enable_bit = (int) obj->integer.value;
+
+ ctx->name = xgene_pmu_dev_name(dev, type, enable_bit);
+ if (!ctx->name) {
+ dev_err(dev, "PMU type %d: Fail to get device name\n", type);
+ goto err;
+ }
+ inf = &ctx->inf;
+ inf->type = type;
+ inf->csr = dev_csr;
+ inf->enable_mask = 1 << enable_bit;
+
+ return ctx;
+err:
+ devm_kfree(dev, ctx);
+ return NULL;
+}
+
+static acpi_status acpi_pmu_dev_add(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct xgene_pmu *xgene_pmu = data;
+ struct xgene_pmu_dev_ctx *ctx;
+ struct acpi_device *adev;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ if (!strcmp(acpi_device_hid(adev), "APMC0D5D"))
+ ctx = acpi_get_pmu_hw_inf(xgene_pmu, adev, PMU_TYPE_L3C);
+ else if (!strcmp(acpi_device_hid(adev), "APMC0D5E"))
+ ctx = acpi_get_pmu_hw_inf(xgene_pmu, adev, PMU_TYPE_IOB);
+ else if (!strcmp(acpi_device_hid(adev), "APMC0D5F"))
+ ctx = acpi_get_pmu_hw_inf(xgene_pmu, adev, PMU_TYPE_MCB);
+ else if (!strcmp(acpi_device_hid(adev), "APMC0D60"))
+ ctx = acpi_get_pmu_hw_inf(xgene_pmu, adev, PMU_TYPE_MC);
+ else
+ ctx = NULL;
+
+ if (!ctx)
+ return AE_OK;
+
+ if (xgene_pmu_dev_add(xgene_pmu, ctx)) {
+ /* Can't add the PMU device, skip it */
+ devm_kfree(xgene_pmu->dev, ctx);
+ return AE_OK;
+ }
+
+ switch (ctx->inf.type) {
+ case PMU_TYPE_L3C:
+ list_add(&ctx->next, &xgene_pmu->l3cpmus);
+ break;
+ case PMU_TYPE_IOB:
+ list_add(&ctx->next, &xgene_pmu->iobpmus);
+ break;
+ case PMU_TYPE_MCB:
+ list_add(&ctx->next, &xgene_pmu->mcbpmus);
+ break;
+ case PMU_TYPE_MC:
+ list_add(&ctx->next, &xgene_pmu->mcpmus);
+ break;
+ }
+ return AE_OK;
+}
+
+static int acpi_pmu_probe_pmu_dev(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ struct device *dev = xgene_pmu->dev;
+ acpi_handle handle;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle)
+ return -EINVAL;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ acpi_pmu_dev_add, NULL, xgene_pmu, NULL);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to probe PMU devices\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+#else
+static int acpi_pmu_probe_pmu_dev(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+static struct
+xgene_pmu_dev_ctx *fdt_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu,
+ struct device_node *np, u32 type)
+{
+ struct device *dev = xgene_pmu->dev;
+ struct xgene_pmu_dev_ctx *ctx;
+ struct hw_pmu_info *inf;
+ void __iomem *dev_csr;
+ struct resource res;
+ int enable_bit;
+ int rc;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc < 0) {
+ dev_err(dev, "PMU type %d: No resource address found\n", type);
+ goto err;
+ }
+ dev_csr = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(dev_csr)) {
+ dev_err(dev, "PMU type %d: Fail to map resource\n", type);
+ goto err;
+ }
+
+ /* A PMU device node without enable-bit-index is always enabled */
+ if (of_property_read_u32(np, "enable-bit-index", &enable_bit))
+ enable_bit = 0;
+
+ ctx->name = xgene_pmu_dev_name(dev, type, enable_bit);
+ if (!ctx->name) {
+ dev_err(dev, "PMU type %d: Fail to get device name\n", type);
+ goto err;
+ }
+ inf = &ctx->inf;
+ inf->type = type;
+ inf->csr = dev_csr;
+ inf->enable_mask = 1 << enable_bit;
+
+ return ctx;
+err:
+ devm_kfree(dev, ctx);
+ return NULL;
+}
+
+static int fdt_pmu_probe_pmu_dev(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ struct xgene_pmu_dev_ctx *ctx;
+ struct device_node *np;
+
+ for_each_child_of_node(pdev->dev.of_node, np) {
+ if (!of_device_is_available(np))
+ continue;
+
+ if (of_device_is_compatible(np, "apm,xgene-pmu-l3c"))
+ ctx = fdt_get_pmu_hw_inf(xgene_pmu, np, PMU_TYPE_L3C);
+ else if (of_device_is_compatible(np, "apm,xgene-pmu-iob"))
+ ctx = fdt_get_pmu_hw_inf(xgene_pmu, np, PMU_TYPE_IOB);
+ else if (of_device_is_compatible(np, "apm,xgene-pmu-mcb"))
+ ctx = fdt_get_pmu_hw_inf(xgene_pmu, np, PMU_TYPE_MCB);
+ else if (of_device_is_compatible(np, "apm,xgene-pmu-mc"))
+ ctx = fdt_get_pmu_hw_inf(xgene_pmu, np, PMU_TYPE_MC);
+ else
+ ctx = NULL;
+
+ if (!ctx)
+ continue;
+
+ if (xgene_pmu_dev_add(xgene_pmu, ctx)) {
+ /* Can't add the PMU device, skip it */
+ devm_kfree(xgene_pmu->dev, ctx);
+ continue;
+ }
+
+ switch (ctx->inf.type) {
+ case PMU_TYPE_L3C:
+ list_add(&ctx->next, &xgene_pmu->l3cpmus);
+ break;
+ case PMU_TYPE_IOB:
+ list_add(&ctx->next, &xgene_pmu->iobpmus);
+ break;
+ case PMU_TYPE_MCB:
+ list_add(&ctx->next, &xgene_pmu->mcbpmus);
+ break;
+ case PMU_TYPE_MC:
+ list_add(&ctx->next, &xgene_pmu->mcpmus);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int xgene_pmu_probe_pmu_dev(struct xgene_pmu *xgene_pmu,
+ struct platform_device *pdev)
+{
+ if (has_acpi_companion(&pdev->dev))
+ return acpi_pmu_probe_pmu_dev(xgene_pmu, pdev);
+ return fdt_pmu_probe_pmu_dev(xgene_pmu, pdev);
+}
+
+static const struct xgene_pmu_data xgene_pmu_data = {
+ .id = PCP_PMU_V1,
+};
+
+static const struct xgene_pmu_data xgene_pmu_v2_data = {
+ .id = PCP_PMU_V2,
+};
+
+static const struct of_device_id xgene_pmu_of_match[] = {
+ { .compatible = "apm,xgene-pmu", .data = &xgene_pmu_data },
+ { .compatible = "apm,xgene-pmu-v2", .data = &xgene_pmu_v2_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_pmu_of_match);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_pmu_acpi_match[] = {
+ {"APMC0D5B", PCP_PMU_V1},
+ {"APMC0D5C", PCP_PMU_V2},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, xgene_pmu_acpi_match);
+#endif
+
+static int xgene_pmu_probe(struct platform_device *pdev)
+{
+ const struct xgene_pmu_data *dev_data;
+ const struct of_device_id *of_id;
+ struct xgene_pmu *xgene_pmu;
+ struct resource *res;
+ int irq, rc;
+ int version;
+
+ xgene_pmu = devm_kzalloc(&pdev->dev, sizeof(*xgene_pmu), GFP_KERNEL);
+ if (!xgene_pmu)
+ return -ENOMEM;
+ xgene_pmu->dev = &pdev->dev;
+ platform_set_drvdata(pdev, xgene_pmu);
+
+ version = -EINVAL;
+ of_id = of_match_device(xgene_pmu_of_match, &pdev->dev);
+ if (of_id) {
+ dev_data = (const struct xgene_pmu_data *) of_id->data;
+ version = dev_data->id;
+ }
+
+#ifdef CONFIG_ACPI
+ if (ACPI_COMPANION(&pdev->dev)) {
+ const struct acpi_device_id *acpi_id;
+
+ acpi_id = acpi_match_device(xgene_pmu_acpi_match, &pdev->dev);
+ if (acpi_id)
+ version = (int) acpi_id->driver_data;
+ }
+#endif
+ if (version < 0)
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&xgene_pmu->l3cpmus);
+ INIT_LIST_HEAD(&xgene_pmu->iobpmus);
+ INIT_LIST_HEAD(&xgene_pmu->mcbpmus);
+ INIT_LIST_HEAD(&xgene_pmu->mcpmus);
+
+ xgene_pmu->version = version;
+ dev_info(&pdev->dev, "X-Gene PMU version %d\n", xgene_pmu->version);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xgene_pmu->pcppmu_csr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xgene_pmu->pcppmu_csr)) {
+ dev_err(&pdev->dev, "ioremap failed for PCP PMU resource\n");
+ rc = PTR_ERR(xgene_pmu->pcppmu_csr);
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ rc = -EINVAL;
+ goto err;
+ }
+ rc = devm_request_irq(&pdev->dev, irq, xgene_pmu_isr,
+ IRQF_NOBALANCING | IRQF_NO_THREAD,
+ dev_name(&pdev->dev), xgene_pmu);
+ if (rc) {
+ dev_err(&pdev->dev, "Could not request IRQ %d\n", irq);
+ goto err;
+ }
+
+ raw_spin_lock_init(&xgene_pmu->lock);
+
+ /* Check for active MCBs and MCUs */
+ rc = xgene_pmu_probe_active_mcb_mcu(xgene_pmu, pdev);
+ if (rc) {
+ dev_warn(&pdev->dev, "Unknown MCB/MCU active status\n");
+ xgene_pmu->mcb_active_mask = 0x1;
+ xgene_pmu->mc_active_mask = 0x1;
+ }
+
+ /* Pick one core to use for cpumask attributes */
+ cpumask_set_cpu(smp_processor_id(), &xgene_pmu->cpu);
+
+ /* Make sure that the overflow interrupt is handled by this CPU */
+ rc = irq_set_affinity(irq, &xgene_pmu->cpu);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed to set interrupt affinity!\n");
+ goto err;
+ }
+
+ /* Walk through the tree for all PMU perf devices */
+ rc = xgene_pmu_probe_pmu_dev(xgene_pmu, pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "No PMU perf devices found!\n");
+ goto err;
+ }
+
+ /* Enable interrupt */
+ xgene_pmu_unmask_int(xgene_pmu);
+
+ return 0;
+
+err:
+ if (xgene_pmu->pcppmu_csr)
+ devm_iounmap(&pdev->dev, xgene_pmu->pcppmu_csr);
+ devm_kfree(&pdev->dev, xgene_pmu);
+
+ return rc;
+}
+
+static void
+xgene_pmu_dev_cleanup(struct xgene_pmu *xgene_pmu, struct list_head *pmus)
+{
+ struct xgene_pmu_dev_ctx *ctx;
+ struct device *dev = xgene_pmu->dev;
+ struct xgene_pmu_dev *pmu_dev;
+
+ list_for_each_entry(ctx, pmus, next) {
+ pmu_dev = ctx->pmu_dev;
+ if (pmu_dev->inf->csr)
+ devm_iounmap(dev, pmu_dev->inf->csr);
+ devm_kfree(dev, ctx);
+ devm_kfree(dev, pmu_dev);
+ }
+}
+
+static int xgene_pmu_remove(struct platform_device *pdev)
+{
+ struct xgene_pmu *xgene_pmu = dev_get_drvdata(&pdev->dev);
+
+ xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->l3cpmus);
+ xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->iobpmus);
+ xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->mcbpmus);
+ xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->mcpmus);
+
+ if (xgene_pmu->pcppmu_csr)
+ devm_iounmap(&pdev->dev, xgene_pmu->pcppmu_csr);
+ devm_kfree(&pdev->dev, xgene_pmu);
+
+ return 0;
+}
+
+static struct platform_driver xgene_pmu_driver = {
+ .probe = xgene_pmu_probe,
+ .remove = xgene_pmu_remove,
+ .driver = {
+ .name = "xgene-pmu",
+ .of_match_table = xgene_pmu_of_match,
+ .acpi_match_table = ACPI_PTR(xgene_pmu_acpi_match),
+ },
+};
+
+builtin_platform_driver(xgene_pmu_driver);
diff --git a/drivers/pinctrl/mvebu/pinctrl-orion.c b/drivers/pinctrl/mvebu/pinctrl-orion.c
index 345c3df669a0..84e144167b44 100644
--- a/drivers/pinctrl/mvebu/pinctrl-orion.c
+++ b/drivers/pinctrl/mvebu/pinctrl-orion.c
@@ -64,11 +64,11 @@ static int orion_mpp_ctrl_set(unsigned pid, unsigned long config)
return 0;
}
-#define V(f5181l, f5182, f5281) \
- ((f5181l << 0) | (f5182 << 1) | (f5281 << 2))
+#define V(f5181, f5182, f5281) \
+ ((f5181 << 0) | (f5182 << 1) | (f5281 << 2))
enum orion_variant {
- V_5181L = V(1, 0, 0),
+ V_5181 = V(1, 0, 0),
V_5182 = V(0, 1, 0),
V_5281 = V(0, 0, 1),
V_ALL = V(1, 1, 1),
@@ -103,13 +103,13 @@ static struct mvebu_mpp_mode orion_mpp_modes[] = {
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL),
MPP_VAR_FUNCTION(0x2, "pci", "req5", V_ALL),
MPP_VAR_FUNCTION(0x4, "nand", "re0", V_5182 | V_5281),
- MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181L),
+ MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181),
MPP_VAR_FUNCTION(0x5, "sata0", "act", V_5182)),
MPP_MODE(7,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL),
MPP_VAR_FUNCTION(0x2, "pci", "gnt5", V_ALL),
MPP_VAR_FUNCTION(0x4, "nand", "we0", V_5182 | V_5281),
- MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181L),
+ MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181),
MPP_VAR_FUNCTION(0x5, "sata1", "act", V_5182)),
MPP_MODE(8,
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL),
@@ -165,7 +165,7 @@ static struct mvebu_mpp_ctrl orion_mpp_controls[] = {
MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl),
};
-static struct pinctrl_gpio_range mv88f5181l_gpio_ranges[] = {
+static struct pinctrl_gpio_range mv88f5181_gpio_ranges[] = {
MPP_GPIO_RANGE(0, 0, 0, 16),
};
@@ -177,14 +177,14 @@ static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = {
MPP_GPIO_RANGE(0, 0, 0, 16),
};
-static struct mvebu_pinctrl_soc_info mv88f5181l_info = {
- .variant = V_5181L,
+static struct mvebu_pinctrl_soc_info mv88f5181_info = {
+ .variant = V_5181,
.controls = orion_mpp_controls,
.ncontrols = ARRAY_SIZE(orion_mpp_controls),
.modes = orion_mpp_modes,
.nmodes = ARRAY_SIZE(orion_mpp_modes),
- .gpioranges = mv88f5181l_gpio_ranges,
- .ngpioranges = ARRAY_SIZE(mv88f5181l_gpio_ranges),
+ .gpioranges = mv88f5181_gpio_ranges,
+ .ngpioranges = ARRAY_SIZE(mv88f5181_gpio_ranges),
};
static struct mvebu_pinctrl_soc_info mv88f5182_info = {
@@ -212,7 +212,8 @@ static struct mvebu_pinctrl_soc_info mv88f5281_info = {
* muxing, they are identical.
*/
static const struct of_device_id orion_pinctrl_of_match[] = {
- { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181l_info },
+ { .compatible = "marvell,88f5181-pinctrl", .data = &mv88f5181_info },
+ { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181_info },
{ .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info },
{ .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info },
{ }
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index 6c084b266651..04053fe1e980 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -19,6 +19,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
#define EC_COMMAND_RETRIES 50
@@ -234,11 +235,44 @@ static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
return ret;
}
+static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
+ u16 cmd, u32 *mask)
+{
+ struct ec_params_get_cmd_versions *pver;
+ struct ec_response_get_cmd_versions *rver;
+ struct cros_ec_command *msg;
+ int ret;
+
+ msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
+ GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->version = 0;
+ msg->command = EC_CMD_GET_CMD_VERSIONS;
+ msg->insize = sizeof(*rver);
+ msg->outsize = sizeof(*pver);
+
+ pver = (struct ec_params_get_cmd_versions *)msg->data;
+ pver->cmd = cmd;
+
+ ret = cros_ec_cmd_xfer(ec_dev, msg);
+ if (ret > 0) {
+ rver = (struct ec_response_get_cmd_versions *)msg->data;
+ *mask = rver->version_mask;
+ }
+
+ kfree(msg);
+
+ return ret;
+}
+
int cros_ec_query_all(struct cros_ec_device *ec_dev)
{
struct device *dev = ec_dev->dev;
struct cros_ec_command *proto_msg;
struct ec_response_get_protocol_info *proto_info;
+ u32 ver_mask = 0;
int ret;
proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
@@ -328,6 +362,15 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
goto exit;
}
+ /* Probe if MKBP event is supported */
+ ret = cros_ec_get_host_command_version_mask(ec_dev,
+ EC_CMD_GET_NEXT_EVENT,
+ &ver_mask);
+ if (ret < 0 || ver_mask == 0)
+ ec_dev->mkbp_event_supported = 0;
+ else
+ ec_dev->mkbp_event_supported = 1;
+
exit:
kfree(proto_msg);
return ret;
@@ -397,3 +440,52 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
return ret;
}
EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
+
+static int get_next_event(struct cros_ec_device *ec_dev)
+{
+ u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
+ struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
+ int ret;
+
+ msg->version = 0;
+ msg->command = EC_CMD_GET_NEXT_EVENT;
+ msg->insize = sizeof(ec_dev->event_data);
+ msg->outsize = 0;
+
+ ret = cros_ec_cmd_xfer(ec_dev, msg);
+ if (ret > 0) {
+ ec_dev->event_size = ret - 1;
+ memcpy(&ec_dev->event_data, msg->data,
+ sizeof(ec_dev->event_data));
+ }
+
+ return ret;
+}
+
+static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
+{
+ u8 buffer[sizeof(struct cros_ec_command) +
+ sizeof(ec_dev->event_data.data)];
+ struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
+
+ msg->version = 0;
+ msg->command = EC_CMD_MKBP_STATE;
+ msg->insize = sizeof(ec_dev->event_data.data);
+ msg->outsize = 0;
+
+ ec_dev->event_size = cros_ec_cmd_xfer(ec_dev, msg);
+ ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;
+ memcpy(&ec_dev->event_data.data, msg->data,
+ sizeof(ec_dev->event_data.data));
+
+ return ec_dev->event_size;
+}
+
+int cros_ec_get_next_event(struct cros_ec_device *ec_dev)
+{
+ if (ec_dev->mkbp_event_supported)
+ return get_next_event(ec_dev);
+ else
+ return get_keyboard_state_event(ec_dev);
+}
+EXPORT_SYMBOL(cros_ec_get_next_event);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 1dba3598cfcb..c890a49587e4 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -4116,7 +4116,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
if (ret > 0) {
struct inode *inode = file_inode(file);
- inode->i_atime = current_fs_time(inode->i_sb);
+ inode->i_atime = current_time(inode);
}
return ret;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index acd4a1524a1e..63454b5cac27 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -1,517 +1,3 @@
-menuconfig POWER_SUPPLY
- bool "Power supply class support"
- help
- Say Y here to enable power supply class support. This allows
- power supply (batteries, AC, USB) monitoring by userspace
- via sysfs and uevent (if available) and/or APM kernel interface
- (if selected below).
-
-if POWER_SUPPLY
-
-config POWER_SUPPLY_DEBUG
- bool "Power supply debug"
- help
- Say Y here to enable debugging messages for power supply class
- and drivers.
-
-config PDA_POWER
- tristate "Generic PDA/phone power driver"
- depends on !S390
- help
- Say Y here to enable generic power driver for PDAs and phones with
- one or two external power supplies (AC/USB) connected to main and
- backup batteries, and optional builtin charger.
-
-config APM_POWER
- tristate "APM emulation for class batteries"
- depends on APM_EMULATION
- help
- Say Y here to enable support APM status emulation using
- battery class devices.
-
-config GENERIC_ADC_BATTERY
- tristate "Generic battery support using IIO"
- depends on IIO
- help
- Say Y here to enable support for the generic battery driver
- which uses IIO framework to read adc.
-
-config MAX8925_POWER
- tristate "MAX8925 battery charger support"
- depends on MFD_MAX8925
- help
- Say Y here to enable support for the battery charger in the Maxim
- MAX8925 PMIC.
-
-config WM831X_BACKUP
- tristate "WM831X backup battery charger support"
- depends on MFD_WM831X
- help
- Say Y here to enable support for the backup battery charger
- in the Wolfson Microelectronics WM831x PMICs.
-
-config WM831X_POWER
- tristate "WM831X PMU support"
- depends on MFD_WM831X
- help
- Say Y here to enable support for the power management unit
- provided by Wolfson Microelectronics WM831x PMICs.
-
-config WM8350_POWER
- tristate "WM8350 PMU support"
- depends on MFD_WM8350
- help
- Say Y here to enable support for the power management unit
- provided by the Wolfson Microelectronics WM8350 PMIC.
-
-config TEST_POWER
- tristate "Test power driver"
- help
- This driver is used for testing. It's safe to say M here.
-
-config BATTERY_88PM860X
- tristate "Marvell 88PM860x battery driver"
- depends on MFD_88PM860X
- help
- Say Y here to enable battery monitor for Marvell 88PM860x chip.
-
-config BATTERY_ACT8945A
- tristate "Active-semi ACT8945A charger driver"
- depends on MFD_ACT8945A || COMPILE_TEST
- help
- Say Y here to enable support for power supply provided by
- Active-semi ActivePath ACT8945A charger.
-
-config BATTERY_DS2760
- tristate "DS2760 battery driver (HP iPAQ & others)"
- depends on W1 && W1_SLAVE_DS2760
- help
- Say Y here to enable support for batteries with ds2760 chip.
-
-config BATTERY_DS2780
- tristate "DS2780 battery driver"
- depends on HAS_IOMEM
- select W1
- select W1_SLAVE_DS2780
- help
- Say Y here to enable support for batteries with ds2780 chip.
-
-config BATTERY_DS2781
- tristate "DS2781 battery driver"
- depends on HAS_IOMEM
- select W1
- select W1_SLAVE_DS2781
- help
- If you enable this you will have the DS2781 battery driver support.
-
- The battery monitor chip is used in many batteries/devices
- as the one who is responsible for charging/discharging/monitoring
- Li+ batteries.
-
- If you are unsure, say N.
-
-config BATTERY_DS2782
- tristate "DS2782/DS2786 standalone gas-gauge"
- depends on I2C
- help
- Say Y here to enable support for the DS2782/DS2786 standalone battery
- gas-gauge.
-
-config BATTERY_PMU
- tristate "Apple PMU battery"
- depends on PPC32 && ADB_PMU
- help
- Say Y here to expose battery information on Apple machines
- through the generic battery class.
-
-config BATTERY_OLPC
- tristate "One Laptop Per Child battery"
- depends on X86_32 && OLPC
- help
- Say Y to enable support for the battery on the OLPC laptop.
-
-config BATTERY_TOSA
- tristate "Sharp SL-6000 (tosa) battery"
- depends on MACH_TOSA && MFD_TC6393XB && TOUCHSCREEN_WM97XX
- help
- Say Y to enable support for the battery on the Sharp Zaurus
- SL-6000 (tosa) models.
-
-config BATTERY_COLLIE
- tristate "Sharp SL-5500 (collie) battery"
- depends on SA1100_COLLIE && MCP_UCB1200
- help
- Say Y to enable support for the battery on the Sharp Zaurus
- SL-5500 (collie) models.
-
-config BATTERY_IPAQ_MICRO
- tristate "iPAQ Atmel Micro ASIC battery driver"
- depends on MFD_IPAQ_MICRO
- help
- Choose this option if you want to monitor battery status on
- Compaq/HP iPAQ h3100 and h3600.
-
-config BATTERY_WM97XX
- bool "WM97xx generic battery driver"
- depends on TOUCHSCREEN_WM97XX=y
- help
- Say Y to enable support for battery measured by WM97xx aux port.
-
-config BATTERY_SBS
- tristate "SBS Compliant gas gauge"
- depends on I2C
- help
- Say Y to include support for SBS battery driver for SBS-compliant
- gas gauges.
-
-config BATTERY_BQ27XXX
- tristate "BQ27xxx battery driver"
- help
- Say Y here to enable support for batteries with BQ27xxx chips.
-
-config BATTERY_BQ27XXX_I2C
- tristate "BQ27xxx I2C support"
- depends on BATTERY_BQ27XXX
- depends on I2C
- default y
- help
- Say Y here to enable support for batteries with BQ27xxx chips
- connected over an I2C bus.
-
-config BATTERY_DA9030
- tristate "DA9030 battery driver"
- depends on PMIC_DA903X
- help
- Say Y here to enable support for batteries charger integrated into
- DA9030 PMIC.
-
-config BATTERY_DA9052
- tristate "Dialog DA9052 Battery"
- depends on PMIC_DA9052
- help
- Say Y here to enable support for batteries charger integrated into
- DA9052 PMIC.
-
-config CHARGER_DA9150
- tristate "Dialog Semiconductor DA9150 Charger support"
- depends on MFD_DA9150
- depends on DA9150_GPADC
- depends on IIO
- help
- Say Y here to enable support for charger unit of the DA9150
- Integrated Charger & Fuel-Gauge IC.
-
- This driver can also be built as a module. If so, the module will be
- called da9150-charger.
-
-config BATTERY_DA9150
- tristate "Dialog Semiconductor DA9150 Fuel Gauge support"
- depends on MFD_DA9150
- help
- Say Y here to enable support for the Fuel-Gauge unit of the DA9150
- Integrated Charger & Fuel-Gauge IC
-
- This driver can also be built as a module. If so, the module will be
- called da9150-fg.
-
-config AXP288_CHARGER
- tristate "X-Powers AXP288 Charger"
- depends on MFD_AXP20X && EXTCON_AXP288
- help
- Say yes here to have support X-Power AXP288 power management IC (PMIC)
- integrated charger.
-
-config AXP288_FUEL_GAUGE
- tristate "X-Powers AXP288 Fuel Gauge"
- depends on MFD_AXP20X && IIO
- help
- Say yes here to have support for X-Power power management IC (PMIC)
- Fuel Gauge. The device provides battery statistics and status
- monitoring as well as alerts for battery over/under voltage and
- over/under temperature.
-
-config BATTERY_MAX17040
- tristate "Maxim MAX17040 Fuel Gauge"
- depends on I2C
- help
- MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
- in handheld and portable equipment. The MAX17040 is configured
- to operate with a single lithium cell
-
-config BATTERY_MAX17042
- tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
- depends on I2C
- select REGMAP_I2C
- help
- MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
- in handheld and portable equipment. The MAX17042 is configured
- to operate with a single lithium cell. MAX8997 and MAX8966 are
- multi-function devices that include fuel gauages that are compatible
- with MAX17042. This driver also supports max17047/50 chips which are
- improved version of max17042.
-
-config BATTERY_Z2
- tristate "Z2 battery driver"
- depends on I2C && MACH_ZIPIT2
- help
- Say Y to include support for the battery on the Zipit Z2.
-
-config BATTERY_S3C_ADC
- tristate "Battery driver for Samsung ADC based monitoring"
- depends on S3C_ADC
- help
- Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
-
-config BATTERY_TWL4030_MADC
- tristate "TWL4030 MADC battery driver"
- depends on TWL4030_MADC
- help
- Say Y here to enable this dumb driver for batteries managed
- through the TWL4030 MADC.
-
-config CHARGER_88PM860X
- tristate "Marvell 88PM860x Charger driver"
- depends on MFD_88PM860X && BATTERY_88PM860X
- help
- Say Y here to enable charger for Marvell 88PM860x chip.
-
-config CHARGER_PCF50633
- tristate "NXP PCF50633 MBC"
- depends on MFD_PCF50633
- help
- Say Y to include support for NXP PCF50633 Main Battery Charger.
-
-config BATTERY_JZ4740
- tristate "Ingenic JZ4740 battery"
- depends on MACH_JZ4740
- depends on MFD_JZ4740_ADC
- help
- Say Y to enable support for the battery on Ingenic JZ4740 based
- boards.
-
- This driver can be build as a module. If so, the module will be
- called jz4740-battery.
-
-config BATTERY_INTEL_MID
- tristate "Battery driver for Intel MID platforms"
- depends on INTEL_SCU_IPC && SPI
- help
- Say Y here to enable the battery driver on Intel MID
- platforms.
-
-config BATTERY_RX51
- tristate "Nokia RX-51 (N900) battery driver"
- depends on TWL4030_MADC
- help
- Say Y here to enable support for battery information on Nokia
- RX-51, also known as N900 tablet.
-
-config CHARGER_ISP1704
- tristate "ISP1704 USB Charger Detection"
- depends on USB_PHY
- depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
- help
- Say Y to enable support for USB Charger Detection with
- ISP1707/ISP1704 USB transceivers.
-
-config CHARGER_MAX8903
- tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
- help
- Say Y to enable support for the MAX8903 DC-DC charger and sysfs.
- The driver supports controlling charger-enable and current-limit
- pins based on the status of charger connections with interrupt
- handlers.
-
-config CHARGER_TWL4030
- tristate "OMAP TWL4030 BCI charger driver"
- depends on IIO && TWL4030_CORE
- help
- Say Y here to enable support for TWL4030 Battery Charge Interface.
-
-config CHARGER_LP8727
- tristate "TI/National Semiconductor LP8727 charger driver"
- depends on I2C
- help
- Say Y here to enable support for LP8727 Charger Driver.
-
-config CHARGER_LP8788
- tristate "TI LP8788 charger driver"
- depends on MFD_LP8788
- depends on LP8788_ADC
- depends on IIO
- help
- Say Y to enable support for the LP8788 linear charger.
-
-config CHARGER_GPIO
- tristate "GPIO charger"
- depends on GPIOLIB || COMPILE_TEST
- help
- Say Y to include support for chargers which report their online status
- through a GPIO pin.
-
- This driver can be build as a module. If so, the module will be
- called gpio-charger.
-
-config CHARGER_MANAGER
- bool "Battery charger manager for multiple chargers"
- depends on REGULATOR
- select EXTCON
- help
- Say Y to enable charger-manager support, which allows multiple
- chargers attached to a battery and multiple batteries attached to a
- system. The charger-manager also can monitor charging status in
- runtime and in suspend-to-RAM by waking up the system periodically
- with help of suspend_again support.
-
-config CHARGER_MAX14577
- tristate "Maxim MAX14577/77836 battery charger driver"
- depends on MFD_MAX14577
- help
- Say Y to enable support for the battery charger control sysfs and
- platform data of MAX14577/77836 MUICs.
-
-config CHARGER_MAX77693
- tristate "Maxim MAX77693 battery charger driver"
- depends on MFD_MAX77693
- help
- Say Y to enable support for the Maxim MAX77693 battery charger.
-
-config CHARGER_MAX8997
- tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
- depends on MFD_MAX8997 && REGULATOR_MAX8997
- help
- Say Y to enable support for the battery charger control sysfs and
- platform data of MAX8997/LP3974 PMICs.
-
-config CHARGER_MAX8998
- tristate "Maxim MAX8998/LP3974 PMIC battery charger driver"
- depends on MFD_MAX8998 && REGULATOR_MAX8998
- help
- Say Y to enable support for the battery charger control sysfs and
- platform data of MAX8998/LP3974 PMICs.
-
-config CHARGER_QCOM_SMBB
- tristate "Qualcomm Switch-Mode Battery Charger and Boost"
- depends on MFD_SPMI_PMIC || COMPILE_TEST
- depends on OF
- depends on EXTCON
- help
- Say Y to include support for the Switch-Mode Battery Charger and
- Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger
- is an integrated, single-cell lithium-ion battery charger. DT
- configuration is required for loading, see the devicetree
- documentation for more detail. The base name for this driver is
- 'pm8941_charger'.
-
-config CHARGER_BQ2415X
- tristate "TI BQ2415x battery charger driver"
- depends on I2C
- help
- Say Y to enable support for the TI BQ2415x battery charger
- PMICs.
-
- You'll need this driver to charge batteries on e.g. Nokia
- RX-51/N900.
-
-config CHARGER_BQ24190
- tristate "TI BQ24190 battery charger driver"
- depends on I2C
- depends on GPIOLIB || COMPILE_TEST
- help
- Say Y to enable support for the TI BQ24190 battery charger.
-
-config CHARGER_BQ24257
- tristate "TI BQ24250/24251/24257 battery charger driver"
- depends on I2C
- depends on GPIOLIB || COMPILE_TEST
- depends on REGMAP_I2C
- help
- Say Y to enable support for the TI BQ24250, BQ24251, and BQ24257 battery
- chargers.
-
-config CHARGER_BQ24735
- tristate "TI BQ24735 battery charger support"
- depends on I2C
- depends on GPIOLIB || COMPILE_TEST
- help
- Say Y to enable support for the TI BQ24735 battery charger.
-
-config CHARGER_BQ25890
- tristate "TI BQ25890 battery charger driver"
- depends on I2C
- depends on GPIOLIB || COMPILE_TEST
- select REGMAP_I2C
- help
- Say Y to enable support for the TI BQ25890 battery charger.
-
-config CHARGER_SMB347
- tristate "Summit Microelectronics SMB347 Battery Charger"
- depends on I2C
- select REGMAP_I2C
- help
- Say Y to include support for Summit Microelectronics SMB347
- Battery Charger.
-
-config CHARGER_TPS65090
- tristate "TPS65090 battery charger driver"
- depends on MFD_TPS65090
- help
- Say Y here to enable support for battery charging with TPS65090
- PMIC chips.
-
-config CHARGER_TPS65217
- tristate "TPS65217 battery charger driver"
- depends on MFD_TPS65217
- help
- Say Y here to enable support for battery charging with TPS65217
- PMIC chips.
-
-config BATTERY_GAUGE_LTC2941
- tristate "LTC2941/LTC2943 Battery Gauge Driver"
- depends on I2C
- help
- Say Y here to include support for LTC2941 and LTC2943 Battery
- Gauge IC. The driver reports the charge count continuously, and
- measures the voltage and temperature every 10 seconds.
-
-config AB8500_BM
- bool "AB8500 Battery Management Driver"
- depends on AB8500_CORE && AB8500_GPADC
- help
- Say Y to include support for AB8500 battery management.
-
-config BATTERY_GOLDFISH
- tristate "Goldfish battery driver"
- depends on GOLDFISH || COMPILE_TEST
- depends on HAS_IOMEM
- help
- Say Y to enable support for the battery and AC power in the
- Goldfish emulator.
-
-config BATTERY_RT5033
- tristate "RT5033 fuel gauge support"
- depends on MFD_RT5033
- help
- This adds support for battery fuel gauge in Richtek RT5033 PMIC.
- The fuelgauge calculates and determines the battery state of charge
- according to battery open circuit voltage.
-
-config CHARGER_RT9455
- tristate "Richtek RT9455 battery charger driver"
- depends on I2C
- depends on GPIOLIB || COMPILE_TEST
- select REGMAP_I2C
- help
- Say Y to enable support for Richtek RT9455 battery charger.
-
-config AXP20X_POWER
- tristate "AXP20x power supply driver"
- depends on MFD_AXP20X
- help
- This driver provides support for the power supply features of
- AXP20x PMIC.
-
-endif # POWER_SUPPLY
-
-source "drivers/power/reset/Kconfig"
source "drivers/power/avs/Kconfig"
+source "drivers/power/reset/Kconfig"
+source "drivers/power/supply/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index e46b75d448a5..ff35c712d824 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -1,76 +1,3 @@
-subdir-ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
-
-power_supply-y := power_supply_core.o
-power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
-power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
-
-obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
-obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
-
-obj-$(CONFIG_PDA_POWER) += pda_power.o
-obj-$(CONFIG_APM_POWER) += apm_power.o
-obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
-obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
-obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
-obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
-obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
-obj-$(CONFIG_TEST_POWER) += test_power.o
-
-obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
-obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
-obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
-obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
-obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
-obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
-obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o
-obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
-obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
-obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
-obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
-obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
-obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
-obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
-obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
-obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o
-obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
-obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
-obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
-obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o
-obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o
-obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
-obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
-obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
-obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
-obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
-obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
-obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
-obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
-obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
-obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
-obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
-obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
-obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
-obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
-obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
-obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
-obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
-obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
-obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
-obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
-obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
-obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
-obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
-obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
-obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
-obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
-obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
-obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
-obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
-obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
obj-$(CONFIG_POWER_AVS) += avs/
-obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
-obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
-obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
obj-$(CONFIG_POWER_RESET) += reset/
-obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
-obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
+obj-$(CONFIG_POWER_SUPPLY) += supply/
diff --git a/drivers/power/act8945a_charger.c b/drivers/power/act8945a_charger.c
deleted file mode 100644
index b5c00e45741e..000000000000
--- a/drivers/power/act8945a_charger.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Power supply driver for the Active-semi ACT8945A PMIC
- *
- * Copyright (C) 2015 Atmel Corporation
- *
- * Author: Wenyou Yang <wenyou.yang@atmel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/regmap.h>
-
-static const char *act8945a_charger_model = "ACT8945A";
-static const char *act8945a_charger_manufacturer = "Active-semi";
-
-/**
- * ACT8945A Charger Register Map
- */
-
-/* 0x70: Reserved */
-#define ACT8945A_APCH_CFG 0x71
-#define ACT8945A_APCH_STATUS 0x78
-#define ACT8945A_APCH_CTRL 0x79
-#define ACT8945A_APCH_STATE 0x7A
-
-/* ACT8945A_APCH_CFG */
-#define APCH_CFG_OVPSET (0x3 << 0)
-#define APCH_CFG_OVPSET_6V6 (0x0 << 0)
-#define APCH_CFG_OVPSET_7V (0x1 << 0)
-#define APCH_CFG_OVPSET_7V5 (0x2 << 0)
-#define APCH_CFG_OVPSET_8V (0x3 << 0)
-#define APCH_CFG_PRETIMO (0x3 << 2)
-#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2)
-#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2)
-#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2)
-#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2)
-#define APCH_CFG_TOTTIMO (0x3 << 4)
-#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4)
-#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4)
-#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4)
-#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4)
-#define APCH_CFG_SUSCHG (0x1 << 7)
-
-#define APCH_STATUS_CHGDAT BIT(0)
-#define APCH_STATUS_INDAT BIT(1)
-#define APCH_STATUS_TEMPDAT BIT(2)
-#define APCH_STATUS_TIMRDAT BIT(3)
-#define APCH_STATUS_CHGSTAT BIT(4)
-#define APCH_STATUS_INSTAT BIT(5)
-#define APCH_STATUS_TEMPSTAT BIT(6)
-#define APCH_STATUS_TIMRSTAT BIT(7)
-
-#define APCH_CTRL_CHGEOCOUT BIT(0)
-#define APCH_CTRL_INDIS BIT(1)
-#define APCH_CTRL_TEMPOUT BIT(2)
-#define APCH_CTRL_TIMRPRE BIT(3)
-#define APCH_CTRL_CHGEOCIN BIT(4)
-#define APCH_CTRL_INCON BIT(5)
-#define APCH_CTRL_TEMPIN BIT(6)
-#define APCH_CTRL_TIMRTOT BIT(7)
-
-#define APCH_STATE_ACINSTAT (0x1 << 1)
-#define APCH_STATE_CSTATE (0x3 << 4)
-#define APCH_STATE_CSTATE_SHIFT 4
-#define APCH_STATE_CSTATE_DISABLED 0x00
-#define APCH_STATE_CSTATE_EOC 0x01
-#define APCH_STATE_CSTATE_FAST 0x02
-#define APCH_STATE_CSTATE_PRE 0x03
-
-struct act8945a_charger {
- struct regmap *regmap;
- bool battery_temperature;
-};
-
-static int act8945a_get_charger_state(struct regmap *regmap, int *val)
-{
- int ret;
- unsigned int status, state;
-
- ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
- if (ret < 0)
- return ret;
-
- ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
- if (ret < 0)
- return ret;
-
- state &= APCH_STATE_CSTATE;
- state >>= APCH_STATE_CSTATE_SHIFT;
-
- if (state == APCH_STATE_CSTATE_EOC) {
- if (status & APCH_STATUS_CHGDAT)
- *val = POWER_SUPPLY_STATUS_FULL;
- else
- *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else if ((state == APCH_STATE_CSTATE_FAST) ||
- (state == APCH_STATE_CSTATE_PRE)) {
- *val = POWER_SUPPLY_STATUS_CHARGING;
- } else {
- *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
- }
-
- return 0;
-}
-
-static int act8945a_get_charge_type(struct regmap *regmap, int *val)
-{
- int ret;
- unsigned int state;
-
- ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
- if (ret < 0)
- return ret;
-
- state &= APCH_STATE_CSTATE;
- state >>= APCH_STATE_CSTATE_SHIFT;
-
- switch (state) {
- case APCH_STATE_CSTATE_PRE:
- *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
- break;
- case APCH_STATE_CSTATE_FAST:
- *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
- break;
- case APCH_STATE_CSTATE_EOC:
- case APCH_STATE_CSTATE_DISABLED:
- default:
- *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
- }
-
- return 0;
-}
-
-static int act8945a_get_battery_health(struct act8945a_charger *charger,
- struct regmap *regmap, int *val)
-{
- int ret;
- unsigned int status;
-
- ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
- if (ret < 0)
- return ret;
-
- if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT))
- *val = POWER_SUPPLY_HEALTH_OVERHEAT;
- else if (!(status & APCH_STATUS_INDAT))
- *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
- else if (status & APCH_STATUS_TIMRDAT)
- *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
- else
- *val = POWER_SUPPLY_HEALTH_GOOD;
-
- return 0;
-}
-
-static enum power_supply_property act8945a_charger_props[] = {
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_CHARGE_TYPE,
- POWER_SUPPLY_PROP_TECHNOLOGY,
- POWER_SUPPLY_PROP_HEALTH,
- POWER_SUPPLY_PROP_MODEL_NAME,
- POWER_SUPPLY_PROP_MANUFACTURER
-};
-
-static int act8945a_charger_get_property(struct power_supply *psy,
- enum power_supply_property prop,
- union power_supply_propval *val)
-{
- struct act8945a_charger *charger = power_supply_get_drvdata(psy);
- struct regmap *regmap = charger->regmap;
- int ret = 0;
-
- switch (prop) {
- case POWER_SUPPLY_PROP_STATUS:
- ret = act8945a_get_charger_state(regmap, &val->intval);
- break;
- case POWER_SUPPLY_PROP_CHARGE_TYPE:
- ret = act8945a_get_charge_type(regmap, &val->intval);
- break;
- case POWER_SUPPLY_PROP_TECHNOLOGY:
- val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
- break;
- case POWER_SUPPLY_PROP_HEALTH:
- ret = act8945a_get_battery_health(charger,
- regmap, &val->intval);
- break;
- case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = act8945a_charger_model;
- break;
- case POWER_SUPPLY_PROP_MANUFACTURER:
- val->strval = act8945a_charger_manufacturer;
- break;
- default:
- return -EINVAL;
- }
-
- return ret;
-}
-
-static const struct power_supply_desc act8945a_charger_desc = {
- .name = "act8945a-charger",
- .type = POWER_SUPPLY_TYPE_BATTERY,
- .get_property = act8945a_charger_get_property,
- .properties = act8945a_charger_props,
- .num_properties = ARRAY_SIZE(act8945a_charger_props),
-};
-
-#define DEFAULT_TOTAL_TIME_OUT 3
-#define DEFAULT_PRE_TIME_OUT 40
-#define DEFAULT_INPUT_OVP_THRESHOLD 6600
-
-static int act8945a_charger_config(struct device *dev,
- struct act8945a_charger *charger)
-{
- struct device_node *np = dev->of_node;
- enum of_gpio_flags flags;
- struct regmap *regmap = charger->regmap;
-
- u32 total_time_out;
- u32 pre_time_out;
- u32 input_voltage_threshold;
- int chglev_pin;
-
- unsigned int value = 0;
-
- if (!np) {
- dev_err(dev, "no charger of node\n");
- return -EINVAL;
- }
-
- charger->battery_temperature = of_property_read_bool(np,
- "active-semi,check-battery-temperature");
-
- chglev_pin = of_get_named_gpio_flags(np,
- "active-semi,chglev-gpios", 0, &flags);
-
- if (gpio_is_valid(chglev_pin)) {
- gpio_set_value(chglev_pin,
- ((flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1));
- }
-
- if (of_property_read_u32(np,
- "active-semi,input-voltage-threshold-microvolt",
- &input_voltage_threshold))
- input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
-
- if (of_property_read_u32(np,
- "active-semi,precondition-timeout",
- &pre_time_out))
- pre_time_out = DEFAULT_PRE_TIME_OUT;
-
- if (of_property_read_u32(np, "active-semi,total-timeout",
- &total_time_out))
- total_time_out = DEFAULT_TOTAL_TIME_OUT;
-
- switch (input_voltage_threshold) {
- case 8000:
- value |= APCH_CFG_OVPSET_8V;
- break;
- case 7500:
- value |= APCH_CFG_OVPSET_7V5;
- break;
- case 7000:
- value |= APCH_CFG_OVPSET_7V;
- break;
- case 6600:
- default:
- value |= APCH_CFG_OVPSET_6V6;
- break;
- }
-
- switch (pre_time_out) {
- case 60:
- value |= APCH_CFG_PRETIMO_60_MIN;
- break;
- case 80:
- value |= APCH_CFG_PRETIMO_80_MIN;
- break;
- case 0:
- value |= APCH_CFG_PRETIMO_DISABLED;
- break;
- case 40:
- default:
- value |= APCH_CFG_PRETIMO_40_MIN;
- break;
- }
-
- switch (total_time_out) {
- case 4:
- value |= APCH_CFG_TOTTIMO_4_HOUR;
- break;
- case 5:
- value |= APCH_CFG_TOTTIMO_5_HOUR;
- break;
- case 0:
- value |= APCH_CFG_TOTTIMO_DISABLED;
- break;
- case 3:
- default:
- value |= APCH_CFG_TOTTIMO_3_HOUR;
- break;
- }
-
- return regmap_write(regmap, ACT8945A_APCH_CFG, value);
-}
-
-static int act8945a_charger_probe(struct platform_device *pdev)
-{
- struct act8945a_charger *charger;
- struct power_supply *psy;
- struct power_supply_config psy_cfg = {};
- int ret;
-
- charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
- if (!charger)
- return -ENOMEM;
-
- charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!charger->regmap) {
- dev_err(&pdev->dev, "Parent did not provide regmap\n");
- return -EINVAL;
- }
-
- ret = act8945a_charger_config(pdev->dev.parent, charger);
- if (ret)
- return ret;
-
- psy_cfg.of_node = pdev->dev.parent->of_node;
- psy_cfg.drv_data = charger;
-
- psy = devm_power_supply_register(&pdev->dev,
- &act8945a_charger_desc,
- &psy_cfg);
- if (IS_ERR(psy)) {
- dev_err(&pdev->dev, "failed to register power supply\n");
- return PTR_ERR(psy);
- }
-
- return 0;
-}
-
-static struct platform_driver act8945a_charger_driver = {
- .driver = {
- .name = "act8945a-charger",
- },
- .probe = act8945a_charger_probe,
-};
-module_platform_driver(act8945a_charger_driver);
-
-MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
-MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c
index c70f1bffe038..09380857a1c5 100644
--- a/drivers/power/reset/keystone-reset.c
+++ b/drivers/power/reset/keystone-reset.c
@@ -139,7 +139,7 @@ static int rsctrl_probe(struct platform_device *pdev)
}
if (val >= WDT_MUX_NUMBER) {
- dev_err(dev, "ti,wdt-list property can contain"
+ dev_err(dev, "ti,wdt-list property can contain "
"only numbers < 4\n");
return -EINVAL;
}
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 2dfbbce0f817..fb512183ace3 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -135,6 +135,65 @@ int reboot_mode_unregister(struct reboot_mode_driver *reboot)
}
EXPORT_SYMBOL_GPL(reboot_mode_unregister);
+static void devm_reboot_mode_release(struct device *dev, void *res)
+{
+ reboot_mode_unregister(*(struct reboot_mode_driver **)res);
+}
+
+/**
+ * devm_reboot_mode_register() - resource managed reboot_mode_register()
+ * @dev: device to associate this resource with
+ * @reboot: reboot mode driver
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int devm_reboot_mode_register(struct device *dev,
+ struct reboot_mode_driver *reboot)
+{
+ struct reboot_mode_driver **dr;
+ int rc;
+
+ dr = devres_alloc(devm_reboot_mode_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ rc = reboot_mode_register(reboot);
+ if (rc) {
+ devres_free(dr);
+ return rc;
+ }
+
+ *dr = reboot;
+ devres_add(dev, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_reboot_mode_register);
+
+static int devm_reboot_mode_match(struct device *dev, void *res, void *data)
+{
+ struct reboot_mode_driver **p = res;
+
+ if (WARN_ON(!p || !*p))
+ return 0;
+
+ return *p == data;
+}
+
+/**
+ * devm_reboot_mode_unregister() - resource managed reboot_mode_unregister()
+ * @dev: device to associate this resource with
+ * @reboot: reboot mode driver
+ */
+void devm_reboot_mode_unregister(struct device *dev,
+ struct reboot_mode_driver *reboot)
+{
+ WARN_ON(devres_release(dev,
+ devm_reboot_mode_release,
+ devm_reboot_mode_match, reboot));
+}
+EXPORT_SYMBOL_GPL(devm_reboot_mode_unregister);
+
MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
MODULE_DESCRIPTION("System reboot mode core library");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/reboot-mode.h b/drivers/power/reset/reboot-mode.h
index 2491bb71f591..75f7fe5c881f 100644
--- a/drivers/power/reset/reboot-mode.h
+++ b/drivers/power/reset/reboot-mode.h
@@ -10,5 +10,9 @@ struct reboot_mode_driver {
int reboot_mode_register(struct reboot_mode_driver *reboot);
int reboot_mode_unregister(struct reboot_mode_driver *reboot);
+int devm_reboot_mode_register(struct device *dev,
+ struct reboot_mode_driver *reboot);
+void devm_reboot_mode_unregister(struct device *dev,
+ struct reboot_mode_driver *reboot);
#endif
diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c
index a488877a3538..2046b31232f7 100644
--- a/drivers/power/reset/st-poweroff.c
+++ b/drivers/power/reset/st-poweroff.c
@@ -28,28 +28,6 @@ struct reset_syscfg {
unsigned int mask_rst_msk;
};
-/* STiH415 */
-#define STIH415_SYSCFG_11 0x2c
-#define STIH415_SYSCFG_15 0x3c
-
-static struct reset_syscfg stih415_reset = {
- .offset_rst = STIH415_SYSCFG_11,
- .mask_rst = BIT(0),
- .offset_rst_msk = STIH415_SYSCFG_15,
- .mask_rst_msk = BIT(0)
-};
-
-/* STiH416 */
-#define STIH416_SYSCFG_500 0x7d0
-#define STIH416_SYSCFG_504 0x7e0
-
-static struct reset_syscfg stih416_reset = {
- .offset_rst = STIH416_SYSCFG_500,
- .mask_rst = BIT(0),
- .offset_rst_msk = STIH416_SYSCFG_504,
- .mask_rst_msk = BIT(0)
-};
-
/* STiH407 */
#define STIH407_SYSCFG_4000 0x0
#define STIH407_SYSCFG_4008 0x20
@@ -61,16 +39,6 @@ static struct reset_syscfg stih407_reset = {
.mask_rst_msk = BIT(0)
};
-/* STiD127 */
-#define STID127_SYSCFG_700 0x0
-#define STID127_SYSCFG_773 0x124
-
-static struct reset_syscfg stid127_reset = {
- .offset_rst = STID127_SYSCFG_773,
- .mask_rst = BIT(0),
- .offset_rst_msk = STID127_SYSCFG_700,
- .mask_rst_msk = BIT(8)
-};
static struct reset_syscfg *st_restart_syscfg;
@@ -99,17 +67,8 @@ static struct notifier_block st_restart_nb = {
static const struct of_device_id st_reset_of_match[] = {
{
- .compatible = "st,stih415-restart",
- .data = (void *)&stih415_reset,
- }, {
- .compatible = "st,stih416-restart",
- .data = (void *)&stih416_reset,
- }, {
.compatible = "st,stih407-restart",
.data = (void *)&stih407_reset,
- }, {
- .compatible = "st,stid127-restart",
- .data = (void *)&stid127_reset,
},
{}
};
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c
index 9e1cba5dd58e..1ecb51d67149 100644
--- a/drivers/power/reset/syscon-reboot-mode.c
+++ b/drivers/power/reset/syscon-reboot-mode.c
@@ -53,8 +53,6 @@ static int syscon_reboot_mode_probe(struct platform_device *pdev)
syscon_rbm->reboot.write = syscon_reboot_mode_write;
syscon_rbm->mask = 0xffffffff;
- dev_set_drvdata(&pdev->dev, syscon_rbm);
-
syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
if (IS_ERR(syscon_rbm->map))
return PTR_ERR(syscon_rbm->map);
@@ -65,20 +63,13 @@ static int syscon_reboot_mode_probe(struct platform_device *pdev)
of_property_read_u32(pdev->dev.of_node, "mask", &syscon_rbm->mask);
- ret = reboot_mode_register(&syscon_rbm->reboot);
+ ret = devm_reboot_mode_register(&pdev->dev, &syscon_rbm->reboot);
if (ret)
dev_err(&pdev->dev, "can't register reboot mode\n");
return ret;
}
-static int syscon_reboot_mode_remove(struct platform_device *pdev)
-{
- struct syscon_reboot_mode *syscon_rbm = dev_get_drvdata(&pdev->dev);
-
- return reboot_mode_unregister(&syscon_rbm->reboot);
-}
-
static const struct of_device_id syscon_reboot_mode_of_match[] = {
{ .compatible = "syscon-reboot-mode" },
{}
@@ -86,7 +77,6 @@ static const struct of_device_id syscon_reboot_mode_of_match[] = {
static struct platform_driver syscon_reboot_mode_driver = {
.probe = syscon_reboot_mode_probe,
- .remove = syscon_reboot_mode_remove,
.driver = {
.name = "syscon-reboot-mode",
.of_match_table = syscon_reboot_mode_of_match,
diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c
index f07e93c97ba3..73c3d93e5318 100644
--- a/drivers/power/reset/xgene-reboot.c
+++ b/drivers/power/reset/xgene-reboot.c
@@ -81,8 +81,10 @@ static int xgene_reboot_probe(struct platform_device *pdev)
ctx->restart_handler.notifier_call = xgene_restart_handler;
ctx->restart_handler.priority = 128;
err = register_restart_handler(&ctx->restart_handler);
- if (err)
+ if (err) {
+ iounmap(ctx->csr);
dev_err(dev, "cannot register restart handler (err=%d)\n", err);
+ }
return err;
}
diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c
index a5b009673d0e..b0b1eb3a78c2 100644
--- a/drivers/power/reset/zx-reboot.c
+++ b/drivers/power/reset/zx-reboot.c
@@ -58,9 +58,12 @@ static int zx_reboot_probe(struct platform_device *pdev)
}
err = register_restart_handler(&zx_restart_nb);
- if (err)
+ if (err) {
+ iounmap(base);
+ iounmap(pcu_base);
dev_err(&pdev->dev, "Register restart handler failed(err=%d)\n",
err);
+ }
return err;
}
diff --git a/drivers/power/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c
index 63c57dc82ac1..63c57dc82ac1 100644
--- a/drivers/power/88pm860x_battery.c
+++ b/drivers/power/supply/88pm860x_battery.c
diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/supply/88pm860x_charger.c
index 2b82e44d9027..2b82e44d9027 100644
--- a/drivers/power/88pm860x_charger.c
+++ b/drivers/power/supply/88pm860x_charger.c
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
new file mode 100644
index 000000000000..76806a0be820
--- /dev/null
+++ b/drivers/power/supply/Kconfig
@@ -0,0 +1,514 @@
+menuconfig POWER_SUPPLY
+ bool "Power supply class support"
+ help
+ Say Y here to enable power supply class support. This allows
+ power supply (batteries, AC, USB) monitoring by userspace
+ via sysfs and uevent (if available) and/or APM kernel interface
+ (if selected below).
+
+if POWER_SUPPLY
+
+config POWER_SUPPLY_DEBUG
+ bool "Power supply debug"
+ help
+ Say Y here to enable debugging messages for power supply class
+ and drivers.
+
+config PDA_POWER
+ tristate "Generic PDA/phone power driver"
+ depends on !S390
+ help
+ Say Y here to enable generic power driver for PDAs and phones with
+ one or two external power supplies (AC/USB) connected to main and
+ backup batteries, and optional builtin charger.
+
+config APM_POWER
+ tristate "APM emulation for class batteries"
+ depends on APM_EMULATION
+ help
+ Say Y here to enable support APM status emulation using
+ battery class devices.
+
+config GENERIC_ADC_BATTERY
+ tristate "Generic battery support using IIO"
+ depends on IIO
+ help
+ Say Y here to enable support for the generic battery driver
+ which uses IIO framework to read adc.
+
+config MAX8925_POWER
+ tristate "MAX8925 battery charger support"
+ depends on MFD_MAX8925
+ help
+ Say Y here to enable support for the battery charger in the Maxim
+ MAX8925 PMIC.
+
+config WM831X_BACKUP
+ tristate "WM831X backup battery charger support"
+ depends on MFD_WM831X
+ help
+ Say Y here to enable support for the backup battery charger
+ in the Wolfson Microelectronics WM831x PMICs.
+
+config WM831X_POWER
+ tristate "WM831X PMU support"
+ depends on MFD_WM831X
+ help
+ Say Y here to enable support for the power management unit
+ provided by Wolfson Microelectronics WM831x PMICs.
+
+config WM8350_POWER
+ tristate "WM8350 PMU support"
+ depends on MFD_WM8350
+ help
+ Say Y here to enable support for the power management unit
+ provided by the Wolfson Microelectronics WM8350 PMIC.
+
+config TEST_POWER
+ tristate "Test power driver"
+ help
+ This driver is used for testing. It's safe to say M here.
+
+config BATTERY_88PM860X
+ tristate "Marvell 88PM860x battery driver"
+ depends on MFD_88PM860X
+ help
+ Say Y here to enable battery monitor for Marvell 88PM860x chip.
+
+config BATTERY_ACT8945A
+ tristate "Active-semi ACT8945A charger driver"
+ depends on MFD_ACT8945A || COMPILE_TEST
+ help
+ Say Y here to enable support for power supply provided by
+ Active-semi ActivePath ACT8945A charger.
+
+config BATTERY_DS2760
+ tristate "DS2760 battery driver (HP iPAQ & others)"
+ depends on W1 && W1_SLAVE_DS2760
+ help
+ Say Y here to enable support for batteries with ds2760 chip.
+
+config BATTERY_DS2780
+ tristate "DS2780 battery driver"
+ depends on HAS_IOMEM
+ select W1
+ select W1_SLAVE_DS2780
+ help
+ Say Y here to enable support for batteries with ds2780 chip.
+
+config BATTERY_DS2781
+ tristate "DS2781 battery driver"
+ depends on HAS_IOMEM
+ select W1
+ select W1_SLAVE_DS2781
+ help
+ If you enable this you will have the DS2781 battery driver support.
+
+ The battery monitor chip is used in many batteries/devices
+ as the one who is responsible for charging/discharging/monitoring
+ Li+ batteries.
+
+ If you are unsure, say N.
+
+config BATTERY_DS2782
+ tristate "DS2782/DS2786 standalone gas-gauge"
+ depends on I2C
+ help
+ Say Y here to enable support for the DS2782/DS2786 standalone battery
+ gas-gauge.
+
+config BATTERY_PMU
+ tristate "Apple PMU battery"
+ depends on PPC32 && ADB_PMU
+ help
+ Say Y here to expose battery information on Apple machines
+ through the generic battery class.
+
+config BATTERY_OLPC
+ tristate "One Laptop Per Child battery"
+ depends on X86_32 && OLPC
+ help
+ Say Y to enable support for the battery on the OLPC laptop.
+
+config BATTERY_TOSA
+ tristate "Sharp SL-6000 (tosa) battery"
+ depends on MACH_TOSA && MFD_TC6393XB && TOUCHSCREEN_WM97XX
+ help
+ Say Y to enable support for the battery on the Sharp Zaurus
+ SL-6000 (tosa) models.
+
+config BATTERY_COLLIE
+ tristate "Sharp SL-5500 (collie) battery"
+ depends on SA1100_COLLIE && MCP_UCB1200
+ help
+ Say Y to enable support for the battery on the Sharp Zaurus
+ SL-5500 (collie) models.
+
+config BATTERY_IPAQ_MICRO
+ tristate "iPAQ Atmel Micro ASIC battery driver"
+ depends on MFD_IPAQ_MICRO
+ help
+ Choose this option if you want to monitor battery status on
+ Compaq/HP iPAQ h3100 and h3600.
+
+config BATTERY_WM97XX
+ bool "WM97xx generic battery driver"
+ depends on TOUCHSCREEN_WM97XX=y
+ help
+ Say Y to enable support for battery measured by WM97xx aux port.
+
+config BATTERY_SBS
+ tristate "SBS Compliant gas gauge"
+ depends on I2C
+ help
+ Say Y to include support for SBS battery driver for SBS-compliant
+ gas gauges.
+
+config BATTERY_BQ27XXX
+ tristate "BQ27xxx battery driver"
+ help
+ Say Y here to enable support for batteries with BQ27xxx chips.
+
+config BATTERY_BQ27XXX_I2C
+ tristate "BQ27xxx I2C support"
+ depends on BATTERY_BQ27XXX
+ depends on I2C
+ default y
+ help
+ Say Y here to enable support for batteries with BQ27xxx chips
+ connected over an I2C bus.
+
+config BATTERY_DA9030
+ tristate "DA9030 battery driver"
+ depends on PMIC_DA903X
+ help
+ Say Y here to enable support for batteries charger integrated into
+ DA9030 PMIC.
+
+config BATTERY_DA9052
+ tristate "Dialog DA9052 Battery"
+ depends on PMIC_DA9052
+ help
+ Say Y here to enable support for batteries charger integrated into
+ DA9052 PMIC.
+
+config CHARGER_DA9150
+ tristate "Dialog Semiconductor DA9150 Charger support"
+ depends on MFD_DA9150
+ depends on DA9150_GPADC
+ depends on IIO
+ help
+ Say Y here to enable support for charger unit of the DA9150
+ Integrated Charger & Fuel-Gauge IC.
+
+ This driver can also be built as a module. If so, the module will be
+ called da9150-charger.
+
+config BATTERY_DA9150
+ tristate "Dialog Semiconductor DA9150 Fuel Gauge support"
+ depends on MFD_DA9150
+ help
+ Say Y here to enable support for the Fuel-Gauge unit of the DA9150
+ Integrated Charger & Fuel-Gauge IC
+
+ This driver can also be built as a module. If so, the module will be
+ called da9150-fg.
+
+config AXP288_CHARGER
+ tristate "X-Powers AXP288 Charger"
+ depends on MFD_AXP20X && EXTCON_AXP288
+ help
+ Say yes here to have support X-Power AXP288 power management IC (PMIC)
+ integrated charger.
+
+config AXP288_FUEL_GAUGE
+ tristate "X-Powers AXP288 Fuel Gauge"
+ depends on MFD_AXP20X && IIO
+ help
+ Say yes here to have support for X-Power power management IC (PMIC)
+ Fuel Gauge. The device provides battery statistics and status
+ monitoring as well as alerts for battery over/under voltage and
+ over/under temperature.
+
+config BATTERY_MAX17040
+ tristate "Maxim MAX17040 Fuel Gauge"
+ depends on I2C
+ help
+ MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
+ in handheld and portable equipment. The MAX17040 is configured
+ to operate with a single lithium cell
+
+config BATTERY_MAX17042
+ tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
+ in handheld and portable equipment. The MAX17042 is configured
+ to operate with a single lithium cell. MAX8997 and MAX8966 are
+ multi-function devices that include fuel gauages that are compatible
+ with MAX17042. This driver also supports max17047/50 chips which are
+ improved version of max17042.
+
+config BATTERY_Z2
+ tristate "Z2 battery driver"
+ depends on I2C && MACH_ZIPIT2
+ help
+ Say Y to include support for the battery on the Zipit Z2.
+
+config BATTERY_S3C_ADC
+ tristate "Battery driver for Samsung ADC based monitoring"
+ depends on S3C_ADC
+ help
+ Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
+
+config BATTERY_TWL4030_MADC
+ tristate "TWL4030 MADC battery driver"
+ depends on TWL4030_MADC
+ help
+ Say Y here to enable this dumb driver for batteries managed
+ through the TWL4030 MADC.
+
+config CHARGER_88PM860X
+ tristate "Marvell 88PM860x Charger driver"
+ depends on MFD_88PM860X && BATTERY_88PM860X
+ help
+ Say Y here to enable charger for Marvell 88PM860x chip.
+
+config CHARGER_PCF50633
+ tristate "NXP PCF50633 MBC"
+ depends on MFD_PCF50633
+ help
+ Say Y to include support for NXP PCF50633 Main Battery Charger.
+
+config BATTERY_JZ4740
+ tristate "Ingenic JZ4740 battery"
+ depends on MACH_JZ4740
+ depends on MFD_JZ4740_ADC
+ help
+ Say Y to enable support for the battery on Ingenic JZ4740 based
+ boards.
+
+ This driver can be build as a module. If so, the module will be
+ called jz4740-battery.
+
+config BATTERY_INTEL_MID
+ tristate "Battery driver for Intel MID platforms"
+ depends on INTEL_SCU_IPC && SPI
+ help
+ Say Y here to enable the battery driver on Intel MID
+ platforms.
+
+config BATTERY_RX51
+ tristate "Nokia RX-51 (N900) battery driver"
+ depends on TWL4030_MADC
+ help
+ Say Y here to enable support for battery information on Nokia
+ RX-51, also known as N900 tablet.
+
+config CHARGER_ISP1704
+ tristate "ISP1704 USB Charger Detection"
+ depends on USB_PHY
+ depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
+ help
+ Say Y to enable support for USB Charger Detection with
+ ISP1707/ISP1704 USB transceivers.
+
+config CHARGER_MAX8903
+ tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
+ help
+ Say Y to enable support for the MAX8903 DC-DC charger and sysfs.
+ The driver supports controlling charger-enable and current-limit
+ pins based on the status of charger connections with interrupt
+ handlers.
+
+config CHARGER_TWL4030
+ tristate "OMAP TWL4030 BCI charger driver"
+ depends on IIO && TWL4030_CORE
+ help
+ Say Y here to enable support for TWL4030 Battery Charge Interface.
+
+config CHARGER_LP8727
+ tristate "TI/National Semiconductor LP8727 charger driver"
+ depends on I2C
+ help
+ Say Y here to enable support for LP8727 Charger Driver.
+
+config CHARGER_LP8788
+ tristate "TI LP8788 charger driver"
+ depends on MFD_LP8788
+ depends on LP8788_ADC
+ depends on IIO
+ help
+ Say Y to enable support for the LP8788 linear charger.
+
+config CHARGER_GPIO
+ tristate "GPIO charger"
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say Y to include support for chargers which report their online status
+ through a GPIO pin.
+
+ This driver can be build as a module. If so, the module will be
+ called gpio-charger.
+
+config CHARGER_MANAGER
+ bool "Battery charger manager for multiple chargers"
+ depends on REGULATOR
+ select EXTCON
+ help
+ Say Y to enable charger-manager support, which allows multiple
+ chargers attached to a battery and multiple batteries attached to a
+ system. The charger-manager also can monitor charging status in
+ runtime and in suspend-to-RAM by waking up the system periodically
+ with help of suspend_again support.
+
+config CHARGER_MAX14577
+ tristate "Maxim MAX14577/77836 battery charger driver"
+ depends on MFD_MAX14577
+ help
+ Say Y to enable support for the battery charger control sysfs and
+ platform data of MAX14577/77836 MUICs.
+
+config CHARGER_MAX77693
+ tristate "Maxim MAX77693 battery charger driver"
+ depends on MFD_MAX77693
+ help
+ Say Y to enable support for the Maxim MAX77693 battery charger.
+
+config CHARGER_MAX8997
+ tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
+ depends on MFD_MAX8997 && REGULATOR_MAX8997
+ help
+ Say Y to enable support for the battery charger control sysfs and
+ platform data of MAX8997/LP3974 PMICs.
+
+config CHARGER_MAX8998
+ tristate "Maxim MAX8998/LP3974 PMIC battery charger driver"
+ depends on MFD_MAX8998 && REGULATOR_MAX8998
+ help
+ Say Y to enable support for the battery charger control sysfs and
+ platform data of MAX8998/LP3974 PMICs.
+
+config CHARGER_QCOM_SMBB
+ tristate "Qualcomm Switch-Mode Battery Charger and Boost"
+ depends on MFD_SPMI_PMIC || COMPILE_TEST
+ depends on OF
+ depends on EXTCON
+ help
+ Say Y to include support for the Switch-Mode Battery Charger and
+ Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger
+ is an integrated, single-cell lithium-ion battery charger. DT
+ configuration is required for loading, see the devicetree
+ documentation for more detail. The base name for this driver is
+ 'pm8941_charger'.
+
+config CHARGER_BQ2415X
+ tristate "TI BQ2415x battery charger driver"
+ depends on I2C
+ help
+ Say Y to enable support for the TI BQ2415x battery charger
+ PMICs.
+
+ You'll need this driver to charge batteries on e.g. Nokia
+ RX-51/N900.
+
+config CHARGER_BQ24190
+ tristate "TI BQ24190 battery charger driver"
+ depends on I2C
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say Y to enable support for the TI BQ24190 battery charger.
+
+config CHARGER_BQ24257
+ tristate "TI BQ24250/24251/24257 battery charger driver"
+ depends on I2C
+ depends on GPIOLIB || COMPILE_TEST
+ depends on REGMAP_I2C
+ help
+ Say Y to enable support for the TI BQ24250, BQ24251, and BQ24257 battery
+ chargers.
+
+config CHARGER_BQ24735
+ tristate "TI BQ24735 battery charger support"
+ depends on I2C
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say Y to enable support for the TI BQ24735 battery charger.
+
+config CHARGER_BQ25890
+ tristate "TI BQ25890 battery charger driver"
+ depends on I2C
+ depends on GPIOLIB || COMPILE_TEST
+ select REGMAP_I2C
+ help
+ Say Y to enable support for the TI BQ25890 battery charger.
+
+config CHARGER_SMB347
+ tristate "Summit Microelectronics SMB347 Battery Charger"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y to include support for Summit Microelectronics SMB347
+ Battery Charger.
+
+config CHARGER_TPS65090
+ tristate "TPS65090 battery charger driver"
+ depends on MFD_TPS65090
+ help
+ Say Y here to enable support for battery charging with TPS65090
+ PMIC chips.
+
+config CHARGER_TPS65217
+ tristate "TPS65217 battery charger driver"
+ depends on MFD_TPS65217
+ help
+ Say Y here to enable support for battery charging with TPS65217
+ PMIC chips.
+
+config BATTERY_GAUGE_LTC2941
+ tristate "LTC2941/LTC2943 Battery Gauge Driver"
+ depends on I2C
+ help
+ Say Y here to include support for LTC2941 and LTC2943 Battery
+ Gauge IC. The driver reports the charge count continuously, and
+ measures the voltage and temperature every 10 seconds.
+
+config AB8500_BM
+ bool "AB8500 Battery Management Driver"
+ depends on AB8500_CORE && AB8500_GPADC
+ help
+ Say Y to include support for AB8500 battery management.
+
+config BATTERY_GOLDFISH
+ tristate "Goldfish battery driver"
+ depends on GOLDFISH || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ Say Y to enable support for the battery and AC power in the
+ Goldfish emulator.
+
+config BATTERY_RT5033
+ tristate "RT5033 fuel gauge support"
+ depends on MFD_RT5033
+ help
+ This adds support for battery fuel gauge in Richtek RT5033 PMIC.
+ The fuelgauge calculates and determines the battery state of charge
+ according to battery open circuit voltage.
+
+config CHARGER_RT9455
+ tristate "Richtek RT9455 battery charger driver"
+ depends on I2C
+ depends on GPIOLIB || COMPILE_TEST
+ select REGMAP_I2C
+ help
+ Say Y to enable support for Richtek RT9455 battery charger.
+
+config AXP20X_POWER
+ tristate "AXP20x power supply driver"
+ depends on MFD_AXP20X
+ help
+ This driver provides support for the power supply features of
+ AXP20x PMIC.
+
+endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
new file mode 100644
index 000000000000..36c599d9a495
--- /dev/null
+++ b/drivers/power/supply/Makefile
@@ -0,0 +1,74 @@
+subdir-ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
+
+power_supply-y := power_supply_core.o
+power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
+power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
+
+obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
+obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
+
+obj-$(CONFIG_PDA_POWER) += pda_power.o
+obj-$(CONFIG_APM_POWER) += apm_power.o
+obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
+obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
+obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
+obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
+obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
+obj-$(CONFIG_TEST_POWER) += test_power.o
+
+obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
+obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
+obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
+obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
+obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
+obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
+obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o
+obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
+obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
+obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
+obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
+obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
+obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
+obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
+obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
+obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o
+obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
+obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
+obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
+obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o
+obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o
+obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
+obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
+obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
+obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
+obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
+obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
+obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
+obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
+obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
+obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
+obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
+obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
+obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
+obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
+obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
+obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
+obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
+obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
+obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
+obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
+obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
+obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
+obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
+obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
+obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
+obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
+obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
+obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
+obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
+obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
+obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
+obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
+obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c
index d29864533093..d29864533093 100644
--- a/drivers/power/ab8500_bmdata.c
+++ b/drivers/power/supply/ab8500_bmdata.c
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index bf2e5dd301e7..6ffdc18f2599 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -1095,7 +1095,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
/* Create a work queue for the btemp */
di->btemp_wq =
- create_singlethread_workqueue("ab8500_btemp_wq");
+ alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
if (di->btemp_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
return -ENOMEM;
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c
index 30de5d42b26a..5cee9aa87aa3 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/supply/ab8500_charger.c
@@ -3540,8 +3540,8 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->usb_state.usb_current = -1;
/* Create a work queue for the charger */
- di->charger_wq =
- create_singlethread_workqueue("ab8500_charger_wq");
+ di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
+ WQ_MEM_RECLAIM);
if (di->charger_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
return -ENOMEM;
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 5a36cf88578a..2199f673118c 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -245,13 +245,8 @@ static LIST_HEAD(ab8500_fg_list);
*/
struct ab8500_fg *ab8500_fg_get(void)
{
- struct ab8500_fg *fg;
-
- if (list_empty(&ab8500_fg_list))
- return NULL;
-
- fg = list_first_entry(&ab8500_fg_list, struct ab8500_fg, node);
- return fg;
+ return list_first_entry_or_null(&ab8500_fg_list, struct ab8500_fg,
+ node);
}
/* Main battery properties */
@@ -3096,7 +3091,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT);
/* Create a work queue for running the FG algorithm */
- di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
+ di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
if (di->fg_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
return -ENOMEM;
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/supply/abx500_chargalg.c
index d9104b1ab7cf..a4411d6bbc96 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/supply/abx500_chargalg.c
@@ -2091,8 +2091,8 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
abx500_chargalg_maintenance_timer_expired;
/* Create a work queue for the chargalg */
- di->chargalg_wq =
- create_singlethread_workqueue("abx500_chargalg_wq");
+ di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
+ WQ_MEM_RECLAIM);
if (di->chargalg_wq == NULL) {
dev_err(di->dev, "failed to create work queue\n");
return -ENOMEM;
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c
new file mode 100644
index 000000000000..d1eb2e359532
--- /dev/null
+++ b/drivers/power/supply/act8945a_charger.c
@@ -0,0 +1,666 @@
+/*
+ * Power supply driver for the Active-semi ACT8945A PMIC
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ *
+ * Author: Wenyou Yang <wenyou.yang@atmel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+
+static const char *act8945a_charger_model = "ACT8945A";
+static const char *act8945a_charger_manufacturer = "Active-semi";
+
+/**
+ * ACT8945A Charger Register Map
+ */
+
+/* 0x70: Reserved */
+#define ACT8945A_APCH_CFG 0x71
+#define ACT8945A_APCH_STATUS 0x78
+#define ACT8945A_APCH_CTRL 0x79
+#define ACT8945A_APCH_STATE 0x7A
+
+/* ACT8945A_APCH_CFG */
+#define APCH_CFG_OVPSET (0x3 << 0)
+#define APCH_CFG_OVPSET_6V6 (0x0 << 0)
+#define APCH_CFG_OVPSET_7V (0x1 << 0)
+#define APCH_CFG_OVPSET_7V5 (0x2 << 0)
+#define APCH_CFG_OVPSET_8V (0x3 << 0)
+#define APCH_CFG_PRETIMO (0x3 << 2)
+#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2)
+#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2)
+#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2)
+#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2)
+#define APCH_CFG_TOTTIMO (0x3 << 4)
+#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4)
+#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4)
+#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4)
+#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4)
+#define APCH_CFG_SUSCHG (0x1 << 7)
+
+#define APCH_STATUS_CHGDAT BIT(0)
+#define APCH_STATUS_INDAT BIT(1)
+#define APCH_STATUS_TEMPDAT BIT(2)
+#define APCH_STATUS_TIMRDAT BIT(3)
+#define APCH_STATUS_CHGSTAT BIT(4)
+#define APCH_STATUS_INSTAT BIT(5)
+#define APCH_STATUS_TEMPSTAT BIT(6)
+#define APCH_STATUS_TIMRSTAT BIT(7)
+
+#define APCH_CTRL_CHGEOCOUT BIT(0)
+#define APCH_CTRL_INDIS BIT(1)
+#define APCH_CTRL_TEMPOUT BIT(2)
+#define APCH_CTRL_TIMRPRE BIT(3)
+#define APCH_CTRL_CHGEOCIN BIT(4)
+#define APCH_CTRL_INCON BIT(5)
+#define APCH_CTRL_TEMPIN BIT(6)
+#define APCH_CTRL_TIMRTOT BIT(7)
+
+#define APCH_STATE_ACINSTAT (0x1 << 1)
+#define APCH_STATE_CSTATE (0x3 << 4)
+#define APCH_STATE_CSTATE_SHIFT 4
+#define APCH_STATE_CSTATE_DISABLED 0x00
+#define APCH_STATE_CSTATE_EOC 0x01
+#define APCH_STATE_CSTATE_FAST 0x02
+#define APCH_STATE_CSTATE_PRE 0x03
+
+struct act8945a_charger {
+ struct power_supply *psy;
+ struct power_supply_desc desc;
+ struct regmap *regmap;
+ struct work_struct work;
+
+ bool init_done;
+ struct gpio_desc *lbo_gpio;
+ struct gpio_desc *chglev_gpio;
+};
+
+static int act8945a_get_charger_state(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status, state;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ switch (state) {
+ case APCH_STATE_CSTATE_PRE:
+ case APCH_STATE_CSTATE_FAST:
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case APCH_STATE_CSTATE_EOC:
+ if (status & APCH_STATUS_CHGDAT)
+ *val = POWER_SUPPLY_STATUS_FULL;
+ else
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case APCH_STATE_CSTATE_DISABLED:
+ default:
+ if (!(status & APCH_STATUS_INDAT))
+ *val = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ }
+
+ return 0;
+}
+
+static int act8945a_get_charge_type(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status, state;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ switch (state) {
+ case APCH_STATE_CSTATE_PRE:
+ *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case APCH_STATE_CSTATE_FAST:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case APCH_STATE_CSTATE_EOC:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ case APCH_STATE_CSTATE_DISABLED:
+ default:
+ if (!(status & APCH_STATUS_INDAT))
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ else
+ *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int act8945a_get_battery_health(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status, state, config;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ switch (state) {
+ case APCH_STATE_CSTATE_DISABLED:
+ if (config & APCH_CFG_SUSCHG) {
+ *val = POWER_SUPPLY_HEALTH_UNKNOWN;
+ } else if (status & APCH_STATUS_INDAT) {
+ if (!(status & APCH_STATUS_TEMPDAT))
+ *val = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (status & APCH_STATUS_TIMRDAT)
+ *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+ else
+ *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ } else {
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ break;
+ case APCH_STATE_CSTATE_PRE:
+ case APCH_STATE_CSTATE_FAST:
+ case APCH_STATE_CSTATE_EOC:
+ default:
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ }
+
+ return 0;
+}
+
+static int act8945a_get_capacity_level(struct act8945a_charger *charger,
+ struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status, state, config;
+ int lbo_level = gpiod_get_value(charger->lbo_gpio);
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ switch (state) {
+ case APCH_STATE_CSTATE_PRE:
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ break;
+ case APCH_STATE_CSTATE_FAST:
+ if (lbo_level)
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+ else
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ break;
+ case APCH_STATE_CSTATE_EOC:
+ if (status & APCH_STATUS_CHGDAT)
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ break;
+ case APCH_STATE_CSTATE_DISABLED:
+ default:
+ if (config & APCH_CFG_SUSCHG) {
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ } else {
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ if (!(status & APCH_STATUS_INDAT)) {
+ if (!lbo_level)
+ *val = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#define MAX_CURRENT_USB_HIGH 450000
+#define MAX_CURRENT_USB_LOW 90000
+#define MAX_CURRENT_USB_PRE 45000
+/*
+ * Riset(K) = 2336 * (1V/Ichg(mA)) - 0.205
+ * Riset = 2.43K
+ */
+#define MAX_CURRENT_AC_HIGH 886527
+#define MAX_CURRENT_AC_LOW 117305
+#define MAX_CURRENT_AC_HIGH_PRE 88653
+#define MAX_CURRENT_AC_LOW_PRE 11731
+
+static int act8945a_get_current_max(struct act8945a_charger *charger,
+ struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int status, state;
+ unsigned int acin_state;
+ int chgin_level = gpiod_get_value(charger->chglev_gpio);
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ acin_state = (state & APCH_STATE_ACINSTAT) >> 1;
+
+ state &= APCH_STATE_CSTATE;
+ state >>= APCH_STATE_CSTATE_SHIFT;
+
+ switch (state) {
+ case APCH_STATE_CSTATE_PRE:
+ if (acin_state) {
+ if (chgin_level)
+ *val = MAX_CURRENT_AC_HIGH_PRE;
+ else
+ *val = MAX_CURRENT_AC_LOW_PRE;
+ } else {
+ *val = MAX_CURRENT_USB_PRE;
+ }
+ break;
+ case APCH_STATE_CSTATE_FAST:
+ if (acin_state) {
+ if (chgin_level)
+ *val = MAX_CURRENT_AC_HIGH;
+ else
+ *val = MAX_CURRENT_AC_LOW;
+ } else {
+ if (chgin_level)
+ *val = MAX_CURRENT_USB_HIGH;
+ else
+ *val = MAX_CURRENT_USB_LOW;
+ }
+ break;
+ case APCH_STATE_CSTATE_EOC:
+ case APCH_STATE_CSTATE_DISABLED:
+ default:
+ *val = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property act8945a_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER
+};
+
+static int act8945a_charger_get_property(struct power_supply *psy,
+ enum power_supply_property prop,
+ union power_supply_propval *val)
+{
+ struct act8945a_charger *charger = power_supply_get_drvdata(psy);
+ struct regmap *regmap = charger->regmap;
+ int ret = 0;
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = act8945a_get_charger_state(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = act8945a_get_charge_type(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = act8945a_get_battery_health(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ ret = act8945a_get_capacity_level(charger,
+ regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ ret = act8945a_get_current_max(charger,
+ regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = act8945a_charger_model;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = act8945a_charger_manufacturer;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int act8945a_enable_interrupt(struct act8945a_charger *charger)
+{
+ struct regmap *regmap = charger->regmap;
+ unsigned char ctrl;
+ int ret;
+
+ ctrl = APCH_CTRL_CHGEOCOUT | APCH_CTRL_CHGEOCIN |
+ APCH_CTRL_INDIS | APCH_CTRL_INCON |
+ APCH_CTRL_TEMPOUT | APCH_CTRL_TEMPIN |
+ APCH_CTRL_TIMRPRE | APCH_CTRL_TIMRTOT;
+ ret = regmap_write(regmap, ACT8945A_APCH_CTRL, ctrl);
+ if (ret)
+ return ret;
+
+ ctrl = APCH_STATUS_CHGSTAT | APCH_STATUS_INSTAT |
+ APCH_STATUS_TEMPSTAT | APCH_STATUS_TIMRSTAT;
+ ret = regmap_write(regmap, ACT8945A_APCH_STATUS, ctrl);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static unsigned int act8945a_set_supply_type(struct act8945a_charger *charger,
+ unsigned int *type)
+{
+ unsigned int status, state;
+ int ret;
+
+ ret = regmap_read(charger->regmap, ACT8945A_APCH_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(charger->regmap, ACT8945A_APCH_STATE, &state);
+ if (ret < 0)
+ return ret;
+
+ if (status & APCH_STATUS_INDAT) {
+ if (state & APCH_STATE_ACINSTAT)
+ *type = POWER_SUPPLY_TYPE_MAINS;
+ else
+ *type = POWER_SUPPLY_TYPE_USB;
+ } else {
+ *type = POWER_SUPPLY_TYPE_BATTERY;
+ }
+
+ return 0;
+}
+
+static void act8945a_work(struct work_struct *work)
+{
+ struct act8945a_charger *charger =
+ container_of(work, struct act8945a_charger, work);
+
+ act8945a_set_supply_type(charger, &charger->desc.type);
+
+ power_supply_changed(charger->psy);
+}
+
+static irqreturn_t act8945a_status_changed(int irq, void *dev_id)
+{
+ struct act8945a_charger *charger = dev_id;
+
+ if (charger->init_done)
+ schedule_work(&charger->work);
+
+ return IRQ_HANDLED;
+}
+
+#define DEFAULT_TOTAL_TIME_OUT 3
+#define DEFAULT_PRE_TIME_OUT 40
+#define DEFAULT_INPUT_OVP_THRESHOLD 6600
+
+static int act8945a_charger_config(struct device *dev,
+ struct act8945a_charger *charger)
+{
+ struct device_node *np = dev->of_node;
+ struct regmap *regmap = charger->regmap;
+
+ u32 total_time_out;
+ u32 pre_time_out;
+ u32 input_voltage_threshold;
+ int err, ret;
+
+ unsigned int tmp;
+ unsigned int value = 0;
+
+ if (!np) {
+ dev_err(dev, "no charger of node\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_read(regmap, ACT8945A_APCH_CFG, &tmp);
+ if (ret)
+ return ret;
+
+ if (tmp & APCH_CFG_SUSCHG) {
+ value |= APCH_CFG_SUSCHG;
+ dev_info(dev, "have been suspended\n");
+ }
+
+ charger->lbo_gpio = devm_gpiod_get_optional(dev, "active-semi,lbo",
+ GPIOD_IN);
+ if (IS_ERR(charger->lbo_gpio)) {
+ err = PTR_ERR(charger->lbo_gpio);
+ dev_err(dev, "unable to claim gpio \"lbo\": %d\n", err);
+ return err;
+ }
+
+ ret = devm_request_irq(dev, gpiod_to_irq(charger->lbo_gpio),
+ act8945a_status_changed,
+ (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
+ "act8945a_lbo_detect", charger);
+ if (ret)
+ dev_info(dev, "failed to request gpio \"lbo\" IRQ\n");
+
+ charger->chglev_gpio = devm_gpiod_get_optional(dev,
+ "active-semi,chglev",
+ GPIOD_IN);
+ if (IS_ERR(charger->chglev_gpio)) {
+ err = PTR_ERR(charger->chglev_gpio);
+ dev_err(dev, "unable to claim gpio \"chglev\": %d\n", err);
+ return err;
+ }
+
+ if (of_property_read_u32(np,
+ "active-semi,input-voltage-threshold-microvolt",
+ &input_voltage_threshold))
+ input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
+
+ if (of_property_read_u32(np,
+ "active-semi,precondition-timeout",
+ &pre_time_out))
+ pre_time_out = DEFAULT_PRE_TIME_OUT;
+
+ if (of_property_read_u32(np, "active-semi,total-timeout",
+ &total_time_out))
+ total_time_out = DEFAULT_TOTAL_TIME_OUT;
+
+ switch (input_voltage_threshold) {
+ case 8000:
+ value |= APCH_CFG_OVPSET_8V;
+ break;
+ case 7500:
+ value |= APCH_CFG_OVPSET_7V5;
+ break;
+ case 7000:
+ value |= APCH_CFG_OVPSET_7V;
+ break;
+ case 6600:
+ default:
+ value |= APCH_CFG_OVPSET_6V6;
+ break;
+ }
+
+ switch (pre_time_out) {
+ case 60:
+ value |= APCH_CFG_PRETIMO_60_MIN;
+ break;
+ case 80:
+ value |= APCH_CFG_PRETIMO_80_MIN;
+ break;
+ case 0:
+ value |= APCH_CFG_PRETIMO_DISABLED;
+ break;
+ case 40:
+ default:
+ value |= APCH_CFG_PRETIMO_40_MIN;
+ break;
+ }
+
+ switch (total_time_out) {
+ case 4:
+ value |= APCH_CFG_TOTTIMO_4_HOUR;
+ break;
+ case 5:
+ value |= APCH_CFG_TOTTIMO_5_HOUR;
+ break;
+ case 0:
+ value |= APCH_CFG_TOTTIMO_DISABLED;
+ break;
+ case 3:
+ default:
+ value |= APCH_CFG_TOTTIMO_3_HOUR;
+ break;
+ }
+
+ return regmap_write(regmap, ACT8945A_APCH_CFG, value);
+}
+
+static int act8945a_charger_probe(struct platform_device *pdev)
+{
+ struct act8945a_charger *charger;
+ struct power_supply_config psy_cfg = {};
+ int irq, ret;
+
+ charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
+ if (!charger)
+ return -ENOMEM;
+
+ charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!charger->regmap) {
+ dev_err(&pdev->dev, "Parent did not provide regmap\n");
+ return -EINVAL;
+ }
+
+ ret = act8945a_charger_config(&pdev->dev, charger);
+ if (ret)
+ return ret;
+
+ irq = of_irq_get(pdev->dev.of_node, 0);
+ if (irq == -EPROBE_DEFER) {
+ dev_err(&pdev->dev, "failed to find IRQ number\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
+ IRQF_TRIGGER_FALLING, "act8945a_interrupt",
+ charger);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
+ return ret;
+ }
+
+ charger->desc.name = "act8945a-charger";
+ charger->desc.get_property = act8945a_charger_get_property;
+ charger->desc.properties = act8945a_charger_props;
+ charger->desc.num_properties = ARRAY_SIZE(act8945a_charger_props);
+
+ ret = act8945a_set_supply_type(charger, &charger->desc.type);
+ if (ret)
+ return -EINVAL;
+
+ psy_cfg.of_node = pdev->dev.of_node;
+ psy_cfg.drv_data = charger;
+
+ charger->psy = devm_power_supply_register(&pdev->dev,
+ &charger->desc,
+ &psy_cfg);
+ if (IS_ERR(charger->psy)) {
+ dev_err(&pdev->dev, "failed to register power supply\n");
+ return PTR_ERR(charger->psy);
+ }
+
+ platform_set_drvdata(pdev, charger);
+
+ INIT_WORK(&charger->work, act8945a_work);
+
+ ret = act8945a_enable_interrupt(charger);
+ if (ret)
+ return -EIO;
+
+ charger->init_done = true;
+
+ return 0;
+}
+
+static int act8945a_charger_remove(struct platform_device *pdev)
+{
+ struct act8945a_charger *charger = platform_get_drvdata(pdev);
+
+ charger->init_done = false;
+ cancel_work_sync(&charger->work);
+
+ return 0;
+}
+
+static struct platform_driver act8945a_charger_driver = {
+ .driver = {
+ .name = "act8945a-charger",
+ },
+ .probe = act8945a_charger_probe,
+ .remove = act8945a_charger_remove,
+};
+module_platform_driver(act8945a_charger_driver);
+
+MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
+MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/apm_power.c b/drivers/power/supply/apm_power.c
index 9d1a7fbcaed4..9d1a7fbcaed4 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/supply/apm_power.c
diff --git a/drivers/power/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index 6af6feb7058d..6af6feb7058d 100644
--- a/drivers/power/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
diff --git a/drivers/power/axp288_charger.c b/drivers/power/supply/axp288_charger.c
index 4030eeb7cf65..75b8e0c7402b 100644
--- a/drivers/power/axp288_charger.c
+++ b/drivers/power/supply/axp288_charger.c
@@ -23,7 +23,6 @@
#include <linux/usb/otg.h>
#include <linux/notifier.h>
#include <linux/power_supply.h>
-#include <linux/notifier.h>
#include <linux/property.h>
#include <linux/mfd/axp20x.h>
#include <linux/extcon.h>
diff --git a/drivers/power/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c
index 50c0110d6b58..5bdde692f724 100644
--- a/drivers/power/axp288_fuel_gauge.c
+++ b/drivers/power/supply/axp288_fuel_gauge.c
@@ -22,7 +22,6 @@
#include <linux/regmap.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
-#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/mfd/axp20x.h>
#include <linux/platform_device.h>
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c
index 73e2f0b79dd4..73e2f0b79dd4 100644
--- a/drivers/power/bq2415x_charger.c
+++ b/drivers/power/supply/bq2415x_charger.c
diff --git a/drivers/power/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index f5746b9f4e83..f5746b9f4e83 100644
--- a/drivers/power/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
diff --git a/drivers/power/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c
index 1fea2c7ef97f..6fc31bdc639b 100644
--- a/drivers/power/bq24257_charger.c
+++ b/drivers/power/supply/bq24257_charger.c
@@ -1068,6 +1068,12 @@ static int bq24257_probe(struct i2c_client *client,
return ret;
}
+ ret = bq24257_power_supply_init(bq);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register power supply\n");
+ return ret;
+ }
+
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq24257_irq_handler_thread,
IRQF_TRIGGER_FALLING |
@@ -1078,12 +1084,6 @@ static int bq24257_probe(struct i2c_client *client,
return ret;
}
- ret = bq24257_power_supply_init(bq);
- if (ret < 0) {
- dev_err(dev, "Failed to register power supply\n");
- return ret;
- }
-
ret = sysfs_create_group(&bq->charger->dev.kobj, &bq24257_attr_group);
if (ret < 0) {
dev_err(dev, "Can't create sysfs entries\n");
diff --git a/drivers/power/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c
index fa454c19ce17..eb7783b42e0a 100644
--- a/drivers/power/bq24735-charger.c
+++ b/drivers/power/supply/bq24735-charger.c
@@ -25,7 +25,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
@@ -49,6 +49,7 @@ struct bq24735 {
struct i2c_client *client;
struct bq24735_platform *pdata;
struct mutex lock;
+ struct gpio_desc *status_gpio;
bool charging;
};
@@ -177,12 +178,8 @@ static int bq24735_config_charger(struct bq24735 *charger)
static bool bq24735_charger_is_present(struct bq24735 *charger)
{
- struct bq24735_platform *pdata = charger->pdata;
- int ret;
-
- if (pdata->status_gpio_valid) {
- ret = gpio_get_value_cansleep(pdata->status_gpio);
- return ret ^= pdata->status_gpio_active_low == 0;
+ if (charger->status_gpio) {
+ return !gpiod_get_value_cansleep(charger->status_gpio);
} else {
int ac = 0;
@@ -201,8 +198,12 @@ static bool bq24735_charger_is_present(struct bq24735 *charger)
static int bq24735_charger_is_charging(struct bq24735 *charger)
{
- int ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
+ int ret;
+ if (!bq24735_charger_is_present(charger))
+ return 0;
+
+ ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
if (ret < 0)
return ret;
@@ -304,7 +305,6 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
struct device_node *np = client->dev.of_node;
u32 val;
int ret;
- enum of_gpio_flags flags;
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -313,12 +313,6 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
return NULL;
}
- pdata->status_gpio = of_get_named_gpio_flags(np, "ti,ac-detect-gpios",
- 0, &flags);
-
- if (flags & OF_GPIO_ACTIVE_LOW)
- pdata->status_gpio_active_low = 1;
-
ret = of_property_read_u32(np, "ti,charge-current", &val);
if (!ret)
pdata->charge_current = val;
@@ -392,21 +386,16 @@ static int bq24735_charger_probe(struct i2c_client *client,
i2c_set_clientdata(client, charger);
- if (gpio_is_valid(charger->pdata->status_gpio)) {
- ret = devm_gpio_request(&client->dev,
- charger->pdata->status_gpio,
- name);
- if (ret) {
- dev_err(&client->dev,
- "Failed GPIO request for GPIO %d: %d\n",
- charger->pdata->status_gpio, ret);
- }
-
- charger->pdata->status_gpio_valid = !ret;
+ charger->status_gpio = devm_gpiod_get_optional(&client->dev,
+ "ti,ac-detect",
+ GPIOD_IN);
+ if (IS_ERR(charger->status_gpio)) {
+ ret = PTR_ERR(charger->status_gpio);
+ dev_err(&client->dev, "Getting gpio failed: %d\n", ret);
+ return ret;
}
- if (!charger->pdata->status_gpio_valid
- || bq24735_charger_is_present(charger)) {
+ if (!charger->status_gpio || bq24735_charger_is_present(charger)) {
ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
diff --git a/drivers/power/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index f993a55cde20..f993a55cde20 100644
--- a/drivers/power/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 323d05a12f9b..3b0dbc689d72 100644
--- a/drivers/power/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -39,6 +39,7 @@
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/param.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
@@ -390,8 +391,35 @@ static struct {
BQ27XXX_PROP(BQ27421, bq27421_battery_props),
};
+static DEFINE_MUTEX(bq27xxx_list_lock);
+static LIST_HEAD(bq27xxx_battery_devices);
+
+static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
+{
+ struct bq27xxx_device_info *di;
+ int ret;
+
+ ret = param_set_uint(val, kp);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&bq27xxx_list_lock);
+ list_for_each_entry(di, &bq27xxx_battery_devices, list) {
+ cancel_delayed_work_sync(&di->work);
+ schedule_delayed_work(&di->work, 0);
+ }
+ mutex_unlock(&bq27xxx_list_lock);
+
+ return ret;
+}
+
+static const struct kernel_param_ops param_ops_poll_interval = {
+ .get = param_get_uint,
+ .set = poll_interval_param_set,
+};
+
static unsigned int poll_interval = 360;
-module_param(poll_interval, uint, 0644);
+module_param_cb(poll_interval, &param_ops_poll_interval, &poll_interval, 0644);
MODULE_PARM_DESC(poll_interval,
"battery poll interval in seconds - 0 disables polling");
@@ -644,8 +672,9 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags)
static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
{
int flags;
+ bool has_singe_flag = di->chip == BQ27000 || di->chip == BQ27010;
- flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
+ flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
if (flags < 0) {
dev_err(di->dev, "error reading flag register:%d\n", flags);
return flags;
@@ -745,7 +774,7 @@ static int bq27xxx_battery_current(struct bq27xxx_device_info *di,
}
if (di->chip == BQ27000 || di->chip == BQ27010) {
- flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
+ flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true);
if (flags & BQ27000_FLAG_CHGS) {
dev_dbg(di->dev, "negative current!\n");
curr = -curr;
@@ -971,6 +1000,10 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
bq27xxx_battery_update(di);
+ mutex_lock(&bq27xxx_list_lock);
+ list_add(&di->list, &bq27xxx_battery_devices);
+ mutex_unlock(&bq27xxx_list_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(bq27xxx_battery_setup);
@@ -989,6 +1022,10 @@ void bq27xxx_battery_teardown(struct bq27xxx_device_info *di)
power_supply_unregister(di->bat);
+ mutex_lock(&bq27xxx_list_lock);
+ list_del(&di->list);
+ mutex_unlock(&bq27xxx_list_lock);
+
mutex_destroy(&di->lock);
}
EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown);
diff --git a/drivers/power/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index 85d4ea2a9c20..85d4ea2a9c20 100644
--- a/drivers/power/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
diff --git a/drivers/power/charger-manager.c b/drivers/power/supply/charger-manager.c
index e664ca7c0afd..e664ca7c0afd 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
diff --git a/drivers/power/collie_battery.c b/drivers/power/supply/collie_battery.c
index 3a0bc608d4b5..3a0bc608d4b5 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/supply/collie_battery.c
diff --git a/drivers/power/da9030_battery.c b/drivers/power/supply/da9030_battery.c
index 5ca0f4d90792..5ca0f4d90792 100644
--- a/drivers/power/da9030_battery.c
+++ b/drivers/power/supply/da9030_battery.c
diff --git a/drivers/power/da9052-battery.c b/drivers/power/supply/da9052-battery.c
index 830ec46fe7d0..830ec46fe7d0 100644
--- a/drivers/power/da9052-battery.c
+++ b/drivers/power/supply/da9052-battery.c
diff --git a/drivers/power/da9150-charger.c b/drivers/power/supply/da9150-charger.c
index 60099815296e..60099815296e 100644
--- a/drivers/power/da9150-charger.c
+++ b/drivers/power/supply/da9150-charger.c
diff --git a/drivers/power/da9150-fg.c b/drivers/power/supply/da9150-fg.c
index 8b8ce978656a..8b8ce978656a 100644
--- a/drivers/power/da9150-fg.c
+++ b/drivers/power/supply/da9150-fg.c
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c
index 80f73ccb77ab..17225689e3f6 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/supply/ds2760_battery.c
@@ -28,8 +28,8 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
-#include "../w1/w1.h"
-#include "../w1/slaves/w1_ds2760.h"
+#include "../../w1/w1.h"
+#include "../../w1/slaves/w1_ds2760.h"
struct ds2760_device_info {
struct device *dev;
@@ -566,7 +566,8 @@ static int ds2760_battery_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
INIT_DELAYED_WORK(&di->set_charged_work,
ds2760_battery_set_charged_work);
- di->monitor_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev));
+ di->monitor_wqueue = alloc_ordered_workqueue(dev_name(&pdev->dev),
+ WQ_MEM_RECLAIM);
if (!di->monitor_wqueue) {
retval = -ESRCH;
goto workqueue_failed;
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c
index d3743d0ad55b..1b3b6fa89c28 100644
--- a/drivers/power/ds2780_battery.c
+++ b/drivers/power/supply/ds2780_battery.c
@@ -21,8 +21,8 @@
#include <linux/power_supply.h>
#include <linux/idr.h>
-#include "../w1/w1.h"
-#include "../w1/slaves/w1_ds2780.h"
+#include "../../w1/w1.h"
+#include "../../w1/slaves/w1_ds2780.h"
/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
#define DS2780_CURRENT_UNITS 1563
diff --git a/drivers/power/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c
index c3680024f399..cc0149131f89 100644
--- a/drivers/power/ds2781_battery.c
+++ b/drivers/power/supply/ds2781_battery.c
@@ -19,8 +19,8 @@
#include <linux/power_supply.h>
#include <linux/idr.h>
-#include "../w1/w1.h"
-#include "../w1/slaves/w1_ds2781.h"
+#include "../../w1/w1.h"
+#include "../../w1/slaves/w1_ds2781.h"
/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
#define DS2781_CURRENT_UNITS 1563
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c
index a1b7e0592245..a1b7e0592245 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/supply/ds2782_battery.c
diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c
index edb36bf781b0..edb36bf781b0 100644
--- a/drivers/power/generic-adc-battery.c
+++ b/drivers/power/supply/generic-adc-battery.c
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c
index f5c525e4482a..f5c525e4482a 100644
--- a/drivers/power/goldfish_battery.c
+++ b/drivers/power/supply/goldfish_battery.c
diff --git a/drivers/power/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index c5869b1941ac..c5869b1941ac 100644
--- a/drivers/power/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/supply/intel_mid_battery.c
index 9fa4acc107ca..dc7feef1bea4 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/supply/intel_mid_battery.c
@@ -689,8 +689,7 @@ static int probe(int irq, struct device *dev)
/* initialize all required framework before enabling interrupts */
INIT_WORK(&pbi->handler, pmic_battery_handle_intrpt);
INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor);
- pbi->monitor_wqueue =
- create_singlethread_workqueue(dev_name(dev));
+ pbi->monitor_wqueue = alloc_workqueue(dev_name(dev), WQ_MEM_RECLAIM, 0);
if (!pbi->monitor_wqueue) {
dev_err(dev, "%s(): wqueue init failed\n", __func__);
retval = -ESRCH;
diff --git a/drivers/power/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c
index 35b01c7d775b..4af7b770f293 100644
--- a/drivers/power/ipaq_micro_battery.c
+++ b/drivers/power/supply/ipaq_micro_battery.c
@@ -235,7 +235,7 @@ static int micro_batt_probe(struct platform_device *pdev)
return -ENOMEM;
mb->micro = dev_get_drvdata(pdev->dev.parent);
- mb->wq = create_singlethread_workqueue("ipaq-battery-wq");
+ mb->wq = alloc_workqueue("ipaq-battery-wq", WQ_MEM_RECLAIM, 0);
if (!mb->wq)
return -ENOMEM;
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c
index 4cd6899b961e..4cd6899b961e 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/supply/isp1704_charger.c
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/supply/jz4740-battery.c
index 88f04f4d1a70..88f04f4d1a70 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/supply/jz4740-battery.c
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c
index 042fb3dacb46..042fb3dacb46 100644
--- a/drivers/power/lp8727_charger.c
+++ b/drivers/power/supply/lp8727_charger.c
diff --git a/drivers/power/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c
index 7321b727d484..7321b727d484 100644
--- a/drivers/power/lp8788-charger.c
+++ b/drivers/power/supply/lp8788-charger.c
diff --git a/drivers/power/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c
index 4adf2ba021ce..4adf2ba021ce 100644
--- a/drivers/power/ltc2941-battery-gauge.c
+++ b/drivers/power/supply/ltc2941-battery-gauge.c
diff --git a/drivers/power/max14577_charger.c b/drivers/power/supply/max14577_charger.c
index a36bcaf62dd4..449fc56f09eb 100644
--- a/drivers/power/max14577_charger.c
+++ b/drivers/power/supply/max14577_charger.c
@@ -2,7 +2,7 @@
* max14577_charger.c - Battery charger driver for the Maxim 14577/77836
*
* Copyright (C) 2013,2014 Samsung Electronics
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.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
@@ -643,6 +643,6 @@ static struct platform_driver max14577_charger_driver = {
};
module_platform_driver(max14577_charger_driver);
-MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("Maxim 14577/77836 charger driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 8689c80202b5..8689c80202b5 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
diff --git a/drivers/power/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index da7a75f82489..da7a75f82489 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
diff --git a/drivers/power/max77693_charger.c b/drivers/power/supply/max77693_charger.c
index 060cab5ae3aa..6c78884bad5e 100644
--- a/drivers/power/max77693_charger.c
+++ b/drivers/power/supply/max77693_charger.c
@@ -2,7 +2,7 @@
* max77693_charger.c - Battery charger driver for the Maxim 77693
*
* Copyright (C) 2014 Samsung Electronics
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.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
@@ -766,6 +766,6 @@ static struct platform_driver max77693_charger_driver = {
};
module_platform_driver(max77693_charger_driver);
-MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("Maxim 77693 charger driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/max8903_charger.c b/drivers/power/supply/max8903_charger.c
index fdc73d686153..fdc73d686153 100644
--- a/drivers/power/max8903_charger.c
+++ b/drivers/power/supply/max8903_charger.c
diff --git a/drivers/power/max8925_power.c b/drivers/power/supply/max8925_power.c
index 3b94620ce5c1..3b94620ce5c1 100644
--- a/drivers/power/max8925_power.c
+++ b/drivers/power/supply/max8925_power.c
diff --git a/drivers/power/max8997_charger.c b/drivers/power/supply/max8997_charger.c
index 0b2eab571528..0b2eab571528 100644
--- a/drivers/power/max8997_charger.c
+++ b/drivers/power/supply/max8997_charger.c
diff --git a/drivers/power/max8998_charger.c b/drivers/power/supply/max8998_charger.c
index b64cf0f14142..b64cf0f14142 100644
--- a/drivers/power/max8998_charger.c
+++ b/drivers/power/supply/max8998_charger.c
diff --git a/drivers/power/olpc_battery.c b/drivers/power/supply/olpc_battery.c
index 9e29b1321648..9e29b1321648 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/supply/olpc_battery.c
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c
index d05597b4e40f..d05597b4e40f 100644
--- a/drivers/power/pcf50633-charger.c
+++ b/drivers/power/supply/pcf50633-charger.c
diff --git a/drivers/power/pda_power.c b/drivers/power/supply/pda_power.c
index dfe1ee89f7c7..dfe1ee89f7c7 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/supply/pda_power.c
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/supply/pm2301_charger.c
index fb62ed3fc38c..78561b6884fc 100644
--- a/drivers/power/pm2301_charger.c
+++ b/drivers/power/supply/pm2301_charger.c
@@ -1054,7 +1054,8 @@ static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
pm2->ac_chg.external = true;
/* Create a work queue for the charger */
- pm2->charger_wq = create_singlethread_workqueue("pm2xxx_charger_wq");
+ pm2->charger_wq = alloc_ordered_workqueue("pm2xxx_charger_wq",
+ WQ_MEM_RECLAIM);
if (pm2->charger_wq == NULL) {
ret = -ENOMEM;
dev_err(pm2->dev, "failed to create work queue\n");
diff --git a/drivers/power/pm2301_charger.h b/drivers/power/supply/pm2301_charger.h
index 24181cf9717b..24181cf9717b 100644
--- a/drivers/power/pm2301_charger.h
+++ b/drivers/power/supply/pm2301_charger.h
diff --git a/drivers/power/pmu_battery.c b/drivers/power/supply/pmu_battery.c
index 9c8d5253812c..9c8d5253812c 100644
--- a/drivers/power/pmu_battery.c
+++ b/drivers/power/supply/pmu_battery.c
diff --git a/drivers/power/power_supply.h b/drivers/power/supply/power_supply.h
index cc439fd89d8d..cc439fd89d8d 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/supply/power_supply.h
diff --git a/drivers/power/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index a74d8ca383a1..a74d8ca383a1 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/supply/power_supply_leds.c
index 2277ad9c2f68..2277ad9c2f68 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/supply/power_supply_leds.c
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index bcde8d13476a..bcde8d13476a 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
diff --git a/drivers/power/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
index b5896ba2a602..b5896ba2a602 100644
--- a/drivers/power/qcom_smbb.c
+++ b/drivers/power/supply/qcom_smbb.c
diff --git a/drivers/power/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c
index bcdd83048492..bcdd83048492 100644
--- a/drivers/power/rt5033_battery.c
+++ b/drivers/power/supply/rt5033_battery.c
diff --git a/drivers/power/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c
index cfdbde9daf94..cfdbde9daf94 100644
--- a/drivers/power/rt9455_charger.c
+++ b/drivers/power/supply/rt9455_charger.c
diff --git a/drivers/power/rx51_battery.c b/drivers/power/supply/rx51_battery.c
index af9383d23d12..af9383d23d12 100644
--- a/drivers/power/rx51_battery.c
+++ b/drivers/power/supply/rx51_battery.c
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/supply/s3c_adc_battery.c
index 0ffe5cd3abf6..0ffe5cd3abf6 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/supply/s3c_adc_battery.c
diff --git a/drivers/power/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index 768b9fcb58ea..8bb2eb38eb1c 100644
--- a/drivers/power/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -26,7 +26,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/stat.h>
@@ -41,6 +41,7 @@ enum {
REG_TIME_TO_EMPTY,
REG_TIME_TO_FULL,
REG_STATUS,
+ REG_CAPACITY_LEVEL,
REG_CYCLE_COUNT,
REG_SERIAL_NUMBER,
REG_REMAINING_CAPACITY,
@@ -68,6 +69,7 @@ enum sbs_battery_mode {
#define MANUFACTURER_ACCESS_SLEEP 0x0011
/* battery status value bits */
+#define BATTERY_INITIALIZED 0x80
#define BATTERY_DISCHARGING 0x40
#define BATTERY_FULL_CHARGED 0x20
#define BATTERY_FULL_DISCHARGED 0x10
@@ -110,6 +112,8 @@ static const struct chip_data {
SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, 65535),
[REG_STATUS] =
SBS_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
+ [REG_CAPACITY_LEVEL] =
+ SBS_DATA(POWER_SUPPLY_PROP_CAPACITY_LEVEL, 0x16, 0, 65535),
[REG_CYCLE_COUNT] =
SBS_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
[REG_DESIGN_CAPACITY] =
@@ -131,6 +135,7 @@ static const struct chip_data {
static enum power_supply_property sbs_properties[] = {
POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
@@ -158,13 +163,13 @@ static enum power_supply_property sbs_properties[] = {
struct sbs_info {
struct i2c_client *client;
struct power_supply *power_supply;
- struct sbs_platform_data *pdata;
bool is_present;
- bool gpio_detect;
+ struct gpio_desc *gpio_detect;
bool enable_detection;
- int irq;
int last_state;
int poll_time;
+ u32 i2c_retry_count;
+ u32 poll_retry_count;
struct delayed_work work;
int ignore_changes;
};
@@ -179,8 +184,7 @@ static int sbs_read_word_data(struct i2c_client *client, u8 address)
s32 ret = 0;
int retries = 1;
- if (chip->pdata)
- retries = max(chip->pdata->i2c_retry_count + 1, 1);
+ retries = chip->i2c_retry_count;
while (retries > 0) {
ret = i2c_smbus_read_word_data(client, address);
@@ -207,10 +211,8 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address,
int retries_length = 1, retries_block = 1;
u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
- if (chip->pdata) {
- retries_length = max(chip->pdata->i2c_retry_count + 1, 1);
- retries_block = max(chip->pdata->i2c_retry_count + 1, 1);
- }
+ retries_length = chip->i2c_retry_count;
+ retries_block = chip->i2c_retry_count;
/* Adapter needs to support these two functions */
if (!i2c_check_functionality(client->adapter,
@@ -274,8 +276,7 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
s32 ret = 0;
int retries = 1;
- if (chip->pdata)
- retries = max(chip->pdata->i2c_retry_count + 1, 1);
+ retries = chip->i2c_retry_count;
while (retries > 0) {
ret = i2c_smbus_write_word_data(client, address,
@@ -302,32 +303,31 @@ static int sbs_get_battery_presence_and_health(
s32 ret;
struct sbs_info *chip = i2c_get_clientdata(client);
- if (psp == POWER_SUPPLY_PROP_PRESENT &&
- chip->gpio_detect) {
- ret = gpio_get_value(chip->pdata->battery_detect);
- if (ret == chip->pdata->battery_detect_present)
- val->intval = 1;
- else
- val->intval = 0;
+ if (psp == POWER_SUPPLY_PROP_PRESENT && chip->gpio_detect) {
+ ret = gpiod_get_value_cansleep(chip->gpio_detect);
+ if (ret < 0)
+ return ret;
+ val->intval = ret;
chip->is_present = val->intval;
return ret;
}
- /* Write to ManufacturerAccess with
- * ManufacturerAccess command and then
- * read the status */
- ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
- MANUFACTURER_ACCESS_STATUS);
+ /*
+ * Write to ManufacturerAccess with ManufacturerAccess command
+ * and then read the status. Do not check for error on the write
+ * since not all batteries implement write access to this command,
+ * while others mandate it.
+ */
+ sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
+ MANUFACTURER_ACCESS_STATUS);
+
+ ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr);
if (ret < 0) {
if (psp == POWER_SUPPLY_PROP_PRESENT)
val->intval = 0; /* battery removed */
return ret;
}
- ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr);
- if (ret < 0)
- return ret;
-
if (ret < sbs_data[REG_MANUFACTURER_DATA].min_value ||
ret > sbs_data[REG_MANUFACTURER_DATA].max_value) {
val->intval = 0;
@@ -377,8 +377,23 @@ static int sbs_get_battery_property(struct i2c_client *client,
if (ret >= sbs_data[reg_offset].min_value &&
ret <= sbs_data[reg_offset].max_value) {
val->intval = ret;
- if (psp != POWER_SUPPLY_PROP_STATUS)
+ if (psp == POWER_SUPPLY_PROP_CAPACITY_LEVEL) {
+ if (!(ret & BATTERY_INITIALIZED))
+ val->intval =
+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ else if (ret & BATTERY_FULL_CHARGED)
+ val->intval =
+ POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else if (ret & BATTERY_FULL_DISCHARGED)
+ val->intval =
+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ else
+ val->intval =
+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ return 0;
+ } else if (psp != POWER_SUPPLY_PROP_STATUS) {
return 0;
+ }
if (ret & BATTERY_FULL_CHARGED)
val->intval = POWER_SUPPLY_STATUS_FULL;
@@ -590,6 +605,7 @@ static int sbs_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_STATUS:
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
case POWER_SUPPLY_PROP_CYCLE_COUNT:
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_CURRENT_NOW:
@@ -661,8 +677,14 @@ done:
static irqreturn_t sbs_irq(int irq, void *devid)
{
- struct power_supply *battery = devid;
+ struct sbs_info *chip = devid;
+ struct power_supply *battery = chip->power_supply;
+ int ret;
+ ret = gpiod_get_value_cansleep(chip->gpio_detect);
+ if (ret < 0)
+ return ret;
+ chip->is_present = ret;
power_supply_changed(battery);
return IRQ_HANDLED;
@@ -681,7 +703,7 @@ static void sbs_external_power_changed(struct power_supply *psy)
cancel_delayed_work_sync(&chip->work);
schedule_delayed_work(&chip->work, HZ);
- chip->poll_time = chip->pdata->poll_retry_count;
+ chip->poll_time = chip->poll_retry_count;
}
static void sbs_delayed_work(struct work_struct *work)
@@ -717,80 +739,6 @@ static void sbs_delayed_work(struct work_struct *work)
}
}
-#if defined(CONFIG_OF)
-
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-
-static const struct of_device_id sbs_dt_ids[] = {
- { .compatible = "sbs,sbs-battery" },
- { .compatible = "ti,bq20z75" },
- { }
-};
-MODULE_DEVICE_TABLE(of, sbs_dt_ids);
-
-static struct sbs_platform_data *sbs_of_populate_pdata(
- struct i2c_client *client)
-{
- struct device_node *of_node = client->dev.of_node;
- struct sbs_platform_data *pdata = client->dev.platform_data;
- enum of_gpio_flags gpio_flags;
- int rc;
- u32 prop;
-
- /* verify this driver matches this device */
- if (!of_node)
- return NULL;
-
- /* if platform data is set, honor it */
- if (pdata)
- return pdata;
-
- /* first make sure at least one property is set, otherwise
- * it won't change behavior from running without pdata.
- */
- if (!of_get_property(of_node, "sbs,i2c-retry-count", NULL) &&
- !of_get_property(of_node, "sbs,poll-retry-count", NULL) &&
- !of_get_property(of_node, "sbs,battery-detect-gpios", NULL))
- goto of_out;
-
- pdata = devm_kzalloc(&client->dev, sizeof(struct sbs_platform_data),
- GFP_KERNEL);
- if (!pdata)
- goto of_out;
-
- rc = of_property_read_u32(of_node, "sbs,i2c-retry-count", &prop);
- if (!rc)
- pdata->i2c_retry_count = prop;
-
- rc = of_property_read_u32(of_node, "sbs,poll-retry-count", &prop);
- if (!rc)
- pdata->poll_retry_count = prop;
-
- if (!of_get_property(of_node, "sbs,battery-detect-gpios", NULL)) {
- pdata->battery_detect = -1;
- goto of_out;
- }
-
- pdata->battery_detect = of_get_named_gpio_flags(of_node,
- "sbs,battery-detect-gpios", 0, &gpio_flags);
-
- if (gpio_flags & OF_GPIO_ACTIVE_LOW)
- pdata->battery_detect_present = 0;
- else
- pdata->battery_detect_present = 1;
-
-of_out:
- return pdata;
-}
-#else
-static struct sbs_platform_data *sbs_of_populate_pdata(
- struct i2c_client *client)
-{
- return client->dev.platform_data;
-}
-#endif
-
static const struct power_supply_desc sbs_default_desc = {
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = sbs_properties,
@@ -819,13 +767,12 @@ static int sbs_probe(struct i2c_client *client,
if (!sbs_desc->name)
return -ENOMEM;
- chip = kzalloc(sizeof(struct sbs_info), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(struct sbs_info), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->client = client;
chip->enable_detection = false;
- chip->gpio_detect = false;
psy_cfg.of_node = client->dev.of_node;
psy_cfg.drv_data = chip;
/* ignore first notification of external change, it is generated
@@ -834,11 +781,31 @@ static int sbs_probe(struct i2c_client *client,
chip->ignore_changes = 1;
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
- pdata = sbs_of_populate_pdata(client);
+ /* use pdata if available, fall back to DT properties,
+ * or hardcoded defaults if not
+ */
+ rc = of_property_read_u32(client->dev.of_node, "sbs,i2c-retry-count",
+ &chip->i2c_retry_count);
+ if (rc)
+ chip->i2c_retry_count = 0;
+
+ rc = of_property_read_u32(client->dev.of_node, "sbs,poll-retry-count",
+ &chip->poll_retry_count);
+ if (rc)
+ chip->poll_retry_count = 0;
if (pdata) {
- chip->gpio_detect = gpio_is_valid(pdata->battery_detect);
- chip->pdata = pdata;
+ chip->poll_retry_count = pdata->poll_retry_count;
+ chip->i2c_retry_count = pdata->i2c_retry_count;
+ }
+ chip->i2c_retry_count = chip->i2c_retry_count + 1;
+
+ chip->gpio_detect = devm_gpiod_get_optional(&client->dev,
+ "sbs,battery-detect", GPIOD_IN);
+ if (IS_ERR(chip->gpio_detect)) {
+ dev_err(&client->dev, "Failed to get gpio: %ld\n",
+ PTR_ERR(chip->gpio_detect));
+ return PTR_ERR(chip->gpio_detect);
}
i2c_set_clientdata(client, chip);
@@ -846,47 +813,26 @@ static int sbs_probe(struct i2c_client *client,
if (!chip->gpio_detect)
goto skip_gpio;
- rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
- if (rc) {
- dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
- chip->gpio_detect = false;
- goto skip_gpio;
- }
-
- rc = gpio_direction_input(pdata->battery_detect);
- if (rc) {
- dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
- gpio_free(pdata->battery_detect);
- chip->gpio_detect = false;
- goto skip_gpio;
- }
-
- irq = gpio_to_irq(pdata->battery_detect);
+ irq = gpiod_to_irq(chip->gpio_detect);
if (irq <= 0) {
dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
- gpio_free(pdata->battery_detect);
- chip->gpio_detect = false;
goto skip_gpio;
}
- rc = request_irq(irq, sbs_irq,
+ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- dev_name(&client->dev), chip->power_supply);
+ dev_name(&client->dev), chip);
if (rc) {
dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
- gpio_free(pdata->battery_detect);
- chip->gpio_detect = false;
goto skip_gpio;
}
- chip->irq = irq;
-
skip_gpio:
/*
* Before we register, we might need to make sure we can actually talk
* to the battery.
*/
- if (!force_load) {
+ if (!(force_load || chip->gpio_detect)) {
rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
if (rc < 0) {
@@ -896,7 +842,7 @@ skip_gpio:
}
}
- chip->power_supply = power_supply_register(&client->dev, sbs_desc,
+ chip->power_supply = devm_power_supply_register(&client->dev, sbs_desc,
&psy_cfg);
if (IS_ERR(chip->power_supply)) {
dev_err(&client->dev,
@@ -915,13 +861,6 @@ skip_gpio:
return 0;
exit_psupply:
- if (chip->irq)
- free_irq(chip->irq, chip->power_supply);
- if (chip->gpio_detect)
- gpio_free(pdata->battery_detect);
-
- kfree(chip);
-
return rc;
}
@@ -929,18 +868,8 @@ static int sbs_remove(struct i2c_client *client)
{
struct sbs_info *chip = i2c_get_clientdata(client);
- if (chip->irq)
- free_irq(chip->irq, chip->power_supply);
- if (chip->gpio_detect)
- gpio_free(chip->pdata->battery_detect);
-
- power_supply_unregister(chip->power_supply);
-
cancel_delayed_work_sync(&chip->work);
- kfree(chip);
- chip = NULL;
-
return 0;
}
@@ -950,16 +879,16 @@ static int sbs_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct sbs_info *chip = i2c_get_clientdata(client);
- s32 ret;
if (chip->poll_time > 0)
cancel_delayed_work_sync(&chip->work);
- /* write to manufacturer access with sleep command */
- ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
+ /*
+ * Write to manufacturer access with sleep command.
+ * Support is manufacturer dependend, so ignore errors.
+ */
+ sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
MANUFACTURER_ACCESS_SLEEP);
- if (chip->is_present && ret < 0)
- return ret;
return 0;
}
@@ -978,13 +907,20 @@ static const struct i2c_device_id sbs_id[] = {
};
MODULE_DEVICE_TABLE(i2c, sbs_id);
+static const struct of_device_id sbs_dt_ids[] = {
+ { .compatible = "sbs,sbs-battery" },
+ { .compatible = "ti,bq20z75" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sbs_dt_ids);
+
static struct i2c_driver sbs_battery_driver = {
.probe = sbs_probe,
.remove = sbs_remove,
.id_table = sbs_id,
.driver = {
.name = "sbs-battery",
- .of_match_table = of_match_ptr(sbs_dt_ids),
+ .of_match_table = sbs_dt_ids,
.pm = SBS_PM_OPS,
},
};
diff --git a/drivers/power/smb347-charger.c b/drivers/power/supply/smb347-charger.c
index 072c5189bd6d..072c5189bd6d 100644
--- a/drivers/power/smb347-charger.c
+++ b/drivers/power/supply/smb347-charger.c
diff --git a/drivers/power/test_power.c b/drivers/power/supply/test_power.c
index 57246cdbd042..57246cdbd042 100644
--- a/drivers/power/test_power.c
+++ b/drivers/power/supply/test_power.c
diff --git a/drivers/power/tosa_battery.c b/drivers/power/supply/tosa_battery.c
index 6e88c1b37945..6e88c1b37945 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/supply/tosa_battery.c
diff --git a/drivers/power/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c
index 1b4b5e09538e..1b4b5e09538e 100644
--- a/drivers/power/tps65090-charger.c
+++ b/drivers/power/supply/tps65090-charger.c
diff --git a/drivers/power/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c
index 4c56e54af6ac..9fd019f9b88c 100644
--- a/drivers/power/tps65217_charger.c
+++ b/drivers/power/supply/tps65217_charger.c
@@ -46,6 +46,8 @@ struct tps65217_charger {
int prev_ac_online;
struct task_struct *poll_task;
+
+ int irq;
};
static enum power_supply_property tps65217_ac_props[] = {
@@ -198,6 +200,7 @@ static int tps65217_charger_probe(struct platform_device *pdev)
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
struct tps65217_charger *charger;
struct power_supply_config cfg = {};
+ int irq;
int ret;
dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -221,18 +224,40 @@ static int tps65217_charger_probe(struct platform_device *pdev)
return PTR_ERR(charger->ac);
}
+ irq = platform_get_irq_byname(pdev, "AC");
+ if (irq < 0)
+ irq = -ENXIO;
+ charger->irq = irq;
+
ret = tps65217_config_charger(charger);
if (ret < 0) {
dev_err(charger->dev, "charger config failed, err %d\n", ret);
return ret;
}
- charger->poll_task = kthread_run(tps65217_charger_poll_task,
- charger, "ktps65217charger");
- if (IS_ERR(charger->poll_task)) {
- ret = PTR_ERR(charger->poll_task);
- dev_err(charger->dev, "Unable to run kthread err %d\n", ret);
- return ret;
+ if (irq != -ENXIO) {
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ tps65217_charger_irq,
+ 0, "tps65217-charger",
+ charger);
+ if (ret) {
+ dev_err(charger->dev,
+ "Unable to register irq %d err %d\n", irq,
+ ret);
+ return ret;
+ }
+
+ /* Check current state */
+ tps65217_charger_irq(irq, charger);
+ } else {
+ charger->poll_task = kthread_run(tps65217_charger_poll_task,
+ charger, "ktps65217charger");
+ if (IS_ERR(charger->poll_task)) {
+ ret = PTR_ERR(charger->poll_task);
+ dev_err(charger->dev,
+ "Unable to run kthread err %d\n", ret);
+ return ret;
+ }
}
return 0;
@@ -242,7 +267,8 @@ static int tps65217_charger_remove(struct platform_device *pdev)
{
struct tps65217_charger *charger = platform_get_drvdata(pdev);
- kthread_stop(charger->poll_task);
+ if (charger->irq == -ENXIO)
+ kthread_stop(charger->poll_task);
return 0;
}
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c
index bcd4dc304f27..bcd4dc304f27 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/supply/twl4030_charger.c
diff --git a/drivers/power/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c
index f5817e422d64..f5817e422d64 100644
--- a/drivers/power/twl4030_madc_battery.c
+++ b/drivers/power/supply/twl4030_madc_battery.c
diff --git a/drivers/power/wm831x_backup.c b/drivers/power/supply/wm831x_backup.c
index 2e33109ca8c7..2e33109ca8c7 100644
--- a/drivers/power/wm831x_backup.c
+++ b/drivers/power/supply/wm831x_backup.c
diff --git a/drivers/power/wm831x_power.c b/drivers/power/supply/wm831x_power.c
index 7082301da945..7082301da945 100644
--- a/drivers/power/wm831x_power.c
+++ b/drivers/power/supply/wm831x_power.c
diff --git a/drivers/power/wm8350_power.c b/drivers/power/supply/wm8350_power.c
index 5c5880664e09..5c5880664e09 100644
--- a/drivers/power/wm8350_power.c
+++ b/drivers/power/supply/wm8350_power.c
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
index c2f09ed35050..6285626d142a 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/supply/wm97xx_battery.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/power/wm97xx_battery.c
- *
* Battery measurement code for WM97xx
*
* based on tosa_battery.c
diff --git a/drivers/power/z2_battery.c b/drivers/power/supply/z2_battery.c
index b201e3facf73..8a43b49cfd35 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/supply/z2_battery.c
@@ -317,7 +317,6 @@ MODULE_DEVICE_TABLE(i2c, z2_batt_id);
static struct i2c_driver z2_batt_driver = {
.driver = {
.name = "z2-battery",
- .owner = THIS_MODULE,
.pm = Z2_BATTERY_PM_OPS
},
.probe = z2_batt_probe,
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index 632701a1d993..b7f300b79ffd 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -958,7 +958,7 @@ static int ps3_vuart_bus_interrupt_get(void)
fail_request_irq:
ps3_vuart_irq_destroy(vuart_bus_priv.virq);
- vuart_bus_priv.virq = NO_IRQ;
+ vuart_bus_priv.virq = 0;
fail_alloc_irq:
kfree(vuart_bus_priv.bmp);
vuart_bus_priv.bmp = NULL;
@@ -982,7 +982,7 @@ static int ps3_vuart_bus_interrupt_put(void)
free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
ps3_vuart_irq_destroy(vuart_bus_priv.virq);
- vuart_bus_priv.virq = NO_IRQ;
+ vuart_bus_priv.virq = 0;
kfree(vuart_bus_priv.bmp);
vuart_bus_priv.bmp = NULL;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 06c75186af80..936f7ccc9736 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -643,11 +643,11 @@ config REGULATOR_RC5T583
outputs which can be controlled by i2c communication.
config REGULATOR_RK808
- tristate "Rockchip RK808 Power regulators"
+ tristate "Rockchip RK808/RK818 Power regulators"
depends on MFD_RK808
help
Select this option to enable the power regulator of ROCKCHIP
- PMIC RK808.
+ PMIC RK808 and RK818.
This driver supports the control of different power rails of device
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 6d9ac76a772f..54382ef902c6 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -244,16 +244,64 @@ static const struct regulator_desc axp22x_drivevbus_regulator = {
.ops = &axp20x_ops_sw,
};
-static const struct regulator_linear_range axp809_dcdc4_ranges[] = {
- REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000),
- REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000),
+static const struct regulator_linear_range axp806_dcdca_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000),
+ REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000),
};
-static const struct regulator_linear_range axp809_dldo1_ranges[] = {
+static const struct regulator_linear_range axp806_dcdcd_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000),
+ REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000),
+};
+
+static const struct regulator_linear_range axp806_cldo2_ranges[] = {
REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000),
REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000),
};
+static const struct regulator_desc axp806_regulators[] = {
+ AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges,
+ 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
+ BIT(0)),
+ AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50,
+ AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)),
+ AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges,
+ 72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
+ BIT(2)),
+ AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges,
+ 64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1,
+ BIT(3)),
+ AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100,
+ AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
+ AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
+ AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)),
+ AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100,
+ AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)),
+ AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
+ AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)),
+ AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100,
+ AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)),
+ AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100,
+ AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)),
+ AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100,
+ AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)),
+ AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100,
+ AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)),
+ AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100,
+ AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)),
+ AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp806_cldo2_ranges,
+ 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2,
+ BIT(5)),
+ AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100,
+ AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)),
+ AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)),
+};
+
+static const struct regulator_linear_range axp809_dcdc4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000),
+};
+
static const struct regulator_desc axp809_regulators[] = {
AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)),
@@ -278,7 +326,7 @@ static const struct regulator_desc axp809_regulators[] = {
AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)),
AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
- AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges,
+ AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp806_cldo2_ranges,
32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
BIT(3)),
AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
@@ -302,6 +350,7 @@ static const struct regulator_desc axp809_regulators[] = {
static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ unsigned int reg = AXP20X_DCDC_FREQ;
u32 min, max, def, step;
switch (axp20x->variant) {
@@ -312,6 +361,14 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
def = 1500;
step = 75;
break;
+ case AXP806_ID:
+ /*
+ * AXP806 DCDC work frequency setting has the same range and
+ * step as AXP22X, but at a different register.
+ * Fall through to the check below.
+ * (See include/linux/mfd/axp20x.h)
+ */
+ reg = AXP806_DCDC_FREQ_CTRL;
case AXP221_ID:
case AXP223_ID:
case AXP809_ID:
@@ -343,7 +400,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
dcdcfreq = (dcdcfreq - min) / step;
- return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
+ return regmap_update_bits(axp20x->regmap, reg,
AXP20X_FREQ_DCDC_MASK, dcdcfreq);
}
@@ -377,6 +434,7 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev)
static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
{
struct axp20x_dev *axp20x = rdev_get_drvdata(rdev);
+ unsigned int reg = AXP20X_DCDC_MODE;
unsigned int mask;
switch (axp20x->variant) {
@@ -392,6 +450,13 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
workmode <<= ffs(mask) - 1;
break;
+ case AXP806_ID:
+ reg = AXP806_DCDC_MODE_CTRL2;
+ /*
+ * AXP806 DCDC regulator IDs have the same range as AXP22X.
+ * Fall through to the check below.
+ * (See include/linux/mfd/axp20x.h)
+ */
case AXP221_ID:
case AXP223_ID:
case AXP809_ID:
@@ -408,7 +473,34 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
return -EINVAL;
}
- return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
+ return regmap_update_bits(rdev->regmap, reg, mask, workmode);
+}
+
+/*
+ * This function checks whether a regulator is part of a poly-phase
+ * output setup based on the registers settings. Returns true if it is.
+ */
+static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
+{
+ u32 reg = 0;
+
+ /* Only AXP806 has poly-phase outputs */
+ if (axp20x->variant != AXP806_ID)
+ return false;
+
+ regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, &reg);
+
+ switch (id) {
+ case AXP806_DCDCB:
+ return (((reg & GENMASK(7, 6)) == BIT(6)) ||
+ ((reg & GENMASK(7, 6)) == BIT(7)));
+ case AXP806_DCDCC:
+ return ((reg & GENMASK(7, 6)) == BIT(7));
+ case AXP806_DCDCE:
+ return !!(reg & BIT(5));
+ }
+
+ return false;
}
static int axp20x_regulator_probe(struct platform_device *pdev)
@@ -440,6 +532,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
"x-powers,drive-vbus-en");
break;
+ case AXP806_ID:
+ regulators = axp806_regulators;
+ nregulators = AXP806_REG_ID_MAX;
+ break;
case AXP809_ID:
regulators = axp809_regulators;
nregulators = AXP809_REG_ID_MAX;
@@ -458,6 +554,14 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
struct regulator_desc *new_desc;
/*
+ * If this regulator is a slave in a poly-phase setup,
+ * skip it, as its controls are bound to the master
+ * regulator and won't work.
+ */
+ if (axp20x_is_polyphase_slave(axp20x, i))
+ continue;
+
+ /*
* Regulators DC1SW and DC5LDO are connected internally,
* so we have to handle their supply names separately.
*
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
index e254272585b2..1b2acc43fea1 100644
--- a/drivers/regulator/qcom_rpm-regulator.c
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -448,6 +448,44 @@ static struct regulator_ops switch_ops = {
};
/*
+ * PM8018 regulators
+ */
+static const struct qcom_rpm_reg pm8018_pldo = {
+ .desc.linear_ranges = pldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
+ .desc.n_voltages = 161,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
+static const struct qcom_rpm_reg pm8018_nldo = {
+ .desc.linear_ranges = nldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
+ .desc.n_voltages = 64,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
+static const struct qcom_rpm_reg pm8018_smps = {
+ .desc.linear_ranges = smps_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
+ .desc.n_voltages = 154,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_smps_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
+static const struct qcom_rpm_reg pm8018_switch = {
+ .desc.ops = &switch_ops,
+ .parts = &rpm8960_switch_parts,
+};
+
+/*
* PM8058 regulators
*/
static const struct qcom_rpm_reg pm8058_pldo = {
@@ -755,6 +793,32 @@ struct rpm_regulator_data {
const char *supply;
};
+static const struct rpm_regulator_data rpm_pm8018_regulators[] = {
+ { "s1", QCOM_RPM_PM8018_SMPS1, &pm8018_smps, "vdd_s1" },
+ { "s2", QCOM_RPM_PM8018_SMPS2, &pm8018_smps, "vdd_s2" },
+ { "s3", QCOM_RPM_PM8018_SMPS3, &pm8018_smps, "vdd_s3" },
+ { "s4", QCOM_RPM_PM8018_SMPS4, &pm8018_smps, "vdd_s4" },
+ { "s5", QCOM_RPM_PM8018_SMPS5, &pm8018_smps, "vdd_s5" },
+
+ { "l2", QCOM_RPM_PM8018_LDO2, &pm8018_pldo, "vdd_l2" },
+ { "l3", QCOM_RPM_PM8018_LDO3, &pm8018_pldo, "vdd_l3" },
+ { "l4", QCOM_RPM_PM8018_LDO4, &pm8018_pldo, "vdd_l4" },
+ { "l5", QCOM_RPM_PM8018_LDO5, &pm8018_pldo, "vdd_l5" },
+ { "l6", QCOM_RPM_PM8018_LDO6, &pm8018_pldo, "vdd_l7" },
+ { "l7", QCOM_RPM_PM8018_LDO7, &pm8018_pldo, "vdd_l7" },
+ { "l8", QCOM_RPM_PM8018_LDO8, &pm8018_nldo, "vdd_l8" },
+ { "l9", QCOM_RPM_PM8018_LDO9, &pm8921_nldo1200,
+ "vdd_l9_l10_l11_l12" },
+ { "l10", QCOM_RPM_PM8018_LDO10, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
+ { "l11", QCOM_RPM_PM8018_LDO11, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
+ { "l12", QCOM_RPM_PM8018_LDO12, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
+ { "l14", QCOM_RPM_PM8018_LDO14, &pm8018_pldo, "vdd_l14" },
+
+ { "lvs1", QCOM_RPM_PM8018_LVS1, &pm8018_switch, "lvs1_in" },
+
+ { }
+};
+
static const struct rpm_regulator_data rpm_pm8058_regulators[] = {
{ "l0", QCOM_RPM_PM8058_LDO0, &pm8058_nldo, "vdd_l0_l1_lvs" },
{ "l1", QCOM_RPM_PM8058_LDO1, &pm8058_nldo, "vdd_l0_l1_lvs" },
@@ -870,6 +934,8 @@ static const struct rpm_regulator_data rpm_pm8921_regulators[] = {
};
static const struct of_device_id rpm_of_match[] = {
+ { .compatible = "qcom,rpm-pm8018-regulators",
+ .data = &rpm_pm8018_regulators },
{ .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators },
{ .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators },
{ .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators },
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index a6767494d39b..3314bf299a51 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -1,11 +1,15 @@
/*
- * Regulator driver for Rockchip RK808
+ * Regulator driver for Rockchip RK808/RK818
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
* Author: Chris Zhong <zyw@rock-chips.com>
* Author: Zhang Qing <zhangqing@rock-chips.com>
*
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ *
* 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.
@@ -32,6 +36,12 @@
#define RK808_BUCK4_VSEL_MASK 0xf
#define RK808_LDO_VSEL_MASK 0x1f
+#define RK818_BUCK_VSEL_MASK 0x3f
+#define RK818_BUCK4_VSEL_MASK 0x1f
+#define RK818_LDO_VSEL_MASK 0x1f
+#define RK818_LDO3_ON_VSEL_MASK 0xf
+#define RK818_BOOST_ON_VSEL_MASK 0xe0
+
/* Ramp rate definitions for buck1 / buck2 only */
#define RK808_RAMP_RATE_OFFSET 3
#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
@@ -454,6 +464,108 @@ static const struct regulator_desc rk808_reg[] = {
RK808_DCDC_EN_REG, BIT(6)),
};
+static const struct regulator_desc rk818_reg[] = {
+ {
+ .name = "DCDC_REG1",
+ .supply_name = "vcc1",
+ .of_match = of_match_ptr("DCDC_REG1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_DCDC1,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK818_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(0),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG2",
+ .supply_name = "vcc2",
+ .of_match = of_match_ptr("DCDC_REG2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_DCDC2,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK818_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(1),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG3",
+ .supply_name = "vcc3",
+ .of_match = of_match_ptr("DCDC_REG3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_DCDC3,
+ .ops = &rk808_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 1,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(2),
+ .owner = THIS_MODULE,
+ },
+ RK8XX_DESC(RK818_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3600, 100,
+ RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(3), 0),
+ RK8XX_DESC(RK818_ID_BOOST, "DCDC_BOOST", "boost", 4700, 5400, 100,
+ RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(4), 0),
+ RK8XX_DESC(RK818_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100,
+ RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(0), 400),
+ RK8XX_DESC(RK818_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
+ RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(1), 400),
+ {
+ .name = "LDO_REG3",
+ .supply_name = "vcc7",
+ .of_match = of_match_ptr("LDO_REG3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_LDO3,
+ .ops = &rk808_reg_ops_ranges,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 16,
+ .linear_ranges = rk808_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
+ .vsel_reg = RK818_LDO3_ON_VSEL_REG,
+ .vsel_mask = RK818_LDO3_ON_VSEL_MASK,
+ .enable_reg = RK818_LDO_EN_REG,
+ .enable_mask = BIT(2),
+ .enable_time = 400,
+ .owner = THIS_MODULE,
+ },
+ RK8XX_DESC(RK818_ID_LDO4, "LDO_REG4", "vcc8", 1800, 3400, 100,
+ RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(3), 400),
+ RK8XX_DESC(RK818_ID_LDO5, "LDO_REG5", "vcc7", 1800, 3400, 100,
+ RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(4), 400),
+ RK8XX_DESC(RK818_ID_LDO6, "LDO_REG6", "vcc8", 800, 2500, 100,
+ RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(5), 400),
+ RK8XX_DESC(RK818_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100,
+ RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(6), 400),
+ RK8XX_DESC(RK818_ID_LDO8, "LDO_REG8", "vcc8", 1800, 3400, 100,
+ RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(7), 400),
+ RK8XX_DESC(RK818_ID_LDO9, "LDO_REG9", "vcc9", 1800, 3400, 100,
+ RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(5), 400),
+ RK8XX_DESC_SWITCH(RK818_ID_SWITCH, "SWITCH_REG", "vcc9",
+ RK818_DCDC_EN_REG, BIT(6)),
+ RK8XX_DESC_SWITCH(RK818_ID_HDMI_SWITCH, "HDMI_SWITCH", "h_5v",
+ RK818_H5V_EN_REG, BIT(0)),
+ RK8XX_DESC_SWITCH(RK818_ID_OTG_SWITCH, "OTG_SWITCH", "usb",
+ RK818_DCDC_EN_REG, BIT(7)),
+};
+
static int rk808_regulator_dt_parse_pdata(struct device *dev,
struct device *client_dev,
struct regmap *map,
@@ -499,7 +611,8 @@ static int rk808_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {};
struct regulator_dev *rk808_rdev;
struct rk808_regulator_data *pdata;
- int ret, i;
+ const struct regulator_desc *regulators;
+ int ret, i, nregulators;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -512,14 +625,29 @@ static int rk808_regulator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pdata);
+ switch (rk808->variant) {
+ case RK808_ID:
+ regulators = rk808_reg;
+ nregulators = RK808_NUM_REGULATORS;
+ break;
+ case RK818_ID:
+ regulators = rk818_reg;
+ nregulators = RK818_NUM_REGULATORS;
+ break;
+ default:
+ dev_err(&client->dev, "unsupported RK8XX ID %lu\n",
+ rk808->variant);
+ return -EINVAL;
+ }
+
config.dev = &client->dev;
config.driver_data = pdata;
config.regmap = rk808->regmap;
/* Instantiate the regulators */
- for (i = 0; i < RK808_NUM_REGULATORS; i++) {
+ for (i = 0; i < nregulators; i++) {
rk808_rdev = devm_regulator_register(&pdev->dev,
- &rk808_reg[i], &config);
+ &regulators[i], &config);
if (IS_ERR(rk808_rdev)) {
dev_err(&client->dev,
"failed to register %d regulator\n", i);
@@ -539,8 +667,9 @@ static struct platform_driver rk808_regulator_driver = {
module_platform_driver(rk808_regulator_driver);
-MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
-MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>");
-MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>");
+MODULE_DESCRIPTION("regulator driver for the RK808/RK818 series PMICs");
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
+MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:rk808-regulator");
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 1a8bf76a925f..f396bfef5d42 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -17,7 +17,7 @@ config OMAP_REMOTEPROC
select REMOTEPROC
select MAILBOX
select OMAP2PLUS_MBOX
- select RPMSG
+ select RPMSG_VIRTIO
help
Say y here to support OMAP's remote processors (dual M3
and DSP on OMAP4) via the remote processor framework.
@@ -59,7 +59,7 @@ config DA8XX_REMOTEPROC
depends on ARCH_DAVINCI_DA8XX
select CMA if MMU
select REMOTEPROC
- select RPMSG
+ select RPMSG_VIRTIO
help
Say y here to support DA8xx/OMAP-L13x remote processors via the
remote processor framework.
@@ -91,6 +91,22 @@ config QCOM_Q6V5_PIL
Say y here to support the Qualcomm Peripherial Image Loader for the
Hexagon V5 based remote processors.
+config QCOM_WCNSS_IRIS
+ tristate
+ depends on OF && ARCH_QCOM
+
+config QCOM_WCNSS_PIL
+ tristate "Qualcomm WCNSS Peripheral Image Loader"
+ depends on OF && ARCH_QCOM
+ depends on QCOM_SMEM
+ select QCOM_MDT_LOADER
+ select QCOM_SCM
+ select QCOM_WCNSS_IRIS
+ select REMOTEPROC
+ help
+ Say y here to support the Peripheral Image Loader for the Qualcomm
+ Wireless Connectivity Subsystem.
+
config ST_REMOTEPROC
tristate "ST remoteproc support"
depends on ARCH_STI
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 92d3758bd15c..6dfb62ed643f 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -13,4 +13,6 @@ obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
obj-$(CONFIG_QCOM_MDT_LOADER) += qcom_mdt_loader.o
obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
+obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o
+obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o
obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index 009e56f67de2..1afac8f31be0 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -147,7 +147,7 @@ static void da8xx_rproc_kick(struct rproc *rproc, int vqid)
{
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
- /* Interupt remote proc */
+ /* Interrupt remote proc */
writel(SYSCFG_CHIPSIG2, drproc->chipsig);
}
@@ -261,7 +261,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
return 0;
free_rproc:
- rproc_put(rproc);
+ rproc_free(rproc);
return ret;
}
@@ -290,7 +290,7 @@ static int da8xx_rproc_remove(struct platform_device *pdev)
disable_irq(drproc->irq);
rproc_del(rproc);
- rproc_put(rproc);
+ rproc_free(rproc);
return 0;
}
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index b74368a91235..fa63bf2eb885 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -96,7 +96,8 @@ static void omap_rproc_kick(struct rproc *rproc, int vqid)
/* send the index of the triggered virtqueue in the mailbox payload */
ret = mbox_send_message(oproc->mbox, (void *)vqid);
if (ret < 0)
- dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret);
+ dev_err(dev, "failed to send mailbox message, status = %d\n",
+ ret);
}
/*
@@ -196,7 +197,7 @@ static int omap_rproc_probe(struct platform_device *pdev)
}
rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops,
- pdata->firmware, sizeof(*oproc));
+ pdata->firmware, sizeof(*oproc));
if (!rproc)
return -ENOMEM;
@@ -214,7 +215,7 @@ static int omap_rproc_probe(struct platform_device *pdev)
return 0;
free_rproc:
- rproc_put(rproc);
+ rproc_free(rproc);
return ret;
}
@@ -223,7 +224,7 @@ static int omap_rproc_remove(struct platform_device *pdev)
struct rproc *rproc = platform_get_drvdata(pdev);
rproc_del(rproc);
- rproc_put(rproc);
+ rproc_free(rproc);
return 0;
}
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index 2a1b2c7d8f2c..2e0caaaa766a 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -863,8 +863,10 @@ static int q6v5_probe(struct platform_device *pdev)
goto free_rproc;
qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
- if (IS_ERR(qproc->state))
+ if (IS_ERR(qproc->state)) {
+ ret = PTR_ERR(qproc->state);
goto free_rproc;
+ }
ret = rproc_add(rproc);
if (ret)
@@ -873,7 +875,7 @@ static int q6v5_probe(struct platform_device *pdev)
return 0;
free_rproc:
- rproc_put(rproc);
+ rproc_free(rproc);
return ret;
}
@@ -883,7 +885,7 @@ static int q6v5_remove(struct platform_device *pdev)
struct q6v5 *qproc = platform_get_drvdata(pdev);
rproc_del(qproc->rproc);
- rproc_put(qproc->rproc);
+ rproc_free(qproc->rproc);
return 0;
}
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
new file mode 100644
index 000000000000..f5cedeaafba1
--- /dev/null
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -0,0 +1,624 @@
+/*
+ * Qualcomm Wireless Connectivity Subsystem Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_scm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/remoteproc.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+#include "qcom_mdt_loader.h"
+#include "remoteproc_internal.h"
+#include "qcom_wcnss.h"
+
+#define WCNSS_CRASH_REASON_SMEM 422
+#define WCNSS_FIRMWARE_NAME "wcnss.mdt"
+#define WCNSS_PAS_ID 6
+
+#define WCNSS_SPARE_NVBIN_DLND BIT(25)
+
+#define WCNSS_PMU_IRIS_XO_CFG BIT(3)
+#define WCNSS_PMU_IRIS_XO_EN BIT(4)
+#define WCNSS_PMU_GC_BUS_MUX_SEL_TOP BIT(5)
+#define WCNSS_PMU_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_IRIS_RESET BIT(7)
+#define WCNSS_PMU_IRIS_RESET_STS BIT(8) /* 1: in progress, 0: done */
+#define WCNSS_PMU_IRIS_XO_READ BIT(9)
+#define WCNSS_PMU_IRIS_XO_READ_STS BIT(10)
+
+#define WCNSS_PMU_XO_MODE_MASK GENMASK(2, 1)
+#define WCNSS_PMU_XO_MODE_19p2 0
+#define WCNSS_PMU_XO_MODE_48 3
+
+struct wcnss_data {
+ size_t pmu_offset;
+ size_t spare_offset;
+
+ const struct wcnss_vreg_info *vregs;
+ size_t num_vregs;
+};
+
+struct qcom_wcnss {
+ struct device *dev;
+ struct rproc *rproc;
+
+ void __iomem *pmu_cfg;
+ void __iomem *spare_out;
+
+ bool use_48mhz_xo;
+
+ int wdog_irq;
+ int fatal_irq;
+ int ready_irq;
+ int handover_irq;
+ int stop_ack_irq;
+
+ struct qcom_smem_state *state;
+ unsigned stop_bit;
+
+ struct mutex iris_lock;
+ struct qcom_iris *iris;
+
+ struct regulator_bulk_data *vregs;
+ size_t num_vregs;
+
+ struct completion start_done;
+ struct completion stop_done;
+
+ phys_addr_t mem_phys;
+ phys_addr_t mem_reloc;
+ void *mem_region;
+ size_t mem_size;
+};
+
+static const struct wcnss_data riva_data = {
+ .pmu_offset = 0x28,
+ .spare_offset = 0xb4,
+
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddmx", 1050000, 1150000, 0 },
+ { "vddcx", 1050000, 1150000, 0 },
+ { "vddpx", 1800000, 1800000, 0 },
+ },
+ .num_vregs = 3,
+};
+
+static const struct wcnss_data pronto_v1_data = {
+ .pmu_offset = 0x1004,
+ .spare_offset = 0x1088,
+
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddmx", 950000, 1150000, 0 },
+ { "vddcx", .super_turbo = true},
+ { "vddpx", 1800000, 1800000, 0 },
+ },
+ .num_vregs = 3,
+};
+
+static const struct wcnss_data pronto_v2_data = {
+ .pmu_offset = 0x1004,
+ .spare_offset = 0x1088,
+
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddmx", 1287500, 1287500, 0 },
+ { "vddcx", .super_turbo = true },
+ { "vddpx", 1800000, 1800000, 0 },
+ },
+ .num_vregs = 3,
+};
+
+void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
+ struct qcom_iris *iris,
+ bool use_48mhz_xo)
+{
+ mutex_lock(&wcnss->iris_lock);
+
+ wcnss->iris = iris;
+ wcnss->use_48mhz_xo = use_48mhz_xo;
+
+ mutex_unlock(&wcnss->iris_lock);
+}
+EXPORT_SYMBOL_GPL(qcom_wcnss_assign_iris);
+
+static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
+{
+ struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+ phys_addr_t fw_addr;
+ size_t fw_size;
+ bool relocate;
+ int ret;
+
+ ret = qcom_scm_pas_init_image(WCNSS_PAS_ID, fw->data, fw->size);
+ if (ret) {
+ dev_err(&rproc->dev, "invalid firmware metadata\n");
+ return ret;
+ }
+
+ ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
+ if (ret) {
+ dev_err(&rproc->dev, "failed to parse mdt header\n");
+ return ret;
+ }
+
+ if (relocate) {
+ wcnss->mem_reloc = fw_addr;
+
+ ret = qcom_scm_pas_mem_setup(WCNSS_PAS_ID, wcnss->mem_phys, fw_size);
+ if (ret) {
+ dev_err(&rproc->dev, "unable to setup memory for image\n");
+ return ret;
+ }
+ }
+
+ return qcom_mdt_load(rproc, fw, rproc->firmware);
+}
+
+static const struct rproc_fw_ops wcnss_fw_ops = {
+ .find_rsc_table = qcom_mdt_find_rsc_table,
+ .load = wcnss_load,
+};
+
+static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
+{
+ u32 val;
+
+ /* Indicate NV download capability */
+ val = readl(wcnss->spare_out);
+ val |= WCNSS_SPARE_NVBIN_DLND;
+ writel(val, wcnss->spare_out);
+}
+
+static void wcnss_configure_iris(struct qcom_wcnss *wcnss)
+{
+ u32 val;
+
+ /* Clear PMU cfg register */
+ writel(0, wcnss->pmu_cfg);
+
+ val = WCNSS_PMU_GC_BUS_MUX_SEL_TOP | WCNSS_PMU_IRIS_XO_EN;
+ writel(val, wcnss->pmu_cfg);
+
+ /* Clear XO_MODE */
+ val &= ~WCNSS_PMU_XO_MODE_MASK;
+ if (wcnss->use_48mhz_xo)
+ val |= WCNSS_PMU_XO_MODE_48 << 1;
+ else
+ val |= WCNSS_PMU_XO_MODE_19p2 << 1;
+ writel(val, wcnss->pmu_cfg);
+
+ /* Reset IRIS */
+ val |= WCNSS_PMU_IRIS_RESET;
+ writel(val, wcnss->pmu_cfg);
+
+ /* Wait for PMU.iris_reg_reset_sts */
+ while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_RESET_STS)
+ cpu_relax();
+
+ /* Clear IRIS reset */
+ val &= ~WCNSS_PMU_IRIS_RESET;
+ writel(val, wcnss->pmu_cfg);
+
+ /* Start IRIS XO configuration */
+ val |= WCNSS_PMU_IRIS_XO_CFG;
+ writel(val, wcnss->pmu_cfg);
+
+ /* Wait for XO configuration to finish */
+ while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_XO_CFG_STS)
+ cpu_relax();
+
+ /* Stop IRIS XO configuration */
+ val &= ~WCNSS_PMU_GC_BUS_MUX_SEL_TOP;
+ val &= ~WCNSS_PMU_IRIS_XO_CFG;
+ writel(val, wcnss->pmu_cfg);
+
+ /* Add some delay for XO to settle */
+ msleep(20);
+}
+
+static int wcnss_start(struct rproc *rproc)
+{
+ struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+ int ret;
+
+ mutex_lock(&wcnss->iris_lock);
+ if (!wcnss->iris) {
+ dev_err(wcnss->dev, "no iris registered\n");
+ ret = -EINVAL;
+ goto release_iris_lock;
+ }
+
+ ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs);
+ if (ret)
+ goto release_iris_lock;
+
+ ret = qcom_iris_enable(wcnss->iris);
+ if (ret)
+ goto disable_regulators;
+
+ wcnss_indicate_nv_download(wcnss);
+ wcnss_configure_iris(wcnss);
+
+ ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
+ if (ret) {
+ dev_err(wcnss->dev,
+ "failed to authenticate image and release reset\n");
+ goto disable_iris;
+ }
+
+ ret = wait_for_completion_timeout(&wcnss->start_done,
+ msecs_to_jiffies(5000));
+ if (wcnss->ready_irq > 0 && ret == 0) {
+ /* We have a ready_irq, but it didn't fire in time. */
+ dev_err(wcnss->dev, "start timed out\n");
+ qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ ret = -ETIMEDOUT;
+ goto disable_iris;
+ }
+
+ ret = 0;
+
+disable_iris:
+ qcom_iris_disable(wcnss->iris);
+disable_regulators:
+ regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs);
+release_iris_lock:
+ mutex_unlock(&wcnss->iris_lock);
+
+ return ret;
+}
+
+static int wcnss_stop(struct rproc *rproc)
+{
+ struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+ int ret;
+
+ if (wcnss->state) {
+ qcom_smem_state_update_bits(wcnss->state,
+ BIT(wcnss->stop_bit),
+ BIT(wcnss->stop_bit));
+
+ ret = wait_for_completion_timeout(&wcnss->stop_done,
+ msecs_to_jiffies(5000));
+ if (ret == 0)
+ dev_err(wcnss->dev, "timed out on wait\n");
+
+ qcom_smem_state_update_bits(wcnss->state,
+ BIT(wcnss->stop_bit),
+ 0);
+ }
+
+ ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ if (ret)
+ dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
+
+ return ret;
+}
+
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+ struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+ int offset;
+
+ offset = da - wcnss->mem_reloc;
+ if (offset < 0 || offset + len > wcnss->mem_size)
+ return NULL;
+
+ return wcnss->mem_region + offset;
+}
+
+static const struct rproc_ops wcnss_ops = {
+ .start = wcnss_start,
+ .stop = wcnss_stop,
+ .da_to_va = wcnss_da_to_va,
+};
+
+static irqreturn_t wcnss_wdog_interrupt(int irq, void *dev)
+{
+ struct qcom_wcnss *wcnss = dev;
+
+ rproc_report_crash(wcnss->rproc, RPROC_WATCHDOG);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)
+{
+ struct qcom_wcnss *wcnss = dev;
+ size_t len;
+ char *msg;
+
+ msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, WCNSS_CRASH_REASON_SMEM, &len);
+ if (!IS_ERR(msg) && len > 0 && msg[0])
+ dev_err(wcnss->dev, "fatal error received: %s\n", msg);
+
+ rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);
+
+ if (!IS_ERR(msg))
+ msg[0] = '\0';
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_ready_interrupt(int irq, void *dev)
+{
+ struct qcom_wcnss *wcnss = dev;
+
+ complete(&wcnss->start_done);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_handover_interrupt(int irq, void *dev)
+{
+ /*
+ * XXX: At this point we're supposed to release the resources that we
+ * have been holding on behalf of the WCNSS. Unfortunately this
+ * interrupt comes way before the other side seems to be done.
+ *
+ * So we're currently relying on the ready interrupt firing later then
+ * this and we just disable the resources at the end of wcnss_start().
+ */
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)
+{
+ struct qcom_wcnss *wcnss = dev;
+
+ complete(&wcnss->stop_done);
+
+ return IRQ_HANDLED;
+}
+
+static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
+ const struct wcnss_vreg_info *info,
+ int num_vregs)
+{
+ struct regulator_bulk_data *bulk;
+ int ret;
+ int i;
+
+ bulk = devm_kcalloc(wcnss->dev,
+ num_vregs, sizeof(struct regulator_bulk_data),
+ GFP_KERNEL);
+ if (!bulk)
+ return -ENOMEM;
+
+ for (i = 0; i < num_vregs; i++)
+ bulk[i].supply = info[i].name;
+
+ ret = devm_regulator_bulk_get(wcnss->dev, num_vregs, bulk);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_vregs; i++) {
+ if (info[i].max_voltage)
+ regulator_set_voltage(bulk[i].consumer,
+ info[i].min_voltage,
+ info[i].max_voltage);
+
+ if (info[i].load_uA)
+ regulator_set_load(bulk[i].consumer, info[i].load_uA);
+ }
+
+ wcnss->vregs = bulk;
+ wcnss->num_vregs = num_vregs;
+
+ return 0;
+}
+
+static int wcnss_request_irq(struct qcom_wcnss *wcnss,
+ struct platform_device *pdev,
+ const char *name,
+ bool optional,
+ irq_handler_t thread_fn)
+{
+ int ret;
+
+ ret = platform_get_irq_byname(pdev, name);
+ if (ret < 0 && optional) {
+ dev_dbg(&pdev->dev, "no %s IRQ defined, ignoring\n", name);
+ return 0;
+ } else if (ret < 0) {
+ dev_err(&pdev->dev, "no %s IRQ defined\n", name);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, ret,
+ NULL, thread_fn,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "wcnss", wcnss);
+ if (ret)
+ dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+
+ return ret;
+}
+
+static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
+{
+ struct device_node *node;
+ struct resource r;
+ int ret;
+
+ node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);
+ if (!node) {
+ dev_err(wcnss->dev, "no memory-region specified\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(node, 0, &r);
+ if (ret)
+ return ret;
+
+ wcnss->mem_phys = wcnss->mem_reloc = r.start;
+ wcnss->mem_size = resource_size(&r);
+ wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
+ if (!wcnss->mem_region) {
+ dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n",
+ &r.start, wcnss->mem_size);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int wcnss_probe(struct platform_device *pdev)
+{
+ const struct wcnss_data *data;
+ struct qcom_wcnss *wcnss;
+ struct resource *res;
+ struct rproc *rproc;
+ void __iomem *mmio;
+ int ret;
+
+ data = of_device_get_match_data(&pdev->dev);
+
+ if (!qcom_scm_is_available())
+ return -EPROBE_DEFER;
+
+ if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
+ dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
+ return -ENXIO;
+ }
+
+ rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,
+ WCNSS_FIRMWARE_NAME, sizeof(*wcnss));
+ if (!rproc) {
+ dev_err(&pdev->dev, "unable to allocate remoteproc\n");
+ return -ENOMEM;
+ }
+
+ rproc->fw_ops = &wcnss_fw_ops;
+
+ wcnss = (struct qcom_wcnss *)rproc->priv;
+ wcnss->dev = &pdev->dev;
+ wcnss->rproc = rproc;
+ platform_set_drvdata(pdev, wcnss);
+
+ init_completion(&wcnss->start_done);
+ init_completion(&wcnss->stop_done);
+
+ mutex_init(&wcnss->iris_lock);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu");
+ mmio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mmio)) {
+ ret = PTR_ERR(mmio);
+ goto free_rproc;
+ };
+
+ ret = wcnss_alloc_memory_region(wcnss);
+ if (ret)
+ goto free_rproc;
+
+ wcnss->pmu_cfg = mmio + data->pmu_offset;
+ wcnss->spare_out = mmio + data->spare_offset;
+
+ ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs);
+ if (ret)
+ goto free_rproc;
+
+ ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt);
+ if (ret < 0)
+ goto free_rproc;
+ wcnss->wdog_irq = ret;
+
+ ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt);
+ if (ret < 0)
+ goto free_rproc;
+ wcnss->fatal_irq = ret;
+
+ ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt);
+ if (ret < 0)
+ goto free_rproc;
+ wcnss->ready_irq = ret;
+
+ ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt);
+ if (ret < 0)
+ goto free_rproc;
+ wcnss->handover_irq = ret;
+
+ ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt);
+ if (ret < 0)
+ goto free_rproc;
+ wcnss->stop_ack_irq = ret;
+
+ if (wcnss->stop_ack_irq) {
+ wcnss->state = qcom_smem_state_get(&pdev->dev, "stop",
+ &wcnss->stop_bit);
+ if (IS_ERR(wcnss->state)) {
+ ret = PTR_ERR(wcnss->state);
+ goto free_rproc;
+ }
+ }
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto free_rproc;
+
+ return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+free_rproc:
+ rproc_free(rproc);
+
+ return ret;
+}
+
+static int wcnss_remove(struct platform_device *pdev)
+{
+ struct qcom_wcnss *wcnss = platform_get_drvdata(pdev);
+
+ of_platform_depopulate(&pdev->dev);
+
+ qcom_smem_state_put(wcnss->state);
+ rproc_del(wcnss->rproc);
+ rproc_free(wcnss->rproc);
+
+ return 0;
+}
+
+static const struct of_device_id wcnss_of_match[] = {
+ { .compatible = "qcom,riva-pil", &riva_data },
+ { .compatible = "qcom,pronto-v1-pil", &pronto_v1_data },
+ { .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },
+ { },
+};
+
+static struct platform_driver wcnss_driver = {
+ .probe = wcnss_probe,
+ .remove = wcnss_remove,
+ .driver = {
+ .name = "qcom-wcnss-pil",
+ .of_match_table = wcnss_of_match,
+ },
+};
+
+module_platform_driver(wcnss_driver);
+MODULE_DESCRIPTION("Qualcomm Peripherial Image Loader for Wireless Subsystem");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_wcnss.h b/drivers/remoteproc/qcom_wcnss.h
new file mode 100644
index 000000000000..9dc4a9fe41e1
--- /dev/null
+++ b/drivers/remoteproc/qcom_wcnss.h
@@ -0,0 +1,22 @@
+#ifndef __QCOM_WNCSS_H__
+#define __QCOM_WNCSS_H__
+
+struct qcom_iris;
+struct qcom_wcnss;
+
+struct wcnss_vreg_info {
+ const char * const name;
+ int min_voltage;
+ int max_voltage;
+
+ int load_uA;
+
+ bool super_turbo;
+};
+
+int qcom_iris_enable(struct qcom_iris *iris);
+void qcom_iris_disable(struct qcom_iris *iris);
+
+void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, struct qcom_iris *iris, bool use_48mhz_xo);
+
+#endif
diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c
new file mode 100644
index 000000000000..f0ca24a8dd0b
--- /dev/null
+++ b/drivers/remoteproc/qcom_wcnss_iris.c
@@ -0,0 +1,188 @@
+/*
+ * Qualcomm Wireless Connectivity Subsystem Iris driver
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include "qcom_wcnss.h"
+
+struct qcom_iris {
+ struct device *dev;
+
+ struct clk *xo_clk;
+
+ struct regulator_bulk_data *vregs;
+ size_t num_vregs;
+};
+
+struct iris_data {
+ const struct wcnss_vreg_info *vregs;
+ size_t num_vregs;
+
+ bool use_48mhz_xo;
+};
+
+static const struct iris_data wcn3620_data = {
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddxo", 1800000, 1800000, 10000 },
+ { "vddrfa", 1300000, 1300000, 100000 },
+ { "vddpa", 3300000, 3300000, 515000 },
+ { "vdddig", 1800000, 1800000, 10000 },
+ },
+ .num_vregs = 4,
+ .use_48mhz_xo = false,
+};
+
+static const struct iris_data wcn3660_data = {
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddxo", 1800000, 1800000, 10000 },
+ { "vddrfa", 1300000, 1300000, 100000 },
+ { "vddpa", 2900000, 3000000, 515000 },
+ { "vdddig", 1200000, 1225000, 10000 },
+ },
+ .num_vregs = 4,
+ .use_48mhz_xo = true,
+};
+
+static const struct iris_data wcn3680_data = {
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddxo", 1800000, 1800000, 10000 },
+ { "vddrfa", 1300000, 1300000, 100000 },
+ { "vddpa", 3300000, 3300000, 515000 },
+ { "vdddig", 1800000, 1800000, 10000 },
+ },
+ .num_vregs = 4,
+ .use_48mhz_xo = true,
+};
+
+int qcom_iris_enable(struct qcom_iris *iris)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(iris->num_vregs, iris->vregs);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(iris->xo_clk);
+ if (ret) {
+ dev_err(iris->dev, "failed to enable xo clk\n");
+ goto disable_regulators;
+ }
+
+ return 0;
+
+disable_regulators:
+ regulator_bulk_disable(iris->num_vregs, iris->vregs);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_iris_enable);
+
+void qcom_iris_disable(struct qcom_iris *iris)
+{
+ clk_disable_unprepare(iris->xo_clk);
+ regulator_bulk_disable(iris->num_vregs, iris->vregs);
+}
+EXPORT_SYMBOL_GPL(qcom_iris_disable);
+
+static int qcom_iris_probe(struct platform_device *pdev)
+{
+ const struct iris_data *data;
+ struct qcom_wcnss *wcnss;
+ struct qcom_iris *iris;
+ int ret;
+ int i;
+
+ iris = devm_kzalloc(&pdev->dev, sizeof(struct qcom_iris), GFP_KERNEL);
+ if (!iris)
+ return -ENOMEM;
+
+ data = of_device_get_match_data(&pdev->dev);
+ wcnss = dev_get_drvdata(pdev->dev.parent);
+
+ iris->xo_clk = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(iris->xo_clk)) {
+ if (PTR_ERR(iris->xo_clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to acquire xo clk\n");
+ return PTR_ERR(iris->xo_clk);
+ }
+
+ iris->num_vregs = data->num_vregs;
+ iris->vregs = devm_kcalloc(&pdev->dev,
+ iris->num_vregs,
+ sizeof(struct regulator_bulk_data),
+ GFP_KERNEL);
+ if (!iris->vregs)
+ return -ENOMEM;
+
+ for (i = 0; i < iris->num_vregs; i++)
+ iris->vregs[i].supply = data->vregs[i].name;
+
+ ret = devm_regulator_bulk_get(&pdev->dev, iris->num_vregs, iris->vregs);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get regulators\n");
+ return ret;
+ }
+
+ for (i = 0; i < iris->num_vregs; i++) {
+ if (data->vregs[i].max_voltage)
+ regulator_set_voltage(iris->vregs[i].consumer,
+ data->vregs[i].min_voltage,
+ data->vregs[i].max_voltage);
+
+ if (data->vregs[i].load_uA)
+ regulator_set_load(iris->vregs[i].consumer,
+ data->vregs[i].load_uA);
+ }
+
+ qcom_wcnss_assign_iris(wcnss, iris, data->use_48mhz_xo);
+
+ return 0;
+}
+
+static int qcom_iris_remove(struct platform_device *pdev)
+{
+ struct qcom_wcnss *wcnss = dev_get_drvdata(pdev->dev.parent);
+
+ qcom_wcnss_assign_iris(wcnss, NULL, false);
+
+ return 0;
+}
+
+static const struct of_device_id iris_of_match[] = {
+ { .compatible = "qcom,wcn3620", .data = &wcn3620_data },
+ { .compatible = "qcom,wcn3660", .data = &wcn3660_data },
+ { .compatible = "qcom,wcn3680", .data = &wcn3680_data },
+ {}
+};
+
+static struct platform_driver wcnss_driver = {
+ .probe = qcom_iris_probe,
+ .remove = qcom_iris_remove,
+ .driver = {
+ .name = "qcom-iris",
+ .of_match_table = iris_of_match,
+ },
+};
+
+module_platform_driver(wcnss_driver);
+MODULE_DESCRIPTION("Qualcomm Wireless Subsystem Iris driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index fe0539ed9cb5..c6bfb3496684 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -78,7 +78,7 @@ static const char *rproc_crash_to_string(enum rproc_crash_type type)
* will try to access an unmapped device address.
*/
static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
- unsigned long iova, int flags, void *token)
+ unsigned long iova, int flags, void *token)
{
struct rproc *rproc = token;
@@ -236,8 +236,8 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
}
notifyid = ret;
- dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
- (unsigned long long)dma, size, notifyid);
+ dev_dbg(dev, "vring%d: va %p dma %pad size 0x%x idr %d\n",
+ i, va, &dma, size, notifyid);
rvring->va = va;
rvring->dma = dma;
@@ -263,19 +263,13 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
struct rproc_vring *rvring = &rvdev->vring[i];
- dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n",
- i, vring->da, vring->num, vring->align);
-
- /* make sure reserved bytes are zeroes */
- if (vring->reserved) {
- dev_err(dev, "vring rsc has non zero reserved bytes\n");
- return -EINVAL;
- }
+ dev_dbg(dev, "vdev rsc: vring%d: da 0x%x, qsz %d, align %d\n",
+ i, vring->da, vring->num, vring->align);
/* verify queue size and vring alignment are sane */
if (!vring->num || !vring->align) {
dev_err(dev, "invalid qsz (%d) or alignment (%d)\n",
- vring->num, vring->align);
+ vring->num, vring->align);
return -EINVAL;
}
@@ -330,7 +324,7 @@ void rproc_free_vring(struct rproc_vring *rvring)
* Returns 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
- int offset, int avail)
+ int offset, int avail)
{
struct device *dev = &rproc->dev;
struct rproc_vdev *rvdev;
@@ -349,7 +343,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
return -EINVAL;
}
- dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n",
+ dev_dbg(dev, "vdev rsc: id %d, dfeatures 0x%x, cfg len %d, %d vrings\n",
rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings);
/* we currently support only two vrings per rvdev */
@@ -358,7 +352,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
return -EINVAL;
}
- rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL);
+ rvdev = kzalloc(sizeof(*rvdev), GFP_KERNEL);
if (!rvdev)
return -ENOMEM;
@@ -407,7 +401,7 @@ free_rvdev:
* Returns 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
- int offset, int avail)
+ int offset, int avail)
{
struct rproc_mem_entry *trace;
struct device *dev = &rproc->dev;
@@ -455,8 +449,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
rproc->num_traces++;
- dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", name, ptr,
- rsc->da, rsc->len);
+ dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n",
+ name, ptr, rsc->da, rsc->len);
return 0;
}
@@ -487,7 +481,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
* are outside those ranges.
*/
static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
- int offset, int avail)
+ int offset, int avail)
{
struct rproc_mem_entry *mapping;
struct device *dev = &rproc->dev;
@@ -530,7 +524,7 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
list_add_tail(&mapping->node, &rproc->mappings);
dev_dbg(dev, "mapped devmem pa 0x%x, da 0x%x, len 0x%x\n",
- rsc->pa, rsc->da, rsc->len);
+ rsc->pa, rsc->da, rsc->len);
return 0;
@@ -558,9 +552,8 @@ out:
* pressure is important; it may have a substantial impact on performance.
*/
static int rproc_handle_carveout(struct rproc *rproc,
- struct fw_rsc_carveout *rsc,
- int offset, int avail)
-
+ struct fw_rsc_carveout *rsc,
+ int offset, int avail)
{
struct rproc_mem_entry *carveout, *mapping;
struct device *dev = &rproc->dev;
@@ -579,8 +572,8 @@ static int rproc_handle_carveout(struct rproc *rproc,
return -EINVAL;
}
- dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n",
- rsc->da, rsc->pa, rsc->len, rsc->flags);
+ dev_dbg(dev, "carveout rsc: name: %s, da 0x%x, pa 0x%x, len 0x%x, flags 0x%x\n",
+ rsc->name, rsc->da, rsc->pa, rsc->len, rsc->flags);
carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
if (!carveout)
@@ -588,13 +581,14 @@ static int rproc_handle_carveout(struct rproc *rproc,
va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL);
if (!va) {
- dev_err(dev->parent, "dma_alloc_coherent err: %d\n", rsc->len);
+ dev_err(dev->parent,
+ "failed to allocate dma memory: len 0x%x\n", rsc->len);
ret = -ENOMEM;
goto free_carv;
}
- dev_dbg(dev, "carveout va %p, dma %llx, len 0x%x\n", va,
- (unsigned long long)dma, rsc->len);
+ dev_dbg(dev, "carveout va %p, dma %pad, len 0x%x\n",
+ va, &dma, rsc->len);
/*
* Ok, this is non-standard.
@@ -616,13 +610,12 @@ static int rproc_handle_carveout(struct rproc *rproc,
if (rproc->domain) {
mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
if (!mapping) {
- dev_err(dev, "kzalloc mapping failed\n");
ret = -ENOMEM;
goto dma_free;
}
ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len,
- rsc->flags);
+ rsc->flags);
if (ret) {
dev_err(dev, "iommu_map failed: %d\n", ret);
goto free_mapping;
@@ -639,8 +632,8 @@ static int rproc_handle_carveout(struct rproc *rproc,
mapping->len = rsc->len;
list_add_tail(&mapping->node, &rproc->mappings);
- dev_dbg(dev, "carveout mapped 0x%x to 0x%llx\n",
- rsc->da, (unsigned long long)dma);
+ dev_dbg(dev, "carveout mapped 0x%x to %pad\n",
+ rsc->da, &dma);
}
/*
@@ -697,17 +690,13 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
- [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
+ [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings,
};
static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = {
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
};
-static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = {
- [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings,
-};
-
/* handle firmware resource entries before booting the remote processor */
static int rproc_handle_resources(struct rproc *rproc, int len,
rproc_handle_resource_t handlers[RSC_LAST])
@@ -757,6 +746,7 @@ static int rproc_handle_resources(struct rproc *rproc, int len,
static void rproc_resource_cleanup(struct rproc *rproc)
{
struct rproc_mem_entry *entry, *tmp;
+ struct rproc_vdev *rvdev, *rvtmp;
struct device *dev = &rproc->dev;
/* clean up debugfs trace entries */
@@ -775,7 +765,7 @@ static void rproc_resource_cleanup(struct rproc *rproc)
if (unmapped != entry->len) {
/* nothing much to do besides complaining */
dev_err(dev, "failed to unmap %u/%zu\n", entry->len,
- unmapped);
+ unmapped);
}
list_del(&entry->node);
@@ -789,6 +779,10 @@ static void rproc_resource_cleanup(struct rproc *rproc)
list_del(&entry->node);
kfree(entry);
}
+
+ /* clean up remote vdev entries */
+ list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
+ rproc_remove_virtio_dev(rvdev);
}
/*
@@ -801,9 +795,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
struct resource_table *table, *loaded_table;
int ret, tablesz;
- if (!rproc->table_ptr)
- return -ENOMEM;
-
ret = rproc_fw_sanity_check(rproc, fw);
if (ret)
return ret;
@@ -830,9 +821,25 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}
- /* Verify that resource table in loaded fw is unchanged */
- if (rproc->table_csum != crc32(0, table, tablesz)) {
- dev_err(dev, "resource checksum failed, fw changed?\n");
+ /*
+ * Create a copy of the resource table. When a virtio device starts
+ * and calls vring_new_virtqueue() the address of the allocated vring
+ * will be stored in the cached_table. Before the device is started,
+ * cached_table will be copied into device memory.
+ */
+ rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
+ if (!rproc->cached_table)
+ goto clean_up;
+
+ rproc->table_ptr = rproc->cached_table;
+
+ /* reset max_notifyid */
+ rproc->max_notifyid = -1;
+
+ /* look for virtio devices and register them */
+ ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
+ if (ret) {
+ dev_err(dev, "Failed to handle vdev resources: %d\n", ret);
goto clean_up;
}
@@ -840,49 +847,50 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
- goto clean_up;
+ goto clean_up_resources;
}
/* load the ELF segments to memory */
ret = rproc_load_segments(rproc, fw);
if (ret) {
dev_err(dev, "Failed to load program segments: %d\n", ret);
- goto clean_up;
+ goto clean_up_resources;
}
/*
* The starting device has been given the rproc->cached_table as the
* resource table. The address of the vring along with the other
* allocated resources (carveouts etc) is stored in cached_table.
- * In order to pass this information to the remote device we must
- * copy this information to device memory.
+ * In order to pass this information to the remote device we must copy
+ * this information to device memory. We also update the table_ptr so
+ * that any subsequent changes will be applied to the loaded version.
*/
loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
- if (loaded_table)
+ if (loaded_table) {
memcpy(loaded_table, rproc->cached_table, tablesz);
+ rproc->table_ptr = loaded_table;
+ }
/* power up the remote processor */
ret = rproc->ops->start(rproc);
if (ret) {
dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
- goto clean_up;
+ goto clean_up_resources;
}
- /*
- * Update table_ptr so that all subsequent vring allocations and
- * virtio fields manipulation update the actual loaded resource table
- * in device memory.
- */
- rproc->table_ptr = loaded_table;
-
rproc->state = RPROC_RUNNING;
dev_info(dev, "remote processor %s is now up\n", rproc->name);
return 0;
-clean_up:
+clean_up_resources:
rproc_resource_cleanup(rproc);
+clean_up:
+ kfree(rproc->cached_table);
+ rproc->cached_table = NULL;
+ rproc->table_ptr = NULL;
+
rproc_disable_iommu(rproc);
return ret;
}
@@ -898,42 +906,11 @@ clean_up:
static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
{
struct rproc *rproc = context;
- struct resource_table *table;
- int ret, tablesz;
-
- if (rproc_fw_sanity_check(rproc, fw) < 0)
- goto out;
-
- /* look for the resource table */
- table = rproc_find_rsc_table(rproc, fw, &tablesz);
- if (!table)
- goto out;
-
- rproc->table_csum = crc32(0, table, tablesz);
-
- /*
- * Create a copy of the resource table. When a virtio device starts
- * and calls vring_new_virtqueue() the address of the allocated vring
- * will be stored in the cached_table. Before the device is started,
- * cached_table will be copied into devic memory.
- */
- rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
- if (!rproc->cached_table)
- goto out;
-
- rproc->table_ptr = rproc->cached_table;
- /* count the number of notify-ids */
- rproc->max_notifyid = -1;
- ret = rproc_handle_resources(rproc, tablesz,
- rproc_count_vrings_handler);
- if (ret)
- goto out;
-
- /* look for virtio devices and register them */
- ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
+ /* if rproc is marked always-on, request it to boot */
+ if (rproc->auto_boot)
+ rproc_boot_nowait(rproc);
-out:
release_firmware(fw);
/* allow rproc_del() contexts, if any, to proceed */
complete_all(&rproc->firmware_loading_complete);
@@ -969,7 +946,7 @@ static int rproc_add_virtio_devices(struct rproc *rproc)
* rproc_trigger_recovery() - recover a remoteproc
* @rproc: the remote processor
*
- * The recovery is done by reseting all the virtio devices, that way all the
+ * The recovery is done by resetting all the virtio devices, that way all the
* rpmsg drivers will be reseted along with the remote processor making the
* remoteproc functional again.
*
@@ -977,23 +954,23 @@ static int rproc_add_virtio_devices(struct rproc *rproc)
*/
int rproc_trigger_recovery(struct rproc *rproc)
{
- struct rproc_vdev *rvdev, *rvtmp;
-
dev_err(&rproc->dev, "recovering %s\n", rproc->name);
init_completion(&rproc->crash_comp);
- /* clean up remote vdev entries */
- list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
- rproc_remove_virtio_dev(rvdev);
+ /* shut down the remote */
+ /* TODO: make sure this works with rproc->power > 1 */
+ rproc_shutdown(rproc);
/* wait until there is no more rproc users */
wait_for_completion(&rproc->crash_comp);
- /* Free the copy of the resource table */
- kfree(rproc->cached_table);
+ /*
+ * boot the remote processor up again
+ */
+ rproc_boot(rproc);
- return rproc_add_virtio_devices(rproc);
+ return 0;
}
/**
@@ -1058,20 +1035,6 @@ static int __rproc_boot(struct rproc *rproc, bool wait)
return ret;
}
- /* loading a firmware is required */
- if (!rproc->firmware) {
- dev_err(dev, "%s: no firmware to load\n", __func__);
- ret = -EINVAL;
- goto unlock_mutex;
- }
-
- /* prevent underlying implementation from being removed */
- if (!try_module_get(dev->parent->driver->owner)) {
- dev_err(dev, "%s: can't get owner\n", __func__);
- ret = -EINVAL;
- goto unlock_mutex;
- }
-
/* skip the boot process if rproc is already powered up */
if (atomic_inc_return(&rproc->power) > 1) {
ret = 0;
@@ -1096,10 +1059,8 @@ static int __rproc_boot(struct rproc *rproc, bool wait)
release_firmware(firmware_p);
downref_rproc:
- if (ret) {
- module_put(dev->parent->driver->owner);
+ if (ret)
atomic_dec(&rproc->power);
- }
unlock_mutex:
mutex_unlock(&rproc->lock);
return ret;
@@ -1173,8 +1134,10 @@ void rproc_shutdown(struct rproc *rproc)
rproc_disable_iommu(rproc);
- /* Give the next start a clean resource table */
- rproc->table_ptr = rproc->cached_table;
+ /* Free the copy of the resource table */
+ kfree(rproc->cached_table);
+ rproc->cached_table = NULL;
+ rproc->table_ptr = NULL;
/* if in crash state, unlock crash handler */
if (rproc->state == RPROC_CRASHED)
@@ -1186,8 +1149,6 @@ void rproc_shutdown(struct rproc *rproc)
out:
mutex_unlock(&rproc->lock);
- if (!ret)
- module_put(dev->parent->driver->owner);
}
EXPORT_SYMBOL(rproc_shutdown);
@@ -1216,6 +1177,12 @@ struct rproc *rproc_get_by_phandle(phandle phandle)
mutex_lock(&rproc_list_mutex);
list_for_each_entry(r, &rproc_list, node) {
if (r->dev.parent && r->dev.parent->of_node == np) {
+ /* prevent underlying implementation from being removed */
+ if (!try_module_get(r->dev.parent->driver->owner)) {
+ dev_err(&r->dev, "can't get owner\n");
+ break;
+ }
+
rproc = r;
get_device(&rproc->dev);
break;
@@ -1335,11 +1302,11 @@ static struct device_type rproc_type = {
* On success the new rproc is returned, and on failure, NULL.
*
* Note: _never_ directly deallocate @rproc, even if it was not registered
- * yet. Instead, when you need to unroll rproc_alloc(), use rproc_put().
+ * yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().
*/
struct rproc *rproc_alloc(struct device *dev, const char *name,
- const struct rproc_ops *ops,
- const char *firmware, int len)
+ const struct rproc_ops *ops,
+ const char *firmware, int len)
{
struct rproc *rproc;
char *p, *template = "rproc-%s-fw";
@@ -1359,7 +1326,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
*/
name_len = strlen(name) + strlen(template) - 2 + 1;
- rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL);
+ rproc = kzalloc(sizeof(*rproc) + len + name_len, GFP_KERNEL);
if (!rproc)
return NULL;
@@ -1374,6 +1341,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
rproc->name = name;
rproc->ops = ops;
rproc->priv = &rproc[1];
+ rproc->auto_boot = true;
device_initialize(&rproc->dev);
rproc->dev.parent = dev;
@@ -1413,7 +1381,22 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
EXPORT_SYMBOL(rproc_alloc);
/**
- * rproc_put() - unroll rproc_alloc()
+ * rproc_free() - unroll rproc_alloc()
+ * @rproc: the remote processor handle
+ *
+ * This function decrements the rproc dev refcount.
+ *
+ * If no one holds any reference to rproc anymore, then its refcount would
+ * now drop to zero, and it would be freed.
+ */
+void rproc_free(struct rproc *rproc)
+{
+ put_device(&rproc->dev);
+}
+EXPORT_SYMBOL(rproc_free);
+
+/**
+ * rproc_put() - release rproc reference
* @rproc: the remote processor handle
*
* This function decrements the rproc dev refcount.
@@ -1423,6 +1406,7 @@ EXPORT_SYMBOL(rproc_alloc);
*/
void rproc_put(struct rproc *rproc)
{
+ module_put(rproc->dev.parent->driver->owner);
put_device(&rproc->dev);
}
EXPORT_SYMBOL(rproc_put);
@@ -1438,7 +1422,7 @@ EXPORT_SYMBOL(rproc_put);
*
* After rproc_del() returns, @rproc isn't freed yet, because
* of the outstanding reference created by rproc_alloc. To decrement that
- * one last refcount, one still needs to call rproc_put().
+ * one last refcount, one still needs to call rproc_free().
*
* Returns 0 on success and -EINVAL if @rproc isn't valid.
*/
@@ -1452,13 +1436,15 @@ int rproc_del(struct rproc *rproc)
/* if rproc is just being registered, wait */
wait_for_completion(&rproc->firmware_loading_complete);
+ /* if rproc is marked always-on, rproc_add() booted it */
+ /* TODO: make sure this works with rproc->power > 1 */
+ if (rproc->auto_boot)
+ rproc_shutdown(rproc);
+
/* clean up remote vdev entries */
list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
rproc_remove_virtio_dev(rvdev);
- /* Free the copy of the resource table */
- kfree(rproc->cached_table);
-
/* the rproc is downref'ed as soon as it's removed from the klist */
mutex_lock(&rproc_list_mutex);
list_del(&rproc->node);
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 74a120b6e206..374797206c79 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -45,7 +45,7 @@ static struct dentry *rproc_dbg;
* as it provides very early tracing with little to no dependencies at all.
*/
static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct rproc_mem_entry *trace = filp->private_data;
int len = strnlen(trace->va, trace->len);
@@ -73,7 +73,7 @@ static const char * const rproc_state_string[] = {
/* expose the state of the remote processor via debugfs */
static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct rproc *rproc = filp->private_data;
unsigned int state;
@@ -83,7 +83,7 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
i = scnprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state],
- rproc->state);
+ rproc->state);
return simple_read_from_buffer(userbuf, count, ppos, buf, i);
}
@@ -130,7 +130,7 @@ static const struct file_operations rproc_state_ops = {
/* expose the name of the remote processor via debugfs */
static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct rproc *rproc = filp->private_data;
/* need room for the name, a newline and a terminating null */
@@ -230,12 +230,12 @@ void rproc_remove_trace_file(struct dentry *tfile)
}
struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
- struct rproc_mem_entry *trace)
+ struct rproc_mem_entry *trace)
{
struct dentry *tfile;
- tfile = debugfs_create_file(name, 0400, rproc->dbg_dir,
- trace, &trace_rproc_ops);
+ tfile = debugfs_create_file(name, 0400, rproc->dbg_dir, trace,
+ &trace_rproc_ops);
if (!tfile) {
dev_err(&rproc->dev, "failed to create debugfs trace entry\n");
return NULL;
@@ -264,11 +264,11 @@ void rproc_create_debug_dir(struct rproc *rproc)
return;
debugfs_create_file("name", 0400, rproc->dbg_dir,
- rproc, &rproc_name_ops);
+ rproc, &rproc_name_ops);
debugfs_create_file("state", 0400, rproc->dbg_dir,
- rproc, &rproc_state_ops);
+ rproc, &rproc_state_ops);
debugfs_create_file("recovery", 0400, rproc->dbg_dir,
- rproc, &rproc_recovery_ops);
+ rproc, &rproc_recovery_ops);
}
void __init rproc_init_debugfs(void)
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index ce283a5b42a1..c523983a4aec 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -166,18 +166,18 @@ rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
continue;
dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
- phdr->p_type, da, memsz, filesz);
+ phdr->p_type, da, memsz, filesz);
if (filesz > memsz) {
dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
- filesz, memsz);
+ filesz, memsz);
ret = -EINVAL;
break;
}
if (offset + filesz > fw->size) {
dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
- offset + filesz, fw->size);
+ offset + filesz, fw->size);
ret = -EINVAL;
break;
}
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 57e1de59bec8..4cf93ca2816e 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -36,10 +36,10 @@ struct rproc;
*/
struct rproc_fw_ops {
struct resource_table *(*find_rsc_table)(struct rproc *rproc,
- const struct firmware *fw,
- int *tablesz);
- struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc,
- const struct firmware *fw);
+ const struct firmware *fw,
+ int *tablesz);
+ struct resource_table *(*find_loaded_rsc_table)(
+ struct rproc *rproc, const struct firmware *fw);
int (*load)(struct rproc *rproc, const struct firmware *fw);
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
@@ -57,7 +57,7 @@ void rproc_remove_virtio_dev(struct rproc_vdev *rvdev);
/* from remoteproc_debugfs.c */
void rproc_remove_trace_file(struct dentry *tfile);
struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
- struct rproc_mem_entry *trace);
+ struct rproc_mem_entry *trace);
void rproc_delete_debug_dir(struct rproc *rproc);
void rproc_create_debug_dir(struct rproc *rproc);
void rproc_init_debugfs(void);
@@ -98,7 +98,8 @@ int rproc_load_segments(struct rproc *rproc, const struct firmware *fw)
static inline
struct resource_table *rproc_find_rsc_table(struct rproc *rproc,
- const struct firmware *fw, int *tablesz)
+ const struct firmware *fw,
+ int *tablesz)
{
if (rproc->fw_ops->find_rsc_table)
return rproc->fw_ops->find_rsc_table(rproc, fw, tablesz);
@@ -108,7 +109,7 @@ struct resource_table *rproc_find_rsc_table(struct rproc *rproc,
static inline
struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
- const struct firmware *fw)
+ const struct firmware *fw)
{
if (rproc->fw_ops->find_loaded_rsc_table)
return rproc->fw_ops->find_loaded_rsc_table(rproc, fw);
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index cc91556313e1..01870a16d6d2 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -69,7 +69,7 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
EXPORT_SYMBOL(rproc_vq_interrupt);
static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
- unsigned id,
+ unsigned int id,
void (*callback)(struct virtqueue *vq),
const char *name)
{
@@ -101,14 +101,14 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
memset(addr, 0, size);
dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n",
- id, addr, len, rvring->notifyid);
+ id, addr, len, rvring->notifyid);
/*
* Create the new vq, and tell virtio we're not interested in
* the 'weak' smp barriers, since we're talking with a real device.
*/
vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr,
- rproc_virtio_notify, callback, name);
+ rproc_virtio_notify, callback, name);
if (!vq) {
dev_err(dev, "vring_new_virtqueue %s failed\n", name);
rproc_free_vring(rvring);
@@ -136,20 +136,14 @@ static void __rproc_virtio_del_vqs(struct virtio_device *vdev)
static void rproc_virtio_del_vqs(struct virtio_device *vdev)
{
- struct rproc *rproc = vdev_to_rproc(vdev);
-
- /* power down the remote processor before deleting vqs */
- rproc_shutdown(rproc);
-
__rproc_virtio_del_vqs(vdev);
}
-static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
- struct virtqueue *vqs[],
- vq_callback_t *callbacks[],
- const char * const names[])
+static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char * const names[])
{
- struct rproc *rproc = vdev_to_rproc(vdev);
int i, ret;
for (i = 0; i < nvqs; ++i) {
@@ -160,13 +154,6 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
}
}
- /* now that the vqs are all set, boot the remote processor */
- ret = rproc_boot_nowait(rproc);
- if (ret) {
- dev_err(&rproc->dev, "rproc_boot() failed %d\n", ret);
- goto error;
- }
-
return 0;
error:
@@ -239,8 +226,8 @@ static int rproc_virtio_finalize_features(struct virtio_device *vdev)
return 0;
}
-static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
- void *buf, unsigned len)
+static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset,
+ void *buf, unsigned int len)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
@@ -257,8 +244,8 @@ static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
memcpy(buf, cfg + offset, len);
}
-static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset,
- const void *buf, unsigned len)
+static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset,
+ const void *buf, unsigned int len)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index 6f056caa8a56..ae8963fcc8c8 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -262,7 +262,7 @@ static int st_rproc_probe(struct platform_device *pdev)
return 0;
free_rproc:
- rproc_put(rproc);
+ rproc_free(rproc);
return ret;
}
@@ -277,7 +277,7 @@ static int st_rproc_remove(struct platform_device *pdev)
of_reserved_mem_device_release(&pdev->dev);
- rproc_put(rproc);
+ rproc_free(rproc);
return 0;
}
diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c
index 53dc17bdd54e..03d69a9a3c5b 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -257,7 +257,7 @@ static int sproc_drv_remove(struct platform_device *pdev)
rproc_del(sproc->rproc);
dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE,
sproc->fw_addr, sproc->fw_dma_addr);
- rproc_put(sproc->rproc);
+ rproc_free(sproc->rproc);
mdev->drv_data = NULL;
@@ -325,7 +325,7 @@ free_mem:
free_rproc:
/* Reset device data upon error */
mdev->drv_data = NULL;
- rproc_put(rproc);
+ rproc_free(rproc);
return err;
}
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 02d271d101b4..18175d0331fd 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -167,6 +167,8 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
goto err;
}
+ rproc->auto_boot = false;
+
wkupm3 = rproc->priv;
wkupm3->rproc = rproc;
wkupm3->pdev = pdev;
@@ -206,7 +208,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
return 0;
err_put_rproc:
- rproc_put(rproc);
+ rproc_free(rproc);
err:
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
@@ -218,7 +220,7 @@ static int wkup_m3_rproc_remove(struct platform_device *pdev)
struct rproc *rproc = platform_get_drvdata(pdev);
rproc_del(rproc);
- rproc_put(rproc);
+ rproc_free(rproc);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 4be1b8c21f6f..06d9fa2f3bc0 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -14,9 +14,58 @@ menuconfig RESET_CONTROLLER
if RESET_CONTROLLER
+config RESET_ATH79
+ bool "AR71xx Reset Driver" if COMPILE_TEST
+ default ATH79
+ help
+ This enables the ATH79 reset controller driver that supports the
+ AR71xx SoC reset controller.
+
+config RESET_BERLIN
+ bool "Berlin Reset Driver" if COMPILE_TEST
+ default ARCH_BERLIN
+ help
+ This enables the reset controller driver for Marvell Berlin SoCs.
+
+config RESET_LPC18XX
+ bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST
+ default ARCH_LPC18XX
+ help
+ This enables the reset controller driver for NXP LPC18xx/43xx SoCs.
+
+config RESET_MESON
+ bool "Meson Reset Driver" if COMPILE_TEST
+ default ARCH_MESON
+ help
+ This enables the reset driver for Amlogic Meson SoCs.
+
config RESET_OXNAS
bool
+config RESET_PISTACHIO
+ bool "Pistachio Reset Driver" if COMPILE_TEST
+ default MACH_PISTACHIO
+ help
+ This enables the reset driver for ImgTec Pistachio SoCs.
+
+config RESET_SOCFPGA
+ bool "SoCFPGA Reset Driver" if COMPILE_TEST
+ default ARCH_SOCFPGA
+ help
+ This enables the reset controller driver for Altera SoCFPGAs.
+
+config RESET_STM32
+ bool "STM32 Reset Driver" if COMPILE_TEST
+ default ARCH_STM32
+ help
+ This enables the RCC reset controller driver for STM32 MCUs.
+
+config RESET_SUNXI
+ bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
+ default ARCH_SUNXI
+ help
+ This enables the reset driver for Allwinner SoCs.
+
config TI_SYSCON_RESET
tristate "TI SYSCON Reset Driver"
depends on HAS_IOMEM
@@ -27,6 +76,22 @@ config TI_SYSCON_RESET
you wish to use the reset framework for such memory-mapped devices,
say Y here. Otherwise, say N.
+config RESET_UNIPHIER
+ tristate "Reset controller driver for UniPhier SoCs"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ depends on OF && MFD_SYSCON
+ default ARCH_UNIPHIER
+ help
+ Support for reset controllers on UniPhier SoCs.
+ Say Y if you want to control reset signals provided by System Control
+ block, Media I/O block, Peripheral Block.
+
+config RESET_ZYNQ
+ bool "ZYNQ Reset Driver" if COMPILE_TEST
+ default ARCH_ZYNQ
+ help
+ This enables the reset controller driver for Xilinx Zynq SoCs.
+
source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 5d65a93d3c43..bbe7026617fc 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,13 +1,15 @@
obj-y += core.o
-obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
-obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
-obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
-obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o
-obj-$(CONFIG_ARCH_MESON) += reset-meson.o
-obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
+obj-y += hisilicon/
obj-$(CONFIG_ARCH_STI) += sti/
-obj-$(CONFIG_ARCH_HISI) += hisilicon/
-obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o
-obj-$(CONFIG_ATH79) += reset-ath79.o
+obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
+obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
+obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
+obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
+obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
+obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_STM32) += reset-stm32.o
+obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
+obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
+obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 395dc9ce492e..b8ae1dbd4c17 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -138,7 +138,8 @@ EXPORT_SYMBOL_GPL(devm_reset_controller_register);
*/
int reset_control_reset(struct reset_control *rstc)
{
- if (WARN_ON(rstc->shared))
+ if (WARN_ON(IS_ERR_OR_NULL(rstc)) ||
+ WARN_ON(rstc->shared))
return -EINVAL;
if (rstc->rcdev->ops->reset)
@@ -161,6 +162,9 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
*/
int reset_control_assert(struct reset_control *rstc)
{
+ if (WARN_ON(IS_ERR_OR_NULL(rstc)))
+ return -EINVAL;
+
if (!rstc->rcdev->ops->assert)
return -ENOTSUPP;
@@ -184,6 +188,9 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
*/
int reset_control_deassert(struct reset_control *rstc)
{
+ if (WARN_ON(IS_ERR_OR_NULL(rstc)))
+ return -EINVAL;
+
if (!rstc->rcdev->ops->deassert)
return -ENOTSUPP;
@@ -204,6 +211,9 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
*/
int reset_control_status(struct reset_control *rstc)
{
+ if (WARN_ON(IS_ERR_OR_NULL(rstc)))
+ return -EINVAL;
+
if (rstc->rcdev->ops->status)
return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig
index 26bf95a83a8e..1ff8b0c80980 100644
--- a/drivers/reset/hisilicon/Kconfig
+++ b/drivers/reset/hisilicon/Kconfig
@@ -1,5 +1,6 @@
config COMMON_RESET_HI6220
tristate "Hi6220 Reset Driver"
- depends on (ARCH_HISI && RESET_CONTROLLER)
+ depends on ARCH_HISI || COMPILE_TEST
+ default ARCH_HISI
help
Build the Hisilicon Hi6220 reset driver.
diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c
index 16d410cd6146..6b97631f5489 100644
--- a/drivers/reset/reset-ath79.c
+++ b/drivers/reset/reset-ath79.c
@@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index 12add9b0fa49..78ebf8424375 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -28,7 +28,6 @@
struct socfpga_reset_data {
spinlock_t lock;
void __iomem *membase;
- u32 modrst_offset;
struct reset_controller_dev rcdev;
};
@@ -45,9 +44,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&data->lock, flags);
- reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
- writel(reg | BIT(offset), data->membase + data->modrst_offset +
- (bank * NR_BANKS));
+ reg = readl(data->membase + (bank * NR_BANKS));
+ writel(reg | BIT(offset), data->membase + (bank * NR_BANKS));
spin_unlock_irqrestore(&data->lock, flags);
return 0;
@@ -67,9 +65,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&data->lock, flags);
- reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
- writel(reg & ~BIT(offset), data->membase + data->modrst_offset +
- (bank * NR_BANKS));
+ reg = readl(data->membase + (bank * NR_BANKS));
+ writel(reg & ~BIT(offset), data->membase + (bank * NR_BANKS));
spin_unlock_irqrestore(&data->lock, flags);
@@ -85,7 +82,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev,
int offset = id % BITS_PER_LONG;
u32 reg;
- reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
+ reg = readl(data->membase + (bank * NR_BANKS));
return !(reg & BIT(offset));
}
@@ -102,6 +99,7 @@ static int socfpga_reset_probe(struct platform_device *pdev)
struct resource *res;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ u32 modrst_offset;
/*
* The binding was mainlined without the required property.
@@ -122,10 +120,11 @@ static int socfpga_reset_probe(struct platform_device *pdev)
if (IS_ERR(data->membase))
return PTR_ERR(data->membase);
- if (of_property_read_u32(np, "altr,modrst-offset", &data->modrst_offset)) {
+ if (of_property_read_u32(np, "altr,modrst-offset", &modrst_offset)) {
dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
- data->modrst_offset = 0x10;
+ modrst_offset = 0x10;
}
+ data->membase += modrst_offset;
spin_lock_init(&data->lock);
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 000000000000..3a7c8527e66a
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+ spinlock_t lock;
+ void __iomem *membase;
+ struct reset_controller_dev rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = container_of(rcdev,
+ struct stm32_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 + (bank * 4));
+ writel(reg | BIT(offset), data->membase + (bank * 4));
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = container_of(rcdev,
+ struct stm32_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 + (bank * 4));
+ writel(reg & ~BIT(offset), data->membase + (bank * 4));
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static const struct reset_control_ops stm32_reset_ops = {
+ .assert = stm32_reset_assert,
+ .deassert = stm32_reset_deassert,
+};
+
+static const struct of_device_id stm32_reset_dt_ids[] = {
+ { .compatible = "st,stm32-rcc", },
+ { /* sentinel */ },
+};
+
+static int stm32_reset_probe(struct platform_device *pdev)
+{
+ struct stm32_reset_data *data;
+ struct resource *res;
+
+ 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 = resource_size(res) * 8;
+ data->rcdev.ops = &stm32_reset_ops;
+ data->rcdev.of_node = pdev->dev.of_node;
+
+ return devm_reset_controller_register(&pdev->dev, &data->rcdev);
+}
+
+static struct platform_driver stm32_reset_driver = {
+ .probe = stm32_reset_probe,
+ .driver = {
+ .name = "stm32-rcc-reset",
+ .of_match_table = stm32_reset_dt_ids,
+ },
+};
+builtin_platform_driver(stm32_reset_driver);
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c
new file mode 100644
index 000000000000..8b2558e7363e
--- /dev/null
+++ b/drivers/reset/reset-uniphier.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/syscon.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/reset-controller.h>
+
+struct uniphier_reset_data {
+ unsigned int id;
+ unsigned int reg;
+ unsigned int bit;
+ unsigned int flags;
+#define UNIPHIER_RESET_ACTIVE_LOW BIT(0)
+};
+
+#define UNIPHIER_RESET_ID_END (unsigned int)(-1)
+
+#define UNIPHIER_RESET_END \
+ { .id = UNIPHIER_RESET_ID_END }
+
+#define UNIPHIER_RESET(_id, _reg, _bit) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .bit = (_bit), \
+ }
+
+#define UNIPHIER_RESETX(_id, _reg, _bit) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .bit = (_bit), \
+ .flags = UNIPHIER_RESET_ACTIVE_LOW, \
+ }
+
+/* System reset data */
+#define UNIPHIER_SLD3_SYS_RESET_STDMAC(id) \
+ UNIPHIER_RESETX((id), 0x2000, 10)
+
+#define UNIPHIER_LD11_SYS_RESET_STDMAC(id) \
+ UNIPHIER_RESETX((id), 0x200c, 8)
+
+#define UNIPHIER_PRO4_SYS_RESET_GIO(id) \
+ UNIPHIER_RESETX((id), 0x2000, 6)
+
+#define UNIPHIER_LD20_SYS_RESET_GIO(id) \
+ UNIPHIER_RESETX((id), 0x200c, 5)
+
+#define UNIPHIER_PRO4_SYS_RESET_USB3(id, ch) \
+ UNIPHIER_RESETX((id), 0x2000 + 0x4 * (ch), 17)
+
+const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* Ether, HSC, MIO */
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, MIO, RLE */
+ UNIPHIER_PRO4_SYS_RESET_GIO(12), /* Ether, SATA, USB3 */
+ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
+ UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC */
+ UNIPHIER_PRO4_SYS_RESET_GIO(12), /* PCIe, USB3 */
+ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
+ UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = {
+ UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, RLE */
+ UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
+ UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
+ UNIPHIER_RESETX(16, 0x2014, 4), /* USB30-PHY0 */
+ UNIPHIER_RESETX(17, 0x2014, 0), /* USB30-PHY1 */
+ UNIPHIER_RESETX(18, 0x2014, 2), /* USB30-PHY2 */
+ UNIPHIER_RESETX(20, 0x2014, 5), /* USB31-PHY0 */
+ UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */
+ UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */
+ UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = {
+ UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC, MIO */
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
+ UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC */
+ UNIPHIER_LD20_SYS_RESET_GIO(12), /* PCIe, USB3 */
+ UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */
+ UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */
+ UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */
+ UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */
+ UNIPHIER_RESET_END,
+};
+
+/* Media I/O reset data */
+#define UNIPHIER_MIO_RESET_SD(id, ch) \
+ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 0)
+
+#define UNIPHIER_MIO_RESET_SD_BRIDGE(id, ch) \
+ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 26)
+
+#define UNIPHIER_MIO_RESET_EMMC_HW_RESET(id, ch) \
+ UNIPHIER_RESETX((id), 0x80 + 0x200 * (ch), 0)
+
+#define UNIPHIER_MIO_RESET_USB2(id, ch) \
+ UNIPHIER_RESETX((id), 0x114 + 0x200 * (ch), 0)
+
+#define UNIPHIER_MIO_RESET_USB2_BRIDGE(id, ch) \
+ UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 24)
+
+#define UNIPHIER_MIO_RESET_DMAC(id) \
+ UNIPHIER_RESETX((id), 0x110, 17)
+
+const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = {
+ UNIPHIER_MIO_RESET_SD(0, 0),
+ UNIPHIER_MIO_RESET_SD(1, 1),
+ UNIPHIER_MIO_RESET_SD(2, 2),
+ UNIPHIER_MIO_RESET_SD_BRIDGE(3, 0),
+ UNIPHIER_MIO_RESET_SD_BRIDGE(4, 1),
+ UNIPHIER_MIO_RESET_SD_BRIDGE(5, 2),
+ UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
+ UNIPHIER_MIO_RESET_DMAC(7),
+ UNIPHIER_MIO_RESET_USB2(8, 0),
+ UNIPHIER_MIO_RESET_USB2(9, 1),
+ UNIPHIER_MIO_RESET_USB2(10, 2),
+ UNIPHIER_MIO_RESET_USB2(11, 3),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(12, 0),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(13, 1),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(14, 2),
+ UNIPHIER_MIO_RESET_USB2_BRIDGE(15, 3),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro5_mio_reset_data[] = {
+ UNIPHIER_MIO_RESET_SD(0, 0),
+ UNIPHIER_MIO_RESET_SD(1, 1),
+ UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
+ UNIPHIER_RESET_END,
+};
+
+/* Peripheral reset data */
+#define UNIPHIER_PERI_RESET_UART(id, ch) \
+ UNIPHIER_RESETX((id), 0x114, 19 + (ch))
+
+#define UNIPHIER_PERI_RESET_I2C(id, ch) \
+ UNIPHIER_RESETX((id), 0x114, 5 + (ch))
+
+#define UNIPHIER_PERI_RESET_FI2C(id, ch) \
+ UNIPHIER_RESETX((id), 0x114, 24 + (ch))
+
+const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
+ UNIPHIER_PERI_RESET_UART(0, 0),
+ UNIPHIER_PERI_RESET_UART(1, 1),
+ UNIPHIER_PERI_RESET_UART(2, 2),
+ UNIPHIER_PERI_RESET_UART(3, 3),
+ UNIPHIER_PERI_RESET_I2C(4, 0),
+ UNIPHIER_PERI_RESET_I2C(5, 1),
+ UNIPHIER_PERI_RESET_I2C(6, 2),
+ UNIPHIER_PERI_RESET_I2C(7, 3),
+ UNIPHIER_PERI_RESET_I2C(8, 4),
+ UNIPHIER_RESET_END,
+};
+
+const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
+ UNIPHIER_PERI_RESET_UART(0, 0),
+ UNIPHIER_PERI_RESET_UART(1, 1),
+ UNIPHIER_PERI_RESET_UART(2, 2),
+ UNIPHIER_PERI_RESET_UART(3, 3),
+ UNIPHIER_PERI_RESET_FI2C(4, 0),
+ UNIPHIER_PERI_RESET_FI2C(5, 1),
+ UNIPHIER_PERI_RESET_FI2C(6, 2),
+ UNIPHIER_PERI_RESET_FI2C(7, 3),
+ UNIPHIER_PERI_RESET_FI2C(8, 4),
+ UNIPHIER_PERI_RESET_FI2C(9, 5),
+ UNIPHIER_PERI_RESET_FI2C(10, 6),
+ UNIPHIER_RESET_END,
+};
+
+/* core implementaton */
+struct uniphier_reset_priv {
+ struct reset_controller_dev rcdev;
+ struct device *dev;
+ struct regmap *regmap;
+ const struct uniphier_reset_data *data;
+};
+
+#define to_uniphier_reset_priv(_rcdev) \
+ container_of(_rcdev, struct uniphier_reset_priv, rcdev)
+
+static int uniphier_reset_update(struct reset_controller_dev *rcdev,
+ unsigned long id, int assert)
+{
+ struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
+ const struct uniphier_reset_data *p;
+
+ for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
+ unsigned int mask, val;
+
+ if (p->id != id)
+ continue;
+
+ mask = BIT(p->bit);
+
+ if (assert)
+ val = mask;
+ else
+ val = ~mask;
+
+ if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
+ val = ~val;
+
+ return regmap_write_bits(priv->regmap, p->reg, mask, val);
+ }
+
+ dev_err(priv->dev, "reset_id=%lu was not handled\n", id);
+ return -EINVAL;
+}
+
+static int uniphier_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return uniphier_reset_update(rcdev, id, 1);
+}
+
+static int uniphier_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return uniphier_reset_update(rcdev, id, 0);
+}
+
+static int uniphier_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
+ const struct uniphier_reset_data *p;
+
+ for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
+ unsigned int val;
+ int ret, asserted;
+
+ if (p->id != id)
+ continue;
+
+ ret = regmap_read(priv->regmap, p->reg, &val);
+ if (ret)
+ return ret;
+
+ asserted = !!(val & BIT(p->bit));
+
+ if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
+ asserted = !asserted;
+
+ return asserted;
+ }
+
+ dev_err(priv->dev, "reset_id=%lu was not found\n", id);
+ return -EINVAL;
+}
+
+static const struct reset_control_ops uniphier_reset_ops = {
+ .assert = uniphier_reset_assert,
+ .deassert = uniphier_reset_deassert,
+ .status = uniphier_reset_status,
+};
+
+static int uniphier_reset_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_reset_priv *priv;
+ const struct uniphier_reset_data *p, *data;
+ struct regmap *regmap;
+ struct device_node *parent;
+ unsigned int nr_resets = 0;
+
+ data = of_device_get_match_data(dev);
+ if (WARN_ON(!data))
+ return -EINVAL;
+
+ parent = of_get_parent(dev->of_node); /* parent should be syscon node */
+ regmap = syscon_node_to_regmap(parent);
+ of_node_put(parent);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to get regmap (error %ld)\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ for (p = data; p->id != UNIPHIER_RESET_ID_END; p++)
+ nr_resets = max(nr_resets, p->id + 1);
+
+ priv->rcdev.ops = &uniphier_reset_ops;
+ priv->rcdev.owner = dev->driver->owner;
+ priv->rcdev.of_node = dev->of_node;
+ priv->rcdev.nr_resets = nr_resets;
+ priv->dev = dev;
+ priv->regmap = regmap;
+ priv->data = data;
+
+ return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
+}
+
+static const struct of_device_id uniphier_reset_match[] = {
+ /* System reset */
+ {
+ .compatible = "socionext,uniphier-sld3-reset",
+ .data = uniphier_sld3_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld4-reset",
+ .data = uniphier_sld3_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro4-reset",
+ .data = uniphier_pro4_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-sld8-reset",
+ .data = uniphier_sld3_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro5-reset",
+ .data = uniphier_pro5_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-reset",
+ .data = uniphier_pxs2_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-reset",
+ .data = uniphier_ld11_sys_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-reset",
+ .data = uniphier_ld20_sys_reset_data,
+ },
+ /* Media I/O reset */
+ {
+ .compatible = "socionext,uniphier-sld3-mio-reset",
+ .data = uniphier_sld3_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld4-mio-reset",
+ .data = uniphier_sld3_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro4-mio-reset",
+ .data = uniphier_sld3_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-sld8-mio-reset",
+ .data = uniphier_sld3_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro5-mio-reset",
+ .data = uniphier_pro5_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-mio-reset",
+ .data = uniphier_pro5_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-mio-reset",
+ .data = uniphier_sld3_mio_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-mio-reset",
+ .data = uniphier_pro5_mio_reset_data,
+ },
+ /* Peripheral reset */
+ {
+ .compatible = "socionext,uniphier-ld4-peri-reset",
+ .data = uniphier_ld4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro4-peri-reset",
+ .data = uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-sld8-peri-reset",
+ .data = uniphier_ld4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pro5-peri-reset",
+ .data = uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-peri-reset",
+ .data = uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-peri-reset",
+ .data = uniphier_pro4_peri_reset_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-peri-reset",
+ .data = uniphier_pro4_peri_reset_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_reset_match);
+
+static struct platform_driver uniphier_reset_driver = {
+ .probe = uniphier_reset_probe,
+ .driver = {
+ .name = "uniphier-reset",
+ .of_match_table = uniphier_reset_match,
+ },
+};
+module_platform_driver(uniphier_reset_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier Reset Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 69a219387582..de31c5f14dd9 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -3,6 +3,20 @@ menu "Rpmsg drivers"
# RPMSG always gets selected by whoever wants it
config RPMSG
tristate
+
+config RPMSG_QCOM_SMD
+ tristate "Qualcomm Shared Memory Driver (SMD)"
+ depends on QCOM_SMEM
+ depends on QCOM_SMD=n
+ select RPMSG
+ help
+ Say y here to enable support for the Qualcomm Shared Memory Driver
+ providing communication channels to remote processors in Qualcomm
+ platforms.
+
+config RPMSG_VIRTIO
+ tristate
+ select RPMSG
select VIRTIO
select VIRTUALIZATION
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 7617fcb8259f..ae9c9132cf76 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1 +1,3 @@
-obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o
+obj-$(CONFIG_RPMSG) += rpmsg_core.o
+obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
+obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
new file mode 100644
index 000000000000..06fef2b4c814
--- /dev/null
+++ b/drivers/rpmsg/qcom_smd.c
@@ -0,0 +1,1434 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications AB.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/wait.h>
+#include <linux/rpmsg.h>
+
+#include "rpmsg_internal.h"
+
+/*
+ * The Qualcomm Shared Memory communication solution provides point-to-point
+ * channels for clients to send and receive streaming or packet based data.
+ *
+ * Each channel consists of a control item (channel info) and a ring buffer
+ * pair. The channel info carry information related to channel state, flow
+ * control and the offsets within the ring buffer.
+ *
+ * All allocated channels are listed in an allocation table, identifying the
+ * pair of items by name, type and remote processor.
+ *
+ * Upon creating a new channel the remote processor allocates channel info and
+ * ring buffer items from the smem heap and populate the allocation table. An
+ * interrupt is sent to the other end of the channel and a scan for new
+ * channels should be done. A channel never goes away, it will only change
+ * state.
+ *
+ * The remote processor signals it intent for bring up the communication
+ * channel by setting the state of its end of the channel to "opening" and
+ * sends out an interrupt. We detect this change and register a smd device to
+ * consume the channel. Upon finding a consumer we finish the handshake and the
+ * channel is up.
+ *
+ * Upon closing a channel, the remote processor will update the state of its
+ * end of the channel and signal us, we will then unregister any attached
+ * device and close our end of the channel.
+ *
+ * Devices attached to a channel can use the qcom_smd_send function to push
+ * data to the channel, this is done by copying the data into the tx ring
+ * buffer, updating the pointers in the channel info and signaling the remote
+ * processor.
+ *
+ * The remote processor does the equivalent when it transfer data and upon
+ * receiving the interrupt we check the channel info for new data and delivers
+ * this to the attached device. If the device is not ready to receive the data
+ * we leave it in the ring buffer for now.
+ */
+
+struct smd_channel_info;
+struct smd_channel_info_pair;
+struct smd_channel_info_word;
+struct smd_channel_info_word_pair;
+
+static const struct rpmsg_endpoint_ops qcom_smd_endpoint_ops;
+
+#define SMD_ALLOC_TBL_COUNT 2
+#define SMD_ALLOC_TBL_SIZE 64
+
+/*
+ * This lists the various smem heap items relevant for the allocation table and
+ * smd channel entries.
+ */
+static const struct {
+ unsigned alloc_tbl_id;
+ unsigned info_base_id;
+ unsigned fifo_base_id;
+} smem_items[SMD_ALLOC_TBL_COUNT] = {
+ {
+ .alloc_tbl_id = 13,
+ .info_base_id = 14,
+ .fifo_base_id = 338
+ },
+ {
+ .alloc_tbl_id = 266,
+ .info_base_id = 138,
+ .fifo_base_id = 202,
+ },
+};
+
+/**
+ * struct qcom_smd_edge - representing a remote processor
+ * @of_node: of_node handle for information related to this edge
+ * @edge_id: identifier of this edge
+ * @remote_pid: identifier of remote processor
+ * @irq: interrupt for signals on this edge
+ * @ipc_regmap: regmap handle holding the outgoing ipc register
+ * @ipc_offset: offset within @ipc_regmap of the register for ipc
+ * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap
+ * @channels: list of all channels detected on this edge
+ * @channels_lock: guard for modifications of @channels
+ * @allocated: array of bitmaps representing already allocated channels
+ * @smem_available: last available amount of smem triggering a channel scan
+ * @scan_work: work item for discovering new channels
+ * @state_work: work item for edge state changes
+ */
+struct qcom_smd_edge {
+ struct device dev;
+
+ struct device_node *of_node;
+ unsigned edge_id;
+ unsigned remote_pid;
+
+ int irq;
+
+ struct regmap *ipc_regmap;
+ int ipc_offset;
+ int ipc_bit;
+
+ struct list_head channels;
+ spinlock_t channels_lock;
+
+ DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);
+
+ unsigned smem_available;
+
+ wait_queue_head_t new_channel_event;
+
+ struct work_struct scan_work;
+ struct work_struct state_work;
+};
+
+/*
+ * SMD channel states.
+ */
+enum smd_channel_state {
+ SMD_CHANNEL_CLOSED,
+ SMD_CHANNEL_OPENING,
+ SMD_CHANNEL_OPENED,
+ SMD_CHANNEL_FLUSHING,
+ SMD_CHANNEL_CLOSING,
+ SMD_CHANNEL_RESET,
+ SMD_CHANNEL_RESET_OPENING
+};
+
+struct qcom_smd_device {
+ struct rpmsg_device rpdev;
+
+ struct qcom_smd_edge *edge;
+};
+
+struct qcom_smd_endpoint {
+ struct rpmsg_endpoint ept;
+
+ struct qcom_smd_channel *qsch;
+};
+
+#define to_smd_device(_rpdev) container_of(_rpdev, struct qcom_smd_device, rpdev)
+#define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev)
+#define to_smd_endpoint(ept) container_of(ept, struct qcom_smd_endpoint, ept)
+
+/**
+ * struct qcom_smd_channel - smd channel struct
+ * @edge: qcom_smd_edge this channel is living on
+ * @qsdev: reference to a associated smd client device
+ * @name: name of the channel
+ * @state: local state of the channel
+ * @remote_state: remote state of the channel
+ * @info: byte aligned outgoing/incoming channel info
+ * @info_word: word aligned outgoing/incoming channel info
+ * @tx_lock: lock to make writes to the channel mutually exclusive
+ * @fblockread_event: wakeup event tied to tx fBLOCKREADINTR
+ * @tx_fifo: pointer to the outgoing ring buffer
+ * @rx_fifo: pointer to the incoming ring buffer
+ * @fifo_size: size of each ring buffer
+ * @bounce_buffer: bounce buffer for reading wrapped packets
+ * @cb: callback function registered for this channel
+ * @recv_lock: guard for rx info modifications and cb pointer
+ * @pkt_size: size of the currently handled packet
+ * @list: lite entry for @channels in qcom_smd_edge
+ */
+struct qcom_smd_channel {
+ struct qcom_smd_edge *edge;
+
+ struct qcom_smd_endpoint *qsept;
+ bool registered;
+
+ char *name;
+ enum smd_channel_state state;
+ enum smd_channel_state remote_state;
+
+ struct smd_channel_info_pair *info;
+ struct smd_channel_info_word_pair *info_word;
+
+ struct mutex tx_lock;
+ wait_queue_head_t fblockread_event;
+
+ void *tx_fifo;
+ void *rx_fifo;
+ int fifo_size;
+
+ void *bounce_buffer;
+
+ spinlock_t recv_lock;
+
+ int pkt_size;
+
+ void *drvdata;
+
+ struct list_head list;
+};
+
+/*
+ * Format of the smd_info smem items, for byte aligned channels.
+ */
+struct smd_channel_info {
+ __le32 state;
+ u8 fDSR;
+ u8 fCTS;
+ u8 fCD;
+ u8 fRI;
+ u8 fHEAD;
+ u8 fTAIL;
+ u8 fSTATE;
+ u8 fBLOCKREADINTR;
+ __le32 tail;
+ __le32 head;
+};
+
+struct smd_channel_info_pair {
+ struct smd_channel_info tx;
+ struct smd_channel_info rx;
+};
+
+/*
+ * Format of the smd_info smem items, for word aligned channels.
+ */
+struct smd_channel_info_word {
+ __le32 state;
+ __le32 fDSR;
+ __le32 fCTS;
+ __le32 fCD;
+ __le32 fRI;
+ __le32 fHEAD;
+ __le32 fTAIL;
+ __le32 fSTATE;
+ __le32 fBLOCKREADINTR;
+ __le32 tail;
+ __le32 head;
+};
+
+struct smd_channel_info_word_pair {
+ struct smd_channel_info_word tx;
+ struct smd_channel_info_word rx;
+};
+
+#define GET_RX_CHANNEL_FLAG(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
+ channel->info_word ? \
+ le32_to_cpu(channel->info_word->rx.param) : \
+ channel->info->rx.param; \
+ })
+
+#define GET_RX_CHANNEL_INFO(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
+ le32_to_cpu(channel->info_word ? \
+ channel->info_word->rx.param : \
+ channel->info->rx.param); \
+ })
+
+#define SET_RX_CHANNEL_FLAG(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
+ if (channel->info_word) \
+ channel->info_word->rx.param = cpu_to_le32(value); \
+ else \
+ channel->info->rx.param = value; \
+ })
+
+#define SET_RX_CHANNEL_INFO(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
+ if (channel->info_word) \
+ channel->info_word->rx.param = cpu_to_le32(value); \
+ else \
+ channel->info->rx.param = cpu_to_le32(value); \
+ })
+
+#define GET_TX_CHANNEL_FLAG(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
+ channel->info_word ? \
+ le32_to_cpu(channel->info_word->tx.param) : \
+ channel->info->tx.param; \
+ })
+
+#define GET_TX_CHANNEL_INFO(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
+ le32_to_cpu(channel->info_word ? \
+ channel->info_word->tx.param : \
+ channel->info->tx.param); \
+ })
+
+#define SET_TX_CHANNEL_FLAG(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
+ if (channel->info_word) \
+ channel->info_word->tx.param = cpu_to_le32(value); \
+ else \
+ channel->info->tx.param = value; \
+ })
+
+#define SET_TX_CHANNEL_INFO(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
+ if (channel->info_word) \
+ channel->info_word->tx.param = cpu_to_le32(value); \
+ else \
+ channel->info->tx.param = cpu_to_le32(value); \
+ })
+
+/**
+ * struct qcom_smd_alloc_entry - channel allocation entry
+ * @name: channel name
+ * @cid: channel index
+ * @flags: channel flags and edge id
+ * @ref_count: reference count of the channel
+ */
+struct qcom_smd_alloc_entry {
+ u8 name[20];
+ __le32 cid;
+ __le32 flags;
+ __le32 ref_count;
+} __packed;
+
+#define SMD_CHANNEL_FLAGS_EDGE_MASK 0xff
+#define SMD_CHANNEL_FLAGS_STREAM BIT(8)
+#define SMD_CHANNEL_FLAGS_PACKET BIT(9)
+
+/*
+ * Each smd packet contains a 20 byte header, with the first 4 being the length
+ * of the packet.
+ */
+#define SMD_PACKET_HEADER_LEN 20
+
+/*
+ * Signal the remote processor associated with 'channel'.
+ */
+static void qcom_smd_signal_channel(struct qcom_smd_channel *channel)
+{
+ struct qcom_smd_edge *edge = channel->edge;
+
+ regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit));
+}
+
+/*
+ * Initialize the tx channel info
+ */
+static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
+{
+ SET_TX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
+ SET_TX_CHANNEL_FLAG(channel, fDSR, 0);
+ SET_TX_CHANNEL_FLAG(channel, fCTS, 0);
+ SET_TX_CHANNEL_FLAG(channel, fCD, 0);
+ SET_TX_CHANNEL_FLAG(channel, fRI, 0);
+ SET_TX_CHANNEL_FLAG(channel, fHEAD, 0);
+ SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
+ SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
+ SET_TX_CHANNEL_INFO(channel, head, 0);
+ SET_RX_CHANNEL_INFO(channel, tail, 0);
+
+ qcom_smd_signal_channel(channel);
+
+ channel->state = SMD_CHANNEL_CLOSED;
+ channel->pkt_size = 0;
+}
+
+/*
+ * Set the callback for a channel, with appropriate locking
+ */
+static void qcom_smd_channel_set_callback(struct qcom_smd_channel *channel,
+ rpmsg_rx_cb_t cb)
+{
+ struct rpmsg_endpoint *ept = &channel->qsept->ept;
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->recv_lock, flags);
+ ept->cb = cb;
+ spin_unlock_irqrestore(&channel->recv_lock, flags);
+};
+
+/*
+ * Calculate the amount of data available in the rx fifo
+ */
+static size_t qcom_smd_channel_get_rx_avail(struct qcom_smd_channel *channel)
+{
+ unsigned head;
+ unsigned tail;
+
+ head = GET_RX_CHANNEL_INFO(channel, head);
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+
+ return (head - tail) & (channel->fifo_size - 1);
+}
+
+/*
+ * Set tx channel state and inform the remote processor
+ */
+static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel,
+ int state)
+{
+ struct qcom_smd_edge *edge = channel->edge;
+ bool is_open = state == SMD_CHANNEL_OPENED;
+
+ if (channel->state == state)
+ return;
+
+ dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state);
+
+ SET_TX_CHANNEL_FLAG(channel, fDSR, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fCTS, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fCD, is_open);
+
+ SET_TX_CHANNEL_INFO(channel, state, state);
+ SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
+
+ channel->state = state;
+ qcom_smd_signal_channel(channel);
+}
+
+/*
+ * Copy count bytes of data using 32bit accesses, if that's required.
+ */
+static void smd_copy_to_fifo(void __iomem *dst,
+ const void *src,
+ size_t count,
+ bool word_aligned)
+{
+ if (word_aligned) {
+ __iowrite32_copy(dst, src, count / sizeof(u32));
+ } else {
+ memcpy_toio(dst, src, count);
+ }
+}
+
+/*
+ * Copy count bytes of data using 32bit accesses, if that is required.
+ */
+static void smd_copy_from_fifo(void *dst,
+ const void __iomem *src,
+ size_t count,
+ bool word_aligned)
+{
+ if (word_aligned) {
+ __ioread32_copy(dst, src, count / sizeof(u32));
+ } else {
+ memcpy_fromio(dst, src, count);
+ }
+}
+
+/*
+ * Read count bytes of data from the rx fifo into buf, but don't advance the
+ * tail.
+ */
+static size_t qcom_smd_channel_peek(struct qcom_smd_channel *channel,
+ void *buf, size_t count)
+{
+ bool word_aligned;
+ unsigned tail;
+ size_t len;
+
+ word_aligned = channel->info_word;
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+
+ len = min_t(size_t, count, channel->fifo_size - tail);
+ if (len) {
+ smd_copy_from_fifo(buf,
+ channel->rx_fifo + tail,
+ len,
+ word_aligned);
+ }
+
+ if (len != count) {
+ smd_copy_from_fifo(buf + len,
+ channel->rx_fifo,
+ count - len,
+ word_aligned);
+ }
+
+ return count;
+}
+
+/*
+ * Advance the rx tail by count bytes.
+ */
+static void qcom_smd_channel_advance(struct qcom_smd_channel *channel,
+ size_t count)
+{
+ unsigned tail;
+
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+ tail += count;
+ tail &= (channel->fifo_size - 1);
+ SET_RX_CHANNEL_INFO(channel, tail, tail);
+}
+
+/*
+ * Read out a single packet from the rx fifo and deliver it to the device
+ */
+static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
+{
+ struct rpmsg_endpoint *ept = &channel->qsept->ept;
+ unsigned tail;
+ size_t len;
+ void *ptr;
+ int ret;
+
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+
+ /* Use bounce buffer if the data wraps */
+ if (tail + channel->pkt_size >= channel->fifo_size) {
+ ptr = channel->bounce_buffer;
+ len = qcom_smd_channel_peek(channel, ptr, channel->pkt_size);
+ } else {
+ ptr = channel->rx_fifo + tail;
+ len = channel->pkt_size;
+ }
+
+ ret = ept->cb(ept->rpdev, ptr, len, ept->priv, RPMSG_ADDR_ANY);
+ if (ret < 0)
+ return ret;
+
+ /* Only forward the tail if the client consumed the data */
+ qcom_smd_channel_advance(channel, len);
+
+ channel->pkt_size = 0;
+
+ return 0;
+}
+
+/*
+ * Per channel interrupt handling
+ */
+static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
+{
+ bool need_state_scan = false;
+ int remote_state;
+ __le32 pktlen;
+ int avail;
+ int ret;
+
+ /* Handle state changes */
+ remote_state = GET_RX_CHANNEL_INFO(channel, state);
+ if (remote_state != channel->remote_state) {
+ channel->remote_state = remote_state;
+ need_state_scan = true;
+ }
+ /* Indicate that we have seen any state change */
+ SET_RX_CHANNEL_FLAG(channel, fSTATE, 0);
+
+ /* Signal waiting qcom_smd_send() about the interrupt */
+ if (!GET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR))
+ wake_up_interruptible(&channel->fblockread_event);
+
+ /* Don't consume any data until we've opened the channel */
+ if (channel->state != SMD_CHANNEL_OPENED)
+ goto out;
+
+ /* Indicate that we've seen the new data */
+ SET_RX_CHANNEL_FLAG(channel, fHEAD, 0);
+
+ /* Consume data */
+ for (;;) {
+ avail = qcom_smd_channel_get_rx_avail(channel);
+
+ if (!channel->pkt_size && avail >= SMD_PACKET_HEADER_LEN) {
+ qcom_smd_channel_peek(channel, &pktlen, sizeof(pktlen));
+ qcom_smd_channel_advance(channel, SMD_PACKET_HEADER_LEN);
+ channel->pkt_size = le32_to_cpu(pktlen);
+ } else if (channel->pkt_size && avail >= channel->pkt_size) {
+ ret = qcom_smd_channel_recv_single(channel);
+ if (ret)
+ break;
+ } else {
+ break;
+ }
+ }
+
+ /* Indicate that we have seen and updated tail */
+ SET_RX_CHANNEL_FLAG(channel, fTAIL, 1);
+
+ /* Signal the remote that we've consumed the data (if requested) */
+ if (!GET_RX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) {
+ /* Ensure ordering of channel info updates */
+ wmb();
+
+ qcom_smd_signal_channel(channel);
+ }
+
+out:
+ return need_state_scan;
+}
+
+/*
+ * The edge interrupts are triggered by the remote processor on state changes,
+ * channel info updates or when new channels are created.
+ */
+static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
+{
+ struct qcom_smd_edge *edge = data;
+ struct qcom_smd_channel *channel;
+ unsigned available;
+ bool kick_scanner = false;
+ bool kick_state = false;
+
+ /*
+ * Handle state changes or data on each of the channels on this edge
+ */
+ spin_lock(&edge->channels_lock);
+ list_for_each_entry(channel, &edge->channels, list) {
+ spin_lock(&channel->recv_lock);
+ kick_state |= qcom_smd_channel_intr(channel);
+ spin_unlock(&channel->recv_lock);
+ }
+ spin_unlock(&edge->channels_lock);
+
+ /*
+ * Creating a new channel requires allocating an smem entry, so we only
+ * have to scan if the amount of available space in smem have changed
+ * since last scan.
+ */
+ available = qcom_smem_get_free_space(edge->remote_pid);
+ if (available != edge->smem_available) {
+ edge->smem_available = available;
+ kick_scanner = true;
+ }
+
+ if (kick_scanner)
+ schedule_work(&edge->scan_work);
+ if (kick_state)
+ schedule_work(&edge->state_work);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Calculate how much space is available in the tx fifo.
+ */
+static size_t qcom_smd_get_tx_avail(struct qcom_smd_channel *channel)
+{
+ unsigned head;
+ unsigned tail;
+ unsigned mask = channel->fifo_size - 1;
+
+ head = GET_TX_CHANNEL_INFO(channel, head);
+ tail = GET_TX_CHANNEL_INFO(channel, tail);
+
+ return mask - ((head - tail) & mask);
+}
+
+/*
+ * Write count bytes of data into channel, possibly wrapping in the ring buffer
+ */
+static int qcom_smd_write_fifo(struct qcom_smd_channel *channel,
+ const void *data,
+ size_t count)
+{
+ bool word_aligned;
+ unsigned head;
+ size_t len;
+
+ word_aligned = channel->info_word;
+ head = GET_TX_CHANNEL_INFO(channel, head);
+
+ len = min_t(size_t, count, channel->fifo_size - head);
+ if (len) {
+ smd_copy_to_fifo(channel->tx_fifo + head,
+ data,
+ len,
+ word_aligned);
+ }
+
+ if (len != count) {
+ smd_copy_to_fifo(channel->tx_fifo,
+ data + len,
+ count - len,
+ word_aligned);
+ }
+
+ head += count;
+ head &= (channel->fifo_size - 1);
+ SET_TX_CHANNEL_INFO(channel, head, head);
+
+ return count;
+}
+
+/**
+ * qcom_smd_send - write data to smd channel
+ * @channel: channel handle
+ * @data: buffer of data to write
+ * @len: number of bytes to write
+ *
+ * This is a blocking write of len bytes into the channel's tx ring buffer and
+ * signal the remote end. It will sleep until there is enough space available
+ * in the tx buffer, utilizing the fBLOCKREADINTR signaling mechanism to avoid
+ * polling.
+ */
+static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
+ int len, bool wait)
+{
+ __le32 hdr[5] = { cpu_to_le32(len), };
+ int tlen = sizeof(hdr) + len;
+ int ret;
+
+ /* Word aligned channels only accept word size aligned data */
+ if (channel->info_word && len % 4)
+ return -EINVAL;
+
+ /* Reject packets that are too big */
+ if (tlen >= channel->fifo_size)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&channel->tx_lock);
+ if (ret)
+ return ret;
+
+ while (qcom_smd_get_tx_avail(channel) < tlen) {
+ if (!wait) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (channel->state != SMD_CHANNEL_OPENED) {
+ ret = -EPIPE;
+ goto out;
+ }
+
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0);
+
+ ret = wait_event_interruptible(channel->fblockread_event,
+ qcom_smd_get_tx_avail(channel) >= tlen ||
+ channel->state != SMD_CHANNEL_OPENED);
+ if (ret)
+ goto out;
+
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
+ }
+
+ SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
+
+ qcom_smd_write_fifo(channel, hdr, sizeof(hdr));
+ qcom_smd_write_fifo(channel, data, len);
+
+ SET_TX_CHANNEL_FLAG(channel, fHEAD, 1);
+
+ /* Ensure ordering of channel info updates */
+ wmb();
+
+ qcom_smd_signal_channel(channel);
+
+out:
+ mutex_unlock(&channel->tx_lock);
+
+ return ret;
+}
+
+/*
+ * Helper for opening a channel
+ */
+static int qcom_smd_channel_open(struct qcom_smd_channel *channel,
+ rpmsg_rx_cb_t cb)
+{
+ size_t bb_size;
+
+ /*
+ * Packets are maximum 4k, but reduce if the fifo is smaller
+ */
+ bb_size = min(channel->fifo_size, SZ_4K);
+ channel->bounce_buffer = kmalloc(bb_size, GFP_KERNEL);
+ if (!channel->bounce_buffer)
+ return -ENOMEM;
+
+ qcom_smd_channel_set_callback(channel, cb);
+ qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING);
+ qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED);
+
+ return 0;
+}
+
+/*
+ * Helper for closing and resetting a channel
+ */
+static void qcom_smd_channel_close(struct qcom_smd_channel *channel)
+{
+ qcom_smd_channel_set_callback(channel, NULL);
+
+ kfree(channel->bounce_buffer);
+ channel->bounce_buffer = NULL;
+
+ qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED);
+ qcom_smd_channel_reset(channel);
+}
+
+static struct qcom_smd_channel *
+qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_channel *ret = NULL;
+ unsigned long flags;
+ unsigned state;
+
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ list_for_each_entry(channel, &edge->channels, list) {
+ if (strcmp(channel->name, name))
+ continue;
+
+ state = GET_RX_CHANNEL_INFO(channel, state);
+ if (state != SMD_CHANNEL_OPENING &&
+ state != SMD_CHANNEL_OPENED)
+ continue;
+
+ ret = channel;
+ break;
+ }
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+
+ return ret;
+}
+
+static void __ept_release(struct kref *kref)
+{
+ struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
+ refcount);
+ kfree(to_smd_endpoint(ept));
+}
+
+static struct rpmsg_endpoint *qcom_smd_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo)
+{
+ struct qcom_smd_endpoint *qsept;
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_device *qsdev = to_smd_device(rpdev);
+ struct qcom_smd_edge *edge = qsdev->edge;
+ struct rpmsg_endpoint *ept;
+ const char *name = chinfo.name;
+ int ret;
+
+ /* Wait up to HZ for the channel to appear */
+ ret = wait_event_interruptible_timeout(edge->new_channel_event,
+ (channel = qcom_smd_find_channel(edge, name)) != NULL,
+ HZ);
+ if (!ret)
+ return NULL;
+
+ if (channel->state != SMD_CHANNEL_CLOSED) {
+ dev_err(&rpdev->dev, "channel %s is busy\n", channel->name);
+ return NULL;
+ }
+
+ qsept = kzalloc(sizeof(*qsept), GFP_KERNEL);
+ if (!qsept)
+ return NULL;
+
+ ept = &qsept->ept;
+
+ kref_init(&ept->refcount);
+
+ ept->rpdev = rpdev;
+ ept->cb = cb;
+ ept->priv = priv;
+ ept->ops = &qcom_smd_endpoint_ops;
+
+ channel->qsept = qsept;
+ qsept->qsch = channel;
+
+ ret = qcom_smd_channel_open(channel, cb);
+ if (ret)
+ goto free_ept;
+
+ return ept;
+
+free_ept:
+ channel->qsept = NULL;
+ kref_put(&ept->refcount, __ept_release);
+ return NULL;
+}
+
+static void qcom_smd_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
+ struct qcom_smd_channel *ch = qsept->qsch;
+
+ qcom_smd_channel_close(ch);
+ ch->qsept = NULL;
+ kref_put(&ept->refcount, __ept_release);
+}
+
+static int qcom_smd_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
+
+ return __qcom_smd_send(qsept->qsch, data, len, true);
+}
+
+static int qcom_smd_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
+
+ return __qcom_smd_send(qsept->qsch, data, len, false);
+}
+
+/*
+ * Finds the device_node for the smd child interested in this channel.
+ */
+static struct device_node *qcom_smd_match_channel(struct device_node *edge_node,
+ const char *channel)
+{
+ struct device_node *child;
+ const char *name;
+ const char *key;
+ int ret;
+
+ for_each_available_child_of_node(edge_node, child) {
+ key = "qcom,smd-channels";
+ ret = of_property_read_string(child, key, &name);
+ if (ret)
+ continue;
+
+ if (strcmp(name, channel) == 0)
+ return child;
+ }
+
+ return NULL;
+}
+
+static const struct rpmsg_device_ops qcom_smd_device_ops = {
+ .create_ept = qcom_smd_create_ept,
+};
+
+static const struct rpmsg_endpoint_ops qcom_smd_endpoint_ops = {
+ .destroy_ept = qcom_smd_destroy_ept,
+ .send = qcom_smd_send,
+ .trysend = qcom_smd_trysend,
+};
+
+/*
+ * Create a smd client device for channel that is being opened.
+ */
+static int qcom_smd_create_device(struct qcom_smd_channel *channel)
+{
+ struct qcom_smd_device *qsdev;
+ struct rpmsg_device *rpdev;
+ struct qcom_smd_edge *edge = channel->edge;
+
+ dev_dbg(&edge->dev, "registering '%s'\n", channel->name);
+
+ qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL);
+ if (!qsdev)
+ return -ENOMEM;
+
+ /* Link qsdev to our SMD edge */
+ qsdev->edge = edge;
+
+ /* Assign callbacks for rpmsg_device */
+ qsdev->rpdev.ops = &qcom_smd_device_ops;
+
+ /* Assign public information to the rpmsg_device */
+ rpdev = &qsdev->rpdev;
+ strncpy(rpdev->id.name, channel->name, RPMSG_NAME_SIZE);
+ rpdev->src = RPMSG_ADDR_ANY;
+ rpdev->dst = RPMSG_ADDR_ANY;
+
+ rpdev->dev.of_node = qcom_smd_match_channel(edge->of_node, channel->name);
+ rpdev->dev.parent = &edge->dev;
+
+ return rpmsg_register_device(rpdev);
+}
+
+/*
+ * Allocate the qcom_smd_channel object for a newly found smd channel,
+ * retrieving and validating the smem items involved.
+ */
+static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *edge,
+ unsigned smem_info_item,
+ unsigned smem_fifo_item,
+ char *name)
+{
+ struct qcom_smd_channel *channel;
+ size_t fifo_size;
+ size_t info_size;
+ void *fifo_base;
+ void *info;
+ int ret;
+
+ channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL);
+ if (!channel)
+ return ERR_PTR(-ENOMEM);
+
+ channel->edge = edge;
+ channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL);
+ if (!channel->name)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&channel->tx_lock);
+ spin_lock_init(&channel->recv_lock);
+ init_waitqueue_head(&channel->fblockread_event);
+
+ info = qcom_smem_get(edge->remote_pid, smem_info_item, &info_size);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+ goto free_name_and_channel;
+ }
+
+ /*
+ * Use the size of the item to figure out which channel info struct to
+ * use.
+ */
+ if (info_size == 2 * sizeof(struct smd_channel_info_word)) {
+ channel->info_word = info;
+ } else if (info_size == 2 * sizeof(struct smd_channel_info)) {
+ channel->info = info;
+ } else {
+ dev_err(&edge->dev,
+ "channel info of size %zu not supported\n", info_size);
+ ret = -EINVAL;
+ goto free_name_and_channel;
+ }
+
+ fifo_base = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_size);
+ if (IS_ERR(fifo_base)) {
+ ret = PTR_ERR(fifo_base);
+ goto free_name_and_channel;
+ }
+
+ /* The channel consist of a rx and tx fifo of equal size */
+ fifo_size /= 2;
+
+ dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
+ name, info_size, fifo_size);
+
+ channel->tx_fifo = fifo_base;
+ channel->rx_fifo = fifo_base + fifo_size;
+ channel->fifo_size = fifo_size;
+
+ qcom_smd_channel_reset(channel);
+
+ return channel;
+
+free_name_and_channel:
+ devm_kfree(&edge->dev, channel->name);
+ devm_kfree(&edge->dev, channel);
+
+ return ERR_PTR(ret);
+}
+
+/*
+ * Scans the allocation table for any newly allocated channels, calls
+ * qcom_smd_create_channel() to create representations of these and add
+ * them to the edge's list of channels.
+ */
+static void qcom_channel_scan_worker(struct work_struct *work)
+{
+ struct qcom_smd_edge *edge = container_of(work, struct qcom_smd_edge, scan_work);
+ struct qcom_smd_alloc_entry *alloc_tbl;
+ struct qcom_smd_alloc_entry *entry;
+ struct qcom_smd_channel *channel;
+ unsigned long flags;
+ unsigned fifo_id;
+ unsigned info_id;
+ int tbl;
+ int i;
+ u32 eflags, cid;
+
+ for (tbl = 0; tbl < SMD_ALLOC_TBL_COUNT; tbl++) {
+ alloc_tbl = qcom_smem_get(edge->remote_pid,
+ smem_items[tbl].alloc_tbl_id, NULL);
+ if (IS_ERR(alloc_tbl))
+ continue;
+
+ for (i = 0; i < SMD_ALLOC_TBL_SIZE; i++) {
+ entry = &alloc_tbl[i];
+ eflags = le32_to_cpu(entry->flags);
+ if (test_bit(i, edge->allocated[tbl]))
+ continue;
+
+ if (entry->ref_count == 0)
+ continue;
+
+ if (!entry->name[0])
+ continue;
+
+ if (!(eflags & SMD_CHANNEL_FLAGS_PACKET))
+ continue;
+
+ if ((eflags & SMD_CHANNEL_FLAGS_EDGE_MASK) != edge->edge_id)
+ continue;
+
+ cid = le32_to_cpu(entry->cid);
+ info_id = smem_items[tbl].info_base_id + cid;
+ fifo_id = smem_items[tbl].fifo_base_id + cid;
+
+ channel = qcom_smd_create_channel(edge, info_id, fifo_id, entry->name);
+ if (IS_ERR(channel))
+ continue;
+
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ list_add(&channel->list, &edge->channels);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+
+ dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name);
+ set_bit(i, edge->allocated[tbl]);
+
+ wake_up_interruptible(&edge->new_channel_event);
+ }
+ }
+
+ schedule_work(&edge->state_work);
+}
+
+/*
+ * This per edge worker scans smem for any new channels and register these. It
+ * then scans all registered channels for state changes that should be handled
+ * by creating or destroying smd client devices for the registered channels.
+ *
+ * LOCKING: edge->channels_lock only needs to cover the list operations, as the
+ * worker is killed before any channels are deallocated
+ */
+static void qcom_channel_state_worker(struct work_struct *work)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_edge *edge = container_of(work,
+ struct qcom_smd_edge,
+ state_work);
+ struct rpmsg_channel_info chinfo;
+ unsigned remote_state;
+ unsigned long flags;
+
+ /*
+ * Register a device for any closed channel where the remote processor
+ * is showing interest in opening the channel.
+ */
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ list_for_each_entry(channel, &edge->channels, list) {
+ if (channel->state != SMD_CHANNEL_CLOSED)
+ continue;
+
+ remote_state = GET_RX_CHANNEL_INFO(channel, state);
+ if (remote_state != SMD_CHANNEL_OPENING &&
+ remote_state != SMD_CHANNEL_OPENED)
+ continue;
+
+ if (channel->registered)
+ continue;
+
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+ qcom_smd_create_device(channel);
+ channel->registered = true;
+ spin_lock_irqsave(&edge->channels_lock, flags);
+
+ channel->registered = true;
+ }
+
+ /*
+ * Unregister the device for any channel that is opened where the
+ * remote processor is closing the channel.
+ */
+ list_for_each_entry(channel, &edge->channels, list) {
+ if (channel->state != SMD_CHANNEL_OPENING &&
+ channel->state != SMD_CHANNEL_OPENED)
+ continue;
+
+ remote_state = GET_RX_CHANNEL_INFO(channel, state);
+ if (remote_state == SMD_CHANNEL_OPENING ||
+ remote_state == SMD_CHANNEL_OPENED)
+ continue;
+
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+
+ strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+ chinfo.src = RPMSG_ADDR_ANY;
+ chinfo.dst = RPMSG_ADDR_ANY;
+ rpmsg_unregister_device(&edge->dev, &chinfo);
+ channel->registered = false;
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ }
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+}
+
+/*
+ * Parses an of_node describing an edge.
+ */
+static int qcom_smd_parse_edge(struct device *dev,
+ struct device_node *node,
+ struct qcom_smd_edge *edge)
+{
+ struct device_node *syscon_np;
+ const char *key;
+ int irq;
+ int ret;
+
+ INIT_LIST_HEAD(&edge->channels);
+ spin_lock_init(&edge->channels_lock);
+
+ INIT_WORK(&edge->scan_work, qcom_channel_scan_worker);
+ INIT_WORK(&edge->state_work, qcom_channel_state_worker);
+
+ edge->of_node = of_node_get(node);
+
+ key = "qcom,smd-edge";
+ ret = of_property_read_u32(node, key, &edge->edge_id);
+ if (ret) {
+ dev_err(dev, "edge missing %s property\n", key);
+ return -EINVAL;
+ }
+
+ edge->remote_pid = QCOM_SMEM_HOST_ANY;
+ key = "qcom,remote-pid";
+ of_property_read_u32(node, key, &edge->remote_pid);
+
+ syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
+ if (!syscon_np) {
+ dev_err(dev, "no qcom,ipc node\n");
+ return -ENODEV;
+ }
+
+ edge->ipc_regmap = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(edge->ipc_regmap))
+ return PTR_ERR(edge->ipc_regmap);
+
+ key = "qcom,ipc";
+ ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset);
+ if (ret < 0) {
+ dev_err(dev, "no offset in %s\n", key);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit);
+ if (ret < 0) {
+ dev_err(dev, "no bit in %s\n", key);
+ return -EINVAL;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq < 0) {
+ dev_err(dev, "required smd interrupt missing\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(dev, irq,
+ qcom_smd_edge_intr, IRQF_TRIGGER_RISING,
+ node->name, edge);
+ if (ret) {
+ dev_err(dev, "failed to request smd irq\n");
+ return ret;
+ }
+
+ edge->irq = irq;
+
+ return 0;
+}
+
+/*
+ * Release function for an edge.
+ * Reset the state of each associated channel and free the edge context.
+ */
+static void qcom_smd_edge_release(struct device *dev)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_edge *edge = to_smd_edge(dev);
+
+ list_for_each_entry(channel, &edge->channels, list) {
+ SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
+ SET_RX_CHANNEL_INFO(channel, head, 0);
+ SET_RX_CHANNEL_INFO(channel, tail, 0);
+ }
+
+ kfree(edge);
+}
+
+/**
+ * qcom_smd_register_edge() - register an edge based on an device_node
+ * @parent: parent device for the edge
+ * @node: device_node describing the edge
+ *
+ * Returns an edge reference, or negative ERR_PTR() on failure.
+ */
+struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
+ struct device_node *node)
+{
+ struct qcom_smd_edge *edge;
+ int ret;
+
+ edge = kzalloc(sizeof(*edge), GFP_KERNEL);
+ if (!edge)
+ return ERR_PTR(-ENOMEM);
+
+ init_waitqueue_head(&edge->new_channel_event);
+
+ edge->dev.parent = parent;
+ edge->dev.release = qcom_smd_edge_release;
+ dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name);
+ ret = device_register(&edge->dev);
+ if (ret) {
+ pr_err("failed to register smd edge\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = qcom_smd_parse_edge(&edge->dev, node, edge);
+ if (ret) {
+ dev_err(&edge->dev, "failed to parse smd edge\n");
+ goto unregister_dev;
+ }
+
+ schedule_work(&edge->scan_work);
+
+ return edge;
+
+unregister_dev:
+ put_device(&edge->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(qcom_smd_register_edge);
+
+static int qcom_smd_remove_device(struct device *dev, void *data)
+{
+ device_unregister(dev);
+
+ return 0;
+}
+
+/**
+ * qcom_smd_unregister_edge() - release an edge and its children
+ * @edge: edge reference acquired from qcom_smd_register_edge
+ */
+int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
+{
+ int ret;
+
+ disable_irq(edge->irq);
+ cancel_work_sync(&edge->scan_work);
+ cancel_work_sync(&edge->state_work);
+
+ ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device);
+ if (ret)
+ dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);
+
+ device_unregister(&edge->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(qcom_smd_unregister_edge);
+
+static int qcom_smd_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
+ void *p;
+
+ /* Wait for smem */
+ p = qcom_smem_get(QCOM_SMEM_HOST_ANY, smem_items[0].alloc_tbl_id, NULL);
+ if (PTR_ERR(p) == -EPROBE_DEFER)
+ return PTR_ERR(p);
+
+ for_each_available_child_of_node(pdev->dev.of_node, node)
+ qcom_smd_register_edge(&pdev->dev, node);
+
+ return 0;
+}
+
+static int qcom_smd_remove_edge(struct device *dev, void *data)
+{
+ struct qcom_smd_edge *edge = to_smd_edge(dev);
+
+ return qcom_smd_unregister_edge(edge);
+}
+
+/*
+ * Shut down all smd clients by making sure that each edge stops processing
+ * events and scanning for new channels, then call destroy on the devices.
+ */
+static int qcom_smd_remove(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge);
+ if (ret)
+ dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id qcom_smd_of_match[] = {
+ { .compatible = "qcom,smd" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_smd_of_match);
+
+static struct platform_driver qcom_smd_driver = {
+ .probe = qcom_smd_probe,
+ .remove = qcom_smd_remove,
+ .driver = {
+ .name = "qcom-smd",
+ .of_match_table = qcom_smd_of_match,
+ },
+};
+
+static int __init qcom_smd_init(void)
+{
+ return platform_driver_register(&qcom_smd_driver);
+}
+subsys_initcall(qcom_smd_init);
+
+static void __exit qcom_smd_exit(void)
+{
+ platform_driver_unregister(&qcom_smd_driver);
+}
+module_exit(qcom_smd_exit);
+
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
+MODULE_DESCRIPTION("Qualcomm Shared Memory Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
new file mode 100644
index 000000000000..b6ea9ffa7381
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -0,0 +1,498 @@
+/*
+ * remote processor messaging bus
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include "rpmsg_internal.h"
+
+/**
+ * rpmsg_create_ept() - create a new rpmsg_endpoint
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @priv: private data for the driver's use
+ * @chinfo: channel_info with the local rpmsg address to bind with @cb
+ *
+ * Every rpmsg address in the system is bound to an rx callback (so when
+ * inbound messages arrive, they are dispatched by the rpmsg bus using the
+ * appropriate callback handler) by means of an rpmsg_endpoint struct.
+ *
+ * This function allows drivers to create such an endpoint, and by that,
+ * bind a callback, and possibly some private data too, to an rpmsg address
+ * (either one that is known in advance, or one that will be dynamically
+ * assigned for them).
+ *
+ * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+ * is already created for them when they are probed by the rpmsg bus
+ * (using the rx callback provided when they registered to the rpmsg bus).
+ *
+ * So things should just work for simple drivers: they already have an
+ * endpoint, their rx callback is bound to their rpmsg address, and when
+ * relevant inbound messages arrive (i.e. messages which their dst address
+ * equals to the src address of their rpmsg channel), the driver's handler
+ * is invoked to process it.
+ *
+ * That said, more complicated drivers might do need to allocate
+ * additional rpmsg addresses, and bind them to different rx callbacks.
+ * To accomplish that, those drivers need to call this function.
+ *
+ * Drivers should provide their @rpdev channel (so the new endpoint would belong
+ * to the same remote processor their channel belongs to), an rx callback
+ * function, an optional private data (which is provided back when the
+ * rx callback is invoked), and an address they want to bind with the
+ * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+ * dynamically assign them an available rpmsg address (drivers should have
+ * a very good reason why not to always use RPMSG_ADDR_ANY here).
+ *
+ * Returns a pointer to the endpoint on success, or NULL on error.
+ */
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo)
+{
+ return rpdev->ops->create_ept(rpdev, cb, priv, chinfo);
+}
+EXPORT_SYMBOL(rpmsg_create_ept);
+
+/**
+ * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
+ * @ept: endpoing to destroy
+ *
+ * Should be used by drivers to destroy an rpmsg endpoint previously
+ * created with rpmsg_create_ept().
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ ept->ops->destroy_ept(ept);
+}
+EXPORT_SYMBOL(rpmsg_destroy_ept);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address and its associated rpmsg
+ * device destination addresses.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ return ept->ops->send(ept, data, len);
+}
+EXPORT_SYMBOL(rpmsg_send);
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
+{
+ return ept->ops->sendto(ept, data, len, dst);
+}
+EXPORT_SYMBOL(rpmsg_sendto);
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len)
+{
+ return ept->ops->send_offchannel(ept, src, dst, data, len);
+}
+EXPORT_SYMBOL(rpmsg_send_offchannel);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source and its associated
+ * rpdev's address as destination.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ return ept->ops->trysend(ept, data, len);
+}
+EXPORT_SYMBOL(rpmsg_trysend);
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
+{
+ return ept->ops->trysendto(ept, data, len, dst);
+}
+EXPORT_SYMBOL(rpmsg_trysendto);
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len)
+{
+ return ept->ops->trysend_offchannel(ept, src, dst, data, len);
+}
+EXPORT_SYMBOL(rpmsg_trysend_offchannel);
+
+/*
+ * match an rpmsg channel with a channel info struct.
+ * this is used to make sure we're not creating rpmsg devices for channels
+ * that already exist.
+ */
+static int rpmsg_device_match(struct device *dev, void *data)
+{
+ struct rpmsg_channel_info *chinfo = data;
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
+ return 0;
+
+ if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
+ return 0;
+
+ if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
+ return 0;
+
+ /* found a match ! */
+ return 1;
+}
+
+struct device *rpmsg_find_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo)
+{
+ return device_find_child(parent, chinfo, rpmsg_device_match);
+
+}
+EXPORT_SYMBOL(rpmsg_find_device);
+
+/* sysfs show configuration fields */
+#define rpmsg_show_attr(field, path, format_string) \
+static ssize_t \
+field##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
+ \
+ return sprintf(buf, format_string, rpdev->path); \
+}
+
+/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
+rpmsg_show_attr(name, id.name, "%s\n");
+rpmsg_show_attr(src, src, "0x%x\n");
+rpmsg_show_attr(dst, dst, "0x%x\n");
+rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
+
+static ssize_t modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
+}
+
+static struct device_attribute rpmsg_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(modalias),
+ __ATTR_RO(dst),
+ __ATTR_RO(src),
+ __ATTR_RO(announce),
+ __ATTR_NULL
+};
+
+/* rpmsg devices and drivers are matched using the service name */
+static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
+ const struct rpmsg_device_id *id)
+{
+ return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
+}
+
+/* match rpmsg channel and rpmsg driver */
+static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
+ const struct rpmsg_device_id *ids = rpdrv->id_table;
+ unsigned int i;
+
+ if (ids)
+ for (i = 0; ids[i].name[0]; i++)
+ if (rpmsg_id_match(rpdev, &ids[i]))
+ return 1;
+
+ return of_driver_match_device(dev, drv);
+}
+
+static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
+ rpdev->id.name);
+}
+
+/*
+ * when an rpmsg driver is probed with a channel, we seamlessly create
+ * it an endpoint, binding its rx callback to a unique local rpmsg
+ * address.
+ *
+ * if we need to, we also announce about this channel to the remote
+ * processor (needed in case the driver is exposing an rpmsg service).
+ */
+static int rpmsg_dev_probe(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+ struct rpmsg_channel_info chinfo = {};
+ struct rpmsg_endpoint *ept;
+ int err;
+
+ strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
+ chinfo.src = rpdev->src;
+ chinfo.dst = RPMSG_ADDR_ANY;
+
+ ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo);
+ if (!ept) {
+ dev_err(dev, "failed to create endpoint\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ rpdev->ept = ept;
+ rpdev->src = ept->addr;
+
+ err = rpdrv->probe(rpdev);
+ if (err) {
+ dev_err(dev, "%s: failed: %d\n", __func__, err);
+ rpmsg_destroy_ept(ept);
+ goto out;
+ }
+
+ if (rpdev->ops->announce_create)
+ err = rpdev->ops->announce_create(rpdev);
+out:
+ return err;
+}
+
+static int rpmsg_dev_remove(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+ int err = 0;
+
+ if (rpdev->ops->announce_destroy)
+ err = rpdev->ops->announce_destroy(rpdev);
+
+ rpdrv->remove(rpdev);
+
+ rpmsg_destroy_ept(rpdev->ept);
+
+ return err;
+}
+
+static struct bus_type rpmsg_bus = {
+ .name = "rpmsg",
+ .match = rpmsg_dev_match,
+ .dev_attrs = rpmsg_dev_attrs,
+ .uevent = rpmsg_uevent,
+ .probe = rpmsg_dev_probe,
+ .remove = rpmsg_dev_remove,
+};
+
+static void rpmsg_release_device(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ kfree(rpdev);
+}
+
+int rpmsg_register_device(struct rpmsg_device *rpdev)
+{
+ struct device *dev = &rpdev->dev;
+ int ret;
+
+ dev_set_name(&rpdev->dev, "%s:%s",
+ dev_name(dev->parent), rpdev->id.name);
+
+ rpdev->dev.bus = &rpmsg_bus;
+ rpdev->dev.release = rpmsg_release_device;
+
+ ret = device_register(&rpdev->dev);
+ if (ret) {
+ dev_err(dev, "device_register failed: %d\n", ret);
+ put_device(&rpdev->dev);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(rpmsg_register_device);
+
+/*
+ * find an existing channel using its name + address properties,
+ * and destroy it
+ */
+int rpmsg_unregister_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo)
+{
+ struct device *dev;
+
+ dev = rpmsg_find_device(parent, chinfo);
+ if (!dev)
+ return -EINVAL;
+
+ device_unregister(dev);
+
+ put_device(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(rpmsg_unregister_device);
+
+/**
+ * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ * @owner: owning module/driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner)
+{
+ rpdrv->drv.bus = &rpmsg_bus;
+ rpdrv->drv.owner = owner;
+ return driver_register(&rpdrv->drv);
+}
+EXPORT_SYMBOL(__register_rpmsg_driver);
+
+/**
+ * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+ driver_unregister(&rpdrv->drv);
+}
+EXPORT_SYMBOL(unregister_rpmsg_driver);
+
+
+static int __init rpmsg_init(void)
+{
+ int ret;
+
+ ret = bus_register(&rpmsg_bus);
+ if (ret)
+ pr_err("failed to register rpmsg bus: %d\n", ret);
+
+ return ret;
+}
+postcore_initcall(rpmsg_init);
+
+static void __exit rpmsg_fini(void)
+{
+ bus_unregister(&rpmsg_bus);
+}
+module_exit(rpmsg_fini);
+
+MODULE_DESCRIPTION("remote processor messaging bus");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
new file mode 100644
index 000000000000..8075a20f919b
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -0,0 +1,82 @@
+/*
+ * remote processor messaging bus internals
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __RPMSG_INTERNAL_H__
+#define __RPMSG_INTERNAL_H__
+
+#include <linux/rpmsg.h>
+
+#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
+#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+
+/**
+ * struct rpmsg_device_ops - indirection table for the rpmsg_device operations
+ * @create_ept: create backend-specific endpoint, requried
+ * @announce_create: announce presence of new channel, optional
+ * @announce_destroy: announce destruction of channel, optional
+ *
+ * Indirection table for the operations that a rpmsg backend should implement.
+ * @announce_create and @announce_destroy are optional as the backend might
+ * advertise new channels implicitly by creating the endpoints.
+ */
+struct rpmsg_device_ops {
+ struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo);
+
+ int (*announce_create)(struct rpmsg_device *ept);
+ int (*announce_destroy)(struct rpmsg_device *ept);
+};
+
+/**
+ * struct rpmsg_endpoint_ops - indirection table for rpmsg_endpoint operations
+ * @destroy_ept: destroy the given endpoint, required
+ * @send: see @rpmsg_send(), required
+ * @sendto: see @rpmsg_sendto(), optional
+ * @send_offchannel: see @rpmsg_send_offchannel(), optional
+ * @trysend: see @rpmsg_trysend(), required
+ * @trysendto: see @rpmsg_trysendto(), optional
+ * @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional
+ *
+ * Indirection table for the operations that a rpmsg backend should implement.
+ * In addition to @destroy_ept, the backend must at least implement @send and
+ * @trysend, while the variants sending data off-channel are optional.
+ */
+struct rpmsg_endpoint_ops {
+ void (*destroy_ept)(struct rpmsg_endpoint *ept);
+
+ int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
+ int (*sendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+ int (*send_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
+
+ int (*trysend)(struct rpmsg_endpoint *ept, void *data, int len);
+ int (*trysendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+ int (*trysend_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
+};
+
+int rpmsg_register_device(struct rpmsg_device *rpdev);
+int rpmsg_unregister_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo);
+
+struct device *rpmsg_find_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo);
+
+#endif
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index fe03b2aef450..3090b0d3072f 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -33,6 +33,9 @@
#include <linux/wait.h>
#include <linux/rpmsg.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+#include "rpmsg_internal.h"
/**
* struct virtproc_info - virtual remote processor state
@@ -72,20 +75,69 @@ struct virtproc_info {
struct rpmsg_endpoint *ns_ept;
};
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
+
/**
- * struct rpmsg_channel_info - internal channel info representation
- * @name: name of service
- * @src: local address
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
* @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
*/
-struct rpmsg_channel_info {
- char name[RPMSG_NAME_SIZE];
+struct rpmsg_hdr {
u32 src;
u32 dst;
+ u32 reserved;
+ u16 len;
+ u16 flags;
+ u8 data[0];
+} __packed;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+ char name[RPMSG_NAME_SIZE];
+ u32 addr;
+ u32 flags;
+} __packed;
+
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+ RPMSG_NS_CREATE = 0,
+ RPMSG_NS_DESTROY = 1,
+};
+
+/**
+ * @vrp: the remote processor this channel belongs to
+ */
+struct virtio_rpmsg_channel {
+ struct rpmsg_device rpdev;
+
+ struct virtproc_info *vrp;
};
-#define to_rpmsg_channel(d) container_of(d, struct rpmsg_channel, dev)
-#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+#define to_virtio_rpmsg_channel(_rpdev) \
+ container_of(_rpdev, struct virtio_rpmsg_channel, rpdev)
/*
* We're allocating buffers of 512 bytes each for communications. The
@@ -118,78 +170,28 @@ struct rpmsg_channel_info {
/* Address 53 is reserved for advertising remote services */
#define RPMSG_NS_ADDR (53)
-/* sysfs show configuration fields */
-#define rpmsg_show_attr(field, path, format_string) \
-static ssize_t \
-field##_show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); \
- \
- return sprintf(buf, format_string, rpdev->path); \
-}
-
-/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
-rpmsg_show_attr(name, id.name, "%s\n");
-rpmsg_show_attr(src, src, "0x%x\n");
-rpmsg_show_attr(dst, dst, "0x%x\n");
-rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
-
-/*
- * Unique (and free running) index for rpmsg devices.
- *
- * Yeah, we're not recycling those numbers (yet?). will be easy
- * to change if/when we want to.
- */
-static unsigned int rpmsg_dev_index;
-
-static ssize_t modalias_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
-
- return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
-}
-
-static struct device_attribute rpmsg_dev_attrs[] = {
- __ATTR_RO(name),
- __ATTR_RO(modalias),
- __ATTR_RO(dst),
- __ATTR_RO(src),
- __ATTR_RO(announce),
- __ATTR_NULL
+static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
+static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len);
+static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
+ u32 dst);
+static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len);
+static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
+static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
+ int len, u32 dst);
+static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len);
+
+static const struct rpmsg_endpoint_ops virtio_endpoint_ops = {
+ .destroy_ept = virtio_rpmsg_destroy_ept,
+ .send = virtio_rpmsg_send,
+ .sendto = virtio_rpmsg_sendto,
+ .send_offchannel = virtio_rpmsg_send_offchannel,
+ .trysend = virtio_rpmsg_trysend,
+ .trysendto = virtio_rpmsg_trysendto,
+ .trysend_offchannel = virtio_rpmsg_trysend_offchannel,
};
-/* rpmsg devices and drivers are matched using the service name */
-static inline int rpmsg_id_match(const struct rpmsg_channel *rpdev,
- const struct rpmsg_device_id *id)
-{
- return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
-}
-
-/* match rpmsg channel and rpmsg driver */
-static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
-{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
- struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
- const struct rpmsg_device_id *ids = rpdrv->id_table;
- unsigned int i;
-
- for (i = 0; ids[i].name[0]; i++)
- if (rpmsg_id_match(rpdev, &ids[i]))
- return 1;
-
- return 0;
-}
-
-static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
-
- return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
- rpdev->id.name);
-}
-
/**
* __ept_release() - deallocate an rpmsg endpoint
* @kref: the ept's reference count
@@ -212,18 +214,17 @@ static void __ept_release(struct kref *kref)
/* for more info, see below documentation of rpmsg_create_ept() */
static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
- struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb,
- void *priv, u32 addr)
+ struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb,
+ void *priv, u32 addr)
{
int id_min, id_max, id;
struct rpmsg_endpoint *ept;
struct device *dev = rpdev ? &rpdev->dev : &vrp->vdev->dev;
ept = kzalloc(sizeof(*ept), GFP_KERNEL);
- if (!ept) {
- dev_err(dev, "failed to kzalloc a new ept\n");
+ if (!ept)
return NULL;
- }
kref_init(&ept->refcount);
mutex_init(&ept->cb_lock);
@@ -231,6 +232,7 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
ept->rpdev = rpdev;
ept->cb = cb;
ept->priv = priv;
+ ept->ops = &virtio_endpoint_ops;
/* do we need to allocate a local address ? */
if (addr == RPMSG_ADDR_ANY) {
@@ -261,52 +263,15 @@ free_ept:
return NULL;
}
-/**
- * rpmsg_create_ept() - create a new rpmsg_endpoint
- * @rpdev: rpmsg channel device
- * @cb: rx callback handler
- * @priv: private data for the driver's use
- * @addr: local rpmsg address to bind with @cb
- *
- * Every rpmsg address in the system is bound to an rx callback (so when
- * inbound messages arrive, they are dispatched by the rpmsg bus using the
- * appropriate callback handler) by means of an rpmsg_endpoint struct.
- *
- * This function allows drivers to create such an endpoint, and by that,
- * bind a callback, and possibly some private data too, to an rpmsg address
- * (either one that is known in advance, or one that will be dynamically
- * assigned for them).
- *
- * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
- * is already created for them when they are probed by the rpmsg bus
- * (using the rx callback provided when they registered to the rpmsg bus).
- *
- * So things should just work for simple drivers: they already have an
- * endpoint, their rx callback is bound to their rpmsg address, and when
- * relevant inbound messages arrive (i.e. messages which their dst address
- * equals to the src address of their rpmsg channel), the driver's handler
- * is invoked to process it.
- *
- * That said, more complicated drivers might do need to allocate
- * additional rpmsg addresses, and bind them to different rx callbacks.
- * To accomplish that, those drivers need to call this function.
- *
- * Drivers should provide their @rpdev channel (so the new endpoint would belong
- * to the same remote processor their channel belongs to), an rx callback
- * function, an optional private data (which is provided back when the
- * rx callback is invoked), and an address they want to bind with the
- * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
- * dynamically assign them an available rpmsg address (drivers should have
- * a very good reason why not to always use RPMSG_ADDR_ANY here).
- *
- * Returns a pointer to the endpoint on success, or NULL on error.
- */
-struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
- rpmsg_rx_cb_t cb, void *priv, u32 addr)
+static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb,
+ void *priv,
+ struct rpmsg_channel_info chinfo)
{
- return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+
+ return __rpmsg_create_ept(vch->vrp, rpdev, cb, priv, chinfo.src);
}
-EXPORT_SYMBOL(rpmsg_create_ept);
/**
* __rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
@@ -334,178 +299,82 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
kref_put(&ept->refcount, __ept_release);
}
-/**
- * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
- * @ept: endpoing to destroy
- *
- * Should be used by drivers to destroy an rpmsg endpoint previously
- * created with rpmsg_create_ept().
- */
-void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
{
- __rpmsg_destroy_ept(ept->rpdev->vrp, ept);
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(ept->rpdev);
+
+ __rpmsg_destroy_ept(vch->vrp, ept);
}
-EXPORT_SYMBOL(rpmsg_destroy_ept);
-/*
- * when an rpmsg driver is probed with a channel, we seamlessly create
- * it an endpoint, binding its rx callback to a unique local rpmsg
- * address.
- *
- * if we need to, we also announce about this channel to the remote
- * processor (needed in case the driver is exposing an rpmsg service).
- */
-static int rpmsg_dev_probe(struct device *dev)
+static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
- struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
- struct virtproc_info *vrp = rpdev->vrp;
- struct rpmsg_endpoint *ept;
- int err;
-
- ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
- if (!ept) {
- dev_err(dev, "failed to create endpoint\n");
- err = -ENOMEM;
- goto out;
- }
-
- rpdev->ept = ept;
- rpdev->src = ept->addr;
-
- err = rpdrv->probe(rpdev);
- if (err) {
- dev_err(dev, "%s: failed: %d\n", __func__, err);
- rpmsg_destroy_ept(ept);
- goto out;
- }
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+ struct virtproc_info *vrp = vch->vrp;
+ struct device *dev = &rpdev->dev;
+ int err = 0;
/* need to tell remote processor's name service about this channel ? */
if (rpdev->announce &&
- virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+ virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
struct rpmsg_ns_msg nsm;
strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
- nsm.addr = rpdev->src;
+ nsm.addr = rpdev->ept->addr;
nsm.flags = RPMSG_NS_CREATE;
- err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+ err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
if (err)
dev_err(dev, "failed to announce service %d\n", err);
}
-out:
return err;
}
-static int rpmsg_dev_remove(struct device *dev)
+static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
- struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
- struct virtproc_info *vrp = rpdev->vrp;
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+ struct virtproc_info *vrp = vch->vrp;
+ struct device *dev = &rpdev->dev;
int err = 0;
/* tell remote processor's name service we're removing this channel */
if (rpdev->announce &&
- virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+ virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
struct rpmsg_ns_msg nsm;
strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
nsm.addr = rpdev->src;
nsm.flags = RPMSG_NS_DESTROY;
- err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+ err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
if (err)
dev_err(dev, "failed to announce service %d\n", err);
}
- rpdrv->remove(rpdev);
-
- rpmsg_destroy_ept(rpdev->ept);
-
return err;
}
-static struct bus_type rpmsg_bus = {
- .name = "rpmsg",
- .match = rpmsg_dev_match,
- .dev_attrs = rpmsg_dev_attrs,
- .uevent = rpmsg_uevent,
- .probe = rpmsg_dev_probe,
- .remove = rpmsg_dev_remove,
+static const struct rpmsg_device_ops virtio_rpmsg_ops = {
+ .create_ept = virtio_rpmsg_create_ept,
+ .announce_create = virtio_rpmsg_announce_create,
+ .announce_destroy = virtio_rpmsg_announce_destroy,
};
-/**
- * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
- * @rpdrv: pointer to a struct rpmsg_driver
- * @owner: owning module/driver
- *
- * Returns 0 on success, and an appropriate error value on failure.
- */
-int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner)
-{
- rpdrv->drv.bus = &rpmsg_bus;
- rpdrv->drv.owner = owner;
- return driver_register(&rpdrv->drv);
-}
-EXPORT_SYMBOL(__register_rpmsg_driver);
-
-/**
- * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
- * @rpdrv: pointer to a struct rpmsg_driver
- *
- * Returns 0 on success, and an appropriate error value on failure.
- */
-void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
-{
- driver_unregister(&rpdrv->drv);
-}
-EXPORT_SYMBOL(unregister_rpmsg_driver);
-
-static void rpmsg_release_device(struct device *dev)
-{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
-
- kfree(rpdev);
-}
-
-/*
- * match an rpmsg channel with a channel info struct.
- * this is used to make sure we're not creating rpmsg devices for channels
- * that already exist.
- */
-static int rpmsg_channel_match(struct device *dev, void *data)
-{
- struct rpmsg_channel_info *chinfo = data;
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
-
- if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
- return 0;
-
- if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
- return 0;
-
- if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
- return 0;
-
- /* found a match ! */
- return 1;
-}
-
/*
* create an rpmsg channel using its name and address info.
* this function will be used to create both static and dynamic
* channels.
*/
-static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
- struct rpmsg_channel_info *chinfo)
+static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
+ struct rpmsg_channel_info *chinfo)
{
- struct rpmsg_channel *rpdev;
+ struct virtio_rpmsg_channel *vch;
+ struct rpmsg_device *rpdev;
struct device *tmp, *dev = &vrp->vdev->dev;
int ret;
/* make sure a similar channel doesn't already exist */
- tmp = device_find_child(dev, chinfo, rpmsg_channel_match);
+ tmp = rpmsg_find_device(dev, chinfo);
if (tmp) {
/* decrement the matched device's refcount back */
put_device(tmp);
@@ -514,62 +383,38 @@ static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
return NULL;
}
- rpdev = kzalloc(sizeof(struct rpmsg_channel), GFP_KERNEL);
- if (!rpdev) {
- pr_err("kzalloc failed\n");
+ vch = kzalloc(sizeof(*vch), GFP_KERNEL);
+ if (!vch)
return NULL;
- }
- rpdev->vrp = vrp;
+ /* Link the channel to our vrp */
+ vch->vrp = vrp;
+
+ /* Assign callbacks for rpmsg_channel */
+ vch->rpdev.ops = &virtio_rpmsg_ops;
+
+ /* Assign public information to the rpmsg_device */
+ rpdev = &vch->rpdev;
rpdev->src = chinfo->src;
rpdev->dst = chinfo->dst;
+ rpdev->ops = &virtio_rpmsg_ops;
/*
* rpmsg server channels has predefined local address (for now),
* and their existence needs to be announced remotely
*/
- rpdev->announce = rpdev->src != RPMSG_ADDR_ANY ? true : false;
+ rpdev->announce = rpdev->src != RPMSG_ADDR_ANY;
strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE);
- /* very simple device indexing plumbing which is enough for now */
- dev_set_name(&rpdev->dev, "rpmsg%d", rpmsg_dev_index++);
-
rpdev->dev.parent = &vrp->vdev->dev;
- rpdev->dev.bus = &rpmsg_bus;
- rpdev->dev.release = rpmsg_release_device;
-
- ret = device_register(&rpdev->dev);
- if (ret) {
- dev_err(dev, "device_register failed: %d\n", ret);
- put_device(&rpdev->dev);
+ ret = rpmsg_register_device(rpdev);
+ if (ret)
return NULL;
- }
return rpdev;
}
-/*
- * find an existing channel using its name + address properties,
- * and destroy it
- */
-static int rpmsg_destroy_channel(struct virtproc_info *vrp,
- struct rpmsg_channel_info *chinfo)
-{
- struct virtio_device *vdev = vrp->vdev;
- struct device *dev;
-
- dev = device_find_child(&vdev->dev, chinfo, rpmsg_channel_match);
- if (!dev)
- return -EINVAL;
-
- device_unregister(dev);
-
- put_device(dev);
-
- return 0;
-}
-
/* super simple buffer "allocator" that is just enough for now */
static void *get_a_tx_buf(struct virtproc_info *vrp)
{
@@ -684,10 +529,12 @@ static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
*
* Returns 0 on success and an appropriate error value on failure.
*/
-int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
- void *data, int len, bool wait)
+static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
+ u32 src, u32 dst,
+ void *data, int len, bool wait)
{
- struct virtproc_info *vrp = rpdev->vrp;
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+ struct virtproc_info *vrp = vch->vrp;
struct device *dev = &rpdev->dev;
struct scatterlist sg;
struct rpmsg_hdr *msg;
@@ -751,10 +598,11 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
memcpy(msg->data, data, len);
dev_dbg(dev, "TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n",
- msg->src, msg->dst, msg->len,
- msg->flags, msg->reserved);
- print_hex_dump(KERN_DEBUG, "rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
- msg, sizeof(*msg) + msg->len, true);
+ msg->src, msg->dst, msg->len, msg->flags, msg->reserved);
+#if defined(CONFIG_DYNAMIC_DEBUG)
+ dynamic_hex_dump("rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
+ msg, sizeof(*msg) + msg->len, true);
+#endif
sg_init_one(&sg, msg, sizeof(*msg) + len);
@@ -780,6 +628,56 @@ out:
}
EXPORT_SYMBOL(rpmsg_send_offchannel_raw);
+static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+ u32 src = ept->addr, dst = rpdev->dst;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
+ u32 dst)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+ u32 src = ept->addr;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+ u32 src = ept->addr, dst = rpdev->dst;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
+ int len, u32 dst)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+ u32 src = ept->addr;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
struct rpmsg_hdr *msg, unsigned int len)
{
@@ -788,17 +686,18 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
int err;
dev_dbg(dev, "From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n",
- msg->src, msg->dst, msg->len,
- msg->flags, msg->reserved);
- print_hex_dump(KERN_DEBUG, "rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
- msg, sizeof(*msg) + msg->len, true);
+ msg->src, msg->dst, msg->len, msg->flags, msg->reserved);
+#if defined(CONFIG_DYNAMIC_DEBUG)
+ dynamic_hex_dump("rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
+ msg, sizeof(*msg) + msg->len, true);
+#endif
/*
* We currently use fixed-sized buffers, so trivially sanitize
* the reported payload length.
*/
if (len > RPMSG_BUF_SIZE ||
- msg->len > (len - sizeof(struct rpmsg_hdr))) {
+ msg->len > (len - sizeof(struct rpmsg_hdr))) {
dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
return -EINVAL;
}
@@ -865,7 +764,7 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
msgs_received++;
msg = virtqueue_get_buf(rvq, &len);
- };
+ }
dev_dbg(dev, "Received %u messages\n", msgs_received);
@@ -892,23 +791,24 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
}
/* invoked when a name service announcement arrives */
-static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
- void *priv, u32 src)
+static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
{
struct rpmsg_ns_msg *msg = data;
- struct rpmsg_channel *newch;
+ struct rpmsg_device *newch;
struct rpmsg_channel_info chinfo;
struct virtproc_info *vrp = priv;
struct device *dev = &vrp->vdev->dev;
int ret;
- print_hex_dump(KERN_DEBUG, "NS announcement: ",
- DUMP_PREFIX_NONE, 16, 1,
- data, len, true);
+#if defined(CONFIG_DYNAMIC_DEBUG)
+ dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1,
+ data, len, true);
+#endif
if (len != sizeof(*msg)) {
dev_err(dev, "malformed ns msg (%d)\n", len);
- return;
+ return -EINVAL;
}
/*
@@ -919,22 +819,22 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
*/
if (rpdev) {
dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
- return;
+ return -EINVAL;
}
/* don't trust the remote processor for null terminating the name */
msg->name[RPMSG_NAME_SIZE - 1] = '\0';
dev_info(dev, "%sing channel %s addr 0x%x\n",
- msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
- msg->name, msg->addr);
+ msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
+ msg->name, msg->addr);
strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = msg->addr;
if (msg->flags & RPMSG_NS_DESTROY) {
- ret = rpmsg_destroy_channel(vrp, &chinfo);
+ ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo);
if (ret)
dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
} else {
@@ -942,6 +842,8 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
if (!newch)
dev_err(dev, "rpmsg_create_channel failed\n");
}
+
+ return 0;
}
static int rpmsg_probe(struct virtio_device *vdev)
@@ -995,8 +897,8 @@ static int rpmsg_probe(struct virtio_device *vdev)
goto vqs_del;
}
- dev_dbg(&vdev->dev, "buffers: va %p, dma 0x%llx\n", bufs_va,
- (unsigned long long)vrp->bufs_dma);
+ dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n",
+ bufs_va, &vrp->bufs_dma);
/* half of the buffers is dedicated for RX */
vrp->rbufs = bufs_va;
@@ -1012,7 +914,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
sg_init_one(&sg, cpu_addr, RPMSG_BUF_SIZE);
err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
- GFP_KERNEL);
+ GFP_KERNEL);
WARN_ON(err); /* sanity check; this can't really happen */
}
@@ -1119,17 +1021,9 @@ static int __init rpmsg_init(void)
{
int ret;
- ret = bus_register(&rpmsg_bus);
- if (ret) {
- pr_err("failed to register rpmsg bus: %d\n", ret);
- return ret;
- }
-
ret = register_virtio_driver(&virtio_ipc_driver);
- if (ret) {
+ if (ret)
pr_err("failed to register virtio driver: %d\n", ret);
- bus_unregister(&rpmsg_bus);
- }
return ret;
}
@@ -1138,7 +1032,6 @@ subsys_initcall(rpmsg_init);
static void __exit rpmsg_fini(void)
{
unregister_virtio_driver(&virtio_ipc_driver);
- bus_unregister(&rpmsg_bus);
}
module_exit(rpmsg_fini);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e215f50794b6..d1e080701264 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -187,6 +187,16 @@ config RTC_DRV_ABX80X
This driver can also be built as a module. If so, the module
will be called rtc-abx80x.
+config RTC_DRV_AC100
+ tristate "X-Powers AC100"
+ depends on MFD_AC100
+ help
+ If you say yes here you get support for the real-time clock found
+ in X-Powers AC100 family peripheral ICs.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ac100.
+
config RTC_DRV_AS3722
tristate "ams AS3722 RTC driver"
depends on MFD_AS3722
@@ -328,11 +338,11 @@ config RTC_DRV_MAX77686
will be called rtc-max77686.
config RTC_DRV_RK808
- tristate "Rockchip RK808 RTC"
+ tristate "Rockchip RK808/RK818 RTC"
depends on MFD_RK808
help
If you say yes here you will get support for the
- RTC of RK808 PMIC.
+ RTC of RK808 and RK818 PMIC.
This driver can also be built as a module. If so, the module
will be called rk808-rtc.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 7cf7ad559c79..8fb994bacdf7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
+obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c
new file mode 100644
index 000000000000..70b4fd0f6122
--- /dev/null
+++ b/drivers/rtc/rtc-ac100.c
@@ -0,0 +1,627 @@
+/*
+ * RTC Driver for X-Powers AC100
+ *
+ * Copyright (c) 2016 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.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.
+ *
+ * This program is distributed in 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/bcd.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ac100.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+
+/* Control register */
+#define AC100_RTC_CTRL_24HOUR BIT(0)
+
+/* Clock output register bits */
+#define AC100_CLKOUT_PRE_DIV_SHIFT 5
+#define AC100_CLKOUT_PRE_DIV_WIDTH 3
+#define AC100_CLKOUT_MUX_SHIFT 4
+#define AC100_CLKOUT_MUX_WIDTH 1
+#define AC100_CLKOUT_DIV_SHIFT 1
+#define AC100_CLKOUT_DIV_WIDTH 3
+#define AC100_CLKOUT_EN BIT(0)
+
+/* RTC */
+#define AC100_RTC_SEC_MASK GENMASK(6, 0)
+#define AC100_RTC_MIN_MASK GENMASK(6, 0)
+#define AC100_RTC_HOU_MASK GENMASK(5, 0)
+#define AC100_RTC_WEE_MASK GENMASK(2, 0)
+#define AC100_RTC_DAY_MASK GENMASK(5, 0)
+#define AC100_RTC_MON_MASK GENMASK(4, 0)
+#define AC100_RTC_YEA_MASK GENMASK(7, 0)
+#define AC100_RTC_YEA_LEAP BIT(15)
+#define AC100_RTC_UPD_TRIGGER BIT(15)
+
+/* Alarm (wall clock) */
+#define AC100_ALM_INT_ENABLE BIT(0)
+
+#define AC100_ALM_SEC_MASK GENMASK(6, 0)
+#define AC100_ALM_MIN_MASK GENMASK(6, 0)
+#define AC100_ALM_HOU_MASK GENMASK(5, 0)
+#define AC100_ALM_WEE_MASK GENMASK(2, 0)
+#define AC100_ALM_DAY_MASK GENMASK(5, 0)
+#define AC100_ALM_MON_MASK GENMASK(4, 0)
+#define AC100_ALM_YEA_MASK GENMASK(7, 0)
+#define AC100_ALM_ENABLE_FLAG BIT(15)
+#define AC100_ALM_UPD_TRIGGER BIT(15)
+
+/*
+ * The year parameter passed to the driver is usually an offset relative to
+ * the year 1900. This macro is used to convert this offset to another one
+ * relative to the minimum year allowed by the hardware.
+ *
+ * The year range is 1970 - 2069. This range is selected to match Allwinner's
+ * driver.
+ */
+#define AC100_YEAR_MIN 1970
+#define AC100_YEAR_MAX 2069
+#define AC100_YEAR_OFF (AC100_YEAR_MIN - 1900)
+
+struct ac100_clkout {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ u8 offset;
+};
+
+#define to_ac100_clkout(_hw) container_of(_hw, struct ac100_clkout, hw)
+
+#define AC100_RTC_32K_NAME "ac100-rtc-32k"
+#define AC100_RTC_32K_RATE 32768
+#define AC100_CLKOUT_NUM 3
+
+static const char * const ac100_clkout_names[AC100_CLKOUT_NUM] = {
+ "ac100-cko1-rtc",
+ "ac100-cko2-rtc",
+ "ac100-cko3-rtc",
+};
+
+struct ac100_rtc_dev {
+ struct rtc_device *rtc;
+ struct device *dev;
+ struct regmap *regmap;
+ int irq;
+ unsigned long alarm;
+
+ struct clk_hw *rtc_32k_clk;
+ struct ac100_clkout clks[AC100_CLKOUT_NUM];
+ struct clk_hw_onecell_data *clk_data;
+};
+
+/**
+ * Clock controls for 3 clock output pins
+ */
+
+static const struct clk_div_table ac100_clkout_prediv[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 4 },
+ { .val = 3, .div = 8 },
+ { .val = 4, .div = 16 },
+ { .val = 5, .div = 32 },
+ { .val = 6, .div = 64 },
+ { .val = 7, .div = 122 },
+ { },
+};
+
+/* Abuse the fact that one parent is 32768 Hz, and the other is 4 MHz */
+static unsigned long ac100_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+ unsigned int reg, div;
+
+ regmap_read(clk->regmap, clk->offset, &reg);
+
+ /* Handle pre-divider first */
+ if (prate != AC100_RTC_32K_RATE) {
+ div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) &
+ ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1);
+ prate = divider_recalc_rate(hw, prate, div,
+ ac100_clkout_prediv, 0);
+ }
+
+ div = (reg >> AC100_CLKOUT_DIV_SHIFT) &
+ (BIT(AC100_CLKOUT_DIV_WIDTH) - 1);
+ return divider_recalc_rate(hw, prate, div, NULL,
+ CLK_DIVIDER_POWER_OF_TWO);
+}
+
+static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ unsigned long best_rate = 0, tmp_rate, tmp_prate;
+ int i;
+
+ if (prate == AC100_RTC_32K_RATE)
+ return divider_round_rate(hw, rate, &prate, NULL,
+ AC100_CLKOUT_DIV_WIDTH,
+ CLK_DIVIDER_POWER_OF_TWO);
+
+ for (i = 0; ac100_clkout_prediv[i].div; i++) {
+ tmp_prate = DIV_ROUND_UP(prate, ac100_clkout_prediv[i].val);
+ tmp_rate = divider_round_rate(hw, rate, &tmp_prate, NULL,
+ AC100_CLKOUT_DIV_WIDTH,
+ CLK_DIVIDER_POWER_OF_TWO);
+
+ if (tmp_rate > rate)
+ continue;
+ if (rate - tmp_rate < best_rate - tmp_rate)
+ best_rate = tmp_rate;
+ }
+
+ return best_rate;
+}
+
+static int ac100_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_hw *best_parent;
+ unsigned long best = 0;
+ int i, num_parents = clk_hw_get_num_parents(hw);
+
+ for (i = 0; i < num_parents; i++) {
+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
+ unsigned long tmp, prate = clk_hw_get_rate(parent);
+
+ tmp = ac100_clkout_round_rate(hw, req->rate, prate);
+
+ if (tmp > req->rate)
+ continue;
+ if (req->rate - tmp < req->rate - best) {
+ best = tmp;
+ best_parent = parent;
+ }
+ }
+
+ if (!best)
+ return -EINVAL;
+
+ req->best_parent_hw = best_parent;
+ req->best_parent_rate = best;
+ req->rate = best;
+
+ return 0;
+}
+
+static int ac100_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+ int div = 0, pre_div = 0;
+
+ do {
+ div = divider_get_val(rate * ac100_clkout_prediv[pre_div].div,
+ prate, NULL, AC100_CLKOUT_DIV_WIDTH,
+ CLK_DIVIDER_POWER_OF_TWO);
+ if (div >= 0)
+ break;
+ } while (prate != AC100_RTC_32K_RATE &&
+ ac100_clkout_prediv[++pre_div].div);
+
+ if (div < 0)
+ return div;
+
+ pre_div = ac100_clkout_prediv[pre_div].val;
+
+ regmap_update_bits(clk->regmap, clk->offset,
+ ((1 << AC100_CLKOUT_DIV_WIDTH) - 1) << AC100_CLKOUT_DIV_SHIFT |
+ ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1) << AC100_CLKOUT_PRE_DIV_SHIFT,
+ (div - 1) << AC100_CLKOUT_DIV_SHIFT |
+ (pre_div - 1) << AC100_CLKOUT_PRE_DIV_SHIFT);
+
+ return 0;
+}
+
+static int ac100_clkout_prepare(struct clk_hw *hw)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+
+ return regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN,
+ AC100_CLKOUT_EN);
+}
+
+static void ac100_clkout_unprepare(struct clk_hw *hw)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+
+ regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, 0);
+}
+
+static int ac100_clkout_is_prepared(struct clk_hw *hw)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+ unsigned int reg;
+
+ regmap_read(clk->regmap, clk->offset, &reg);
+
+ return reg & AC100_CLKOUT_EN;
+}
+
+static u8 ac100_clkout_get_parent(struct clk_hw *hw)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+ unsigned int reg;
+
+ regmap_read(clk->regmap, clk->offset, &reg);
+
+ return (reg >> AC100_CLKOUT_MUX_SHIFT) & 0x1;
+}
+
+static int ac100_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct ac100_clkout *clk = to_ac100_clkout(hw);
+
+ return regmap_update_bits(clk->regmap, clk->offset,
+ BIT(AC100_CLKOUT_MUX_SHIFT),
+ index ? BIT(AC100_CLKOUT_MUX_SHIFT) : 0);
+}
+
+static const struct clk_ops ac100_clkout_ops = {
+ .prepare = ac100_clkout_prepare,
+ .unprepare = ac100_clkout_unprepare,
+ .is_prepared = ac100_clkout_is_prepared,
+ .recalc_rate = ac100_clkout_recalc_rate,
+ .determine_rate = ac100_clkout_determine_rate,
+ .get_parent = ac100_clkout_get_parent,
+ .set_parent = ac100_clkout_set_parent,
+ .set_rate = ac100_clkout_set_rate,
+};
+
+static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip)
+{
+ struct device_node *np = chip->dev->of_node;
+ const char *parents[2] = {AC100_RTC_32K_NAME};
+ int i, ret;
+
+ chip->clk_data = devm_kzalloc(chip->dev, sizeof(*chip->clk_data) +
+ sizeof(*chip->clk_data->hws) *
+ AC100_CLKOUT_NUM,
+ GFP_KERNEL);
+ if (!chip->clk_data)
+ return -ENOMEM;
+
+ chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev,
+ AC100_RTC_32K_NAME,
+ NULL, 0,
+ AC100_RTC_32K_RATE);
+ if (IS_ERR(chip->rtc_32k_clk)) {
+ ret = PTR_ERR(chip->rtc_32k_clk);
+ dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n",
+ ret);
+ return ret;
+ }
+
+ parents[1] = of_clk_get_parent_name(np, 0);
+ if (!parents[1]) {
+ dev_err(chip->dev, "Failed to get ADDA 4M clock\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < AC100_CLKOUT_NUM; i++) {
+ struct ac100_clkout *clk = &chip->clks[i];
+ struct clk_init_data init = {
+ .name = ac100_clkout_names[i],
+ .ops = &ac100_clkout_ops,
+ .parent_names = parents,
+ .num_parents = ARRAY_SIZE(parents),
+ .flags = 0,
+ };
+
+ clk->regmap = chip->regmap;
+ clk->offset = AC100_CLKOUT_CTRL1 + i;
+ clk->hw.init = &init;
+
+ ret = devm_clk_hw_register(chip->dev, &clk->hw);
+ if (ret) {
+ dev_err(chip->dev, "Failed to register clk '%s': %d\n",
+ init.name, ret);
+ goto err_unregister_rtc_32k;
+ }
+
+ chip->clk_data->hws[i] = &clk->hw;
+ }
+
+ chip->clk_data->num = i;
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data);
+ if (ret)
+ goto err_unregister_rtc_32k;
+
+ return 0;
+
+err_unregister_rtc_32k:
+ clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
+
+ return ret;
+}
+
+static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip)
+{
+ of_clk_del_provider(chip->dev->of_node);
+ clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
+}
+
+/**
+ * RTC related bits
+ */
+static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+ struct regmap *regmap = chip->regmap;
+ u16 reg[7];
+ int ret;
+
+ ret = regmap_bulk_read(regmap, AC100_RTC_SEC, reg, 7);
+ if (ret)
+ return ret;
+
+ rtc_tm->tm_sec = bcd2bin(reg[0] & AC100_RTC_SEC_MASK);
+ rtc_tm->tm_min = bcd2bin(reg[1] & AC100_RTC_MIN_MASK);
+ rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK);
+ rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK);
+ rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK);
+ rtc_tm->tm_mon = bcd2bin(reg[5] & AC100_RTC_MON_MASK) - 1;
+ rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK) +
+ AC100_YEAR_OFF;
+
+ return rtc_valid_tm(rtc_tm);
+}
+
+static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+ struct regmap *regmap = chip->regmap;
+ int year;
+ u16 reg[8];
+
+ /* our RTC has a limited year range... */
+ year = rtc_tm->tm_year - AC100_YEAR_OFF;
+ if (year < 0 || year > (AC100_YEAR_MAX - 1900)) {
+ dev_err(dev, "rtc only supports year in range %d - %d\n",
+ AC100_YEAR_MIN, AC100_YEAR_MAX);
+ return -EINVAL;
+ }
+
+ /* convert to BCD */
+ reg[0] = bin2bcd(rtc_tm->tm_sec) & AC100_RTC_SEC_MASK;
+ reg[1] = bin2bcd(rtc_tm->tm_min) & AC100_RTC_MIN_MASK;
+ reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK;
+ reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK;
+ reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK;
+ reg[5] = bin2bcd(rtc_tm->tm_mon + 1) & AC100_RTC_MON_MASK;
+ reg[6] = bin2bcd(year) & AC100_RTC_YEA_MASK;
+ /* trigger write */
+ reg[7] = AC100_RTC_UPD_TRIGGER;
+
+ /* Is it a leap year? */
+ if (is_leap_year(year + AC100_YEAR_OFF + 1900))
+ reg[6] |= AC100_RTC_YEA_LEAP;
+
+ return regmap_bulk_write(regmap, AC100_RTC_SEC, reg, 8);
+}
+
+static int ac100_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
+{
+ struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+ struct regmap *regmap = chip->regmap;
+ unsigned int val;
+
+ val = en ? AC100_ALM_INT_ENABLE : 0;
+
+ return regmap_write(regmap, AC100_ALM_INT_ENA, val);
+}
+
+static int ac100_rtc_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+ struct regmap *regmap = chip->regmap;
+ struct rtc_time *alrm_tm = &alrm->time;
+ u16 reg[7];
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(regmap, AC100_ALM_INT_ENA, &val);
+ if (ret)
+ return ret;
+
+ alrm->enabled = !!(val & AC100_ALM_INT_ENABLE);
+
+ ret = regmap_bulk_read(regmap, AC100_ALM_SEC, reg, 7);
+ if (ret)
+ return ret;
+
+ alrm_tm->tm_sec = bcd2bin(reg[0] & AC100_ALM_SEC_MASK);
+ alrm_tm->tm_min = bcd2bin(reg[1] & AC100_ALM_MIN_MASK);
+ alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK);
+ alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK);
+ alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK);
+ alrm_tm->tm_mon = bcd2bin(reg[5] & AC100_ALM_MON_MASK) - 1;
+ alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK) +
+ AC100_YEAR_OFF;
+
+ return 0;
+}
+
+static int ac100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+ struct regmap *regmap = chip->regmap;
+ struct rtc_time *alrm_tm = &alrm->time;
+ u16 reg[8];
+ int year;
+ int ret;
+
+ /* our alarm has a limited year range... */
+ year = alrm_tm->tm_year - AC100_YEAR_OFF;
+ if (year < 0 || year > (AC100_YEAR_MAX - 1900)) {
+ dev_err(dev, "alarm only supports year in range %d - %d\n",
+ AC100_YEAR_MIN, AC100_YEAR_MAX);
+ return -EINVAL;
+ }
+
+ /* convert to BCD */
+ reg[0] = (bin2bcd(alrm_tm->tm_sec) & AC100_ALM_SEC_MASK) |
+ AC100_ALM_ENABLE_FLAG;
+ reg[1] = (bin2bcd(alrm_tm->tm_min) & AC100_ALM_MIN_MASK) |
+ AC100_ALM_ENABLE_FLAG;
+ reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) |
+ AC100_ALM_ENABLE_FLAG;
+ /* Do not enable weekday alarm */
+ reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK;
+ reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) |
+ AC100_ALM_ENABLE_FLAG;
+ reg[5] = (bin2bcd(alrm_tm->tm_mon + 1) & AC100_ALM_MON_MASK) |
+ AC100_ALM_ENABLE_FLAG;
+ reg[6] = (bin2bcd(year) & AC100_ALM_YEA_MASK) |
+ AC100_ALM_ENABLE_FLAG;
+ /* trigger write */
+ reg[7] = AC100_ALM_UPD_TRIGGER;
+
+ ret = regmap_bulk_write(regmap, AC100_ALM_SEC, reg, 8);
+ if (ret)
+ return ret;
+
+ return ac100_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+static irqreturn_t ac100_rtc_irq(int irq, void *data)
+{
+ struct ac100_rtc_dev *chip = data;
+ struct regmap *regmap = chip->regmap;
+ unsigned int val = 0;
+ int ret;
+
+ mutex_lock(&chip->rtc->ops_lock);
+
+ /* read status */
+ ret = regmap_read(regmap, AC100_ALM_INT_STA, &val);
+ if (ret)
+ goto out;
+
+ if (val & AC100_ALM_INT_ENABLE) {
+ /* signal rtc framework */
+ rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
+
+ /* clear status */
+ ret = regmap_write(regmap, AC100_ALM_INT_STA, val);
+ if (ret)
+ goto out;
+
+ /* disable interrupt */
+ ret = ac100_rtc_alarm_irq_enable(chip->dev, 0);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&chip->rtc->ops_lock);
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops ac100_rtc_ops = {
+ .read_time = ac100_rtc_get_time,
+ .set_time = ac100_rtc_set_time,
+ .read_alarm = ac100_rtc_get_alarm,
+ .set_alarm = ac100_rtc_set_alarm,
+ .alarm_irq_enable = ac100_rtc_alarm_irq_enable,
+};
+
+static int ac100_rtc_probe(struct platform_device *pdev)
+{
+ struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent);
+ struct ac100_rtc_dev *chip;
+ int ret;
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ platform_set_drvdata(pdev, chip);
+ chip->dev = &pdev->dev;
+ chip->regmap = ac100->regmap;
+
+ chip->irq = platform_get_irq(pdev, 0);
+ if (chip->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ return chip->irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL,
+ ac100_rtc_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ dev_name(&pdev->dev), chip);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not request IRQ\n");
+ return ret;
+ }
+
+ /* always use 24 hour mode */
+ regmap_write_bits(chip->regmap, AC100_RTC_CTRL, AC100_RTC_CTRL_24HOUR,
+ AC100_RTC_CTRL_24HOUR);
+
+ /* disable counter alarm interrupt */
+ regmap_write(chip->regmap, AC100_ALM_INT_ENA, 0);
+
+ /* clear counter alarm pending interrupts */
+ regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE);
+
+ chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-ac100",
+ &ac100_rtc_ops, THIS_MODULE);
+ if (IS_ERR(chip->rtc)) {
+ dev_err(&pdev->dev, "unable to register device\n");
+ return PTR_ERR(chip->rtc);
+ }
+
+ ret = ac100_rtc_register_clks(chip);
+ if (ret)
+ return ret;
+
+ dev_info(&pdev->dev, "RTC enabled\n");
+
+ return 0;
+}
+
+static int ac100_rtc_remove(struct platform_device *pdev)
+{
+ struct ac100_rtc_dev *chip = platform_get_drvdata(pdev);
+
+ ac100_rtc_unregister_clks(chip);
+
+ return 0;
+}
+
+static const struct of_device_id ac100_rtc_match[] = {
+ { .compatible = "x-powers,ac100-rtc" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ac100_rtc_match);
+
+static struct platform_driver ac100_rtc_driver = {
+ .probe = ac100_rtc_probe,
+ .remove = ac100_rtc_remove,
+ .driver = {
+ .name = "ac100-rtc",
+ .of_match_table = of_match_ptr(ac100_rtc_match),
+ },
+};
+module_platform_driver(ac100_rtc_driver);
+
+MODULE_DESCRIPTION("X-Powers AC100 RTC driver");
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 795fcbd02ea3..fac835530671 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -428,6 +428,7 @@ static const struct pm8xxx_rtc_regs pm8941_regs = {
*/
static const struct of_device_id pm8xxx_id_table[] = {
{ .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
+ { .compatible = "qcom,pm8018-rtc", .data = &pm8921_regs },
{ .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
{ .compatible = "qcom,pm8941-rtc", .data = &pm8941_regs },
{ },
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 5d7fbe4e907e..637cf8973c9e 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -3,7 +3,7 @@
*
* Debug traces for zfcp.
*
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2016
*/
#define KMSG_COMPONENT "zfcp"
@@ -65,7 +65,7 @@ void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
* @tag: tag indicating which kind of unsolicited status has been received
* @req: request for which a response was received
*/
-void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
+void zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req)
{
struct zfcp_dbf *dbf = req->adapter->dbf;
struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
@@ -85,6 +85,8 @@ void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
rec->u.res.req_issued = req->issued;
rec->u.res.prot_status = q_pref->prot_status;
rec->u.res.fsf_status = q_head->fsf_status;
+ rec->u.res.port_handle = q_head->port_handle;
+ rec->u.res.lun_handle = q_head->lun_handle;
memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual,
FSF_PROT_STATUS_QUAL_SIZE);
@@ -97,7 +99,7 @@ void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
rec->pl_len, "fsf_res", req->req_id);
}
- debug_event(dbf->hba, 1, rec, sizeof(*rec));
+ debug_event(dbf->hba, level, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->hba_lock, flags);
}
@@ -241,7 +243,8 @@ static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
if (sdev) {
rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status);
rec->lun = zfcp_scsi_dev_lun(sdev);
- }
+ } else
+ rec->lun = ZFCP_DBF_INVALID_LUN;
}
/**
@@ -320,13 +323,48 @@ void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
+/**
+ * zfcp_dbf_rec_run_wka - trace wka port event with info like running recovery
+ * @tag: identifier for event
+ * @wka_port: well known address port
+ * @req_id: request ID to correlate with potential HBA trace record
+ */
+void zfcp_dbf_rec_run_wka(char *tag, struct zfcp_fc_wka_port *wka_port,
+ u64 req_id)
+{
+ struct zfcp_dbf *dbf = wka_port->adapter->dbf;
+ struct zfcp_dbf_rec *rec = &dbf->rec_buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dbf->rec_lock, flags);
+ memset(rec, 0, sizeof(*rec));
+
+ rec->id = ZFCP_DBF_REC_RUN;
+ memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->port_status = wka_port->status;
+ rec->d_id = wka_port->d_id;
+ rec->lun = ZFCP_DBF_INVALID_LUN;
+
+ rec->u.run.fsf_req_id = req_id;
+ rec->u.run.rec_status = ~0;
+ rec->u.run.rec_step = ~0;
+ rec->u.run.rec_action = ~0;
+ rec->u.run.rec_count = ~0;
+
+ debug_event(dbf->rec, 1, rec, sizeof(*rec));
+ spin_unlock_irqrestore(&dbf->rec_lock, flags);
+}
+
static inline
-void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
- u64 req_id, u32 d_id)
+void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf,
+ char *paytag, struct scatterlist *sg, u8 id, u16 len,
+ u64 req_id, u32 d_id, u16 cap_len)
{
struct zfcp_dbf_san *rec = &dbf->san_buf;
u16 rec_len;
unsigned long flags;
+ struct zfcp_dbf_pay *payload = &dbf->pay_buf;
+ u16 pay_sum = 0;
spin_lock_irqsave(&dbf->san_lock, flags);
memset(rec, 0, sizeof(*rec));
@@ -334,10 +372,41 @@ void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
rec->id = id;
rec->fsf_req_id = req_id;
rec->d_id = d_id;
- rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD);
- memcpy(rec->payload, data, rec_len);
memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+ rec->pl_len = len; /* full length even if we cap pay below */
+ if (!sg)
+ goto out;
+ rec_len = min_t(unsigned int, sg->length, ZFCP_DBF_SAN_MAX_PAYLOAD);
+ memcpy(rec->payload, sg_virt(sg), rec_len); /* part of 1st sg entry */
+ if (len <= rec_len)
+ goto out; /* skip pay record if full content in rec->payload */
+
+ /* if (len > rec_len):
+ * dump data up to cap_len ignoring small duplicate in rec->payload
+ */
+ spin_lock_irqsave(&dbf->pay_lock, flags);
+ memset(payload, 0, sizeof(*payload));
+ memcpy(payload->area, paytag, ZFCP_DBF_TAG_LEN);
+ payload->fsf_req_id = req_id;
+ payload->counter = 0;
+ for (; sg && pay_sum < cap_len; sg = sg_next(sg)) {
+ u16 pay_len, offset = 0;
+
+ while (offset < sg->length && pay_sum < cap_len) {
+ pay_len = min((u16)ZFCP_DBF_PAY_MAX_REC,
+ (u16)(sg->length - offset));
+ /* cap_len <= pay_sum < cap_len+ZFCP_DBF_PAY_MAX_REC */
+ memcpy(payload->data, sg_virt(sg) + offset, pay_len);
+ debug_event(dbf->pay, 1, payload,
+ zfcp_dbf_plen(pay_len));
+ payload->counter++;
+ offset += pay_len;
+ pay_sum += pay_len;
+ }
+ }
+ spin_unlock(&dbf->pay_lock);
+out:
debug_event(dbf->san, 1, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->san_lock, flags);
}
@@ -354,9 +423,62 @@ void zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id)
struct zfcp_fsf_ct_els *ct_els = fsf->data;
u16 length;
- length = (u16)(ct_els->req->length + FC_CT_HDR_LEN);
- zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length,
- fsf->req_id, d_id);
+ length = (u16)zfcp_qdio_real_bytes(ct_els->req);
+ zfcp_dbf_san(tag, dbf, "san_req", ct_els->req, ZFCP_DBF_SAN_REQ,
+ length, fsf->req_id, d_id, length);
+}
+
+static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
+ struct zfcp_fsf_req *fsf,
+ u16 len)
+{
+ struct zfcp_fsf_ct_els *ct_els = fsf->data;
+ struct fc_ct_hdr *reqh = sg_virt(ct_els->req);
+ struct fc_ns_gid_ft *reqn = (struct fc_ns_gid_ft *)(reqh + 1);
+ struct scatterlist *resp_entry = ct_els->resp;
+ struct fc_gpn_ft_resp *acc;
+ int max_entries, x, last = 0;
+
+ if (!(memcmp(tag, "fsscth2", 7) == 0
+ && ct_els->d_id == FC_FID_DIR_SERV
+ && reqh->ct_rev == FC_CT_REV
+ && reqh->ct_in_id[0] == 0
+ && reqh->ct_in_id[1] == 0
+ && reqh->ct_in_id[2] == 0
+ && reqh->ct_fs_type == FC_FST_DIR
+ && reqh->ct_fs_subtype == FC_NS_SUBTYPE
+ && reqh->ct_options == 0
+ && reqh->_ct_resvd1 == 0
+ && reqh->ct_cmd == FC_NS_GPN_FT
+ /* reqh->ct_mr_size can vary so do not match but read below */
+ && reqh->_ct_resvd2 == 0
+ && reqh->ct_reason == 0
+ && reqh->ct_explan == 0
+ && reqh->ct_vendor == 0
+ && reqn->fn_resvd == 0
+ && reqn->fn_domain_id_scope == 0
+ && reqn->fn_area_id_scope == 0
+ && reqn->fn_fc4_type == FC_TYPE_FCP))
+ return len; /* not GPN_FT response so do not cap */
+
+ acc = sg_virt(resp_entry);
+ max_entries = (reqh->ct_mr_size * 4 / sizeof(struct fc_gpn_ft_resp))
+ + 1 /* zfcp_fc_scan_ports: bytes correct, entries off-by-one
+ * to account for header as 1st pseudo "entry" */;
+
+ /* the basic CT_IU preamble is the same size as one entry in the GPN_FT
+ * response, allowing us to skip special handling for it - just skip it
+ */
+ for (x = 1; x < max_entries && !last; x++) {
+ if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
+ acc++;
+ else
+ acc = sg_virt(++resp_entry);
+
+ last = acc->fp_flags & FC_NS_FID_LAST;
+ }
+ len = min(len, (u16)(x * sizeof(struct fc_gpn_ft_resp)));
+ return len; /* cap after last entry */
}
/**
@@ -370,9 +492,10 @@ void zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf)
struct zfcp_fsf_ct_els *ct_els = fsf->data;
u16 length;
- length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN);
- zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length,
- fsf->req_id, 0);
+ length = (u16)zfcp_qdio_real_bytes(ct_els->resp);
+ zfcp_dbf_san(tag, dbf, "san_res", ct_els->resp, ZFCP_DBF_SAN_RES,
+ length, fsf->req_id, ct_els->d_id,
+ zfcp_dbf_san_res_cap_len_if_gpn_ft(tag, fsf, length));
}
/**
@@ -386,11 +509,13 @@ void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
struct fsf_status_read_buffer *srb =
(struct fsf_status_read_buffer *) fsf->data;
u16 length;
+ struct scatterlist sg;
length = (u16)(srb->length -
offsetof(struct fsf_status_read_buffer, payload));
- zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length,
- fsf->req_id, ntoh24(srb->d_id));
+ sg_init_one(&sg, srb->payload.data, length);
+ zfcp_dbf_san(tag, dbf, "san_els", &sg, ZFCP_DBF_SAN_ELS, length,
+ fsf->req_id, ntoh24(srb->d_id), length);
}
/**
@@ -399,7 +524,8 @@ void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
* @sc: pointer to struct scsi_cmnd
* @fsf: pointer to struct zfcp_fsf_req
*/
-void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
+void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc,
+ struct zfcp_fsf_req *fsf)
{
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) sc->device->host->hostdata[0];
@@ -442,7 +568,7 @@ void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
}
}
- debug_event(dbf->scsi, 1, rec, sizeof(*rec));
+ debug_event(dbf->scsi, level, rec, sizeof(*rec));
spin_unlock_irqrestore(&dbf->scsi_lock, flags);
}
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 0be3d48681ae..36d07584271d 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -2,7 +2,7 @@
* zfcp device driver
* debug feature declarations
*
- * Copyright IBM Corp. 2008, 2010
+ * Copyright IBM Corp. 2008, 2015
*/
#ifndef ZFCP_DBF_H
@@ -17,6 +17,11 @@
#define ZFCP_DBF_INVALID_LUN 0xFFFFFFFFFFFFFFFFull
+enum zfcp_dbf_pseudo_erp_act_type {
+ ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD = 0xff,
+ ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL = 0xfe,
+};
+
/**
* struct zfcp_dbf_rec_trigger - trace record for triggered recovery action
* @ready: number of ready recovery actions
@@ -110,6 +115,7 @@ struct zfcp_dbf_san {
u32 d_id;
#define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32)
char payload[ZFCP_DBF_SAN_MAX_PAYLOAD];
+ u16 pl_len;
} __packed;
/**
@@ -126,6 +132,8 @@ struct zfcp_dbf_hba_res {
u8 prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
u32 fsf_status;
u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+ u32 port_handle;
+ u32 lun_handle;
} __packed;
/**
@@ -279,7 +287,7 @@ static inline
void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)
{
if (debug_level_enabled(req->adapter->dbf->hba, level))
- zfcp_dbf_hba_fsf_res(tag, req);
+ zfcp_dbf_hba_fsf_res(tag, level, req);
}
/**
@@ -318,7 +326,7 @@ void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd,
scmd->device->host->hostdata[0];
if (debug_level_enabled(adapter->dbf->scsi, level))
- zfcp_dbf_scsi(tag, scmd, req);
+ zfcp_dbf_scsi(tag, level, scmd, req);
}
/**
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 3fb410977014..a59d678125bd 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -3,7 +3,7 @@
*
* Error Recovery Procedures (ERP).
*
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2015
*/
#define KMSG_COMPONENT "zfcp"
@@ -1217,8 +1217,14 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
- if (result == ZFCP_ERP_SUCCEEDED)
- zfcp_scsi_schedule_rport_register(port);
+ /* This switch case might also happen after a forced reopen
+ * was successfully done and thus overwritten with a new
+ * non-forced reopen at `ersfs_2'. In this case, we must not
+ * do the clean-up of the non-forced version.
+ */
+ if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
+ if (result == ZFCP_ERP_SUCCEEDED)
+ zfcp_scsi_schedule_rport_register(port);
/* fall through */
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
put_device(&port->dev);
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 5b500652572b..c8fed9fa1cca 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -3,7 +3,7 @@
*
* External function declarations.
*
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2015
*/
#ifndef ZFCP_EXT_H
@@ -35,8 +35,9 @@ extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *);
extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *,
struct zfcp_port *, struct scsi_device *, u8, u8);
extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *);
+extern void zfcp_dbf_rec_run_wka(char *, struct zfcp_fc_wka_port *, u64);
extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_fsf_res(char *, int, struct zfcp_fsf_req *);
extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
@@ -44,7 +45,8 @@ extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *);
extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_scsi(char *, int, struct scsi_cmnd *,
+ struct zfcp_fsf_req *);
/* zfcp_erp.c */
extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 522a633c866a..75f820ca17b7 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -3,7 +3,7 @@
*
* Implementation of FSF commands.
*
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2015
*/
#define KMSG_COMPONENT "zfcp"
@@ -508,7 +508,10 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
fc_host_port_type(shost) = FC_PORTTYPE_PTP;
break;
case FSF_TOPO_FABRIC:
- fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+ if (bottom->connection_features & FSF_FEATURE_NPIV_MODE)
+ fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+ else
+ fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
break;
case FSF_TOPO_AL:
fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
@@ -613,7 +616,6 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
fc_host_permanent_port_name(shost) = bottom->wwpn;
- fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
} else
fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
@@ -982,8 +984,12 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
if (zfcp_adapter_multi_buffer_active(adapter)) {
if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
return -EIO;
+ qtcb->bottom.support.req_buf_length =
+ zfcp_qdio_real_bytes(sg_req);
if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
return -EIO;
+ qtcb->bottom.support.resp_buf_length =
+ zfcp_qdio_real_bytes(sg_resp);
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
zfcp_qdio_sbale_count(sg_req));
@@ -1073,6 +1079,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
req->handler = zfcp_fsf_send_ct_handler;
req->qtcb->header.port_handle = wka_port->handle;
+ ct->d_id = wka_port->d_id;
req->data = ct;
zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);
@@ -1169,6 +1176,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
hton24(req->qtcb->bottom.support.d_id, d_id);
req->handler = zfcp_fsf_send_els_handler;
+ els->d_id = d_id;
req->data = els;
zfcp_dbf_san_req("fssels1", req, d_id);
@@ -1575,7 +1583,7 @@ out:
int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
{
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
- struct zfcp_fsf_req *req;
+ struct zfcp_fsf_req *req = NULL;
int retval = -EIO;
spin_lock_irq(&qdio->req_q_lock);
@@ -1604,6 +1612,8 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
zfcp_fsf_req_free(req);
out:
spin_unlock_irq(&qdio->req_q_lock);
+ if (req && !IS_ERR(req))
+ zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id);
return retval;
}
@@ -1628,7 +1638,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
{
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
- struct zfcp_fsf_req *req;
+ struct zfcp_fsf_req *req = NULL;
int retval = -EIO;
spin_lock_irq(&qdio->req_q_lock);
@@ -1657,6 +1667,8 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
zfcp_fsf_req_free(req);
out:
spin_unlock_irq(&qdio->req_q_lock);
+ if (req && !IS_ERR(req))
+ zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id);
return retval;
}
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 57ae3ae1046d..be1c04b334c5 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -3,7 +3,7 @@
*
* Interface to the FSF support functions.
*
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2015
*/
#ifndef FSF_H
@@ -436,6 +436,7 @@ struct zfcp_blk_drv_data {
* @handler_data: data passed to handler function
* @port: Optional pointer to port for zfcp internal ELS (only test link ADISC)
* @status: used to pass error status to calling function
+ * @d_id: Destination ID of either open WKA port for CT or of D_ID for ELS
*/
struct zfcp_fsf_ct_els {
struct scatterlist *req;
@@ -444,6 +445,7 @@ struct zfcp_fsf_ct_els {
void *handler_data;
struct zfcp_port *port;
int status;
+ u32 d_id;
};
#endif /* FSF_H */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index b3c6ff49103b..9069f98a1817 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -3,7 +3,7 @@
*
* Interface to Linux SCSI midlayer.
*
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2015
*/
#define KMSG_COMPONENT "zfcp"
@@ -556,6 +556,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
ids.port_id = port->d_id;
ids.roles = FC_RPORT_ROLE_FCP_TARGET;
+ zfcp_dbf_rec_trig("scpaddy", port->adapter, port, NULL,
+ ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD,
+ ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD);
rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
if (!rport) {
dev_err(&port->adapter->ccw_device->dev,
@@ -577,6 +580,9 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
struct fc_rport *rport = port->rport;
if (rport) {
+ zfcp_dbf_rec_trig("scpdely", port->adapter, port, NULL,
+ ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL,
+ ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL);
fc_remote_port_delete(rport);
port->rport = NULL;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 7d1b4317eccc..3e2bdb90813c 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -396,18 +396,6 @@ config SCSI_3W_SAS
Please read the comments at the top of
<file:drivers/scsi/3w-sas.c>.
-config SCSI_7000FASST
- tristate "7000FASST SCSI support"
- depends on ISA && SCSI && ISA_DMA_API
- select CHECK_SIGNATURE
- help
- This driver supports the Western Digital 7000 SCSI host adapter
- family. Some information is in the source:
- <file:drivers/scsi/wd7000.c>.
-
- To compile this driver as a module, choose M here: the
- module will be called wd7000.
-
config SCSI_ACARD
tristate "ACARD SCSI support"
depends on PCI && SCSI
@@ -512,18 +500,6 @@ config SCSI_ADVANSYS
To compile this driver as a module, choose M here: the
module will be called advansys.
-config SCSI_IN2000
- tristate "Always IN2000 SCSI support"
- depends on ISA && SCSI
- help
- This is support for an ISA bus SCSI host adapter. You'll find more
- information in <file:Documentation/scsi/in2000.txt>. If it doesn't work
- out of the box, you may have to change the jumpers for IRQ or
- address selection.
-
- To compile this driver as a module, choose M here: the
- module will be called in2000.
-
config SCSI_ARCMSR
tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter"
depends on PCI && SCSI
@@ -540,6 +516,7 @@ config SCSI_ARCMSR
source "drivers/scsi/esas2r/Kconfig"
source "drivers/scsi/megaraid/Kconfig.megaraid"
source "drivers/scsi/mpt3sas/Kconfig"
+source "drivers/scsi/smartpqi/Kconfig"
source "drivers/scsi/ufs/Kconfig"
config SCSI_HPTIOP
@@ -660,20 +637,6 @@ config SCSI_DMX3191D
To compile this driver as a module, choose M here: the
module will be called dmx3191d.
-config SCSI_DTC3280
- tristate "DTC3180/3280 SCSI support"
- depends on ISA && SCSI
- select SCSI_SPI_ATTRS
- select CHECK_SIGNATURE
- help
- This is support for DTC 3180/3280 SCSI Host Adapters. Please read
- the SCSI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, and the file
- <file:Documentation/scsi/dtc3x80.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called dtc.
-
config SCSI_EATA
tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support"
depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
@@ -1248,20 +1211,6 @@ config SCSI_NCR53C8XX_NO_DISCONNECT
not allow targets to disconnect is not reasonable if there is more
than 1 device on a SCSI bus. The normal answer therefore is N.
-config SCSI_PAS16
- tristate "PAS16 SCSI support"
- depends on ISA && SCSI
- select SCSI_SPI_ATTRS
- ---help---
- This is support for a SCSI host adapter. It is explained in section
- 3.10 of the SCSI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. If it doesn't work out
- of the box, you may have to change some settings in
- <file:drivers/scsi/pas16.h>.
-
- To compile this driver as a module, choose M here: the
- module will be called pas16.
-
config SCSI_QLOGIC_FAS
tristate "Qlogic FAS SCSI support"
depends on ISA && SCSI
@@ -1382,89 +1331,6 @@ config SCSI_AM53C974
To compile this driver as a module, choose M here: the
module will be called am53c974.
-config SCSI_T128
- tristate "Trantor T128/T128F/T228 SCSI support"
- depends on ISA && SCSI
- select SCSI_SPI_ATTRS
- select CHECK_SIGNATURE
- ---help---
- This is support for a SCSI host adapter. It is explained in section
- 3.11 of the SCSI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. If it doesn't work out
- of the box, you may have to change some settings in
- <file:drivers/scsi/t128.h>. Note that Trantor was purchased by
- Adaptec, and some former Trantor products are being sold under the
- Adaptec name.
-
- To compile this driver as a module, choose M here: the
- module will be called t128.
-
-config SCSI_U14_34F
- tristate "UltraStor 14F/34F support"
- depends on ISA && SCSI && ISA_DMA_API
- ---help---
- This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
- The source at <file:drivers/scsi/u14-34f.c> contains some
- information about this hardware. If the driver doesn't work out of
- the box, you may have to change some settings in
- <file: drivers/scsi/u14-34f.c>. Read the SCSI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that there is also
- another driver for the same hardware: "UltraStor SCSI support",
- below. You should say Y to both only if you want 24F support as
- well.
-
- To compile this driver as a module, choose M here: the
- module will be called u14-34f.
-
-config SCSI_U14_34F_TAGGED_QUEUE
- bool "enable tagged command queueing"
- depends on SCSI_U14_34F
- help
- This is a feature of SCSI-2 which improves performance: the host
- adapter can send several SCSI commands to a device's queue even if
- previous commands haven't finished yet.
- This is equivalent to the "u14-34f=tc:y" boot option.
-
-config SCSI_U14_34F_LINKED_COMMANDS
- bool "enable elevator sorting"
- depends on SCSI_U14_34F
- help
- This option enables elevator sorting for all probed SCSI disks and
- CD-ROMs. It definitely reduces the average seek distance when doing
- random seeks, but this does not necessarily result in a noticeable
- performance improvement: your mileage may vary...
- This is equivalent to the "u14-34f=lc:y" boot option.
-
-config SCSI_U14_34F_MAX_TAGS
- int "maximum number of queued commands"
- depends on SCSI_U14_34F
- default "8"
- help
- This specifies how many SCSI commands can be maximally queued for
- each probed SCSI device. You should reduce the default value of 8
- only if you have disks with buggy or limited tagged command support.
- Minimum is 2 and maximum is 14. This value is also the window size
- used by the elevator sorting option above. The effective value used
- by the driver for each probed SCSI device is reported at boot time.
- This is equivalent to the "u14-34f=mq:8" boot option.
-
-config SCSI_ULTRASTOR
- tristate "UltraStor SCSI support"
- depends on X86 && ISA && SCSI && ISA_DMA_API
- ---help---
- This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
- adapter family. This driver is explained in section 3.12 of the
- SCSI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. If it doesn't work out
- of the box, you may have to change some settings in
- <file:drivers/scsi/ultrastor.h>.
-
- Note that there is also another driver for the same hardware:
- "UltraStor 14F/34F support", above.
-
- To compile this driver as a module, choose M here: the
- module will be called ultrastor.
-
config SCSI_NSP32
tristate "Workbit NinjaSCSI-32Bi/UDE support"
depends on PCI && SCSI && !64BIT
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index d5397987e731..38d938d7fe67 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -61,9 +61,7 @@ obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o
obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o
obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o
obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o
-obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o
obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/
-obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o
obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
obj-$(CONFIG_SCSI_AHA1542) += aha1542.o
obj-$(CONFIG_SCSI_AHA1740) += aha1740.o
@@ -75,7 +73,6 @@ obj-$(CONFIG_SCSI_PM8001) += pm8001/
obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
-obj-$(CONFIG_SCSI_IN2000) += in2000.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o
obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o
@@ -90,15 +87,12 @@ obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor/
-obj-$(CONFIG_SCSI_PAS16) += pas16.o
-obj-$(CONFIG_SCSI_T128) += t128.o
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
obj-$(CONFIG_SCSI_HPSA) += hpsa.o
-obj-$(CONFIG_SCSI_DTC3280) += dtc.o
+obj-$(CONFIG_SCSI_SMARTPQI) += smartpqi/
obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/
obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o
-obj-$(CONFIG_SCSI_7000FASST) += wd7000.o
obj-$(CONFIG_SCSI_EATA) += eata.o
obj-$(CONFIG_SCSI_DC395x) += dc395x.o
obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 43908bbb3b23..db2739079cbb 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -230,13 +230,6 @@ static int NCR5380_poll_politely2(struct Scsi_Host *instance,
return -ETIMEDOUT;
}
-static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
- int reg, int bit, int val, int wait)
-{
- return NCR5380_poll_politely2(instance, reg, bit, val,
- reg, bit, val, wait);
-}
-
#if NDEBUG
static struct {
unsigned char mask;
@@ -1854,11 +1847,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* XXX - need to source or sink data here, as appropriate */
}
} else {
- /* Break up transfer into 3 ms chunks,
- * presuming 6 accesses per handshake.
+ /* Transfer a small chunk so that the
+ * irq mode lock is not held too long.
*/
- transfersize = min((unsigned long)cmd->SCp.this_residual,
- hostdata->accesses_per_ms / 2);
+ transfersize = min(cmd->SCp.this_residual,
+ NCR5380_PIO_CHUNK_SIZE);
len = transfersize;
NCR5380_transfer_pio(instance, &phase, &len,
(unsigned char **)&cmd->SCp.ptr);
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index c60728785d89..965d92339455 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -250,6 +250,8 @@ struct NCR5380_cmd {
#define NCR5380_CMD_SIZE (sizeof(struct NCR5380_cmd))
+#define NCR5380_PIO_CHUNK_SIZE 256
+
static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
{
return ((struct scsi_cmnd *)ncmd_ptr) - 1;
@@ -292,8 +294,14 @@ static void NCR5380_reselect(struct Scsi_Host *instance);
static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *);
static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
-static int NCR5380_poll_politely(struct Scsi_Host *, int, int, int, int);
static int NCR5380_poll_politely2(struct Scsi_Host *, int, int, int, int, int, int, int);
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+ int reg, int bit, int val, int wait)
+{
+ return NCR5380_poll_politely2(instance, reg, bit, val,
+ reg, bit, val, wait);
+}
+
#endif /* __KERNEL__ */
#endif /* NCR5380_H */
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 28f8b8a1b8a4..0c453880f214 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -613,7 +613,7 @@ static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
* @dev: Adapter
* @comm: communications method
*/
-int aac_src_select_comm(struct aac_dev *dev, int comm)
+static int aac_src_select_comm(struct aac_dev *dev, int comm)
{
switch (comm) {
case AAC_COMM_MESSAGE:
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 0fdc98bc2338..7c713f797535 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -632,7 +632,7 @@ int asd_init_hw(struct asd_ha_struct *asd_ha)
pci_name(asd_ha->pcidev));
return err;
}
- pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
+ err = pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
v | SC_TMR_DIS);
if (err) {
asd_printk("couldn't disable split completion timer of %s\n",
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 7640498964a5..3d53d636b17b 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2388,15 +2388,23 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
}
case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
unsigned char *ver_addr;
- int32_t user_len, cnt2end;
+ uint32_t user_len;
+ int32_t cnt2end;
uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ user_len = pcmdmessagefld->cmdmessage.Length;
+ if (user_len > ARCMSR_API_DATA_BUFLEN) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+
ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC);
if (!ver_addr) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
ptmpuserbuffer = ver_addr;
- user_len = pcmdmessagefld->cmdmessage.Length;
+
memcpy(ptmpuserbuffer,
pcmdmessagefld->messagedatabuffer, user_len);
spin_lock_irqsave(&acb->wqbuffer_lock, flags);
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index ee5ace873535..b1d0fdc5d5e1 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -8,7 +8,7 @@
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -89,7 +89,7 @@ struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */
u32 max_eqd; /* in usecs */
u32 prev_eqd; /* in usecs */
u32 et_eqd; /* configured val when aic is off */
- ulong jiffs;
+ ulong jiffies;
u64 eq_prev; /* Used to calculate eqe */
};
@@ -100,7 +100,7 @@ struct be_eq_obj {
struct be_queue_info q;
struct beiscsi_hba *phba;
struct be_queue_info *cq;
- struct work_struct work_cqs; /* Work Item */
+ struct work_struct mcc_work; /* Work Item */
struct irq_poll iopoll;
};
@@ -111,8 +111,11 @@ struct be_mcc_obj {
struct beiscsi_mcc_tag_state {
unsigned long tag_state;
-#define MCC_TAG_STATE_RUNNING 1
-#define MCC_TAG_STATE_TIMEOUT 2
+#define MCC_TAG_STATE_RUNNING 0
+#define MCC_TAG_STATE_TIMEOUT 1
+#define MCC_TAG_STATE_ASYNC 2
+#define MCC_TAG_STATE_IGNORE 3
+ void (*cbfn)(struct beiscsi_hba *, unsigned int);
struct be_dma_mem tag_mem_state;
};
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index a55eaeea37e7..be65da2988fb 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -8,7 +8,7 @@
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -21,110 +21,77 @@
#include "be.h"
#include "be_mgmt.h"
-int beiscsi_pci_soft_reset(struct beiscsi_hba *phba)
-{
- u32 sreset;
- u8 *pci_reset_offset = 0;
- u8 *pci_online0_offset = 0;
- u8 *pci_online1_offset = 0;
- u32 pconline0 = 0;
- u32 pconline1 = 0;
- u32 i;
-
- pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET;
- pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0;
- pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1;
- sreset = readl((void *)pci_reset_offset);
- sreset |= BE2_SET_RESET;
- writel(sreset, (void *)pci_reset_offset);
-
- i = 0;
- while (sreset & BE2_SET_RESET) {
- if (i > 64)
- break;
- msleep(100);
- sreset = readl((void *)pci_reset_offset);
- i++;
- }
-
- if (sreset & BE2_SET_RESET) {
- printk(KERN_ERR DRV_NAME
- " Soft Reset did not deassert\n");
- return -EIO;
- }
- pconline1 = BE2_MPU_IRAM_ONLINE;
- writel(pconline0, (void *)pci_online0_offset);
- writel(pconline1, (void *)pci_online1_offset);
-
- sreset |= BE2_SET_RESET;
- writel(sreset, (void *)pci_reset_offset);
-
- i = 0;
- while (sreset & BE2_SET_RESET) {
- if (i > 64)
- break;
- msleep(1);
- sreset = readl((void *)pci_reset_offset);
- i++;
- }
- if (sreset & BE2_SET_RESET) {
- printk(KERN_ERR DRV_NAME
- " MPU Online Soft Reset did not deassert\n");
- return -EIO;
- }
- return 0;
-}
-
-int be_chk_reset_complete(struct beiscsi_hba *phba)
-{
- unsigned int num_loop;
- u8 *mpu_sem = 0;
- u32 status;
-
- num_loop = 1000;
- mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
- msleep(5000);
-
- while (num_loop) {
- status = readl((void *)mpu_sem);
-
- if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000)
- break;
- msleep(60);
- num_loop--;
- }
-
- if ((status & 0x80000000) || (!num_loop)) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BC_%d : Failed in be_chk_reset_complete"
- "status = 0x%x\n", status);
- return -EIO;
- }
-
- return 0;
-}
-
-unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
-{
- unsigned int tag = 0;
+/* UE Status Low CSR */
+static const char * const desc_ue_status_low[] = {
+ "CEV",
+ "CTX",
+ "DBUF",
+ "ERX",
+ "Host",
+ "MPU",
+ "NDMA",
+ "PTC ",
+ "RDMA ",
+ "RXF ",
+ "RXIPS ",
+ "RXULP0 ",
+ "RXULP1 ",
+ "RXULP2 ",
+ "TIM ",
+ "TPOST ",
+ "TPRE ",
+ "TXIPS ",
+ "TXULP0 ",
+ "TXULP1 ",
+ "UC ",
+ "WDMA ",
+ "TXULP2 ",
+ "HOST1 ",
+ "P0_OB_LINK ",
+ "P1_OB_LINK ",
+ "HOST_GPIO ",
+ "MBOX ",
+ "AXGMAC0",
+ "AXGMAC1",
+ "JTAG",
+ "MPU_INTPEND"
+};
- spin_lock(&phba->ctrl.mcc_lock);
- if (phba->ctrl.mcc_tag_available) {
- tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
- phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
- phba->ctrl.mcc_tag_status[tag] = 0;
- phba->ctrl.ptag_state[tag].tag_state = 0;
- }
- if (tag) {
- phba->ctrl.mcc_tag_available--;
- if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1))
- phba->ctrl.mcc_alloc_index = 0;
- else
- phba->ctrl.mcc_alloc_index++;
- }
- spin_unlock(&phba->ctrl.mcc_lock);
- return tag;
-}
+/* UE Status High CSR */
+static const char * const desc_ue_status_hi[] = {
+ "LPCMEMHOST",
+ "MGMT_MAC",
+ "PCS0ONLINE",
+ "MPU_IRAM",
+ "PCS1ONLINE",
+ "PCTL0",
+ "PCTL1",
+ "PMEM",
+ "RR",
+ "TXPB",
+ "RXPP",
+ "XAUI",
+ "TXP",
+ "ARM",
+ "IPC",
+ "HOST2",
+ "HOST3",
+ "HOST4",
+ "HOST5",
+ "HOST6",
+ "HOST7",
+ "HOST8",
+ "HOST9",
+ "NETC",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown"
+};
struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
unsigned int *ref_tag)
@@ -133,7 +100,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
struct be_mcc_wrb *wrb = NULL;
unsigned int tag;
- spin_lock_bh(&phba->ctrl.mcc_lock);
+ spin_lock(&phba->ctrl.mcc_lock);
if (mccq->used == mccq->len) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT |
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
@@ -160,6 +127,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
phba->ctrl.mcc_tag_status[tag] = 0;
phba->ctrl.ptag_state[tag].tag_state = 0;
+ phba->ctrl.ptag_state[tag].cbfn = NULL;
phba->ctrl.mcc_tag_available--;
if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1))
phba->ctrl.mcc_alloc_index = 0;
@@ -174,7 +142,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
mccq->used++;
alloc_failed:
- spin_unlock_bh(&phba->ctrl.mcc_lock);
+ spin_unlock(&phba->ctrl.mcc_lock);
return wrb;
}
@@ -182,7 +150,7 @@ void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag)
{
struct be_queue_info *mccq = &ctrl->mcc_obj.q;
- spin_lock_bh(&ctrl->mcc_lock);
+ spin_lock(&ctrl->mcc_lock);
tag = tag & MCC_Q_CMD_TAG_MASK;
ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
@@ -191,16 +159,71 @@ void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag)
ctrl->mcc_free_index++;
ctrl->mcc_tag_available++;
mccq->used--;
- spin_unlock_bh(&ctrl->mcc_lock);
+ spin_unlock(&ctrl->mcc_lock);
}
-/**
- * beiscsi_fail_session(): Closing session with appropriate error
- * @cls_session: ptr to session
- **/
-void beiscsi_fail_session(struct iscsi_cls_session *cls_session)
+/*
+ * beiscsi_mcc_compl_status - Return the status of MCC completion
+ * @phba: Driver private structure
+ * @tag: Tag for the MBX Command
+ * @wrb: the WRB used for the MBX Command
+ * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero
+ */
+int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba,
+ unsigned int tag,
+ struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem)
{
- iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ uint16_t status = 0, addl_status = 0, wrb_num = 0;
+ struct be_cmd_resp_hdr *mbx_resp_hdr;
+ struct be_cmd_req_hdr *mbx_hdr;
+ struct be_mcc_wrb *temp_wrb;
+ uint32_t mcc_tag_status;
+ int rc = 0;
+
+ mcc_tag_status = phba->ctrl.mcc_tag_status[tag];
+ status = (mcc_tag_status & CQE_STATUS_MASK);
+ addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >>
+ CQE_STATUS_ADDL_SHIFT);
+
+ if (mbx_cmd_mem) {
+ mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
+ } else {
+ wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >>
+ CQE_STATUS_WRB_SHIFT;
+ temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
+ mbx_hdr = embedded_payload(temp_wrb);
+
+ if (wrb)
+ *wrb = temp_wrb;
+ }
+
+ if (status || addl_status) {
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
+ BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX Cmd Failed for Subsys : %d Opcode : %d with Status : %d and Extd_Status : %d\n",
+ mbx_hdr->subsystem, mbx_hdr->opcode,
+ status, addl_status);
+ rc = -EIO;
+ if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
+ mbx_resp_hdr = (struct be_cmd_resp_hdr *)mbx_hdr;
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
+ BEISCSI_LOG_CONFIG,
+ "BC_%d : Insufficient Buffer Error Resp_Len : %d Actual_Resp_Len : %d\n",
+ mbx_resp_hdr->response_length,
+ mbx_resp_hdr->actual_resp_len);
+ rc = -EAGAIN;
+ }
+ }
+
+ return rc;
}
/*
@@ -217,26 +240,34 @@ void beiscsi_fail_session(struct iscsi_cls_session *cls_session)
* Failure: Non-Zero
**/
int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb,
+ unsigned int tag,
+ struct be_mcc_wrb **wrb,
struct be_dma_mem *mbx_cmd_mem)
{
int rc = 0;
- uint32_t mcc_tag_status;
- uint16_t status = 0, addl_status = 0, wrb_num = 0;
- struct be_mcc_wrb *temp_wrb;
- struct be_cmd_req_hdr *mbx_hdr;
- struct be_cmd_resp_hdr *mbx_resp_hdr;
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- if (beiscsi_error(phba))
- return -EPERM;
+ if (beiscsi_hba_in_error(phba)) {
+ clear_bit(MCC_TAG_STATE_RUNNING,
+ &phba->ctrl.ptag_state[tag].tag_state);
+ return -EIO;
+ }
/* wait for the mccq completion */
- rc = wait_event_interruptible_timeout(
- phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_tag_status[tag],
- msecs_to_jiffies(
- BEISCSI_HOST_MBX_TIMEOUT));
+ rc = wait_event_interruptible_timeout(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_tag_status[tag],
+ msecs_to_jiffies(
+ BEISCSI_HOST_MBX_TIMEOUT));
+ /**
+ * Return EIO if port is being disabled. Associated DMA memory, if any,
+ * is freed by the caller. When port goes offline, MCCQ is cleaned up
+ * so does WRB.
+ */
+ if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
+ clear_bit(MCC_TAG_STATE_RUNNING,
+ &phba->ctrl.ptag_state[tag].tag_state);
+ return -EIO;
+ }
+
/**
* If MBOX cmd timeout expired, tag and resource allocated
* for cmd is not freed until FW returns completion.
@@ -270,47 +301,7 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
return -EBUSY;
}
- rc = 0;
- mcc_tag_status = phba->ctrl.mcc_tag_status[tag];
- status = (mcc_tag_status & CQE_STATUS_MASK);
- addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >>
- CQE_STATUS_ADDL_SHIFT);
-
- if (mbx_cmd_mem) {
- mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
- } else {
- wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >>
- CQE_STATUS_WRB_SHIFT;
- temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
- mbx_hdr = embedded_payload(temp_wrb);
-
- if (wrb)
- *wrb = temp_wrb;
- }
-
- if (status || addl_status) {
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
- BEISCSI_LOG_CONFIG,
- "BC_%d : MBX Cmd Failed for "
- "Subsys : %d Opcode : %d with "
- "Status : %d and Extd_Status : %d\n",
- mbx_hdr->subsystem,
- mbx_hdr->opcode,
- status, addl_status);
- rc = -EIO;
- if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
- mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr;
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
- BEISCSI_LOG_CONFIG,
- "BC_%d : Insufficient Buffer Error "
- "Resp_Len : %d Actual_Resp_Len : %d\n",
- mbx_resp_hdr->response_length,
- mbx_resp_hdr->actual_resp_len);
- rc = -EAGAIN;
- }
- }
+ rc = __beiscsi_mcc_compl_status(phba, tag, wrb, mbx_cmd_mem);
free_mcc_wrb(&phba->ctrl, tag);
return rc;
@@ -330,11 +321,10 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
static int beiscsi_process_mbox_compl(struct be_ctrl_info *ctrl,
struct be_mcc_compl *compl)
{
- u16 compl_status, extd_status;
struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
struct be_cmd_req_hdr *hdr = embedded_payload(wrb);
- struct be_cmd_resp_hdr *resp_hdr;
+ u16 compl_status, extd_status;
/**
* To check if valid bit is set, check the entire word as we don't know
@@ -368,14 +358,7 @@ static int beiscsi_process_mbox_compl(struct be_ctrl_info *ctrl,
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BC_%d : error in cmd completion: Subsystem : %d Opcode : %d status(compl/extd)=%d/%d\n",
hdr->subsystem, hdr->opcode, compl_status, extd_status);
-
- if (compl_status == MCC_STATUS_INSUFFICIENT_BUFFER) {
- /* if status is insufficient buffer, check the length */
- resp_hdr = (struct be_cmd_resp_hdr *) hdr;
- if (resp_hdr->response_length)
- return 0;
- }
- return -EINVAL;
+ return compl_status;
}
static void beiscsi_process_async_link(struct beiscsi_hba *phba,
@@ -391,18 +374,19 @@ static void beiscsi_process_async_link(struct beiscsi_hba *phba,
* This has been newly introduced in SKH-R Firmware 10.0.338.45.
**/
if (evt->port_link_status & BE_ASYNC_LINK_UP_MASK) {
- phba->state = BE_ADAPTER_LINK_UP | BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
+ set_bit(BEISCSI_HBA_LINK_UP, &phba->state);
+ if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state))
+ beiscsi_start_boot_work(phba, BE_BOOT_INVALID_SHANDLE);
__beiscsi_log(phba, KERN_ERR,
"BC_%d : Link Up on Port %d tag 0x%x\n",
evt->physical_port, evt->event_tag);
} else {
- phba->state = BE_ADAPTER_LINK_DOWN;
+ clear_bit(BEISCSI_HBA_LINK_UP, &phba->state);
__beiscsi_log(phba, KERN_ERR,
"BC_%d : Link Down on Port %d tag 0x%x\n",
evt->physical_port, evt->event_tag);
iscsi_host_for_each_session(phba->shost,
- beiscsi_fail_session);
+ beiscsi_session_fail);
}
}
@@ -482,8 +466,8 @@ void beiscsi_process_async_event(struct beiscsi_hba *phba,
beiscsi_process_async_link(phba, compl);
break;
case ASYNC_EVENT_CODE_ISCSI:
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
+ if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state))
+ beiscsi_start_boot_work(phba, BE_BOOT_INVALID_SHANDLE);
sev = KERN_ERR;
break;
case ASYNC_EVENT_CODE_SLI:
@@ -519,6 +503,9 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
return 0;
}
+ /* end MCC with this tag */
+ clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state);
+
if (test_bit(MCC_TAG_STATE_TIMEOUT, &ctrl->ptag_state[tag].tag_state)) {
beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
@@ -529,9 +516,11 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
* Only for non-embedded cmd, PCI resource is allocated.
**/
tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
- if (tag_mem->size)
+ if (tag_mem->size) {
pci_free_consistent(ctrl->pdev, tag_mem->size,
tag_mem->va, tag_mem->dma);
+ tag_mem->size = 0;
+ }
free_mcc_wrb(ctrl, tag);
return 0;
}
@@ -550,57 +539,25 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
CQE_STATUS_ADDL_MASK;
ctrl->mcc_tag_status[tag] |= (compl_status & CQE_STATUS_MASK);
- /* write ordering forced in wake_up_interruptible */
- clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state);
- wake_up_interruptible(&ctrl->mcc_wait[tag]);
- return 0;
-}
-
-/*
- * be_mcc_compl_poll()- Wait for MBX completion
- * @phba: driver private structure
- *
- * Wait till no more pending mcc requests are present
- *
- * return
- * Success: 0
- * Failure: Non-Zero
- *
- **/
-int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- int i;
-
- if (!test_bit(MCC_TAG_STATE_RUNNING,
- &ctrl->ptag_state[tag].tag_state)) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d: tag %u state not running\n", tag);
+ if (test_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state)) {
+ if (ctrl->ptag_state[tag].cbfn)
+ ctrl->ptag_state[tag].cbfn(phba, tag);
+ else
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : MBX ASYNC command with no callback\n");
+ free_mcc_wrb(ctrl, tag);
return 0;
}
- for (i = 0; i < mcc_timeout; i++) {
- if (beiscsi_error(phba))
- return -EIO;
- beiscsi_process_mcc_cq(phba);
- /* after polling, wrb and tag need to be released */
- if (!test_bit(MCC_TAG_STATE_RUNNING,
- &ctrl->ptag_state[tag].tag_state)) {
- free_mcc_wrb(ctrl, tag);
- break;
- }
- udelay(100);
- }
-
- if (i < mcc_timeout)
+ if (test_bit(MCC_TAG_STATE_IGNORE, &ctrl->ptag_state[tag].tag_state)) {
+ /* just check completion status and free wrb */
+ __beiscsi_mcc_compl_status(phba, tag, NULL, NULL);
+ free_mcc_wrb(ctrl, tag);
return 0;
+ }
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : FW Timed Out\n");
- phba->fw_timeout = true;
- beiscsi_ue_detect(phba);
- return -EBUSY;
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ return 0;
}
void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag)
@@ -642,7 +599,7 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
*/
timeout = jiffies + msecs_to_jiffies(BEISCSI_MBX_RDY_BIT_TIMEOUT);
do {
- if (beiscsi_error(phba))
+ if (beiscsi_hba_in_error(phba))
return -EIO;
ready = ioread32(db);
@@ -655,16 +612,14 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
if (time_after(jiffies, timeout))
break;
- msleep(20);
+ /* 1ms sleep is enough in most cases */
+ schedule_timeout_uninterruptible(msecs_to_jiffies(1));
} while (!ready);
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BC_%d : FW Timed Out\n");
-
- phba->fw_timeout = true;
- beiscsi_ue_detect(phba);
-
+ set_bit(BEISCSI_HBA_FW_TIMEOUT, &phba->state);
return -EBUSY;
}
@@ -679,7 +634,7 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
* Success: 0
* Failure: Non-Zero
**/
-int be_mbox_notify(struct be_ctrl_info *ctrl)
+static int be_mbox_notify(struct be_ctrl_info *ctrl)
{
int status;
u32 val = 0;
@@ -819,87 +774,6 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
return status;
}
-/**
- * be_cmd_fw_initialize()- Initialize FW
- * @ctrl: Pointer to function control structure
- *
- * Send FW initialize pattern for the function.
- *
- * return
- * Success: 0
- * Failure: Non-Zero value
- **/
-int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
-{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
- int status;
- u8 *endian_check;
-
- mutex_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
-
- endian_check = (u8 *) wrb;
- *endian_check++ = 0xFF;
- *endian_check++ = 0x12;
- *endian_check++ = 0x34;
- *endian_check++ = 0xFF;
- *endian_check++ = 0xFF;
- *endian_check++ = 0x56;
- *endian_check++ = 0x78;
- *endian_check++ = 0xFF;
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
-
- status = be_mbox_notify(ctrl);
- if (status)
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BC_%d : be_cmd_fw_initialize Failed\n");
-
- mutex_unlock(&ctrl->mbox_lock);
- return status;
-}
-
-/**
- * be_cmd_fw_uninit()- Uinitialize FW
- * @ctrl: Pointer to function control structure
- *
- * Send FW uninitialize pattern for the function
- *
- * return
- * Success: 0
- * Failure: Non-Zero value
- **/
-int be_cmd_fw_uninit(struct be_ctrl_info *ctrl)
-{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
- int status;
- u8 *endian_check;
-
- mutex_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
-
- endian_check = (u8 *) wrb;
- *endian_check++ = 0xFF;
- *endian_check++ = 0xAA;
- *endian_check++ = 0xBB;
- *endian_check++ = 0xFF;
- *endian_check++ = 0xFF;
- *endian_check++ = 0xCC;
- *endian_check++ = 0xDD;
- *endian_check = 0xFF;
-
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
-
- status = be_mbox_notify(ctrl);
- if (status)
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BC_%d : be_cmd_fw_uninit Failed\n");
-
- mutex_unlock(&ctrl->mbox_lock);
- return status;
-}
-
int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *cq, struct be_queue_info *eq,
bool sol_evts, bool no_delay, int coalesce_wm)
@@ -1343,25 +1217,6 @@ error:
return status;
}
-int beiscsi_cmd_reset_function(struct beiscsi_hba *phba)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_post_sgl_pages_req *req = embedded_payload(wrb);
- int status;
-
- mutex_lock(&ctrl->mbox_lock);
-
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
- status = be_mbox_notify(ctrl);
-
- mutex_unlock(&ctrl->mbox_lock);
- return status;
-}
-
/**
* be_cmd_set_vlan()- Configure VLAN paramters on the adapter
* @phba: device priv structure instance
@@ -1402,3 +1257,564 @@ int be_cmd_set_vlan(struct beiscsi_hba *phba,
return tag;
}
+
+int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
+{
+ struct be_dma_mem nonemb_cmd;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mgmt_controller_attributes *req;
+ struct be_sge *sge = nonembedded_sgl(wrb);
+ int status = 0;
+
+ nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
+ sizeof(struct be_mgmt_controller_attributes),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : pci_alloc_consistent failed in %s\n",
+ __func__);
+ return -ENOMEM;
+ }
+ nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
+ req = nonemb_cmd.va;
+ memset(req, 0, sizeof(*req));
+ mutex_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req));
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd.size);
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va;
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : Firmware Version of CMD : %s\n"
+ "Firmware Version is : %s\n"
+ "Developer Build, not performing version check...\n",
+ resp->params.hba_attribs
+ .flashrom_version_string,
+ resp->params.hba_attribs.
+ firmware_version_string);
+
+ phba->fw_config.iscsi_features =
+ resp->params.hba_attribs.iscsi_features;
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BM_%d : phba->fw_config.iscsi_features = %d\n",
+ phba->fw_config.iscsi_features);
+ memcpy(phba->fw_ver_str, resp->params.hba_attribs.
+ firmware_version_string, BEISCSI_VER_STRLEN);
+ } else
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : Failed in beiscsi_check_supported_fw\n");
+ mutex_unlock(&ctrl->mbox_lock);
+ if (nonemb_cmd.va)
+ pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
+ return status;
+}
+
+/**
+ * beiscsi_get_fw_config()- Get the FW config for the function
+ * @ctrl: ptr to Ctrl Info
+ * @phba: ptr to the dev priv structure
+ *
+ * Get the FW config and resources available for the function.
+ * The resources are created based on the count received here.
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero Value
+ **/
+int beiscsi_get_fw_config(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_fw_cfg *pfw_cfg = embedded_payload(wrb);
+ uint32_t cid_count, icd_count;
+ int status = -EINVAL;
+ uint8_t ulp_num = 0;
+
+ mutex_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0);
+
+ be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
+ EMBED_MBX_MAX_PAYLOAD_SIZE);
+
+ if (be_mbox_notify(ctrl)) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : Failed in beiscsi_get_fw_config\n");
+ goto fail_init;
+ }
+
+ /* FW response formats depend on port id */
+ phba->fw_config.phys_port = pfw_cfg->phys_port;
+ if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid physical port id %d\n",
+ phba->fw_config.phys_port);
+ goto fail_init;
+ }
+
+ /* populate and check FW config against min and max values */
+ if (!is_chip_be2_be3r(phba)) {
+ phba->fw_config.eqid_count = pfw_cfg->eqid_count;
+ phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+ if (phba->fw_config.eqid_count == 0 ||
+ phba->fw_config.eqid_count > 2048) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid EQ count %d\n",
+ phba->fw_config.eqid_count);
+ goto fail_init;
+ }
+ if (phba->fw_config.cqid_count == 0 ||
+ phba->fw_config.cqid_count > 4096) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid CQ count %d\n",
+ phba->fw_config.cqid_count);
+ goto fail_init;
+ }
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : EQ_Count : %d CQ_Count : %d\n",
+ phba->fw_config.eqid_count,
+ phba->fw_config.cqid_count);
+ }
+
+ /**
+ * Check on which all ULP iSCSI Protocol is loaded.
+ * Set the Bit for those ULP. This set flag is used
+ * at all places in the code to check on which ULP
+ * iSCSi Protocol is loaded
+ **/
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
+ if (pfw_cfg->ulp[ulp_num].ulp_mode &
+ BEISCSI_ULP_ISCSI_INI_MODE) {
+ set_bit(ulp_num, &phba->fw_config.ulp_supported);
+
+ /* Get the CID, ICD and Chain count for each ULP */
+ phba->fw_config.iscsi_cid_start[ulp_num] =
+ pfw_cfg->ulp[ulp_num].sq_base;
+ phba->fw_config.iscsi_cid_count[ulp_num] =
+ pfw_cfg->ulp[ulp_num].sq_count;
+
+ phba->fw_config.iscsi_icd_start[ulp_num] =
+ pfw_cfg->ulp[ulp_num].icd_base;
+ phba->fw_config.iscsi_icd_count[ulp_num] =
+ pfw_cfg->ulp[ulp_num].icd_count;
+
+ phba->fw_config.iscsi_chain_start[ulp_num] =
+ pfw_cfg->chain_icd[ulp_num].chain_base;
+ phba->fw_config.iscsi_chain_count[ulp_num] =
+ pfw_cfg->chain_icd[ulp_num].chain_count;
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : Function loaded on ULP : %d\n"
+ "\tiscsi_cid_count : %d\n"
+ "\tiscsi_cid_start : %d\n"
+ "\t iscsi_icd_count : %d\n"
+ "\t iscsi_icd_start : %d\n",
+ ulp_num,
+ phba->fw_config.
+ iscsi_cid_count[ulp_num],
+ phba->fw_config.
+ iscsi_cid_start[ulp_num],
+ phba->fw_config.
+ iscsi_icd_count[ulp_num],
+ phba->fw_config.
+ iscsi_icd_start[ulp_num]);
+ }
+ }
+
+ if (phba->fw_config.ulp_supported == 0) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 %x\n",
+ pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode,
+ pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode);
+ goto fail_init;
+ }
+
+ /**
+ * ICD is shared among ULPs. Use icd_count of any one loaded ULP
+ **/
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
+ if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
+ break;
+ icd_count = phba->fw_config.iscsi_icd_count[ulp_num];
+ if (icd_count == 0 || icd_count > 65536) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d: invalid ICD count %d\n", icd_count);
+ goto fail_init;
+ }
+
+ cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) +
+ BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1);
+ if (cid_count == 0 || cid_count > 4096) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d: invalid CID count %d\n", cid_count);
+ goto fail_init;
+ }
+
+ /**
+ * Check FW is dual ULP aware i.e. can handle either
+ * of the protocols.
+ */
+ phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
+ BEISCSI_FUNC_DUA_MODE);
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : DUA Mode : 0x%x\n",
+ phba->fw_config.dual_ulp_aware);
+
+ /* all set, continue using this FW config */
+ status = 0;
+fail_init:
+ mutex_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+/**
+ * beiscsi_get_port_name()- Get port name for the function
+ * @ctrl: ptr to Ctrl Info
+ * @phba: ptr to the dev priv structure
+ *
+ * Get the alphanumeric character for port
+ *
+ **/
+int beiscsi_get_port_name(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba)
+{
+ int ret = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_port_name *ioctl;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ memset(wrb, 0, sizeof(*wrb));
+ ioctl = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0);
+ be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_PORT_NAME,
+ EMBED_MBX_MAX_PAYLOAD_SIZE);
+ ret = be_mbox_notify(ctrl);
+ phba->port_name = 0;
+ if (!ret) {
+ phba->port_name = ioctl->p.resp.port_names >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+ } else {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n",
+ ret, ioctl->h.resp_hdr.status);
+ }
+
+ if (phba->port_name == 0)
+ phba->port_name = '?';
+
+ mutex_unlock(&ctrl->mbox_lock);
+ return ret;
+}
+
+int beiscsi_set_uer_feature(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_cmd_set_features *ioctl;
+ struct be_mcc_wrb *wrb;
+ int ret = 0;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ memset(wrb, 0, sizeof(*wrb));
+ ioctl = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0);
+ be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_FEATURES,
+ EMBED_MBX_MAX_PAYLOAD_SIZE);
+ ioctl->feature = BE_CMD_SET_FEATURE_UER;
+ ioctl->param_len = sizeof(ioctl->param.req);
+ ioctl->param.req.uer = BE_CMD_UER_SUPP_BIT;
+ ret = be_mbox_notify(ctrl);
+ if (!ret) {
+ phba->ue2rp = ioctl->param.resp.ue2rp;
+ set_bit(BEISCSI_HBA_UER_SUPP, &phba->state);
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : HBA error recovery supported\n");
+ } else {
+ /**
+ * Check "MCC_STATUS_INVALID_LENGTH" for SKH.
+ * Older FW versions return this error.
+ */
+ if (ret == MCC_STATUS_ILLEGAL_REQUEST ||
+ ret == MCC_STATUS_INVALID_LENGTH)
+ __beiscsi_log(phba, KERN_INFO,
+ "BG_%d : HBA error recovery not supported\n");
+ }
+
+ mutex_unlock(&ctrl->mbox_lock);
+ return ret;
+}
+
+static u32 beiscsi_get_post_stage(struct beiscsi_hba *phba)
+{
+ u32 sem;
+
+ if (is_chip_be2_be3r(phba))
+ sem = ioread32(phba->csr_va + SLIPORT_SEMAPHORE_OFFSET_BEx);
+ else
+ pci_read_config_dword(phba->pcidev,
+ SLIPORT_SEMAPHORE_OFFSET_SH, &sem);
+ return sem;
+}
+
+int beiscsi_check_fw_rdy(struct beiscsi_hba *phba)
+{
+ u32 loop, post, rdy = 0;
+
+ loop = 1000;
+ while (loop--) {
+ post = beiscsi_get_post_stage(phba);
+ if (post & POST_ERROR_BIT)
+ break;
+ if ((post & POST_STAGE_MASK) == POST_STAGE_ARMFW_RDY) {
+ rdy = 1;
+ break;
+ }
+ msleep(60);
+ }
+
+ if (!rdy) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : FW not ready 0x%x\n", post);
+ }
+
+ return rdy;
+}
+
+int beiscsi_cmd_function_reset(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_post_sgl_pages_req *req = embedded_payload(wrb);
+ int status;
+
+ mutex_lock(&ctrl->mbox_lock);
+
+ req = embedded_payload(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
+ status = be_mbox_notify(ctrl);
+
+ mutex_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int beiscsi_cmd_special_wrb(struct be_ctrl_info *ctrl, u32 load)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
+ u8 *endian_check;
+ int status;
+
+ mutex_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ endian_check = (u8 *) wrb;
+ if (load) {
+ /* to start communicating */
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0x12;
+ *endian_check++ = 0x34;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0x56;
+ *endian_check++ = 0x78;
+ *endian_check++ = 0xFF;
+ } else {
+ /* to stop communicating */
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0xAA;
+ *endian_check++ = 0xBB;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0xCC;
+ *endian_check++ = 0xDD;
+ *endian_check = 0xFF;
+ }
+ be_dws_cpu_to_le(wrb, sizeof(*wrb));
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BC_%d : special WRB message failed\n");
+ mutex_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int beiscsi_init_sliport(struct beiscsi_hba *phba)
+{
+ int status;
+
+ /* check POST stage before talking to FW */
+ status = beiscsi_check_fw_rdy(phba);
+ if (!status)
+ return -EIO;
+
+ /* clear all error states after checking FW rdy */
+ phba->state &= ~BEISCSI_HBA_IN_ERR;
+
+ /* check again UER support */
+ phba->state &= ~BEISCSI_HBA_UER_SUPP;
+
+ /*
+ * SLI COMMON_FUNCTION_RESET completion is indicated by BMBX RDY bit.
+ * It should clean up any stale info in FW for this fn.
+ */
+ status = beiscsi_cmd_function_reset(phba);
+ if (status) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BC_%d : SLI Function Reset failed\n");
+ return status;
+ }
+
+ /* indicate driver is loading */
+ return beiscsi_cmd_special_wrb(&phba->ctrl, 1);
+}
+
+/**
+ * beiscsi_cmd_iscsi_cleanup()- Inform FW to cleanup EP data structures.
+ * @phba: pointer to dev priv structure
+ * @ulp: ULP number.
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero Value
+ **/
+int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct iscsi_cleanup_req_v1 *req_v1;
+ struct iscsi_cleanup_req *req;
+ struct be_mcc_wrb *wrb;
+ int status;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ req = embedded_payload(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
+
+ /**
+ * TODO: Check with FW folks the chute value to be set.
+ * For now, use the ULP_MASK as the chute value.
+ */
+ if (is_chip_be2_be3r(phba)) {
+ req->chute = (1 << ulp);
+ req->hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp);
+ req->data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp);
+ } else {
+ req_v1 = (struct iscsi_cleanup_req_v1 *)req;
+ req_v1->hdr.version = 1;
+ req_v1->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba,
+ ulp));
+ req_v1->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba,
+ ulp));
+ }
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT,
+ "BG_%d : %s failed %d\n", __func__, ulp);
+ mutex_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+/*
+ * beiscsi_detect_ue()- Detect Unrecoverable Error on adapter
+ * @phba: Driver priv structure
+ *
+ * Read registers linked to UE and check for the UE status
+ **/
+int beiscsi_detect_ue(struct beiscsi_hba *phba)
+{
+ uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
+ uint32_t ue_hi = 0, ue_lo = 0;
+ uint8_t i = 0;
+ int ret = 0;
+
+ pci_read_config_dword(phba->pcidev,
+ PCICFG_UE_STATUS_LOW, &ue_lo);
+ pci_read_config_dword(phba->pcidev,
+ PCICFG_UE_STATUS_MASK_LOW,
+ &ue_mask_lo);
+ pci_read_config_dword(phba->pcidev,
+ PCICFG_UE_STATUS_HIGH,
+ &ue_hi);
+ pci_read_config_dword(phba->pcidev,
+ PCICFG_UE_STATUS_MASK_HI,
+ &ue_mask_hi);
+
+ ue_lo = (ue_lo & ~ue_mask_lo);
+ ue_hi = (ue_hi & ~ue_mask_hi);
+
+
+ if (ue_lo || ue_hi) {
+ set_bit(BEISCSI_HBA_IN_UE, &phba->state);
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : HBA error detected\n");
+ ret = 1;
+ }
+
+ if (ue_lo) {
+ for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+ if (ue_lo & 1)
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : UE_LOW %s bit set\n",
+ desc_ue_status_low[i]);
+ }
+ }
+
+ if (ue_hi) {
+ for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+ if (ue_hi & 1)
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : UE_HIGH %s bit set\n",
+ desc_ue_status_hi[i]);
+ }
+ }
+ return ret;
+}
+
+/*
+ * beiscsi_detect_tpe()- Detect Transient Parity Error on adapter
+ * @phba: Driver priv structure
+ *
+ * Read SLIPORT SEMAPHORE register to check for UER
+ *
+ **/
+int beiscsi_detect_tpe(struct beiscsi_hba *phba)
+{
+ u32 post, status;
+ int ret = 0;
+
+ post = beiscsi_get_post_stage(phba);
+ status = post & POST_STAGE_MASK;
+ if ((status & POST_ERR_RECOVERY_CODE_MASK) ==
+ POST_STAGE_RECOVERABLE_ERR) {
+ set_bit(BEISCSI_HBA_IN_TPE, &phba->state);
+ __beiscsi_log(phba, KERN_INFO,
+ "BC_%d : HBA error recoverable: 0x%x\n", post);
+ ret = 1;
+ } else {
+ __beiscsi_log(phba, KERN_INFO,
+ "BC_%d : HBA in UE: 0x%x\n", post);
+ }
+
+ return ret;
+}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index deeb951e6874..328fb5b973cd 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -8,7 +8,7 @@
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -57,6 +57,7 @@ struct be_mcc_wrb {
#define MCC_STATUS_ILLEGAL_REQUEST 0x2
#define MCC_STATUS_ILLEGAL_FIELD 0x3
#define MCC_STATUS_INSUFFICIENT_BUFFER 0x4
+#define MCC_STATUS_INVALID_LENGTH 0x74
#define CQE_STATUS_COMPL_MASK 0xFFFF
#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
@@ -97,11 +98,23 @@ struct be_mcc_compl {
#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */
#define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */
-/********** MPU semphore ******************/
-#define MPU_EP_SEMAPHORE_OFFSET 0xac
-#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
-#define EP_SEMAPHORE_POST_ERR_MASK 0x1
-#define EP_SEMAPHORE_POST_ERR_SHIFT 31
+/********** MPU semphore: used for SH & BE ******************/
+#define SLIPORT_SOFTRESET_OFFSET 0x5c /* CSR BAR offset */
+#define SLIPORT_SEMAPHORE_OFFSET_BEx 0xac /* CSR BAR offset */
+#define SLIPORT_SEMAPHORE_OFFSET_SH 0x94 /* PCI-CFG offset */
+#define POST_STAGE_MASK 0x0000FFFF
+#define POST_ERROR_BIT 0x80000000
+#define POST_ERR_RECOVERY_CODE_MASK 0xF000
+
+/* Soft Reset register masks */
+#define SLIPORT_SOFTRESET_SR_MASK 0x00000080 /* SR bit */
+
+/* MPU semphore POST stage values */
+#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */
+#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */
+#define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */
+#define POST_STAGE_ARMFW_RDY 0xC000 /* FW is done with POST */
+#define POST_STAGE_RECOVERABLE_ERR 0xE000 /* Recoverable err detected */
/********** MCC door bell ************/
#define DB_MCCQ_OFFSET 0x140
@@ -109,9 +122,6 @@ struct be_mcc_compl {
/* Number of entries posted */
#define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */
-/* MPU semphore POST stage values */
-#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */
-
/**
* When the async bit of mcc_compl is set, the last 4 bytes of
* mcc_compl is interpreted as follows:
@@ -217,6 +227,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
#define OPCODE_COMMON_FUNCTION_RESET 61
#define OPCODE_COMMON_GET_PORT_NAME 77
+#define OPCODE_COMMON_SET_FEATURES 191
/**
* LIST of opcodes that are common between Initiator and Target
@@ -345,8 +356,8 @@ struct be_cmd_req_logout_fw_sess {
struct be_cmd_resp_logout_fw_sess {
struct be_cmd_resp_hdr hdr; /* dw[4] */
-#define BEISCSI_MGMT_SESSION_CLOSE 0x20
uint32_t session_status;
+#define BE_SESS_STATUS_CLOSE 0x20
} __packed;
struct mgmt_conn_login_options {
@@ -365,6 +376,14 @@ struct ip_addr_format {
u16 size_of_structure;
u8 reserved;
u8 ip_type;
+#define BEISCSI_IP_TYPE_V4 0x1
+#define BEISCSI_IP_TYPE_STATIC_V4 0x3
+#define BEISCSI_IP_TYPE_DHCP_V4 0x5
+/* type v4 values < type v6 values */
+#define BEISCSI_IP_TYPE_V6 0x10
+#define BEISCSI_IP_TYPE_ROUTABLE_V6 0x30
+#define BEISCSI_IP_TYPE_LINK_LOCAL_V6 0x50
+#define BEISCSI_IP_TYPE_AUTO_V6 0x90
u8 addr[16];
u32 rsvd0;
} __packed;
@@ -430,8 +449,13 @@ struct be_cmd_get_boot_target_req {
struct be_cmd_get_boot_target_resp {
struct be_cmd_resp_hdr hdr;
- u32 boot_session_count;
- int boot_session_handle;
+ u32 boot_session_count;
+ u32 boot_session_handle;
+/**
+ * FW returns 0xffffffff if it couldn't establish connection with
+ * configured boot target.
+ */
+#define BE_BOOT_INVALID_SHANDLE 0xffffffff
};
struct be_cmd_reopen_session_req {
@@ -699,16 +723,59 @@ struct be_cmd_get_nic_conf_resp {
u8 mac_address[ETH_ALEN];
} __packed;
-#define BEISCSI_ALIAS_LEN 32
+/******************** Get HBA NAME *******************/
struct be_cmd_hba_name {
struct be_cmd_req_hdr hdr;
u16 flags;
u16 rsvd0;
u8 initiator_name[ISCSI_NAME_LEN];
- u8 initiator_alias[BEISCSI_ALIAS_LEN];
+#define BE_INI_ALIAS_LEN 32
+ u8 initiator_alias[BE_INI_ALIAS_LEN];
} __packed;
+/******************** COMMON SET Features *******************/
+#define BE_CMD_SET_FEATURE_UER 0x10
+#define BE_CMD_UER_SUPP_BIT 0x1
+struct be_uer_req {
+ u32 uer;
+ u32 rsvd;
+};
+
+struct be_uer_resp {
+ u32 uer;
+ u16 ue2rp;
+ u16 ue2sr;
+};
+
+struct be_cmd_set_features {
+ union {
+ struct be_cmd_req_hdr req_hdr;
+ struct be_cmd_resp_hdr resp_hdr;
+ } h;
+ u32 feature;
+ u32 param_len;
+ union {
+ struct be_uer_req req;
+ struct be_uer_resp resp;
+ u32 rsvd[2];
+ } param;
+} __packed;
+
+int beiscsi_cmd_function_reset(struct beiscsi_hba *phba);
+
+int beiscsi_cmd_special_wrb(struct be_ctrl_info *ctrl, u32 load);
+
+int beiscsi_check_fw_rdy(struct beiscsi_hba *phba);
+
+int beiscsi_init_sliport(struct beiscsi_hba *phba);
+
+int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num);
+
+int beiscsi_detect_ue(struct beiscsi_hba *phba);
+
+int beiscsi_detect_tpe(struct beiscsi_hba *phba);
+
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay);
@@ -723,24 +790,21 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
struct be_queue_info *mccq,
struct be_queue_info *cq);
-int be_poll_mcc(struct be_ctrl_info *ctrl);
-int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba);
unsigned int be_cmd_get_initname(struct beiscsi_hba *phba);
void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag);
-int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *,
+int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *,
int num);
int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb,
+ unsigned int tag,
+ struct be_mcc_wrb **wrb,
struct be_dma_mem *mbx_cmd_mem);
-/*ISCSI Functuions */
-int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
-int be_cmd_fw_uninit(struct be_ctrl_info *ctrl);
-
+int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba,
+ unsigned int tag,
+ struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem);
struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
-int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag);
void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag);
struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
unsigned int *ref_tag);
@@ -749,9 +813,6 @@ void beiscsi_process_async_event(struct beiscsi_hba *phba,
int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
struct be_mcc_compl *compl);
-
-int be_mbox_notify(struct be_ctrl_info *ctrl);
-
int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
struct be_queue_info *cq,
struct be_queue_info *dq, int length,
@@ -767,8 +828,6 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
struct be_dma_mem *q_mem, u32 page_offset,
u32 num_pages);
-int beiscsi_cmd_reset_function(struct beiscsi_hba *phba);
-
int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
struct be_queue_info *wrbq,
struct hwi_wrb_context *pwrb_context,
@@ -777,6 +836,15 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
/* Configuration Functions */
int be_cmd_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
+int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba);
+
+int beiscsi_get_fw_config(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba);
+
+int beiscsi_get_port_name(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba);
+
+int beiscsi_set_uer_feature(struct beiscsi_hba *phba);
+
struct be_default_pdu_context {
u32 dw[4];
} __packed;
@@ -999,7 +1067,16 @@ struct iscsi_cleanup_req {
u16 chute;
u8 hdr_ring_id;
u8 data_ring_id;
+} __packed;
+struct iscsi_cleanup_req_v1 {
+ struct be_cmd_req_hdr hdr;
+ u16 chute;
+ u16 rsvd1;
+ u16 hdr_ring_id;
+ u16 rsvd2;
+ u16 data_ring_id;
+ u16 rsvd3;
} __packed;
struct eq_delay {
@@ -1368,14 +1445,9 @@ struct be_cmd_get_port_name {
* the cxn
*/
-int beiscsi_pci_soft_reset(struct beiscsi_hba *phba);
-int be_chk_reset_complete(struct beiscsi_hba *phba);
-
void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
bool embedded, u8 sge_cnt);
void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
u8 subsystem, u8 opcode, int cmd_len);
-
-void beiscsi_fail_session(struct iscsi_cls_session *cls_session);
#endif /* !BEISCSI_CMDS_H */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 09f89a3eaa87..ba258217614e 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,10 +7,10 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com)
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -52,22 +52,20 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
if (!ep) {
- printk(KERN_ERR
- "beiscsi_session_create: invalid ep\n");
+ pr_err("beiscsi_session_create: invalid ep\n");
return NULL;
}
beiscsi_ep = ep->dd_data;
phba = beiscsi_ep->phba;
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : PCI_ERROR Recovery\n");
- return NULL;
- } else {
+ if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
- "BS_%d : In beiscsi_session_create\n");
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
+ return NULL;
}
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : In beiscsi_session_create\n");
if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : Cannot handle %d cmds."
@@ -120,6 +118,16 @@ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
}
/**
+ * beiscsi_session_fail(): Closing session with appropriate error
+ * @cls_session: ptr to session
+ **/
+void beiscsi_session_fail(struct iscsi_cls_session *cls_session)
+{
+ iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+}
+
+
+/**
* beiscsi_conn_create - create an instance of iscsi connection
* @cls_session: ptr to iscsi_cls_session
* @cid: iscsi cid
@@ -237,7 +245,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
}
-static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba)
+static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
{
if (phba->ipv4_iface)
return 0;
@@ -256,7 +264,7 @@ static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba)
return 0;
}
-static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba)
+static int beiscsi_iface_create_ipv6(struct beiscsi_hba *phba)
{
if (phba->ipv6_iface)
return 0;
@@ -275,79 +283,31 @@ static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba)
return 0;
}
-void beiscsi_create_def_ifaces(struct beiscsi_hba *phba)
+void beiscsi_iface_create_default(struct beiscsi_hba *phba)
{
struct be_cmd_get_if_info_resp *if_info;
- if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info)) {
- beiscsi_create_ipv4_iface(phba);
+ if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V4, &if_info)) {
+ beiscsi_iface_create_ipv4(phba);
kfree(if_info);
}
- if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info)) {
- beiscsi_create_ipv6_iface(phba);
+ if (!beiscsi_if_get_info(phba, BEISCSI_IP_TYPE_V6, &if_info)) {
+ beiscsi_iface_create_ipv6(phba);
kfree(if_info);
}
}
-void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba)
+void beiscsi_iface_destroy_default(struct beiscsi_hba *phba)
{
- if (phba->ipv6_iface)
+ if (phba->ipv6_iface) {
iscsi_destroy_iface(phba->ipv6_iface);
- if (phba->ipv4_iface)
- iscsi_destroy_iface(phba->ipv4_iface);
-}
-
-static int
-beiscsi_set_static_ip(struct Scsi_Host *shost,
- struct iscsi_iface_param_info *iface_param,
- void *data, uint32_t dt_len)
-{
- struct beiscsi_hba *phba = iscsi_host_priv(shost);
- struct iscsi_iface_param_info *iface_ip = NULL;
- struct iscsi_iface_param_info *iface_subnet = NULL;
- struct nlattr *nla;
- int ret;
-
-
- switch (iface_param->param) {
- case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
- nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
- if (nla)
- iface_ip = nla_data(nla);
-
- nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
- if (nla)
- iface_subnet = nla_data(nla);
- break;
- case ISCSI_NET_PARAM_IPV4_ADDR:
- iface_ip = iface_param;
- nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
- if (nla)
- iface_subnet = nla_data(nla);
- break;
- case ISCSI_NET_PARAM_IPV4_SUBNET:
- iface_subnet = iface_param;
- nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
- if (nla)
- iface_ip = nla_data(nla);
- break;
- default:
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Unsupported param %d\n",
- iface_param->param);
+ phba->ipv6_iface = NULL;
}
-
- if (!iface_ip || !iface_subnet) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : IP and Subnet Mask required\n");
- return -EINVAL;
+ if (phba->ipv4_iface) {
+ iscsi_destroy_iface(phba->ipv4_iface);
+ phba->ipv4_iface = NULL;
}
-
- ret = mgmt_set_ip(phba, iface_ip, iface_subnet,
- ISCSI_BOOTPROTO_STATIC);
-
- return ret;
}
/**
@@ -363,137 +323,141 @@ beiscsi_set_static_ip(struct Scsi_Host *shost,
* Failure: Non-Zero Value
**/
static int
-beiscsi_set_vlan_tag(struct Scsi_Host *shost,
- struct iscsi_iface_param_info *iface_param)
+beiscsi_iface_config_vlan(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param)
{
struct beiscsi_hba *phba = iscsi_host_priv(shost);
- int ret;
-
- /* Get the Interface Handle */
- ret = mgmt_get_all_if_id(phba);
- if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Getting Interface Handle Failed\n");
- return ret;
- }
+ int ret = -EPERM;
switch (iface_param->param) {
case ISCSI_NET_PARAM_VLAN_ENABLED:
+ ret = 0;
if (iface_param->value[0] != ISCSI_VLAN_ENABLE)
- ret = mgmt_set_vlan(phba, BEISCSI_VLAN_DISABLE);
+ ret = beiscsi_if_set_vlan(phba, BEISCSI_VLAN_DISABLE);
break;
case ISCSI_NET_PARAM_VLAN_TAG:
- ret = mgmt_set_vlan(phba,
- *((uint16_t *)iface_param->value));
+ ret = beiscsi_if_set_vlan(phba,
+ *((uint16_t *)iface_param->value));
break;
- default:
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BS_%d : Unknown Param Type : %d\n",
- iface_param->param);
- return -ENOSYS;
}
return ret;
}
static int
-beiscsi_set_ipv4(struct Scsi_Host *shost,
- struct iscsi_iface_param_info *iface_param,
- void *data, uint32_t dt_len)
+beiscsi_iface_config_ipv4(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *info,
+ void *data, uint32_t dt_len)
{
struct beiscsi_hba *phba = iscsi_host_priv(shost);
- int ret = 0;
+ u8 *ip = NULL, *subnet = NULL, *gw;
+ struct nlattr *nla;
+ int ret = -EPERM;
/* Check the param */
- switch (iface_param->param) {
+ switch (info->param) {
+ case ISCSI_NET_PARAM_IFACE_ENABLE:
+ if (info->value[0] == ISCSI_IFACE_ENABLE)
+ ret = beiscsi_iface_create_ipv4(phba);
+ else {
+ iscsi_destroy_iface(phba->ipv4_iface);
+ phba->ipv4_iface = NULL;
+ }
+ break;
case ISCSI_NET_PARAM_IPV4_GW:
- ret = mgmt_set_gateway(phba, iface_param);
+ gw = info->value;
+ ret = beiscsi_if_set_gw(phba, BEISCSI_IP_TYPE_V4, gw);
break;
case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
- if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
- ret = mgmt_set_ip(phba, iface_param,
- NULL, ISCSI_BOOTPROTO_DHCP);
- else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
- ret = beiscsi_set_static_ip(shost, iface_param,
- data, dt_len);
+ if (info->value[0] == ISCSI_BOOTPROTO_DHCP)
+ ret = beiscsi_if_en_dhcp(phba, BEISCSI_IP_TYPE_V4);
+ else if (info->value[0] == ISCSI_BOOTPROTO_STATIC)
+ /* release DHCP IP address */
+ ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,
+ NULL, NULL);
else
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : Invalid BOOTPROTO: %d\n",
- iface_param->value[0]);
+ info->value[0]);
break;
- case ISCSI_NET_PARAM_IFACE_ENABLE:
- if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
- ret = beiscsi_create_ipv4_iface(phba);
- else
- iscsi_destroy_iface(phba->ipv4_iface);
- break;
- case ISCSI_NET_PARAM_IPV4_SUBNET:
case ISCSI_NET_PARAM_IPV4_ADDR:
- ret = beiscsi_set_static_ip(shost, iface_param,
- data, dt_len);
+ ip = info->value;
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET);
+ if (nla) {
+ info = nla_data(nla);
+ subnet = info->value;
+ }
+ ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,
+ ip, subnet);
break;
- case ISCSI_NET_PARAM_VLAN_ENABLED:
- case ISCSI_NET_PARAM_VLAN_TAG:
- ret = beiscsi_set_vlan_tag(shost, iface_param);
+ case ISCSI_NET_PARAM_IPV4_SUBNET:
+ /*
+ * OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR ioctl needs IP
+ * and subnet both. Find IP to be applied for this subnet.
+ */
+ subnet = info->value;
+ nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR);
+ if (nla) {
+ info = nla_data(nla);
+ ip = info->value;
+ }
+ ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4,
+ ip, subnet);
break;
- default:
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Param %d not supported\n",
- iface_param->param);
}
return ret;
}
static int
-beiscsi_set_ipv6(struct Scsi_Host *shost,
- struct iscsi_iface_param_info *iface_param,
- void *data, uint32_t dt_len)
+beiscsi_iface_config_ipv6(struct Scsi_Host *shost,
+ struct iscsi_iface_param_info *iface_param,
+ void *data, uint32_t dt_len)
{
struct beiscsi_hba *phba = iscsi_host_priv(shost);
- int ret = 0;
+ int ret = -EPERM;
switch (iface_param->param) {
case ISCSI_NET_PARAM_IFACE_ENABLE:
if (iface_param->value[0] == ISCSI_IFACE_ENABLE)
- ret = beiscsi_create_ipv6_iface(phba);
+ ret = beiscsi_iface_create_ipv6(phba);
else {
iscsi_destroy_iface(phba->ipv6_iface);
- ret = 0;
+ phba->ipv6_iface = NULL;
}
break;
case ISCSI_NET_PARAM_IPV6_ADDR:
- ret = mgmt_set_ip(phba, iface_param, NULL,
- ISCSI_BOOTPROTO_STATIC);
+ ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V6,
+ iface_param->value, NULL);
break;
- case ISCSI_NET_PARAM_VLAN_ENABLED:
- case ISCSI_NET_PARAM_VLAN_TAG:
- ret = beiscsi_set_vlan_tag(shost, iface_param);
- break;
- default:
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Param %d not supported\n",
- iface_param->param);
}
return ret;
}
-int be2iscsi_iface_set_param(struct Scsi_Host *shost,
- void *data, uint32_t dt_len)
+int beiscsi_iface_set_param(struct Scsi_Host *shost,
+ void *data, uint32_t dt_len)
{
struct iscsi_iface_param_info *iface_param = NULL;
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct nlattr *attrib;
uint32_t rm_len = dt_len;
- int ret = 0 ;
+ int ret;
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : In PCI_ERROR Recovery\n");
+ if (!beiscsi_hba_is_online(phba)) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY;
}
+ /* update interface_handle */
+ ret = beiscsi_if_get_handle(phba);
+ if (ret) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
+ "BS_%d : Getting Interface Handle Failed\n");
+ return ret;
+ }
+
nla_for_each_attr(attrib, data, dt_len, rm_len) {
iface_param = nla_data(attrib);
@@ -512,40 +476,58 @@ int be2iscsi_iface_set_param(struct Scsi_Host *shost,
return -EINVAL;
}
- switch (iface_param->iface_type) {
- case ISCSI_IFACE_TYPE_IPV4:
- ret = beiscsi_set_ipv4(shost, iface_param,
- data, dt_len);
- break;
- case ISCSI_IFACE_TYPE_IPV6:
- ret = beiscsi_set_ipv6(shost, iface_param,
- data, dt_len);
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : %s.0 set param %d",
+ (iface_param->iface_type == ISCSI_IFACE_TYPE_IPV4) ?
+ "ipv4" : "ipv6", iface_param->param);
+
+ ret = -EPERM;
+ switch (iface_param->param) {
+ case ISCSI_NET_PARAM_VLAN_ENABLED:
+ case ISCSI_NET_PARAM_VLAN_TAG:
+ ret = beiscsi_iface_config_vlan(shost, iface_param);
break;
default:
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Invalid iface type :%d passed\n",
- iface_param->iface_type);
- break;
+ switch (iface_param->iface_type) {
+ case ISCSI_IFACE_TYPE_IPV4:
+ ret = beiscsi_iface_config_ipv4(shost,
+ iface_param,
+ data, dt_len);
+ break;
+ case ISCSI_IFACE_TYPE_IPV6:
+ ret = beiscsi_iface_config_ipv6(shost,
+ iface_param,
+ data, dt_len);
+ break;
+ }
}
+ if (ret == -EPERM) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BS_%d : %s.0 set param %d not permitted",
+ (iface_param->iface_type ==
+ ISCSI_IFACE_TYPE_IPV4) ? "ipv4" : "ipv6",
+ iface_param->param);
+ ret = 0;
+ }
if (ret)
- return ret;
+ break;
}
return ret;
}
-static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
- struct iscsi_iface *iface, int param,
- char *buf)
+static int __beiscsi_iface_get_param(struct beiscsi_hba *phba,
+ struct iscsi_iface *iface,
+ int param, char *buf)
{
struct be_cmd_get_if_info_resp *if_info;
- int len, ip_type = BE2_IPV4;
+ int len, ip_type = BEISCSI_IP_TYPE_V4;
if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
- ip_type = BE2_IPV6;
+ ip_type = BEISCSI_IP_TYPE_V6;
- len = mgmt_get_if_info(phba, ip_type, &if_info);
+ len = beiscsi_if_get_info(phba, ip_type, &if_info);
if (len)
return len;
@@ -567,24 +549,24 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
break;
case ISCSI_NET_PARAM_VLAN_ENABLED:
len = sprintf(buf, "%s\n",
- (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
- ? "Disabled\n" : "Enabled\n");
+ (if_info->vlan_priority == BEISCSI_VLAN_DISABLE) ?
+ "disable" : "enable");
break;
case ISCSI_NET_PARAM_VLAN_ID:
if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
len = -EINVAL;
else
len = sprintf(buf, "%d\n",
- (if_info->vlan_priority &
- ISCSI_MAX_VLAN_ID));
+ (if_info->vlan_priority &
+ ISCSI_MAX_VLAN_ID));
break;
case ISCSI_NET_PARAM_VLAN_PRIORITY:
if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
len = -EINVAL;
else
len = sprintf(buf, "%d\n",
- ((if_info->vlan_priority >> 13) &
- ISCSI_MAX_VLAN_PRIORITY));
+ ((if_info->vlan_priority >> 13) &
+ ISCSI_MAX_VLAN_PRIORITY));
break;
default:
WARN_ON(1);
@@ -594,18 +576,20 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
return len;
}
-int be2iscsi_iface_get_param(struct iscsi_iface *iface,
- enum iscsi_param_type param_type,
- int param, char *buf)
+int beiscsi_iface_get_param(struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf)
{
struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct be_cmd_get_def_gateway_resp gateway;
- int len = -ENOSYS;
+ int len = -EPERM;
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : In PCI_ERROR Recovery\n");
+ if (param_type != ISCSI_NET_PARAM)
+ return 0;
+ if (!beiscsi_hba_is_online(phba)) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY;
}
@@ -617,19 +601,22 @@ int be2iscsi_iface_get_param(struct iscsi_iface *iface,
case ISCSI_NET_PARAM_VLAN_ENABLED:
case ISCSI_NET_PARAM_VLAN_ID:
case ISCSI_NET_PARAM_VLAN_PRIORITY:
- len = be2iscsi_get_if_param(phba, iface, param, buf);
+ len = __beiscsi_iface_get_param(phba, iface, param, buf);
break;
case ISCSI_NET_PARAM_IFACE_ENABLE:
- len = sprintf(buf, "enabled\n");
+ if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
+ len = sprintf(buf, "%s\n",
+ phba->ipv4_iface ? "enable" : "disable");
+ else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
+ len = sprintf(buf, "%s\n",
+ phba->ipv6_iface ? "enable" : "disable");
break;
case ISCSI_NET_PARAM_IPV4_GW:
memset(&gateway, 0, sizeof(gateway));
- len = mgmt_get_gateway(phba, BE2_IPV4, &gateway);
+ len = beiscsi_if_get_gw(phba, BEISCSI_IP_TYPE_V4, &gateway);
if (!len)
len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr);
break;
- default:
- len = -ENOSYS;
}
return len;
@@ -647,7 +634,7 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep,
enum iscsi_param param, char *buf)
{
struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
- int len = 0;
+ int len;
beiscsi_log(beiscsi_ep->phba, KERN_INFO,
BEISCSI_LOG_CONFIG,
@@ -659,13 +646,13 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep,
len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- if (beiscsi_ep->ip_type == BE2_IPV4)
+ if (beiscsi_ep->ip_type == BEISCSI_IP_TYPE_V4)
len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);
else
len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
break;
default:
- return -ENOSYS;
+ len = -EPERM;
}
return len;
}
@@ -758,7 +745,7 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost)
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct iscsi_cls_host *ihost = shost->shost_data;
- ihost->port_state = (phba->state & BE_ADAPTER_LINK_UP) ?
+ ihost->port_state = test_bit(BEISCSI_HBA_LINK_UP, &phba->state) ?
ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;
}
@@ -810,16 +797,13 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
struct beiscsi_hba *phba = iscsi_host_priv(shost);
int status = 0;
-
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : In PCI_ERROR Recovery\n");
- return -EBUSY;
- } else {
+ if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
- "BS_%d : In beiscsi_get_host_param,"
- " param = %d\n", param);
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
+ return -EBUSY;
}
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : In beiscsi_get_host_param, param = %d\n", param);
switch (param) {
case ISCSI_HOST_PARAM_HWADDRESS:
@@ -961,15 +945,13 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : In PCI_ERROR Recovery\n");
+ if (!beiscsi_hba_is_online(phba)) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY;
- } else {
- beiscsi_log(beiscsi_conn->phba, KERN_INFO,
- BEISCSI_LOG_CONFIG,
- "BS_%d : In beiscsi_conn_start\n");
}
+ beiscsi_log(beiscsi_conn->phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : In beiscsi_conn_start\n");
memset(&params, 0, sizeof(struct beiscsi_offload_params));
beiscsi_ep = beiscsi_conn->ep;
@@ -1186,28 +1168,20 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
struct iscsi_endpoint *ep;
int ret;
- if (shost)
- phba = iscsi_host_priv(shost);
- else {
+ if (!shost) {
ret = -ENXIO;
- printk(KERN_ERR
- "beiscsi_ep_connect shost is NULL\n");
+ pr_err("beiscsi_ep_connect shost is NULL\n");
return ERR_PTR(ret);
}
- if (beiscsi_error(phba)) {
+ phba = iscsi_host_priv(shost);
+ if (!beiscsi_hba_is_online(phba)) {
ret = -EIO;
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BS_%d : The FW state Not Stable!!!\n");
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
return ERR_PTR(ret);
}
-
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- ret = -EBUSY;
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : In PCI_ERROR Recovery\n");
- return ERR_PTR(ret);
- } else if (phba->state & BE_ADAPTER_LINK_DOWN) {
+ if (!test_bit(BEISCSI_HBA_LINK_UP, &phba->state)) {
ret = -EBUSY;
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
"BS_%d : The Adapter Port state is Down!!!\n");
@@ -1361,9 +1335,9 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
tcp_upload_flag = CONNECTION_UPLOAD_ABORT;
}
- if (phba->state & BE_ADAPTER_PCI_ERR) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : PCI_ERROR Recovery\n");
+ if (!beiscsi_hba_is_online(phba)) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BS_%d : HBA in error 0x%lx\n", phba->state);
goto free_ep;
}
@@ -1386,7 +1360,7 @@ free_ep:
iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
}
-umode_t be2iscsi_attr_is_visible(int param_type, int param)
+umode_t beiscsi_attr_is_visible(int param_type, int param)
{
switch (param_type) {
case ISCSI_NET_PARAM:
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 0c84e1c0763a..e4d67dfea4cb 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Avago Technologies
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,10 +7,10 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com)
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Avago Technologies
* 3333 Susan Street
@@ -23,25 +23,18 @@
#include "be_main.h"
#include "be_mgmt.h"
-#define BE2_IPV4 0x1
-#define BE2_IPV6 0x10
-#define BE2_DHCP_V4 0x05
+void beiscsi_iface_create_default(struct beiscsi_hba *phba);
-#define NON_BLOCKING 0x0
-#define BLOCKING 0x1
+void beiscsi_iface_destroy_default(struct beiscsi_hba *phba);
-void beiscsi_create_def_ifaces(struct beiscsi_hba *phba);
-
-void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba);
-
-int be2iscsi_iface_get_param(struct iscsi_iface *iface,
+int beiscsi_iface_get_param(struct iscsi_iface *iface,
enum iscsi_param_type param_type,
int param, char *buf);
-int be2iscsi_iface_set_param(struct Scsi_Host *shost,
+int beiscsi_iface_set_param(struct Scsi_Host *shost,
void *data, uint32_t count);
-umode_t be2iscsi_attr_is_visible(int param_type, int param);
+umode_t beiscsi_attr_is_visible(int param_type, int param);
void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_offload_params *params);
@@ -57,6 +50,8 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
void beiscsi_session_destroy(struct iscsi_cls_session *cls_session);
+void beiscsi_session_fail(struct iscsi_cls_session *cls_session);
+
struct iscsi_cls_conn *beiscsi_conn_create(struct iscsi_cls_session
*cls_session, uint32_t cid);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index f05e7737107d..6a6906f847db 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,10 +7,10 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com)
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -374,170 +374,6 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
return iscsi_eh_device_reset(sc);
}
-static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf)
-{
- struct beiscsi_hba *phba = data;
- struct mgmt_session_info *boot_sess = &phba->boot_sess;
- struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0];
- char *str = buf;
- int rc;
-
- switch (type) {
- case ISCSI_BOOT_TGT_NAME:
- rc = sprintf(buf, "%.*s\n",
- (int)strlen(boot_sess->target_name),
- (char *)&boot_sess->target_name);
- break;
- case ISCSI_BOOT_TGT_IP_ADDR:
- if (boot_conn->dest_ipaddr.ip_type == 0x1)
- rc = sprintf(buf, "%pI4\n",
- (char *)&boot_conn->dest_ipaddr.addr);
- else
- rc = sprintf(str, "%pI6\n",
- (char *)&boot_conn->dest_ipaddr.addr);
- break;
- case ISCSI_BOOT_TGT_PORT:
- rc = sprintf(str, "%d\n", boot_conn->dest_port);
- break;
-
- case ISCSI_BOOT_TGT_CHAP_NAME:
- rc = sprintf(str, "%.*s\n",
- boot_conn->negotiated_login_options.auth_data.chap.
- target_chap_name_length,
- (char *)&boot_conn->negotiated_login_options.
- auth_data.chap.target_chap_name);
- break;
- case ISCSI_BOOT_TGT_CHAP_SECRET:
- rc = sprintf(str, "%.*s\n",
- boot_conn->negotiated_login_options.auth_data.chap.
- target_secret_length,
- (char *)&boot_conn->negotiated_login_options.
- auth_data.chap.target_secret);
- break;
- case ISCSI_BOOT_TGT_REV_CHAP_NAME:
- rc = sprintf(str, "%.*s\n",
- boot_conn->negotiated_login_options.auth_data.chap.
- intr_chap_name_length,
- (char *)&boot_conn->negotiated_login_options.
- auth_data.chap.intr_chap_name);
- break;
- case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
- rc = sprintf(str, "%.*s\n",
- boot_conn->negotiated_login_options.auth_data.chap.
- intr_secret_length,
- (char *)&boot_conn->negotiated_login_options.
- auth_data.chap.intr_secret);
- break;
- case ISCSI_BOOT_TGT_FLAGS:
- rc = sprintf(str, "2\n");
- break;
- case ISCSI_BOOT_TGT_NIC_ASSOC:
- rc = sprintf(str, "0\n");
- break;
- default:
- rc = -ENOSYS;
- break;
- }
- return rc;
-}
-
-static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf)
-{
- struct beiscsi_hba *phba = data;
- char *str = buf;
- int rc;
-
- switch (type) {
- case ISCSI_BOOT_INI_INITIATOR_NAME:
- rc = sprintf(str, "%s\n", phba->boot_sess.initiator_iscsiname);
- break;
- default:
- rc = -ENOSYS;
- break;
- }
- return rc;
-}
-
-static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf)
-{
- struct beiscsi_hba *phba = data;
- char *str = buf;
- int rc;
-
- switch (type) {
- case ISCSI_BOOT_ETH_FLAGS:
- rc = sprintf(str, "2\n");
- break;
- case ISCSI_BOOT_ETH_INDEX:
- rc = sprintf(str, "0\n");
- break;
- case ISCSI_BOOT_ETH_MAC:
- rc = beiscsi_get_macaddr(str, phba);
- break;
- default:
- rc = -ENOSYS;
- break;
- }
- return rc;
-}
-
-
-static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type)
-{
- umode_t rc;
-
- switch (type) {
- case ISCSI_BOOT_TGT_NAME:
- case ISCSI_BOOT_TGT_IP_ADDR:
- case ISCSI_BOOT_TGT_PORT:
- case ISCSI_BOOT_TGT_CHAP_NAME:
- case ISCSI_BOOT_TGT_CHAP_SECRET:
- case ISCSI_BOOT_TGT_REV_CHAP_NAME:
- case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
- case ISCSI_BOOT_TGT_NIC_ASSOC:
- case ISCSI_BOOT_TGT_FLAGS:
- rc = S_IRUGO;
- break;
- default:
- rc = 0;
- break;
- }
- return rc;
-}
-
-static umode_t beiscsi_ini_get_attr_visibility(void *data, int type)
-{
- umode_t rc;
-
- switch (type) {
- case ISCSI_BOOT_INI_INITIATOR_NAME:
- rc = S_IRUGO;
- break;
- default:
- rc = 0;
- break;
- }
- return rc;
-}
-
-
-static umode_t beiscsi_eth_get_attr_visibility(void *data, int type)
-{
- umode_t rc;
-
- switch (type) {
- case ISCSI_BOOT_ETH_FLAGS:
- case ISCSI_BOOT_ETH_MAC:
- case ISCSI_BOOT_ETH_INDEX:
- rc = S_IRUGO;
- break;
- default:
- rc = 0;
- break;
- }
- return rc;
-}
-
/*------------------- PCI Driver operations and data ----------------- */
static const struct pci_device_id beiscsi_pci_id_table[] = {
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
@@ -850,12 +686,11 @@ static void hwi_ring_eq_db(struct beiscsi_hba *phba,
static irqreturn_t be_isr_mcc(int irq, void *dev_id)
{
struct beiscsi_hba *phba;
- struct be_eq_entry *eqe = NULL;
+ struct be_eq_entry *eqe;
struct be_queue_info *eq;
struct be_queue_info *mcc;
- unsigned int num_eq_processed;
+ unsigned int mcc_events;
struct be_eq_obj *pbe_eq;
- unsigned long flags;
pbe_eq = dev_id;
eq = &pbe_eq->q;
@@ -863,27 +698,23 @@ static irqreturn_t be_isr_mcc(int irq, void *dev_id)
mcc = &phba->ctrl.mcc_obj.cq;
eqe = queue_tail_node(eq);
- num_eq_processed = 0;
-
+ mcc_events = 0;
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
if (((eqe->dw[offsetof(struct amap_eq_entry,
resource_id) / 32] &
EQE_RESID_MASK) >> 16) == mcc->id) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_mcc_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
+ mcc_events++;
}
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
eqe = queue_tail_node(eq);
- num_eq_processed++;
}
- if (pbe_eq->todo_mcc_cq)
- queue_work(phba->wq, &pbe_eq->work_cqs);
- if (num_eq_processed)
- hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1);
+ if (mcc_events) {
+ queue_work(phba->wq, &pbe_eq->mcc_work);
+ hwi_ring_eq_db(phba, eq->id, 1, mcc_events, 1, 1);
+ }
return IRQ_HANDLED;
}
@@ -902,7 +733,6 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
eq = &pbe_eq->q;
phba = pbe_eq->phba;
-
/* disable interrupt till iopoll completes */
hwi_ring_eq_db(phba, eq->id, 1, 0, 0, 1);
irq_poll_sched(&pbe_eq->iopoll);
@@ -920,14 +750,13 @@ static irqreturn_t be_isr(int irq, void *dev_id)
struct beiscsi_hba *phba;
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
- struct be_eq_entry *eqe = NULL;
+ struct be_eq_entry *eqe;
struct be_queue_info *eq;
struct be_queue_info *mcc;
- unsigned long flags, index;
- unsigned int num_mcceq_processed, num_ioeq_processed;
+ unsigned int mcc_events, io_events;
struct be_ctrl_info *ctrl;
struct be_eq_obj *pbe_eq;
- int isr;
+ int isr, rearm;
phba = dev_id;
ctrl = &phba->ctrl;
@@ -942,44 +771,35 @@ static irqreturn_t be_isr(int irq, void *dev_id)
eq = &phwi_context->be_eq[0].q;
mcc = &phba->ctrl.mcc_obj.cq;
- index = 0;
eqe = queue_tail_node(eq);
- num_ioeq_processed = 0;
- num_mcceq_processed = 0;
+ io_events = 0;
+ mcc_events = 0;
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
if (((eqe->dw[offsetof(struct amap_eq_entry,
- resource_id) / 32] &
- EQE_RESID_MASK) >> 16) == mcc->id) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_mcc_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- num_mcceq_processed++;
- } else {
- irq_poll_sched(&pbe_eq->iopoll);
- num_ioeq_processed++;
- }
+ resource_id) / 32] & EQE_RESID_MASK) >> 16) == mcc->id)
+ mcc_events++;
+ else
+ io_events++;
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
eqe = queue_tail_node(eq);
}
- if (num_ioeq_processed || num_mcceq_processed) {
- if (pbe_eq->todo_mcc_cq)
- queue_work(phba->wq, &pbe_eq->work_cqs);
-
- if ((num_mcceq_processed) && (!num_ioeq_processed))
- hwi_ring_eq_db(phba, eq->id, 0,
- (num_ioeq_processed +
- num_mcceq_processed) , 1, 1);
- else
- hwi_ring_eq_db(phba, eq->id, 0,
- (num_ioeq_processed +
- num_mcceq_processed), 0, 1);
-
- return IRQ_HANDLED;
- } else
+ if (!io_events && !mcc_events)
return IRQ_NONE;
+
+ /* no need to rearm if interrupt is only for IOs */
+ rearm = 0;
+ if (mcc_events) {
+ queue_work(phba->wq, &pbe_eq->mcc_work);
+ /* rearm for MCCQ */
+ rearm = 1;
+ }
+ if (io_events)
+ irq_poll_sched(&pbe_eq->iopoll);
+ hwi_ring_eq_db(phba, eq->id, 0, (io_events + mcc_events), rearm, 1);
+ return IRQ_HANDLED;
}
@@ -1077,57 +897,6 @@ void hwi_ring_cq_db(struct beiscsi_hba *phba,
iowrite32(val, phba->db_va + DB_CQ_OFFSET);
}
-static unsigned int
-beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
- struct beiscsi_hba *phba,
- struct pdu_base *ppdu,
- unsigned long pdu_len,
- void *pbuffer, unsigned long buf_len)
-{
- struct iscsi_conn *conn = beiscsi_conn->conn;
- struct iscsi_session *session = conn->session;
- struct iscsi_task *task;
- struct beiscsi_io_task *io_task;
- struct iscsi_hdr *login_hdr;
-
- switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] &
- PDUBASE_OPCODE_MASK) {
- case ISCSI_OP_NOOP_IN:
- pbuffer = NULL;
- buf_len = 0;
- break;
- case ISCSI_OP_ASYNC_EVENT:
- break;
- case ISCSI_OP_REJECT:
- WARN_ON(!pbuffer);
- WARN_ON(!(buf_len == 48));
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
- "BM_%d : In ISCSI_OP_REJECT\n");
- break;
- case ISCSI_OP_LOGIN_RSP:
- case ISCSI_OP_TEXT_RSP:
- task = conn->login_task;
- io_task = task->dd_data;
- login_hdr = (struct iscsi_hdr *)ppdu;
- login_hdr->itt = io_task->libiscsi_itt;
- break;
- default:
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : Unrecognized opcode 0x%x in async msg\n",
- (ppdu->
- dw[offsetof(struct amap_pdu_base, opcode) / 32]
- & PDUBASE_OPCODE_MASK));
- return 1;
- }
-
- spin_lock_bh(&session->back_lock);
- __iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len);
- spin_unlock_bh(&session->back_lock);
- return 0;
-}
-
static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
{
struct sgl_handle *psgl_handle;
@@ -1199,6 +968,9 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context,
pwrb_context->alloc_index++;
spin_unlock_bh(&pwrb_context->wrb_lock);
+ if (pwrb_handle)
+ memset(pwrb_handle->pwrb, 0, sizeof(*pwrb_handle->pwrb));
+
return pwrb_handle;
}
@@ -1440,11 +1212,10 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_hba *phba, struct sol_cqe *psol)
{
struct hwi_wrb_context *pwrb_context;
- struct wrb_handle *pwrb_handle = NULL;
+ uint16_t wrb_index, cid, cri_index;
struct hwi_controller *phwi_ctrlr;
+ struct wrb_handle *pwrb_handle;
struct iscsi_task *task;
- struct beiscsi_io_task *io_task;
- uint16_t wrb_index, cid, cri_index;
phwi_ctrlr = phba->phwi_ctrlr;
if (is_chip_be2_be3r(phba)) {
@@ -1463,9 +1234,6 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index];
task = pwrb_handle->pio_handle;
-
- io_task = task->dd_data;
- memset(io_task->pwrb_handle->pwrb, 0, sizeof(struct iscsi_wrb));
iscsi_put_task(task);
}
@@ -1614,431 +1382,428 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
spin_unlock_bh(&session->back_lock);
}
-static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context
- *pasync_ctx, unsigned int is_header,
- unsigned int host_write_ptr)
+/**
+ * ASYNC PDUs include
+ * a. Unsolicited NOP-In (target initiated NOP-In)
+ * b. ASYNC Messages
+ * c. Reject PDU
+ * d. Login response
+ * These headers arrive unprocessed by the EP firmware.
+ * iSCSI layer processes them.
+ */
+static unsigned int
+beiscsi_complete_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct pdu_base *phdr, void *pdata, unsigned int dlen)
{
- if (is_header)
- return &pasync_ctx->async_entry[host_write_ptr].
- header_busy_list;
- else
- return &pasync_ctx->async_entry[host_write_ptr].data_busy_list;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct beiscsi_io_task *io_task;
+ struct iscsi_hdr *login_hdr;
+ struct iscsi_task *task;
+ u8 code;
+
+ code = AMAP_GET_BITS(struct amap_pdu_base, opcode, phdr);
+ switch (code) {
+ case ISCSI_OP_NOOP_IN:
+ pdata = NULL;
+ dlen = 0;
+ break;
+ case ISCSI_OP_ASYNC_EVENT:
+ break;
+ case ISCSI_OP_REJECT:
+ WARN_ON(!pdata);
+ WARN_ON(!(dlen == 48));
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
+ "BM_%d : In ISCSI_OP_REJECT\n");
+ break;
+ case ISCSI_OP_LOGIN_RSP:
+ case ISCSI_OP_TEXT_RSP:
+ task = conn->login_task;
+ io_task = task->dd_data;
+ login_hdr = (struct iscsi_hdr *)phdr;
+ login_hdr->itt = io_task->libiscsi_itt;
+ break;
+ default:
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+ "BM_%d : unrecognized async PDU opcode 0x%x\n",
+ code);
+ return 1;
+ }
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)phdr, pdata, dlen);
+ return 0;
+}
+
+static inline void
+beiscsi_hdl_put_handle(struct hd_async_context *pasync_ctx,
+ struct hd_async_handle *pasync_handle)
+{
+ if (pasync_handle->is_header) {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_header.free_list);
+ pasync_ctx->async_header.free_entries++;
+ } else {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_data.free_list);
+ pasync_ctx->async_data.free_entries++;
+ }
}
-static struct async_pdu_handle *
-hwi_get_async_handle(struct beiscsi_hba *phba,
- struct beiscsi_conn *beiscsi_conn,
- struct hwi_async_pdu_context *pasync_ctx,
- struct i_t_dpdu_cqe *pdpdu_cqe, unsigned int *pcq_index)
+static struct hd_async_handle *
+beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn,
+ struct hd_async_context *pasync_ctx,
+ struct i_t_dpdu_cqe *pdpdu_cqe)
{
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct hd_async_handle *pasync_handle;
struct be_bus_address phys_addr;
- struct list_head *pbusy_list;
- struct async_pdu_handle *pasync_handle = NULL;
- unsigned char is_header = 0;
- unsigned int index, dpl;
+ u8 final, error = 0;
+ u16 cid, code, ci;
+ u32 dpl;
+ cid = beiscsi_conn->beiscsi_conn_cid;
+ /**
+ * This function is invoked to get the right async_handle structure
+ * from a given DEF PDU CQ entry.
+ *
+ * - index in CQ entry gives the vertical index
+ * - address in CQ entry is the offset where the DMA last ended
+ * - final - no more notifications for this PDU
+ */
if (is_chip_be2_be3r(phba)) {
dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
dpl, pdpdu_cqe);
- index = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
+ ci = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
index, pdpdu_cqe);
+ final = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
+ final, pdpdu_cqe);
} else {
dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2,
dpl, pdpdu_cqe);
- index = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2,
+ ci = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2,
index, pdpdu_cqe);
+ final = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2,
+ final, pdpdu_cqe);
}
- phys_addr.u.a32.address_lo =
- (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
- db_addr_lo) / 32] - dpl);
- phys_addr.u.a32.address_hi =
- pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
- db_addr_hi) / 32];
-
- phys_addr.u.a64.address =
- *((unsigned long long *)(&phys_addr.u.a64.address));
-
- switch (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32]
- & PDUCQE_CODE_MASK) {
+ /**
+ * DB addr Hi/Lo is same for BE and SKH.
+ * Subtract the dataplacementlength to get to the base.
+ */
+ phys_addr.u.a32.address_lo = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
+ db_addr_lo, pdpdu_cqe);
+ phys_addr.u.a32.address_lo -= dpl;
+ phys_addr.u.a32.address_hi = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
+ db_addr_hi, pdpdu_cqe);
+
+ code = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, code, pdpdu_cqe);
+ switch (code) {
case UNSOL_HDR_NOTIFY:
- is_header = 1;
-
- pbusy_list = hwi_get_async_busy_list(pasync_ctx,
- is_header, index);
+ pasync_handle = pasync_ctx->async_entry[ci].header;
break;
+ case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
+ error = 1;
case UNSOL_DATA_NOTIFY:
- pbusy_list = hwi_get_async_busy_list(pasync_ctx,
- is_header, index);
+ pasync_handle = pasync_ctx->async_entry[ci].data;
break;
+ /* called only for above codes */
default:
- pbusy_list = NULL;
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : Unexpected code=%d\n",
- pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
- code) / 32] & PDUCQE_CODE_MASK);
- return NULL;
+ pasync_handle = NULL;
+ break;
}
- WARN_ON(list_empty(pbusy_list));
- list_for_each_entry(pasync_handle, pbusy_list, link) {
- if (pasync_handle->pa.u.a64.address == phys_addr.u.a64.address)
- break;
+ if (!pasync_handle) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI,
+ "BM_%d : cid %d async PDU handle not found - code %d ci %d addr %llx\n",
+ cid, code, ci, phys_addr.u.a64.address);
+ return pasync_handle;
}
- WARN_ON(!pasync_handle);
+ if (pasync_handle->pa.u.a64.address != phys_addr.u.a64.address ||
+ pasync_handle->index != ci) {
+ /* driver bug - if ci does not match async handle index */
+ error = 1;
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI,
+ "BM_%d : cid %u async PDU handle mismatch - addr in %cQE %llx at %u:addr in CQE %llx ci %u\n",
+ cid, pasync_handle->is_header ? 'H' : 'D',
+ pasync_handle->pa.u.a64.address,
+ pasync_handle->index,
+ phys_addr.u.a64.address, ci);
+ /* FW has stale address - attempt continuing by dropping */
+ }
- pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID(
- beiscsi_conn->beiscsi_conn_cid);
- pasync_handle->is_header = is_header;
+ /**
+ * Each CID is associated with unique CRI.
+ * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different.
+ **/
+ pasync_handle->cri = BE_GET_ASYNC_CRI_FROM_CID(cid);
+ pasync_handle->is_final = final;
pasync_handle->buffer_len = dpl;
- *pcq_index = index;
+ /* empty the slot */
+ if (pasync_handle->is_header)
+ pasync_ctx->async_entry[ci].header = NULL;
+ else
+ pasync_ctx->async_entry[ci].data = NULL;
+ /**
+ * DEF PDU header and data buffers with errors should be simply
+ * dropped as there are no consumers for it.
+ */
+ if (error) {
+ beiscsi_hdl_put_handle(pasync_ctx, pasync_handle);
+ pasync_handle = NULL;
+ }
return pasync_handle;
}
-static unsigned int
-hwi_update_async_writables(struct beiscsi_hba *phba,
- struct hwi_async_pdu_context *pasync_ctx,
- unsigned int is_header, unsigned int cq_index)
+static void
+beiscsi_hdl_purge_handles(struct beiscsi_hba *phba,
+ struct hd_async_context *pasync_ctx,
+ u16 cri)
{
- struct list_head *pbusy_list;
- struct async_pdu_handle *pasync_handle;
- unsigned int num_entries, writables = 0;
- unsigned int *pep_read_ptr, *pwritables;
-
- num_entries = pasync_ctx->num_entries;
- if (is_header) {
- pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr;
- pwritables = &pasync_ctx->async_header.writables;
- } else {
- pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr;
- pwritables = &pasync_ctx->async_data.writables;
- }
-
- while ((*pep_read_ptr) != cq_index) {
- (*pep_read_ptr)++;
- *pep_read_ptr = (*pep_read_ptr) % num_entries;
-
- pbusy_list = hwi_get_async_busy_list(pasync_ctx, is_header,
- *pep_read_ptr);
- if (writables == 0)
- WARN_ON(list_empty(pbusy_list));
-
- if (!list_empty(pbusy_list)) {
- pasync_handle = list_entry(pbusy_list->next,
- struct async_pdu_handle,
- link);
- WARN_ON(!pasync_handle);
- pasync_handle->consumed = 1;
- }
-
- writables++;
- }
+ struct hd_async_handle *pasync_handle, *tmp_handle;
+ struct list_head *plist;
- if (!writables) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
- "BM_%d : Duplicate notification received - index 0x%x!!\n",
- cq_index);
- WARN_ON(1);
+ plist = &pasync_ctx->async_entry[cri].wq.list;
+ list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) {
+ list_del(&pasync_handle->link);
+ beiscsi_hdl_put_handle(pasync_ctx, pasync_handle);
}
- *pwritables = *pwritables + writables;
- return 0;
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wq.list);
+ pasync_ctx->async_entry[cri].wq.hdr_len = 0;
+ pasync_ctx->async_entry[cri].wq.bytes_received = 0;
+ pasync_ctx->async_entry[cri].wq.bytes_needed = 0;
}
-static void hwi_free_async_msg(struct beiscsi_hba *phba,
- struct hwi_async_pdu_context *pasync_ctx,
- unsigned int cri)
+static unsigned int
+beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct hd_async_context *pasync_ctx,
+ u16 cri)
{
- struct async_pdu_handle *pasync_handle, *tmp_handle;
+ struct iscsi_session *session = beiscsi_conn->conn->session;
+ struct hd_async_handle *pasync_handle, *plast_handle;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ void *phdr = NULL, *pdata = NULL;
+ u32 dlen = 0, status = 0;
struct list_head *plist;
- plist = &pasync_ctx->async_entry[cri].wait_queue.list;
- list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) {
- list_del(&pasync_handle->link);
-
- if (pasync_handle->is_header) {
- list_add_tail(&pasync_handle->link,
- &pasync_ctx->async_header.free_list);
- pasync_ctx->async_header.free_entries++;
- } else {
- list_add_tail(&pasync_handle->link,
- &pasync_ctx->async_data.free_list);
- pasync_ctx->async_data.free_entries++;
+ plist = &pasync_ctx->async_entry[cri].wq.list;
+ plast_handle = NULL;
+ list_for_each_entry(pasync_handle, plist, link) {
+ plast_handle = pasync_handle;
+ /* get the header, the first entry */
+ if (!phdr) {
+ phdr = pasync_handle->pbuffer;
+ continue;
+ }
+ /* use first buffer to collect all the data */
+ if (!pdata) {
+ pdata = pasync_handle->pbuffer;
+ dlen = pasync_handle->buffer_len;
+ continue;
}
+ memcpy(pdata + dlen, pasync_handle->pbuffer,
+ pasync_handle->buffer_len);
+ dlen += pasync_handle->buffer_len;
}
- INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list);
- pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0;
- pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
+ if (!plast_handle->is_final) {
+ /* last handle should have final PDU notification from FW */
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI,
+ "BM_%d : cid %u %p fwd async PDU with last handle missing - HL%u:DN%u:DR%u\n",
+ beiscsi_conn->beiscsi_conn_cid, plast_handle,
+ pasync_ctx->async_entry[cri].wq.hdr_len,
+ pasync_ctx->async_entry[cri].wq.bytes_needed,
+ pasync_ctx->async_entry[cri].wq.bytes_received);
+ }
+ spin_lock_bh(&session->back_lock);
+ status = beiscsi_complete_pdu(beiscsi_conn, phdr, pdata, dlen);
+ spin_unlock_bh(&session->back_lock);
+ beiscsi_hdl_purge_handles(phba, pasync_ctx, cri);
+ return status;
}
-static struct phys_addr *
-hwi_get_ring_address(struct hwi_async_pdu_context *pasync_ctx,
- unsigned int is_header, unsigned int host_write_ptr)
+static unsigned int
+beiscsi_hdl_gather_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct hd_async_context *pasync_ctx,
+ struct hd_async_handle *pasync_handle)
{
- struct phys_addr *pasync_sge = NULL;
+ unsigned int bytes_needed = 0, status = 0;
+ u16 cri = pasync_handle->cri;
+ struct cri_wait_queue *wq;
+ struct beiscsi_hba *phba;
+ struct pdu_base *ppdu;
+ char *err = "";
- if (is_header)
- pasync_sge = pasync_ctx->async_header.ring_base;
- else
- pasync_sge = pasync_ctx->async_data.ring_base;
+ phba = beiscsi_conn->phba;
+ wq = &pasync_ctx->async_entry[cri].wq;
+ if (pasync_handle->is_header) {
+ /* check if PDU hdr is rcv'd when old hdr not completed */
+ if (wq->hdr_len) {
+ err = "incomplete";
+ goto drop_pdu;
+ }
+ ppdu = pasync_handle->pbuffer;
+ bytes_needed = AMAP_GET_BITS(struct amap_pdu_base,
+ data_len_hi, ppdu);
+ bytes_needed <<= 16;
+ bytes_needed |= be16_to_cpu(AMAP_GET_BITS(struct amap_pdu_base,
+ data_len_lo, ppdu));
+ wq->hdr_len = pasync_handle->buffer_len;
+ wq->bytes_received = 0;
+ wq->bytes_needed = bytes_needed;
+ list_add_tail(&pasync_handle->link, &wq->list);
+ if (!bytes_needed)
+ status = beiscsi_hdl_fwd_pdu(beiscsi_conn,
+ pasync_ctx, cri);
+ } else {
+ /* check if data received has header and is needed */
+ if (!wq->hdr_len || !wq->bytes_needed) {
+ err = "header less";
+ goto drop_pdu;
+ }
+ wq->bytes_received += pasync_handle->buffer_len;
+ /* Something got overwritten? Better catch it here. */
+ if (wq->bytes_received > wq->bytes_needed) {
+ err = "overflow";
+ goto drop_pdu;
+ }
+ list_add_tail(&pasync_handle->link, &wq->list);
+ if (wq->bytes_received == wq->bytes_needed)
+ status = beiscsi_hdl_fwd_pdu(beiscsi_conn,
+ pasync_ctx, cri);
+ }
+ return status;
- return pasync_sge + host_write_ptr;
+drop_pdu:
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI,
+ "BM_%d : cid %u async PDU %s - def-%c:HL%u:DN%u:DR%u\n",
+ beiscsi_conn->beiscsi_conn_cid, err,
+ pasync_handle->is_header ? 'H' : 'D',
+ wq->hdr_len, wq->bytes_needed,
+ pasync_handle->buffer_len);
+ /* discard this handle */
+ beiscsi_hdl_put_handle(pasync_ctx, pasync_handle);
+ /* free all the other handles in cri_wait_queue */
+ beiscsi_hdl_purge_handles(phba, pasync_ctx, cri);
+ /* try continuing */
+ return status;
}
-static void hwi_post_async_buffers(struct beiscsi_hba *phba,
- unsigned int is_header, uint8_t ulp_num)
+static void
+beiscsi_hdq_post_handles(struct beiscsi_hba *phba,
+ u8 header, u8 ulp_num)
{
+ struct hd_async_handle *pasync_handle, *tmp, **slot;
+ struct hd_async_context *pasync_ctx;
struct hwi_controller *phwi_ctrlr;
- struct hwi_async_pdu_context *pasync_ctx;
- struct async_pdu_handle *pasync_handle;
- struct list_head *pfree_link, *pbusy_list;
+ struct list_head *hfree_list;
struct phys_addr *pasync_sge;
- unsigned int ring_id, num_entries;
- unsigned int host_write_num, doorbell_offset;
- unsigned int writables;
- unsigned int i = 0;
- u32 doorbell = 0;
+ u32 ring_id, doorbell = 0;
+ u16 index, num_entries;
+ u32 doorbell_offset;
+ u16 prod = 0, cons;
phwi_ctrlr = phba->phwi_ctrlr;
pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num);
num_entries = pasync_ctx->num_entries;
-
- if (is_header) {
- writables = min(pasync_ctx->async_header.writables,
- pasync_ctx->async_header.free_entries);
- pfree_link = pasync_ctx->async_header.free_list.next;
- host_write_num = pasync_ctx->async_header.host_write_ptr;
+ if (header) {
+ cons = pasync_ctx->async_header.free_entries;
+ hfree_list = &pasync_ctx->async_header.free_list;
ring_id = phwi_ctrlr->default_pdu_hdr[ulp_num].id;
doorbell_offset = phwi_ctrlr->default_pdu_hdr[ulp_num].
- doorbell_offset;
+ doorbell_offset;
} else {
- writables = min(pasync_ctx->async_data.writables,
- pasync_ctx->async_data.free_entries);
- pfree_link = pasync_ctx->async_data.free_list.next;
- host_write_num = pasync_ctx->async_data.host_write_ptr;
+ cons = pasync_ctx->async_data.free_entries;
+ hfree_list = &pasync_ctx->async_data.free_list;
ring_id = phwi_ctrlr->default_pdu_data[ulp_num].id;
doorbell_offset = phwi_ctrlr->default_pdu_data[ulp_num].
- doorbell_offset;
+ doorbell_offset;
}
+ /* number of entries posted must be in multiples of 8 */
+ if (cons % 8)
+ return;
- writables = (writables / 8) * 8;
- if (writables) {
- for (i = 0; i < writables; i++) {
- pbusy_list =
- hwi_get_async_busy_list(pasync_ctx, is_header,
- host_write_num);
- pasync_handle =
- list_entry(pfree_link, struct async_pdu_handle,
- link);
- WARN_ON(!pasync_handle);
- pasync_handle->consumed = 0;
-
- pfree_link = pfree_link->next;
-
- pasync_sge = hwi_get_ring_address(pasync_ctx,
- is_header, host_write_num);
-
- pasync_sge->hi = pasync_handle->pa.u.a32.address_lo;
- pasync_sge->lo = pasync_handle->pa.u.a32.address_hi;
-
- list_move(&pasync_handle->link, pbusy_list);
-
- host_write_num++;
- host_write_num = host_write_num % num_entries;
- }
-
- if (is_header) {
- pasync_ctx->async_header.host_write_ptr =
- host_write_num;
- pasync_ctx->async_header.free_entries -= writables;
- pasync_ctx->async_header.writables -= writables;
- pasync_ctx->async_header.busy_entries += writables;
- } else {
- pasync_ctx->async_data.host_write_ptr = host_write_num;
- pasync_ctx->async_data.free_entries -= writables;
- pasync_ctx->async_data.writables -= writables;
- pasync_ctx->async_data.busy_entries += writables;
- }
-
- doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK;
- doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT;
- doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT;
- doorbell |= (writables & DB_DEF_PDU_CQPROC_MASK)
- << DB_DEF_PDU_CQPROC_SHIFT;
-
- iowrite32(doorbell, phba->db_va + doorbell_offset);
- }
-}
-
-static void hwi_flush_default_pdu_buffer(struct beiscsi_hba *phba,
- struct beiscsi_conn *beiscsi_conn,
- struct i_t_dpdu_cqe *pdpdu_cqe)
-{
- struct hwi_controller *phwi_ctrlr;
- struct hwi_async_pdu_context *pasync_ctx;
- struct async_pdu_handle *pasync_handle = NULL;
- unsigned int cq_index = -1;
- uint16_t cri_index = BE_GET_CRI_FROM_CID(
- beiscsi_conn->beiscsi_conn_cid);
-
- phwi_ctrlr = phba->phwi_ctrlr;
- pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr,
- BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr,
- cri_index));
-
- pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx,
- pdpdu_cqe, &cq_index);
- BUG_ON(pasync_handle->is_header != 0);
- if (pasync_handle->consumed == 0)
- hwi_update_async_writables(phba, pasync_ctx,
- pasync_handle->is_header, cq_index);
-
- hwi_free_async_msg(phba, pasync_ctx, pasync_handle->cri);
- hwi_post_async_buffers(phba, pasync_handle->is_header,
- BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr,
- cri_index));
-}
-
-static unsigned int
-hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
- struct beiscsi_hba *phba,
- struct hwi_async_pdu_context *pasync_ctx, unsigned short cri)
-{
- struct list_head *plist;
- struct async_pdu_handle *pasync_handle;
- void *phdr = NULL;
- unsigned int hdr_len = 0, buf_len = 0;
- unsigned int status, index = 0, offset = 0;
- void *pfirst_buffer = NULL;
- unsigned int num_buf = 0;
-
- plist = &pasync_ctx->async_entry[cri].wait_queue.list;
+ list_for_each_entry_safe(pasync_handle, tmp, hfree_list, link) {
+ list_del_init(&pasync_handle->link);
+ pasync_handle->is_final = 0;
+ pasync_handle->buffer_len = 0;
- list_for_each_entry(pasync_handle, plist, link) {
- if (index == 0) {
- phdr = pasync_handle->pbuffer;
- hdr_len = pasync_handle->buffer_len;
- } else {
- buf_len = pasync_handle->buffer_len;
- if (!num_buf) {
- pfirst_buffer = pasync_handle->pbuffer;
- num_buf++;
- }
- memcpy(pfirst_buffer + offset,
- pasync_handle->pbuffer, buf_len);
- offset += buf_len;
+ /* handles can be consumed out of order, use index in handle */
+ index = pasync_handle->index;
+ WARN_ON(pasync_handle->is_header != header);
+ if (header)
+ slot = &pasync_ctx->async_entry[index].header;
+ else
+ slot = &pasync_ctx->async_entry[index].data;
+ /**
+ * The slot just tracks handle's hold and release, so
+ * overwriting at the same index won't do any harm but
+ * needs to be caught.
+ */
+ if (*slot != NULL) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI,
+ "BM_%d : async PDU %s slot at %u not empty\n",
+ header ? "header" : "data", index);
}
- index++;
+ /**
+ * We use same freed index as in completion to post so this
+ * operation is not required for refills. Its required only
+ * for ring creation.
+ */
+ if (header)
+ pasync_sge = pasync_ctx->async_header.ring_base;
+ else
+ pasync_sge = pasync_ctx->async_data.ring_base;
+ pasync_sge += index;
+ /* if its a refill then address is same; hi is lo */
+ WARN_ON(pasync_sge->hi &&
+ pasync_sge->hi != pasync_handle->pa.u.a32.address_lo);
+ WARN_ON(pasync_sge->lo &&
+ pasync_sge->lo != pasync_handle->pa.u.a32.address_hi);
+ pasync_sge->hi = pasync_handle->pa.u.a32.address_lo;
+ pasync_sge->lo = pasync_handle->pa.u.a32.address_hi;
+
+ *slot = pasync_handle;
+ if (++prod == cons)
+ break;
}
+ if (header)
+ pasync_ctx->async_header.free_entries -= prod;
+ else
+ pasync_ctx->async_data.free_entries -= prod;
- status = beiscsi_process_async_pdu(beiscsi_conn, phba,
- phdr, hdr_len, pfirst_buffer,
- offset);
-
- hwi_free_async_msg(phba, pasync_ctx, cri);
- return 0;
-}
-
-static unsigned int
-hwi_gather_async_pdu(struct beiscsi_conn *beiscsi_conn,
- struct beiscsi_hba *phba,
- struct async_pdu_handle *pasync_handle)
-{
- struct hwi_async_pdu_context *pasync_ctx;
- struct hwi_controller *phwi_ctrlr;
- unsigned int bytes_needed = 0, status = 0;
- unsigned short cri = pasync_handle->cri;
- struct pdu_base *ppdu;
-
- phwi_ctrlr = phba->phwi_ctrlr;
- pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr,
- BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr,
- BE_GET_CRI_FROM_CID(beiscsi_conn->
- beiscsi_conn_cid)));
-
- list_del(&pasync_handle->link);
- if (pasync_handle->is_header) {
- pasync_ctx->async_header.busy_entries--;
- if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) {
- hwi_free_async_msg(phba, pasync_ctx, cri);
- BUG();
- }
-
- pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
- pasync_ctx->async_entry[cri].wait_queue.hdr_received = 1;
- pasync_ctx->async_entry[cri].wait_queue.hdr_len =
- (unsigned short)pasync_handle->buffer_len;
- list_add_tail(&pasync_handle->link,
- &pasync_ctx->async_entry[cri].wait_queue.list);
-
- ppdu = pasync_handle->pbuffer;
- bytes_needed = ((((ppdu->dw[offsetof(struct amap_pdu_base,
- data_len_hi) / 32] & PDUBASE_DATALENHI_MASK) << 8) &
- 0xFFFF0000) | ((be16_to_cpu((ppdu->
- dw[offsetof(struct amap_pdu_base, data_len_lo) / 32]
- & PDUBASE_DATALENLO_MASK) >> 16)) & 0x0000FFFF));
-
- if (status == 0) {
- pasync_ctx->async_entry[cri].wait_queue.bytes_needed =
- bytes_needed;
-
- if (bytes_needed == 0)
- status = hwi_fwd_async_msg(beiscsi_conn, phba,
- pasync_ctx, cri);
- }
- } else {
- pasync_ctx->async_data.busy_entries--;
- if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) {
- list_add_tail(&pasync_handle->link,
- &pasync_ctx->async_entry[cri].wait_queue.
- list);
- pasync_ctx->async_entry[cri].wait_queue.
- bytes_received +=
- (unsigned short)pasync_handle->buffer_len;
-
- if (pasync_ctx->async_entry[cri].wait_queue.
- bytes_received >=
- pasync_ctx->async_entry[cri].wait_queue.
- bytes_needed)
- status = hwi_fwd_async_msg(beiscsi_conn, phba,
- pasync_ctx, cri);
- }
- }
- return status;
+ doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK;
+ doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT;
+ doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT;
+ doorbell |= (prod & DB_DEF_PDU_CQPROC_MASK) << DB_DEF_PDU_CQPROC_SHIFT;
+ iowrite32(doorbell, phba->db_va + doorbell_offset);
}
-static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
- struct beiscsi_hba *phba,
- struct i_t_dpdu_cqe *pdpdu_cqe)
+static void
+beiscsi_hdq_process_compl(struct beiscsi_conn *beiscsi_conn,
+ struct i_t_dpdu_cqe *pdpdu_cqe)
{
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct hd_async_handle *pasync_handle = NULL;
+ struct hd_async_context *pasync_ctx;
struct hwi_controller *phwi_ctrlr;
- struct hwi_async_pdu_context *pasync_ctx;
- struct async_pdu_handle *pasync_handle = NULL;
- unsigned int cq_index = -1;
- uint16_t cri_index = BE_GET_CRI_FROM_CID(
- beiscsi_conn->beiscsi_conn_cid);
+ u16 cid_cri;
+ u8 ulp_num;
phwi_ctrlr = phba->phwi_ctrlr;
- pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr,
- BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr,
- cri_index));
-
- pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx,
- pdpdu_cqe, &cq_index);
-
- if (pasync_handle->consumed == 0)
- hwi_update_async_writables(phba, pasync_ctx,
- pasync_handle->is_header, cq_index);
+ cid_cri = BE_GET_CRI_FROM_CID(beiscsi_conn->beiscsi_conn_cid);
+ ulp_num = BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cid_cri);
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num);
+ pasync_handle = beiscsi_hdl_get_handle(beiscsi_conn, pasync_ctx,
+ pdpdu_cqe);
+ if (!pasync_handle)
+ return;
- hwi_gather_async_pdu(beiscsi_conn, phba, pasync_handle);
- hwi_post_async_buffers(phba, pasync_handle->is_header,
- BEISCSI_GET_ULP_FROM_CRI(
- phwi_ctrlr, cri_index));
+ beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle);
+ beiscsi_hdq_post_handles(phba, pasync_handle->is_header, ulp_num);
}
void beiscsi_process_mcc_cq(struct beiscsi_hba *phba)
@@ -2051,6 +1816,9 @@ void beiscsi_process_mcc_cq(struct beiscsi_hba *phba)
mcc_compl = queue_tail_node(mcc_cq);
mcc_compl->flags = le32_to_cpu(mcc_compl->flags);
while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) {
+ if (beiscsi_hba_in_error(phba))
+ return;
+
if (num_processed >= 32) {
hwi_ring_cq_db(phba, mcc_cq->id,
num_processed, 0);
@@ -2073,6 +1841,19 @@ void beiscsi_process_mcc_cq(struct beiscsi_hba *phba)
hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1);
}
+static void beiscsi_mcc_work(struct work_struct *work)
+{
+ struct be_eq_obj *pbe_eq;
+ struct beiscsi_hba *phba;
+
+ pbe_eq = container_of(work, struct be_eq_obj, mcc_work);
+ phba = pbe_eq->phba;
+ beiscsi_process_mcc_cq(phba);
+ /* rearm EQ for further interrupts */
+ if (!beiscsi_hba_in_error(phba))
+ hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
+}
+
/**
* beiscsi_process_cq()- Process the Completion Queue
* @pbe_eq: Event Q on which the Completion has come
@@ -2101,6 +1882,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] &
CQE_VALID_MASK) {
+ if (beiscsi_hba_in_error(phba))
+ return 0;
+
be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
code = (sol->dw[offsetof(struct amap_sol_cqe, code) /
@@ -2165,8 +1949,8 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
cqe_desc[code], code, cid);
spin_lock_bh(&phba->async_pdu_lock);
- hwi_process_default_pdu_ring(beiscsi_conn, phba,
- (struct i_t_dpdu_cqe *)sol);
+ beiscsi_hdq_process_compl(beiscsi_conn,
+ (struct i_t_dpdu_cqe *)sol);
spin_unlock_bh(&phba->async_pdu_lock);
break;
case UNSOL_DATA_NOTIFY:
@@ -2176,8 +1960,8 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
cqe_desc[code], code, cid);
spin_lock_bh(&phba->async_pdu_lock);
- hwi_process_default_pdu_ring(beiscsi_conn, phba,
- (struct i_t_dpdu_cqe *)sol);
+ beiscsi_hdq_process_compl(beiscsi_conn,
+ (struct i_t_dpdu_cqe *)sol);
spin_unlock_bh(&phba->async_pdu_lock);
break;
case CXN_INVALIDATE_INDEX_NOTIFY:
@@ -2213,8 +1997,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
"BM_%d : Dropping %s[%d] on DPDU ring on CID : %d\n",
cqe_desc[code], code, cid);
spin_lock_bh(&phba->async_pdu_lock);
- hwi_flush_default_pdu_buffer(phba, beiscsi_conn,
- (struct i_t_dpdu_cqe *) sol);
+ /* driver consumes the entry and drops the contents */
+ beiscsi_hdq_process_compl(beiscsi_conn,
+ (struct i_t_dpdu_cqe *)sol);
spin_unlock_bh(&phba->async_pdu_lock);
break;
case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL:
@@ -2262,60 +2047,32 @@ proc_next_cqe:
return total;
}
-void beiscsi_process_all_cqs(struct work_struct *work)
-{
- unsigned long flags;
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
- struct beiscsi_hba *phba;
- struct be_eq_obj *pbe_eq =
- container_of(work, struct be_eq_obj, work_cqs);
-
- phba = pbe_eq->phba;
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
-
- if (pbe_eq->todo_mcc_cq) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_mcc_cq = false;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_mcc_cq(phba);
- }
-
- if (pbe_eq->todo_cq) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_cq = false;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);
- }
-
- /* rearm EQ for further interrupts */
- hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
-}
-
static int be_iopoll(struct irq_poll *iop, int budget)
{
- unsigned int ret, num_eq_processed;
+ unsigned int ret, io_events;
struct beiscsi_hba *phba;
struct be_eq_obj *pbe_eq;
struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
- num_eq_processed = 0;
pbe_eq = container_of(iop, struct be_eq_obj, iopoll);
phba = pbe_eq->phba;
+ if (beiscsi_hba_in_error(phba)) {
+ irq_poll_complete(iop);
+ return 0;
+ }
+
+ io_events = 0;
eq = &pbe_eq->q;
eqe = queue_tail_node(eq);
-
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] &
EQE_VALID_MASK) {
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
eqe = queue_tail_node(eq);
- num_eq_processed++;
+ io_events++;
}
-
- hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+ hwi_ring_eq_db(phba, eq->id, 1, io_events, 0, 1);
ret = beiscsi_process_cq(pbe_eq, budget);
pbe_eq->cq_count += ret;
@@ -2325,7 +2082,8 @@ static int be_iopoll(struct irq_poll *iop, int budget)
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
"BM_%d : rearm pbe_eq->q.id =%d ret %d\n",
pbe_eq->q.id, ret);
- hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
+ if (!beiscsi_hba_in_error(phba))
+ hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
return ret;
}
@@ -2691,20 +2449,20 @@ static void beiscsi_find_mem_req(struct beiscsi_hba *phba)
(ulp_num * MEM_DESCR_OFFSET));
phba->mem_req[mem_descr_index] =
BEISCSI_GET_CID_COUNT(phba, ulp_num) *
- sizeof(struct async_pdu_handle);
+ sizeof(struct hd_async_handle);
mem_descr_index = (HWI_MEM_ASYNC_DATA_HANDLE_ULP0 +
(ulp_num * MEM_DESCR_OFFSET));
phba->mem_req[mem_descr_index] =
BEISCSI_GET_CID_COUNT(phba, ulp_num) *
- sizeof(struct async_pdu_handle);
+ sizeof(struct hd_async_handle);
mem_descr_index = (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 +
(ulp_num * MEM_DESCR_OFFSET));
phba->mem_req[mem_descr_index] =
- sizeof(struct hwi_async_pdu_context) +
+ sizeof(struct hd_async_context) +
(BEISCSI_GET_CID_COUNT(phba, ulp_num) *
- sizeof(struct hwi_async_entry));
+ sizeof(struct hd_async_entry));
}
}
}
@@ -2963,35 +2721,34 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
uint8_t ulp_num;
struct hwi_controller *phwi_ctrlr;
struct hba_parameters *p = &phba->params;
- struct hwi_async_pdu_context *pasync_ctx;
- struct async_pdu_handle *pasync_header_h, *pasync_data_h;
+ struct hd_async_context *pasync_ctx;
+ struct hd_async_handle *pasync_header_h, *pasync_data_h;
unsigned int index, idx, num_per_mem, num_async_data;
struct be_mem_descriptor *mem_descr;
for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
+ /* get async_ctx for each ULP */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 +
(ulp_num * MEM_DESCR_OFFSET));
phwi_ctrlr = phba->phwi_ctrlr;
phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num] =
- (struct hwi_async_pdu_context *)
+ (struct hd_async_context *)
mem_descr->mem_array[0].virtual_address;
pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num];
memset(pasync_ctx, 0, sizeof(*pasync_ctx));
pasync_ctx->async_entry =
- (struct hwi_async_entry *)
+ (struct hd_async_entry *)
((long unsigned int)pasync_ctx +
- sizeof(struct hwi_async_pdu_context));
+ sizeof(struct hd_async_context));
pasync_ctx->num_entries = BEISCSI_GET_CID_COUNT(phba,
ulp_num);
- pasync_ctx->buffer_size = p->defpdu_hdr_sz;
-
+ /* setup header buffers */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_HEADER_BUF_ULP0 +
(ulp_num * MEM_DESCR_OFFSET);
@@ -3008,6 +2765,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
"BM_%d : No Virtual address for ULP : %d\n",
ulp_num);
+ pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz;
pasync_ctx->async_header.va_base =
mem_descr->mem_array[0].virtual_address;
@@ -3015,6 +2773,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
mem_descr->mem_array[0].
bus_address.u.a64.address;
+ /* setup header buffer sgls */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_HEADER_RING_ULP0 +
(ulp_num * MEM_DESCR_OFFSET);
@@ -3034,6 +2793,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx->async_header.ring_base =
mem_descr->mem_array[0].virtual_address;
+ /* setup header buffer handles */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE_ULP0 +
(ulp_num * MEM_DESCR_OFFSET);
@@ -3052,9 +2812,9 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx->async_header.handle_base =
mem_descr->mem_array[0].virtual_address;
- pasync_ctx->async_header.writables = 0;
INIT_LIST_HEAD(&pasync_ctx->async_header.free_list);
+ /* setup data buffer sgls */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_DATA_RING_ULP0 +
(ulp_num * MEM_DESCR_OFFSET);
@@ -3074,6 +2834,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx->async_data.ring_base =
mem_descr->mem_array[0].virtual_address;
+ /* setup data buffer handles */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_DATA_HANDLE_ULP0 +
(ulp_num * MEM_DESCR_OFFSET);
@@ -3085,16 +2846,16 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
pasync_ctx->async_data.handle_base =
mem_descr->mem_array[0].virtual_address;
- pasync_ctx->async_data.writables = 0;
INIT_LIST_HEAD(&pasync_ctx->async_data.free_list);
pasync_header_h =
- (struct async_pdu_handle *)
+ (struct hd_async_handle *)
pasync_ctx->async_header.handle_base;
pasync_data_h =
- (struct async_pdu_handle *)
+ (struct hd_async_handle *)
pasync_ctx->async_data.handle_base;
+ /* setup data buffers */
mem_descr = (struct be_mem_descriptor *)phba->init_mem;
mem_descr += HWI_MEM_ASYNC_DATA_BUF_ULP0 +
(ulp_num * MEM_DESCR_OFFSET);
@@ -3112,6 +2873,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
ulp_num);
idx = 0;
+ pasync_ctx->async_data.buffer_size = p->defpdu_data_sz;
pasync_ctx->async_data.va_base =
mem_descr->mem_array[idx].virtual_address;
pasync_ctx->async_data.pa_base.u.a64.address =
@@ -3125,7 +2887,8 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
for (index = 0; index < BEISCSI_GET_CID_COUNT
(phba, ulp_num); index++) {
pasync_header_h->cri = -1;
- pasync_header_h->index = (char)index;
+ pasync_header_h->is_header = 1;
+ pasync_header_h->index = index;
INIT_LIST_HEAD(&pasync_header_h->link);
pasync_header_h->pbuffer =
(void *)((unsigned long)
@@ -3142,14 +2905,13 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
free_list);
pasync_header_h++;
pasync_ctx->async_header.free_entries++;
- pasync_ctx->async_header.writables++;
-
INIT_LIST_HEAD(&pasync_ctx->async_entry[index].
- wait_queue.list);
- INIT_LIST_HEAD(&pasync_ctx->async_entry[index].
- header_busy_list);
+ wq.list);
+ pasync_ctx->async_entry[index].header = NULL;
+
pasync_data_h->cri = -1;
- pasync_data_h->index = (char)index;
+ pasync_data_h->is_header = 0;
+ pasync_data_h->index = index;
INIT_LIST_HEAD(&pasync_data_h->link);
if (!num_async_data) {
@@ -3184,16 +2946,8 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
free_list);
pasync_data_h++;
pasync_ctx->async_data.free_entries++;
- pasync_ctx->async_data.writables++;
-
- INIT_LIST_HEAD(&pasync_ctx->async_entry[index].
- data_busy_list);
+ pasync_ctx->async_entry[index].data = NULL;
}
-
- pasync_ctx->async_header.host_write_ptr = 0;
- pasync_ctx->async_header.ep_read_ptr = -1;
- pasync_ctx->async_data.host_write_ptr = 0;
- pasync_ctx->async_data.ep_read_ptr = -1;
}
}
@@ -3265,8 +3019,8 @@ static int be_fill_queue(struct be_queue_info *q,
static int beiscsi_create_eqs(struct beiscsi_hba *phba,
struct hwi_context_memory *phwi_context)
{
+ int ret = -ENOMEM, eq_for_mcc;
unsigned int i, num_eq_pages;
- int ret = 0, eq_for_mcc;
struct be_queue_info *eq;
struct be_dma_mem *mem;
void *eq_vaddress;
@@ -3284,8 +3038,8 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
mem = &eq->dma_mem;
phwi_context->be_eq[i].phba = phba;
eq_vaddress = pci_alloc_consistent(phba->pcidev,
- num_eq_pages * PAGE_SIZE,
- &paddr);
+ num_eq_pages * PAGE_SIZE,
+ &paddr);
if (!eq_vaddress)
goto create_eq_error;
@@ -3313,6 +3067,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
phwi_context->be_eq[i].q.id);
}
return 0;
+
create_eq_error:
for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
eq = &phwi_context->be_eq[i].q;
@@ -3329,11 +3084,11 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
struct hwi_context_memory *phwi_context)
{
unsigned int i, num_cq_pages;
- int ret = 0;
struct be_queue_info *cq, *eq;
struct be_dma_mem *mem;
struct be_eq_obj *pbe_eq;
void *cq_vaddress;
+ int ret = -ENOMEM;
dma_addr_t paddr;
num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
@@ -3347,10 +3102,11 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
pbe_eq->phba = phba;
mem = &cq->dma_mem;
cq_vaddress = pci_alloc_consistent(phba->pcidev,
- num_cq_pages * PAGE_SIZE,
- &paddr);
+ num_cq_pages * PAGE_SIZE,
+ &paddr);
if (!cq_vaddress)
goto create_cq_error;
+
ret = be_fill_queue(cq, phba->params.num_cq_entries,
sizeof(struct sol_cqe), cq_vaddress);
if (ret) {
@@ -3385,7 +3141,6 @@ create_cq_error:
mem->va, mem->dma);
}
return ret;
-
}
static int
@@ -3437,7 +3192,6 @@ beiscsi_create_def_hdr(struct beiscsi_hba *phba,
"BM_%d : iscsi hdr def pdu id for ULP : %d is %d\n",
ulp_num,
phwi_context->be_def_hdrq[ulp_num].id);
- hwi_post_async_buffers(phba, BEISCSI_DEFQ_HDR, ulp_num);
return 0;
}
@@ -3492,11 +3246,9 @@ beiscsi_create_def_data(struct beiscsi_hba *phba,
ulp_num,
phwi_context->be_def_dataq[ulp_num].id);
- hwi_post_async_buffers(phba, BEISCSI_DEFQ_DATA, ulp_num);
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
"BM_%d : DEFAULT PDU DATA RING CREATED"
"on ULP : %d\n", ulp_num);
-
return 0;
}
@@ -3716,10 +3468,53 @@ static void free_wrb_handles(struct beiscsi_hba *phba)
static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
{
- struct be_queue_info *q;
struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_dma_mem *ptag_mem;
+ struct be_queue_info *q;
+ int i, tag;
q = &phba->ctrl.mcc_obj.q;
+ for (i = 0; i < MAX_MCC_CMD; i++) {
+ tag = i + 1;
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state))
+ continue;
+
+ if (test_bit(MCC_TAG_STATE_TIMEOUT,
+ &ctrl->ptag_state[tag].tag_state)) {
+ ptag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+ if (ptag_mem->size) {
+ pci_free_consistent(ctrl->pdev,
+ ptag_mem->size,
+ ptag_mem->va,
+ ptag_mem->dma);
+ ptag_mem->size = 0;
+ }
+ continue;
+ }
+ /**
+ * If MCC is still active and waiting then wake up the process.
+ * We are here only because port is going offline. The process
+ * sees that (BEISCSI_HBA_ONLINE is cleared) and EIO error is
+ * returned for the operation and allocated memory cleaned up.
+ */
+ if (waitqueue_active(&ctrl->mcc_wait[tag])) {
+ ctrl->mcc_tag_status[tag] = MCC_STATUS_FAILED;
+ ctrl->mcc_tag_status[tag] |= CQE_VALID_MASK;
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ /*
+ * Control tag info gets reinitialized in enable
+ * so wait for the process to clear running state.
+ */
+ while (test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state))
+ schedule_timeout_uninterruptible(HZ);
+ }
+ /**
+ * For MCC with tag_states MCC_TAG_STATE_ASYNC and
+ * MCC_TAG_STATE_IGNORE nothing needs to done.
+ */
+ }
if (q->created) {
beiscsi_cmd_q_destroy(ctrl, q, QTYPE_MCCQ);
be_queue_free(phba, q);
@@ -3732,68 +3527,6 @@ static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
}
}
-static void hwi_cleanup(struct beiscsi_hba *phba)
-{
- struct be_queue_info *q;
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
- struct hwi_async_pdu_context *pasync_ctx;
- int i, eq_for_mcc, ulp_num;
-
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
-
- be_cmd_iscsi_remove_template_hdr(ctrl);
-
- for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
- q = &phwi_context->be_wrbq[i];
- if (q->created)
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
- }
- kfree(phwi_context->be_wrbq);
- free_wrb_handles(phba);
-
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
- if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
- q = &phwi_context->be_def_hdrq[ulp_num];
- if (q->created)
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
-
- q = &phwi_context->be_def_dataq[ulp_num];
- if (q->created)
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
-
- pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num];
- }
- }
-
- beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
-
- for (i = 0; i < (phba->num_cpus); i++) {
- q = &phwi_context->be_cq[i];
- if (q->created) {
- be_queue_free(phba, q);
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
- }
- }
-
- be_mcc_queues_destroy(phba);
- if (phba->msix_enabled)
- eq_for_mcc = 1;
- else
- eq_for_mcc = 0;
- for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
- q = &phwi_context->be_eq[i].q;
- if (q->created) {
- be_queue_free(phba, q);
- beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
- }
- }
- be_cmd_fw_uninit(ctrl);
-}
-
static int be_mcc_queues_create(struct beiscsi_hba *phba,
struct hwi_context_memory *phwi_context)
{
@@ -3875,6 +3608,118 @@ static void find_num_cpus(struct beiscsi_hba *phba)
}
}
+static void hwi_purge_eq(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *eq;
+ struct be_eq_entry *eqe = NULL;
+ int i, eq_msix;
+ unsigned int num_processed;
+
+ if (beiscsi_hba_in_error(phba))
+ return;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ if (phba->msix_enabled)
+ eq_msix = 1;
+ else
+ eq_msix = 0;
+
+ for (i = 0; i < (phba->num_cpus + eq_msix); i++) {
+ eq = &phwi_context->be_eq[i].q;
+ eqe = queue_tail_node(eq);
+ num_processed = 0;
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_processed++;
+ }
+
+ if (num_processed)
+ hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1);
+ }
+}
+
+static void hwi_cleanup_port(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *q;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct hd_async_context *pasync_ctx;
+ int i, eq_for_mcc, ulp_num;
+
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
+ if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
+ beiscsi_cmd_iscsi_cleanup(phba, ulp_num);
+
+ /**
+ * Purge all EQ entries that may have been left out. This is to
+ * workaround a problem we've seen occasionally where driver gets an
+ * interrupt with EQ entry bit set after stopping the controller.
+ */
+ hwi_purge_eq(phba);
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+
+ be_cmd_iscsi_remove_template_hdr(ctrl);
+
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ q = &phwi_context->be_wrbq[i];
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
+ }
+ kfree(phwi_context->be_wrbq);
+ free_wrb_handles(phba);
+
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
+ if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
+
+ q = &phwi_context->be_def_hdrq[ulp_num];
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+ q = &phwi_context->be_def_dataq[ulp_num];
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+ pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num];
+ }
+ }
+
+ beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
+
+ for (i = 0; i < (phba->num_cpus); i++) {
+ q = &phwi_context->be_cq[i];
+ if (q->created) {
+ be_queue_free(phba, q);
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+ }
+ }
+
+ be_mcc_queues_destroy(phba);
+ if (phba->msix_enabled)
+ eq_for_mcc = 1;
+ else
+ eq_for_mcc = 0;
+ for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
+ q = &phwi_context->be_eq[i].q;
+ if (q->created) {
+ be_queue_free(phba, q);
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
+ }
+ }
+ /* this ensures complete FW cleanup */
+ beiscsi_cmd_function_reset(phba);
+ /* last communication, indicate driver is unloading */
+ beiscsi_cmd_special_wrb(&phba->ctrl, 0);
+}
+
static int hwi_init_port(struct beiscsi_hba *phba)
{
struct hwi_controller *phwi_ctrlr;
@@ -3887,9 +3732,8 @@ static int hwi_init_port(struct beiscsi_hba *phba)
phwi_context = phwi_ctrlr->phwi_ctxt;
phwi_context->max_eqd = 128;
phwi_context->min_eqd = 0;
- phwi_context->cur_eqd = 0;
- be_cmd_fw_initialize(&phba->ctrl);
- /* set optic state to unknown */
+ phwi_context->cur_eqd = 32;
+ /* set port optic state to unknown */
phba->optic_state = 0xff;
status = beiscsi_create_eqs(phba, phwi_context);
@@ -3903,7 +3747,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
if (status != 0)
goto error;
- status = mgmt_check_supported_fw(ctrl, phba);
+ status = beiscsi_check_supported_fw(ctrl, phba);
if (status != 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : Unsupported fw version\n");
@@ -3919,7 +3763,6 @@ static int hwi_init_port(struct beiscsi_hba *phba)
for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
def_pdu_ring_sz =
BEISCSI_GET_CID_COUNT(phba, ulp_num) *
sizeof(struct phys_addr);
@@ -3945,6 +3788,15 @@ static int hwi_init_port(struct beiscsi_hba *phba)
ulp_num);
goto error;
}
+ /**
+ * Now that the default PDU rings have been created,
+ * let EP know about it.
+ * Call beiscsi_cmd_iscsi_cleanup before posting?
+ */
+ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR,
+ ulp_num);
+ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA,
+ ulp_num);
}
}
@@ -3973,7 +3825,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
uint16_t cri = 0;
- struct hwi_async_pdu_context *pasync_ctx;
+ struct hd_async_context *pasync_ctx;
pasync_ctx = HWI_GET_ASYNC_PDU_CTX(
phwi_ctrlr, ulp_num);
@@ -3985,6 +3837,14 @@ static int hwi_init_port(struct beiscsi_hba *phba)
phwi_ctrlr->wrb_context[cri].cid] =
async_arr_idx++;
}
+ /**
+ * Now that the default PDU rings have been created,
+ * let EP know about it.
+ */
+ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR,
+ ulp_num);
+ beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA,
+ ulp_num);
}
}
@@ -3995,7 +3855,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
error:
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : hwi_init_port failed");
- hwi_cleanup(phba);
+ hwi_cleanup_port(phba);
return status;
}
@@ -4354,149 +4214,6 @@ static void hwi_disable_intr(struct beiscsi_hba *phba)
"BM_%d : In hwi_disable_intr, Already Disabled\n");
}
-/**
- * beiscsi_get_boot_info()- Get the boot session info
- * @phba: The device priv structure instance
- *
- * Get the boot target info and store in driver priv structure
- *
- * return values
- * Success: 0
- * Failure: Non-Zero Value
- **/
-static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
-{
- struct be_cmd_get_session_resp *session_resp;
- struct be_dma_mem nonemb_cmd;
- unsigned int tag;
- unsigned int s_handle;
- int ret = -ENOMEM;
-
- /* Get the session handle of the boot target */
- ret = be_mgmt_get_boot_shandle(phba, &s_handle);
- if (ret) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BM_%d : No boot session\n");
-
- if (ret == -ENXIO)
- phba->get_boot = 0;
-
-
- return ret;
- }
- phba->get_boot = 0;
- nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev,
- sizeof(*session_resp),
- &nonemb_cmd.dma);
- if (nonemb_cmd.va == NULL) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BM_%d : Failed to allocate memory for"
- "beiscsi_get_session_info\n");
-
- return -ENOMEM;
- }
-
- tag = mgmt_get_session_info(phba, s_handle,
- &nonemb_cmd);
- if (!tag) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BM_%d : beiscsi_get_session_info"
- " Failed\n");
-
- goto boot_freemem;
- }
-
- ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
- if (ret) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BM_%d : beiscsi_get_session_info Failed");
-
- if (ret != -EBUSY)
- goto boot_freemem;
- else
- return ret;
- }
-
- session_resp = nonemb_cmd.va ;
-
- memcpy(&phba->boot_sess, &session_resp->session_info,
- sizeof(struct mgmt_session_info));
-
- beiscsi_logout_fw_sess(phba,
- phba->boot_sess.session_handle);
- ret = 0;
-
-boot_freemem:
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
- return ret;
-}
-
-static void beiscsi_boot_release(void *data)
-{
- struct beiscsi_hba *phba = data;
-
- scsi_host_put(phba->shost);
-}
-
-static int beiscsi_setup_boot_info(struct beiscsi_hba *phba)
-{
- struct iscsi_boot_kobj *boot_kobj;
-
- /* it has been created previously */
- if (phba->boot_kset)
- return 0;
-
- /* get boot info using mgmt cmd */
- if (beiscsi_get_boot_info(phba))
- /* Try to see if we can carry on without this */
- return 0;
-
- phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no);
- if (!phba->boot_kset)
- return -ENOMEM;
-
- /* get a ref because the show function will ref the phba */
- if (!scsi_host_get(phba->shost))
- goto free_kset;
- boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba,
- beiscsi_show_boot_tgt_info,
- beiscsi_tgt_get_attr_visibility,
- beiscsi_boot_release);
- if (!boot_kobj)
- goto put_shost;
-
- if (!scsi_host_get(phba->shost))
- goto free_kset;
- boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba,
- beiscsi_show_boot_ini_info,
- beiscsi_ini_get_attr_visibility,
- beiscsi_boot_release);
- if (!boot_kobj)
- goto put_shost;
-
- if (!scsi_host_get(phba->shost))
- goto free_kset;
- boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba,
- beiscsi_show_boot_eth_info,
- beiscsi_eth_get_attr_visibility,
- beiscsi_boot_release);
- if (!boot_kobj)
- goto put_shost;
- return 0;
-
-put_shost:
- scsi_host_put(phba->shost);
-free_kset:
- iscsi_boot_destroy_kset(phba->boot_kset);
- phba->boot_kset = NULL;
- return -ENOMEM;
-}
-
static int beiscsi_init_port(struct beiscsi_hba *phba)
{
int ret;
@@ -4516,7 +4233,8 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
goto do_cleanup_ctrlr;
}
- if (hba_setup_cid_tbls(phba)) {
+ ret = hba_setup_cid_tbls(phba);
+ if (ret < 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : Failed in hba_setup_cid_tbls\n");
kfree(phba->io_sgl_hndl_base);
@@ -4527,61 +4245,15 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
return ret;
do_cleanup_ctrlr:
- hwi_cleanup(phba);
+ hwi_cleanup_port(phba);
return ret;
}
-static void hwi_purge_eq(struct beiscsi_hba *phba)
-{
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
- struct be_queue_info *eq;
- struct be_eq_entry *eqe = NULL;
- int i, eq_msix;
- unsigned int num_processed;
-
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
- if (phba->msix_enabled)
- eq_msix = 1;
- else
- eq_msix = 0;
-
- for (i = 0; i < (phba->num_cpus + eq_msix); i++) {
- eq = &phwi_context->be_eq[i].q;
- eqe = queue_tail_node(eq);
- num_processed = 0;
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_processed++;
- }
-
- if (num_processed)
- hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1);
- }
-}
-
-static void beiscsi_clean_port(struct beiscsi_hba *phba)
+static void beiscsi_cleanup_port(struct beiscsi_hba *phba)
{
- int mgmt_status, ulp_num;
struct ulp_cid_info *ptr_cid_info = NULL;
+ int ulp_num;
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
- if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) {
- mgmt_status = mgmt_epfw_cleanup(phba, ulp_num);
- if (mgmt_status)
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_INIT,
- "BM_%d : mgmt_epfw_cleanup FAILED"
- " for ULP_%d\n", ulp_num);
- }
- }
-
- hwi_purge_eq(phba);
- hwi_cleanup(phba);
kfree(phba->io_sgl_hndl_base);
kfree(phba->eh_sgl_hndl_base);
kfree(phba->ep_array);
@@ -4598,7 +4270,6 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
}
}
}
-
}
/**
@@ -4625,16 +4296,12 @@ beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
io_task = task->dd_data;
if (io_task->pwrb_handle) {
- memset(io_task->pwrb_handle->pwrb, 0,
- sizeof(struct iscsi_wrb));
- free_wrb_handle(phba, pwrb_context,
- io_task->pwrb_handle);
+ free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
io_task->pwrb_handle = NULL;
}
if (io_task->psgl_handle) {
- free_mgmt_sgl_handle(phba,
- io_task->psgl_handle);
+ free_mgmt_sgl_handle(phba, io_task->psgl_handle);
io_task->psgl_handle = NULL;
}
@@ -4671,6 +4338,7 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
io_task->bhs_pa.u.a64.address);
io_task->cmd_bhs = NULL;
+ task->hdr = NULL;
}
if (task->sc) {
@@ -4686,7 +4354,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
}
if (io_task->scsi_cmnd) {
- scsi_dma_unmap(io_task->scsi_cmnd);
+ if (io_task->num_sg)
+ scsi_dma_unmap(io_task->scsi_cmnd);
io_task->scsi_cmnd = NULL;
}
} else {
@@ -5051,7 +4720,6 @@ static int beiscsi_mtask(struct iscsi_task *task)
cid = beiscsi_conn->beiscsi_conn_cid;
pwrb = io_task->pwrb_handle->pwrb;
- memset(pwrb, 0, sizeof(*pwrb));
if (is_chip_be2_be3r(phba)) {
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
@@ -5165,6 +4833,15 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
int num_sg;
unsigned int writedir = 0, xferlen = 0;
+ phba = io_task->conn->phba;
+ /**
+ * HBA in error includes BEISCSI_HBA_FW_TIMEOUT. IO path might be
+ * operational if FW still gets heartbeat from EP FW. Is management
+ * path really needed to continue further?
+ */
+ if (!beiscsi_hba_is_online(phba))
+ return -EIO;
+
if (!io_task->conn->login_in_progress)
task->hdr->exp_statsn = 0;
@@ -5172,8 +4849,8 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return beiscsi_mtask(task);
io_task->scsi_cmnd = sc;
+ io_task->num_sg = 0;
num_sg = scsi_dma_map(sc);
- phba = io_task->conn->phba;
if (num_sg < 0) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI,
@@ -5184,6 +4861,11 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return num_sg;
}
+ /**
+ * For scsi cmd task, check num_sg before unmapping in cleanup_task.
+ * For management task, cleanup_task checks mtask_addr before unmapping.
+ */
+ io_task->num_sg = num_sg;
xferlen = scsi_bufflen(sc);
sg = scsi_sglist(sc);
if (sc->sc_data_direction == DMA_TO_DEVICE)
@@ -5213,6 +4895,12 @@ static int beiscsi_bsg_request(struct bsg_job *job)
shost = iscsi_job_to_shost(job);
phba = iscsi_host_priv(shost);
+ if (!beiscsi_hba_is_online(phba)) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BM_%d : HBA in error 0x%lx\n", phba->state);
+ return -ENXIO;
+ }
+
switch (bsg_req->msgcode) {
case ISCSI_BSG_HST_VENDOR:
nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
@@ -5240,6 +4928,14 @@ static int beiscsi_bsg_request(struct bsg_job *job)
phba->ctrl.mcc_tag_status[tag],
msecs_to_jiffies(
BEISCSI_HOST_MBX_TIMEOUT));
+
+ if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
+ clear_bit(MCC_TAG_STATE_RUNNING,
+ &phba->ctrl.ptag_state[tag].tag_state);
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ return -EIO;
+ }
extd_status = (phba->ctrl.mcc_tag_status[tag] &
CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT;
status = phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_MASK;
@@ -5283,106 +4979,294 @@ void beiscsi_hba_attrs_init(struct beiscsi_hba *phba)
beiscsi_log_enable_init(phba, beiscsi_log_enable);
}
-/*
- * beiscsi_quiesce()- Cleanup Driver resources
- * @phba: Instance Priv structure
- * @unload_state:i Clean or EEH unload state
- *
- * Free the OS and HW resources held by the driver
- **/
-static void beiscsi_quiesce(struct beiscsi_hba *phba,
- uint32_t unload_state)
+void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle)
{
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
- struct be_eq_obj *pbe_eq;
- unsigned int i, msix_vec;
+ if (phba->boot_struct.boot_kset)
+ return;
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
- hwi_disable_intr(phba);
- if (phba->msix_enabled) {
- for (i = 0; i <= phba->num_cpus; i++) {
- msix_vec = phba->msix_entries[i].vector;
- free_irq(msix_vec, &phwi_context->be_eq[i]);
- kfree(phba->msi_name[i]);
- }
- } else
- if (phba->pcidev->irq)
- free_irq(phba->pcidev->irq, phba);
- pci_disable_msix(phba->pcidev);
- cancel_delayed_work_sync(&phba->beiscsi_hw_check_task);
+ /* skip if boot work is already in progress */
+ if (test_and_set_bit(BEISCSI_HBA_BOOT_WORK, &phba->state))
+ return;
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- irq_poll_disable(&pbe_eq->iopoll);
+ phba->boot_struct.retry = 3;
+ phba->boot_struct.tag = 0;
+ phba->boot_struct.s_handle = s_handle;
+ phba->boot_struct.action = BEISCSI_BOOT_GET_SHANDLE;
+ schedule_work(&phba->boot_work);
+}
+
+static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf)
+{
+ struct beiscsi_hba *phba = data;
+ struct mgmt_session_info *boot_sess = &phba->boot_struct.boot_sess;
+ struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0];
+ char *str = buf;
+ int rc = -EPERM;
+
+ switch (type) {
+ case ISCSI_BOOT_TGT_NAME:
+ rc = sprintf(buf, "%.*s\n",
+ (int)strlen(boot_sess->target_name),
+ (char *)&boot_sess->target_name);
+ break;
+ case ISCSI_BOOT_TGT_IP_ADDR:
+ if (boot_conn->dest_ipaddr.ip_type == BEISCSI_IP_TYPE_V4)
+ rc = sprintf(buf, "%pI4\n",
+ (char *)&boot_conn->dest_ipaddr.addr);
+ else
+ rc = sprintf(str, "%pI6\n",
+ (char *)&boot_conn->dest_ipaddr.addr);
+ break;
+ case ISCSI_BOOT_TGT_PORT:
+ rc = sprintf(str, "%d\n", boot_conn->dest_port);
+ break;
+
+ case ISCSI_BOOT_TGT_CHAP_NAME:
+ rc = sprintf(str, "%.*s\n",
+ boot_conn->negotiated_login_options.auth_data.chap.
+ target_chap_name_length,
+ (char *)&boot_conn->negotiated_login_options.
+ auth_data.chap.target_chap_name);
+ break;
+ case ISCSI_BOOT_TGT_CHAP_SECRET:
+ rc = sprintf(str, "%.*s\n",
+ boot_conn->negotiated_login_options.auth_data.chap.
+ target_secret_length,
+ (char *)&boot_conn->negotiated_login_options.
+ auth_data.chap.target_secret);
+ break;
+ case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+ rc = sprintf(str, "%.*s\n",
+ boot_conn->negotiated_login_options.auth_data.chap.
+ intr_chap_name_length,
+ (char *)&boot_conn->negotiated_login_options.
+ auth_data.chap.intr_chap_name);
+ break;
+ case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+ rc = sprintf(str, "%.*s\n",
+ boot_conn->negotiated_login_options.auth_data.chap.
+ intr_secret_length,
+ (char *)&boot_conn->negotiated_login_options.
+ auth_data.chap.intr_secret);
+ break;
+ case ISCSI_BOOT_TGT_FLAGS:
+ rc = sprintf(str, "2\n");
+ break;
+ case ISCSI_BOOT_TGT_NIC_ASSOC:
+ rc = sprintf(str, "0\n");
+ break;
}
+ return rc;
+}
- if (unload_state == BEISCSI_CLEAN_UNLOAD) {
- destroy_workqueue(phba->wq);
- beiscsi_clean_port(phba);
- beiscsi_free_mem(phba);
+static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf)
+{
+ struct beiscsi_hba *phba = data;
+ char *str = buf;
+ int rc = -EPERM;
- beiscsi_unmap_pci_function(phba);
- pci_free_consistent(phba->pcidev,
- phba->ctrl.mbox_mem_alloced.size,
- phba->ctrl.mbox_mem_alloced.va,
- phba->ctrl.mbox_mem_alloced.dma);
- } else {
- hwi_purge_eq(phba);
- hwi_cleanup(phba);
+ switch (type) {
+ case ISCSI_BOOT_INI_INITIATOR_NAME:
+ rc = sprintf(str, "%s\n",
+ phba->boot_struct.boot_sess.initiator_iscsiname);
+ break;
}
+ return rc;
+}
+
+static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf)
+{
+ struct beiscsi_hba *phba = data;
+ char *str = buf;
+ int rc = -EPERM;
+ switch (type) {
+ case ISCSI_BOOT_ETH_FLAGS:
+ rc = sprintf(str, "2\n");
+ break;
+ case ISCSI_BOOT_ETH_INDEX:
+ rc = sprintf(str, "0\n");
+ break;
+ case ISCSI_BOOT_ETH_MAC:
+ rc = beiscsi_get_macaddr(str, phba);
+ break;
+ }
+ return rc;
}
-static void beiscsi_remove(struct pci_dev *pcidev)
+static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type)
{
- struct beiscsi_hba *phba = NULL;
+ umode_t rc = 0;
- phba = pci_get_drvdata(pcidev);
- if (!phba) {
- dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n");
- return;
+ switch (type) {
+ case ISCSI_BOOT_TGT_NAME:
+ case ISCSI_BOOT_TGT_IP_ADDR:
+ case ISCSI_BOOT_TGT_PORT:
+ case ISCSI_BOOT_TGT_CHAP_NAME:
+ case ISCSI_BOOT_TGT_CHAP_SECRET:
+ case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+ case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+ case ISCSI_BOOT_TGT_NIC_ASSOC:
+ case ISCSI_BOOT_TGT_FLAGS:
+ rc = S_IRUGO;
+ break;
}
+ return rc;
+}
- beiscsi_destroy_def_ifaces(phba);
- iscsi_boot_destroy_kset(phba->boot_kset);
- iscsi_host_remove(phba->shost);
- beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
- pci_dev_put(phba->pcidev);
- iscsi_host_free(phba->shost);
- pci_disable_pcie_error_reporting(pcidev);
- pci_set_drvdata(pcidev, NULL);
- pci_release_regions(pcidev);
- pci_disable_device(pcidev);
+static umode_t beiscsi_ini_get_attr_visibility(void *data, int type)
+{
+ umode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_INI_INITIATOR_NAME:
+ rc = S_IRUGO;
+ break;
+ }
+ return rc;
}
-static void beiscsi_msix_enable(struct beiscsi_hba *phba)
+static umode_t beiscsi_eth_get_attr_visibility(void *data, int type)
{
- int i, status;
+ umode_t rc = 0;
- for (i = 0; i <= phba->num_cpus; i++)
- phba->msix_entries[i].entry = i;
+ switch (type) {
+ case ISCSI_BOOT_ETH_FLAGS:
+ case ISCSI_BOOT_ETH_MAC:
+ case ISCSI_BOOT_ETH_INDEX:
+ rc = S_IRUGO;
+ break;
+ }
+ return rc;
+}
- status = pci_enable_msix_range(phba->pcidev, phba->msix_entries,
- phba->num_cpus + 1, phba->num_cpus + 1);
- if (status > 0)
- phba->msix_enabled = true;
+static void beiscsi_boot_kobj_release(void *data)
+{
+ struct beiscsi_hba *phba = data;
- return;
+ scsi_host_put(phba->shost);
}
-static void be_eqd_update(struct beiscsi_hba *phba)
+static int beiscsi_boot_create_kset(struct beiscsi_hba *phba)
{
+ struct boot_struct *bs = &phba->boot_struct;
+ struct iscsi_boot_kobj *boot_kobj;
+
+ if (bs->boot_kset) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d: boot_kset already created\n");
+ return 0;
+ }
+
+ bs->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no);
+ if (!bs->boot_kset) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d: boot_kset alloc failed\n");
+ return -ENOMEM;
+ }
+
+ /* get shost ref because the show function will refer phba */
+ if (!scsi_host_get(phba->shost))
+ goto free_kset;
+
+ boot_kobj = iscsi_boot_create_target(bs->boot_kset, 0, phba,
+ beiscsi_show_boot_tgt_info,
+ beiscsi_tgt_get_attr_visibility,
+ beiscsi_boot_kobj_release);
+ if (!boot_kobj)
+ goto put_shost;
+
+ if (!scsi_host_get(phba->shost))
+ goto free_kset;
+
+ boot_kobj = iscsi_boot_create_initiator(bs->boot_kset, 0, phba,
+ beiscsi_show_boot_ini_info,
+ beiscsi_ini_get_attr_visibility,
+ beiscsi_boot_kobj_release);
+ if (!boot_kobj)
+ goto put_shost;
+
+ if (!scsi_host_get(phba->shost))
+ goto free_kset;
+
+ boot_kobj = iscsi_boot_create_ethernet(bs->boot_kset, 0, phba,
+ beiscsi_show_boot_eth_info,
+ beiscsi_eth_get_attr_visibility,
+ beiscsi_boot_kobj_release);
+ if (!boot_kobj)
+ goto put_shost;
+
+ return 0;
+
+put_shost:
+ scsi_host_put(phba->shost);
+free_kset:
+ iscsi_boot_destroy_kset(bs->boot_kset);
+ bs->boot_kset = NULL;
+ return -ENOMEM;
+}
+
+static void beiscsi_boot_work(struct work_struct *work)
+{
+ struct beiscsi_hba *phba =
+ container_of(work, struct beiscsi_hba, boot_work);
+ struct boot_struct *bs = &phba->boot_struct;
+ unsigned int tag = 0;
+
+ if (!beiscsi_hba_is_online(phba))
+ return;
+
+ beiscsi_log(phba, KERN_INFO,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BM_%d : %s action %d\n",
+ __func__, phba->boot_struct.action);
+
+ switch (phba->boot_struct.action) {
+ case BEISCSI_BOOT_REOPEN_SESS:
+ tag = beiscsi_boot_reopen_sess(phba);
+ break;
+ case BEISCSI_BOOT_GET_SHANDLE:
+ tag = __beiscsi_boot_get_shandle(phba, 1);
+ break;
+ case BEISCSI_BOOT_GET_SINFO:
+ tag = beiscsi_boot_get_sinfo(phba);
+ break;
+ case BEISCSI_BOOT_LOGOUT_SESS:
+ tag = beiscsi_boot_logout_sess(phba);
+ break;
+ case BEISCSI_BOOT_CREATE_KSET:
+ beiscsi_boot_create_kset(phba);
+ /**
+ * updated boot_kset is made visible to all before
+ * ending the boot work.
+ */
+ mb();
+ clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state);
+ return;
+ }
+ if (!tag) {
+ if (bs->retry--)
+ schedule_work(&phba->boot_work);
+ else
+ clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state);
+ }
+}
+
+static void beiscsi_eqd_update_work(struct work_struct *work)
+{
+ struct hwi_context_memory *phwi_context;
struct be_set_eqd set_eqd[MAX_CPUS];
- struct be_aic_obj *aic;
- struct be_eq_obj *pbe_eq;
struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
+ struct be_eq_obj *pbe_eq;
+ struct beiscsi_hba *phba;
+ unsigned int pps, delta;
+ struct be_aic_obj *aic;
int eqd, i, num = 0;
- ulong now;
- u32 pps, delta;
- unsigned int tag;
+ unsigned long now;
+
+ phba = container_of(work, struct beiscsi_hba, eqd_update.work);
+ if (!beiscsi_hba_is_online(phba))
+ return;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -5391,13 +5275,13 @@ static void be_eqd_update(struct beiscsi_hba *phba)
aic = &phba->aic_obj[i];
pbe_eq = &phwi_context->be_eq[i];
now = jiffies;
- if (!aic->jiffs || time_before(now, aic->jiffs) ||
+ if (!aic->jiffies || time_before(now, aic->jiffies) ||
pbe_eq->cq_count < aic->eq_prev) {
- aic->jiffs = now;
+ aic->jiffies = now;
aic->eq_prev = pbe_eq->cq_count;
continue;
}
- delta = jiffies_to_msecs(now - aic->jiffs);
+ delta = jiffies_to_msecs(now - aic->jiffies);
pps = (((u32)(pbe_eq->cq_count - aic->eq_prev) * 1000) / delta);
eqd = (pps / 1500) << 2;
@@ -5406,7 +5290,7 @@ static void be_eqd_update(struct beiscsi_hba *phba)
eqd = min_t(u32, eqd, phwi_context->max_eqd);
eqd = max_t(u32, eqd, phwi_context->min_eqd);
- aic->jiffs = now;
+ aic->jiffies = now;
aic->eq_prev = pbe_eq->cq_count;
if (eqd != aic->prev_eqd) {
@@ -5416,53 +5300,242 @@ static void be_eqd_update(struct beiscsi_hba *phba)
num++;
}
}
- if (num) {
- tag = be_cmd_modify_eq_delay(phba, set_eqd, num);
- if (tag)
- beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
+ if (num)
+ /* completion of this is ignored */
+ beiscsi_modify_eq_delay(phba, set_eqd, num);
+
+ schedule_delayed_work(&phba->eqd_update,
+ msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
+}
+
+static void beiscsi_msix_enable(struct beiscsi_hba *phba)
+{
+ int i, status;
+
+ for (i = 0; i <= phba->num_cpus; i++)
+ phba->msix_entries[i].entry = i;
+
+ status = pci_enable_msix_range(phba->pcidev, phba->msix_entries,
+ phba->num_cpus + 1, phba->num_cpus + 1);
+ if (status > 0)
+ phba->msix_enabled = true;
+}
+
+static void beiscsi_hw_tpe_check(unsigned long ptr)
+{
+ struct beiscsi_hba *phba;
+ u32 wait;
+
+ phba = (struct beiscsi_hba *)ptr;
+ /* if not TPE, do nothing */
+ if (!beiscsi_detect_tpe(phba))
+ return;
+
+ /* wait default 4000ms before recovering */
+ wait = 4000;
+ if (phba->ue2rp > BEISCSI_UE_DETECT_INTERVAL)
+ wait = phba->ue2rp - BEISCSI_UE_DETECT_INTERVAL;
+ queue_delayed_work(phba->wq, &phba->recover_port,
+ msecs_to_jiffies(wait));
+}
+
+static void beiscsi_hw_health_check(unsigned long ptr)
+{
+ struct beiscsi_hba *phba;
+
+ phba = (struct beiscsi_hba *)ptr;
+ beiscsi_detect_ue(phba);
+ if (beiscsi_detect_ue(phba)) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d : port in error: %lx\n", phba->state);
+ /* sessions are no longer valid, so first fail the sessions */
+ queue_work(phba->wq, &phba->sess_work);
+
+ /* detect UER supported */
+ if (!test_bit(BEISCSI_HBA_UER_SUPP, &phba->state))
+ return;
+ /* modify this timer to check TPE */
+ phba->hw_check.function = beiscsi_hw_tpe_check;
}
+
+ mod_timer(&phba->hw_check,
+ jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
}
-static void be_check_boot_session(struct beiscsi_hba *phba)
+/*
+ * beiscsi_enable_port()- Enables the disabled port.
+ * Only port resources freed in disable function are reallocated.
+ * This is called in HBA error handling path.
+ *
+ * @phba: Instance of driver private structure
+ *
+ **/
+static int beiscsi_enable_port(struct beiscsi_hba *phba)
{
- if (beiscsi_setup_boot_info(phba))
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Could not set up "
- "iSCSI boot info on async event.\n");
+ struct hwi_context_memory *phwi_context;
+ struct hwi_controller *phwi_ctrlr;
+ struct be_eq_obj *pbe_eq;
+ int ret, i;
+
+ if (test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d : %s : port is online %lx\n",
+ __func__, phba->state);
+ return 0;
+ }
+
+ ret = beiscsi_init_sliport(phba);
+ if (ret)
+ return ret;
+
+ if (enable_msix)
+ find_num_cpus(phba);
+ else
+ phba->num_cpus = 1;
+ if (enable_msix) {
+ beiscsi_msix_enable(phba);
+ if (!phba->msix_enabled)
+ phba->num_cpus = 1;
+ }
+
+ beiscsi_get_params(phba);
+ /* Re-enable UER. If different TPE occurs then it is recoverable. */
+ beiscsi_set_uer_feature(phba);
+
+ phba->shost->max_id = phba->params.cxns_per_ctrl;
+ phba->shost->can_queue = phba->params.ios_per_ctrl;
+ ret = hwi_init_controller(phba);
+ if (ret) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d : init controller failed %d\n", ret);
+ goto disable_msix;
+ }
+
+ for (i = 0; i < MAX_MCC_CMD; i++) {
+ init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
+ phba->ctrl.mcc_tag[i] = i + 1;
+ phba->ctrl.mcc_tag_status[i + 1] = 0;
+ phba->ctrl.mcc_tag_available++;
+ }
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll);
+ }
+
+ i = (phba->msix_enabled) ? i : 0;
+ /* Work item for MCC handling */
+ pbe_eq = &phwi_context->be_eq[i];
+ INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work);
+
+ ret = beiscsi_init_irqs(phba);
+ if (ret < 0) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d : setup IRQs failed %d\n", ret);
+ goto cleanup_port;
+ }
+ hwi_enable_intr(phba);
+ /* port operational: clear all error bits */
+ set_bit(BEISCSI_HBA_ONLINE, &phba->state);
+ __beiscsi_log(phba, KERN_INFO,
+ "BM_%d : port online: 0x%lx\n", phba->state);
+
+ /* start hw_check timer and eqd_update work */
+ schedule_delayed_work(&phba->eqd_update,
+ msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
+
+ /**
+ * Timer function gets modified for TPE detection.
+ * Always reinit to do health check first.
+ */
+ phba->hw_check.function = beiscsi_hw_health_check;
+ mod_timer(&phba->hw_check,
+ jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
+ return 0;
+
+cleanup_port:
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ irq_poll_disable(&pbe_eq->iopoll);
+ }
+ hwi_cleanup_port(phba);
+
+disable_msix:
+ if (phba->msix_enabled)
+ pci_disable_msix(phba->pcidev);
+
+ return ret;
}
/*
- * beiscsi_hw_health_check()- Check adapter health
- * @work: work item to check HW health
+ * beiscsi_disable_port()- Disable port and cleanup driver resources.
+ * This is called in HBA error handling and driver removal.
+ * @phba: Instance Priv structure
+ * @unload: indicate driver is unloading
*
- * Check if adapter in an unrecoverable state or not.
+ * Free the OS and HW resources held by the driver
**/
-static void
-beiscsi_hw_health_check(struct work_struct *work)
+static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload)
{
- struct beiscsi_hba *phba =
- container_of(work, struct beiscsi_hba,
- beiscsi_hw_check_task.work);
+ struct hwi_context_memory *phwi_context;
+ struct hwi_controller *phwi_ctrlr;
+ struct be_eq_obj *pbe_eq;
+ unsigned int i, msix_vec;
- be_eqd_update(phba);
+ if (!test_and_clear_bit(BEISCSI_HBA_ONLINE, &phba->state))
+ return;
- if (phba->state & BE_ADAPTER_CHECK_BOOT) {
- if ((phba->get_boot > 0) && (!phba->boot_kset)) {
- phba->get_boot--;
- if (!(phba->get_boot % BE_GET_BOOT_TO))
- be_check_boot_session(phba);
- } else {
- phba->state &= ~BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = 0;
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ hwi_disable_intr(phba);
+ if (phba->msix_enabled) {
+ for (i = 0; i <= phba->num_cpus; i++) {
+ msix_vec = phba->msix_entries[i].vector;
+ free_irq(msix_vec, &phwi_context->be_eq[i]);
+ kfree(phba->msi_name[i]);
}
+ } else
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+ pci_disable_msix(phba->pcidev);
+
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ irq_poll_disable(&pbe_eq->iopoll);
}
+ cancel_delayed_work_sync(&phba->eqd_update);
+ cancel_work_sync(&phba->boot_work);
+ /* WQ might be running cancel queued mcc_work if we are not exiting */
+ if (!unload && beiscsi_hba_in_error(phba)) {
+ pbe_eq = &phwi_context->be_eq[i];
+ cancel_work_sync(&pbe_eq->mcc_work);
+ }
+ hwi_cleanup_port(phba);
+}
- beiscsi_ue_detect(phba);
+static void beiscsi_sess_work(struct work_struct *work)
+{
+ struct beiscsi_hba *phba;
- schedule_delayed_work(&phba->beiscsi_hw_check_task,
- msecs_to_jiffies(1000));
+ phba = container_of(work, struct beiscsi_hba, sess_work);
+ /*
+ * This work gets scheduled only in case of HBA error.
+ * Old sessions are gone so need to be re-established.
+ * iscsi_session_failure needs process context hence this work.
+ */
+ iscsi_host_for_each_session(phba->shost, beiscsi_session_fail);
}
+static void beiscsi_recover_port(struct work_struct *work)
+{
+ struct beiscsi_hba *phba;
+
+ phba = container_of(work, struct beiscsi_hba, recover_port.work);
+ beiscsi_disable_port(phba, 0);
+ beiscsi_enable_port(phba);
+}
static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev,
pci_channel_state_t state)
@@ -5470,12 +5543,18 @@ static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev,
struct beiscsi_hba *phba = NULL;
phba = (struct beiscsi_hba *)pci_get_drvdata(pdev);
- phba->state |= BE_ADAPTER_PCI_ERR;
+ set_bit(BEISCSI_HBA_PCI_ERR, &phba->state);
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : EEH error detected\n");
- beiscsi_quiesce(phba, BEISCSI_EEH_UNLOAD);
+ /* first stop UE detection when PCI error detected */
+ del_timer_sync(&phba->hw_check);
+ cancel_delayed_work_sync(&phba->recover_port);
+
+ /* sessions are no longer valid, so first fail the sessions */
+ iscsi_host_for_each_session(phba->shost, beiscsi_session_fail);
+ beiscsi_disable_port(phba, 0);
if (state == pci_channel_io_perm_failure) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5515,9 +5594,8 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- /* Wait for the CHIP Reset to complete */
- status = be_chk_reset_complete(phba);
- if (!status) {
+ status = beiscsi_check_fw_rdy(phba);
+ if (status) {
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT,
"BM_%d : EEH Reset Completed\n");
} else {
@@ -5532,87 +5610,16 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev)
static void beiscsi_eeh_resume(struct pci_dev *pdev)
{
- int ret = 0, i;
- struct be_eq_obj *pbe_eq;
- struct beiscsi_hba *phba = NULL;
- struct hwi_controller *phwi_ctrlr;
- struct hwi_context_memory *phwi_context;
+ struct beiscsi_hba *phba;
+ int ret;
phba = (struct beiscsi_hba *)pci_get_drvdata(pdev);
pci_save_state(pdev);
- if (enable_msix)
- find_num_cpus(phba);
- else
- phba->num_cpus = 1;
-
- if (enable_msix) {
- beiscsi_msix_enable(phba);
- if (!phba->msix_enabled)
- phba->num_cpus = 1;
- }
-
- ret = beiscsi_cmd_reset_function(phba);
- if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Reset Failed\n");
- goto ret_err;
- }
-
- ret = be_chk_reset_complete(phba);
- if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Failed to get out of reset.\n");
- goto ret_err;
- }
-
- beiscsi_get_params(phba);
- phba->shost->max_id = phba->params.cxns_per_ctrl;
- phba->shost->can_queue = phba->params.ios_per_ctrl;
- ret = hwi_init_controller(phba);
- if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_eeh_resume -"
- "Failed to initialize beiscsi_hba.\n");
- goto ret_err;
- }
-
- for (i = 0; i < MAX_MCC_CMD; i++) {
- init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
- phba->ctrl.mcc_tag[i] = i + 1;
- phba->ctrl.mcc_tag_status[i + 1] = 0;
- phba->ctrl.mcc_tag_available++;
- }
-
- phwi_ctrlr = phba->phwi_ctrlr;
- phwi_context = phwi_ctrlr->phwi_ctxt;
-
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
- be_iopoll);
- }
-
- i = (phba->msix_enabled) ? i : 0;
- /* Work item for MCC handling */
- pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
-
- ret = beiscsi_init_irqs(phba);
- if (ret < 0) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_eeh_resume - "
- "Failed to beiscsi_init_irqs\n");
- goto ret_err;
- }
-
- hwi_enable_intr(phba);
- phba->state &= ~BE_ADAPTER_PCI_ERR;
-
- return;
-ret_err:
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : AER EEH Resume Failed\n");
+ ret = beiscsi_enable_port(phba);
+ if (ret)
+ __beiscsi_log(phba, KERN_ERR,
+ "BM_%d : AER EEH resume failed\n");
}
static int beiscsi_dev_probe(struct pci_dev *pcidev,
@@ -5622,7 +5629,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
struct be_eq_obj *pbe_eq;
- int ret = 0, i;
+ unsigned int s_handle;
+ int ret, i;
ret = beiscsi_enable_pci(pcidev);
if (ret < 0) {
@@ -5635,6 +5643,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
if (!phba) {
dev_err(&pcidev->dev,
"beiscsi_dev_probe - Failed in beiscsi_hba_alloc\n");
+ ret = -ENOMEM;
goto disable_pci;
}
@@ -5650,10 +5659,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
/* Initialize Driver configuration Paramters */
beiscsi_hba_attrs_init(phba);
- phba->fw_timeout = false;
phba->mac_addr_set = false;
-
switch (pcidev->device) {
case BE_DEVICE_ID1:
case OC_DEVICE_ID1:
@@ -5677,39 +5684,26 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
ret = be_ctrl_init(phba, pcidev);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_dev_probe-"
- "Failed in be_ctrl_init\n");
+ "BM_%d : be_ctrl_init failed\n");
goto hba_free;
}
- /*
- * FUNCTION_RESET should clean up any stale info in FW for this fn
- */
- ret = beiscsi_cmd_reset_function(phba);
- if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Reset Failed\n");
- goto hba_free;
- }
- ret = be_chk_reset_complete(phba);
- if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Failed to get out of reset.\n");
+ ret = beiscsi_init_sliport(phba);
+ if (ret)
goto hba_free;
- }
spin_lock_init(&phba->io_sgl_lock);
spin_lock_init(&phba->mgmt_sgl_lock);
- spin_lock_init(&phba->isr_lock);
spin_lock_init(&phba->async_pdu_lock);
- ret = mgmt_get_fw_config(&phba->ctrl, phba);
+ ret = beiscsi_get_fw_config(&phba->ctrl, phba);
if (ret != 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : Error getting fw config\n");
goto free_port;
}
- mgmt_get_port_name(&phba->ctrl, phba);
+ beiscsi_get_port_name(&phba->ctrl, phba);
beiscsi_get_params(phba);
+ beiscsi_set_uer_feature(phba);
if (enable_msix)
find_num_cpus(phba);
@@ -5754,25 +5748,24 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : beiscsi_dev_probe-"
"Failed to allocate work queue\n");
+ ret = -ENOMEM;
goto free_twq;
}
- INIT_DELAYED_WORK(&phba->beiscsi_hw_check_task,
- beiscsi_hw_health_check);
+ INIT_DELAYED_WORK(&phba->eqd_update, beiscsi_eqd_update_work);
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
- be_iopoll);
+ irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll);
}
i = (phba->msix_enabled) ? i : 0;
/* Work item for MCC handling */
pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
+ INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work);
ret = beiscsi_init_irqs(phba);
if (ret < 0) {
@@ -5783,22 +5776,42 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
}
hwi_enable_intr(phba);
- if (iscsi_host_add(phba->shost, &phba->pcidev->dev))
+ ret = iscsi_host_add(phba->shost, &phba->pcidev->dev);
+ if (ret)
goto free_blkenbld;
- if (beiscsi_setup_boot_info(phba))
- /*
- * log error but continue, because we may not be using
- * iscsi boot.
+ /* set online bit after port is operational */
+ set_bit(BEISCSI_HBA_ONLINE, &phba->state);
+ __beiscsi_log(phba, KERN_INFO,
+ "BM_%d : port online: 0x%lx\n", phba->state);
+
+ INIT_WORK(&phba->boot_work, beiscsi_boot_work);
+ ret = beiscsi_boot_get_shandle(phba, &s_handle);
+ if (ret > 0) {
+ beiscsi_start_boot_work(phba, s_handle);
+ /**
+ * Set this bit after starting the work to let
+ * probe handle it first.
+ * ASYNC event can too schedule this work.
*/
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Could not set up "
- "iSCSI boot info.\n");
+ set_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state);
+ }
- beiscsi_create_def_ifaces(phba);
- schedule_delayed_work(&phba->beiscsi_hw_check_task,
- msecs_to_jiffies(1000));
+ beiscsi_iface_create_default(phba);
+ schedule_delayed_work(&phba->eqd_update,
+ msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
+ INIT_WORK(&phba->sess_work, beiscsi_sess_work);
+ INIT_DELAYED_WORK(&phba->recover_port, beiscsi_recover_port);
+ /**
+ * Start UE detection here. UE before this will cause stall in probe
+ * and eventually fail the probe.
+ */
+ init_timer(&phba->hw_check);
+ phba->hw_check.function = beiscsi_hw_health_check;
+ phba->hw_check.data = (unsigned long)phba;
+ mod_timer(&phba->hw_check,
+ jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
"\n\n\n BM_%d : SUCCESS - DRIVER LOADED\n\n\n");
return 0;
@@ -5810,7 +5823,8 @@ free_blkenbld:
irq_poll_disable(&pbe_eq->iopoll);
}
free_twq:
- beiscsi_clean_port(phba);
+ hwi_cleanup_port(phba);
+ beiscsi_cleanup_port(phba);
beiscsi_free_mem(phba);
free_port:
pci_free_consistent(phba->pcidev,
@@ -5830,6 +5844,49 @@ disable_pci:
return ret;
}
+static void beiscsi_remove(struct pci_dev *pcidev)
+{
+ struct beiscsi_hba *phba = NULL;
+
+ phba = pci_get_drvdata(pcidev);
+ if (!phba) {
+ dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n");
+ return;
+ }
+
+ /* first stop UE detection before unloading */
+ del_timer_sync(&phba->hw_check);
+ cancel_delayed_work_sync(&phba->recover_port);
+ cancel_work_sync(&phba->sess_work);
+
+ beiscsi_iface_destroy_default(phba);
+ iscsi_host_remove(phba->shost);
+ beiscsi_disable_port(phba, 1);
+
+ /* after cancelling boot_work */
+ iscsi_boot_destroy_kset(phba->boot_struct.boot_kset);
+
+ /* free all resources */
+ destroy_workqueue(phba->wq);
+ beiscsi_cleanup_port(phba);
+ beiscsi_free_mem(phba);
+
+ /* ctrl uninit */
+ beiscsi_unmap_pci_function(phba);
+ pci_free_consistent(phba->pcidev,
+ phba->ctrl.mbox_mem_alloced.size,
+ phba->ctrl.mbox_mem_alloced.va,
+ phba->ctrl.mbox_mem_alloced.dma);
+
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+ pci_disable_pcie_error_reporting(pcidev);
+ pci_set_drvdata(pcidev, NULL);
+ pci_release_regions(pcidev);
+ pci_disable_device(pcidev);
+}
+
+
static struct pci_error_handlers beiscsi_eeh_handlers = {
.error_detected = beiscsi_eeh_err_detected,
.slot_reset = beiscsi_eeh_reset,
@@ -5846,9 +5903,9 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.create_conn = beiscsi_conn_create,
.bind_conn = beiscsi_conn_bind,
.destroy_conn = iscsi_conn_teardown,
- .attr_is_visible = be2iscsi_attr_is_visible,
- .set_iface_param = be2iscsi_iface_set_param,
- .get_iface_param = be2iscsi_iface_get_param,
+ .attr_is_visible = beiscsi_attr_is_visible,
+ .set_iface_param = beiscsi_iface_set_param,
+ .get_iface_param = beiscsi_iface_get_param,
.set_param = beiscsi_set_param,
.get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
@@ -5877,7 +5934,6 @@ static struct pci_driver beiscsi_pci_driver = {
.err_handler = &beiscsi_eeh_handlers
};
-
static int __init beiscsi_module_init(void)
{
int ret;
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 30a4606d9a3b..6376657e45f7 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,10 +7,10 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com)
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_iscsi.h>
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "11.0.0.0"
+#define BUILD_STR "11.2.0.0"
#define BE_NAME "Emulex OneConnect" \
"Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -82,36 +82,12 @@
#define BEISCSI_MAX_FRAGS_INIT 192
#define BE_NUM_MSIX_ENTRIES 1
-#define MPU_EP_CONTROL 0
-#define MPU_EP_SEMAPHORE 0xac
-#define BE2_SOFT_RESET 0x5c
-#define BE2_PCI_ONLINE0 0xb0
-#define BE2_PCI_ONLINE1 0xb4
-#define BE2_SET_RESET 0x80
-#define BE2_MPU_IRAM_ONLINE 0x00000080
-
#define BE_SENSE_INFO_SIZE 258
#define BE_ISCSI_PDU_HEADER_SIZE 64
#define BE_MIN_MEM_SIZE 16384
#define MAX_CMD_SZ 65536
#define IIOC_SCSI_DATA 0x05 /* Write Operation */
-#define INVALID_SESS_HANDLE 0xFFFFFFFF
-
-/**
- * Adapter States
- **/
-#define BE_ADAPTER_LINK_UP 0x001
-#define BE_ADAPTER_LINK_DOWN 0x002
-#define BE_ADAPTER_PCI_ERR 0x004
-#define BE_ADAPTER_CHECK_BOOT 0x008
-
-
-#define BEISCSI_CLEAN_UNLOAD 0x01
-#define BEISCSI_EEH_UNLOAD 0x02
-
-#define BE_GET_BOOT_RETRIES 45
-#define BE_GET_BOOT_TO 20
/**
* hardware needs the async PDU buffers to be posted in multiples of 8
* So have atleast 8 of them by default
@@ -378,7 +354,6 @@ struct beiscsi_hba {
struct sgl_handle **eh_sgl_hndl_base;
spinlock_t io_sgl_lock;
spinlock_t mgmt_sgl_lock;
- spinlock_t isr_lock;
spinlock_t async_pdu_lock;
unsigned int age;
struct list_head hba_queue;
@@ -390,7 +365,6 @@ struct beiscsi_hba {
struct ulp_cid_info *cid_array_info[BEISCSI_ULP_COUNT];
struct iscsi_endpoint **ep_array;
struct beiscsi_conn **conn_table;
- struct iscsi_boot_kset *boot_kset;
struct Scsi_Host *shost;
struct iscsi_iface *ipv4_iface;
struct iscsi_iface *ipv6_iface;
@@ -418,12 +392,33 @@ struct beiscsi_hba {
unsigned long ulp_supported;
} fw_config;
- unsigned int state;
+ unsigned long state;
+#define BEISCSI_HBA_ONLINE 0
+#define BEISCSI_HBA_LINK_UP 1
+#define BEISCSI_HBA_BOOT_FOUND 2
+#define BEISCSI_HBA_BOOT_WORK 3
+#define BEISCSI_HBA_UER_SUPP 4
+#define BEISCSI_HBA_PCI_ERR 5
+#define BEISCSI_HBA_FW_TIMEOUT 6
+#define BEISCSI_HBA_IN_UE 7
+#define BEISCSI_HBA_IN_TPE 8
+
+/* error bits */
+#define BEISCSI_HBA_IN_ERR ((1 << BEISCSI_HBA_PCI_ERR) | \
+ (1 << BEISCSI_HBA_FW_TIMEOUT) | \
+ (1 << BEISCSI_HBA_IN_UE) | \
+ (1 << BEISCSI_HBA_IN_TPE))
+
u8 optic_state;
- int get_boot;
- bool fw_timeout;
- bool ue_detected;
- struct delayed_work beiscsi_hw_check_task;
+ struct delayed_work eqd_update;
+ /* update EQ delay timer every 1000ms */
+#define BEISCSI_EQD_UPDATE_INTERVAL 1000
+ struct timer_list hw_check;
+ /* check for UE every 1000ms */
+#define BEISCSI_UE_DETECT_INTERVAL 1000
+ u32 ue2rp;
+ struct delayed_work recover_port;
+ struct work_struct sess_work;
bool mac_addr_set;
u8 mac_address[ETH_ALEN];
@@ -435,7 +430,6 @@ struct beiscsi_hba {
struct be_ctrl_info ctrl;
unsigned int generation;
unsigned int interface_handle;
- struct mgmt_session_info boot_sess;
struct invalidate_command_table inv_tbl[128];
struct be_aic_obj aic_obj[MAX_CPUS];
@@ -444,8 +438,29 @@ struct beiscsi_hba {
struct scatterlist *sg,
uint32_t num_sg, uint32_t xferlen,
uint32_t writedir);
+ struct boot_struct {
+ int retry;
+ unsigned int tag;
+ unsigned int s_handle;
+ struct be_dma_mem nonemb_cmd;
+ enum {
+ BEISCSI_BOOT_REOPEN_SESS = 1,
+ BEISCSI_BOOT_GET_SHANDLE,
+ BEISCSI_BOOT_GET_SINFO,
+ BEISCSI_BOOT_LOGOUT_SESS,
+ BEISCSI_BOOT_CREATE_KSET,
+ } action;
+ struct mgmt_session_info boot_sess;
+ struct iscsi_boot_kset *boot_kset;
+ } boot_struct;
+ struct work_struct boot_work;
};
+#define beiscsi_hba_in_error(phba) ((phba)->state & BEISCSI_HBA_IN_ERR)
+#define beiscsi_hba_is_online(phba) \
+ (!beiscsi_hba_in_error((phba)) && \
+ test_bit(BEISCSI_HBA_ONLINE, &phba->state))
+
struct beiscsi_session {
struct pci_pool *bhs_pool;
};
@@ -508,6 +523,7 @@ struct beiscsi_io_task {
struct sgl_handle *psgl_handle;
struct beiscsi_conn *conn;
struct scsi_cmnd *scsi_cmnd;
+ int num_sg;
struct hwi_wrb_context *pwrb_context;
unsigned int cmd_sn;
unsigned int flags;
@@ -592,80 +608,81 @@ struct amap_beiscsi_offload_params {
u8 max_recv_data_segment_length[32];
};
-/* void hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
- struct beiscsi_hba *phba, struct sol_cqe *psol);*/
-
-struct async_pdu_handle {
+struct hd_async_handle {
struct list_head link;
struct be_bus_address pa;
void *pbuffer;
- unsigned int consumed;
- unsigned char index;
- unsigned char is_header;
- unsigned short cri;
- unsigned long buffer_len;
+ u32 buffer_len;
+ u16 index;
+ u16 cri;
+ u8 is_header;
+ u8 is_final;
};
-struct hwi_async_entry {
- struct {
- unsigned char hdr_received;
- unsigned char hdr_len;
- unsigned short bytes_received;
+/**
+ * This has list of async PDUs that are waiting to be processed.
+ * Buffers live in this list for a brief duration before they get
+ * processed and posted back to hardware.
+ * Note that we don't really need one cri_wait_queue per async_entry.
+ * We need one cri_wait_queue per CRI. Its easier to manage if this
+ * is tagged along with the async_entry.
+ */
+struct hd_async_entry {
+ struct cri_wait_queue {
+ unsigned short hdr_len;
+ unsigned int bytes_received;
unsigned int bytes_needed;
struct list_head list;
- } wait_queue;
-
- struct list_head header_busy_list;
- struct list_head data_busy_list;
+ } wq;
+ /* handles posted to FW resides here */
+ struct hd_async_handle *header;
+ struct hd_async_handle *data;
};
-struct hwi_async_pdu_context {
- struct {
- struct be_bus_address pa_base;
- void *va_base;
- void *ring_base;
- struct async_pdu_handle *handle_base;
-
- unsigned int host_write_ptr;
- unsigned int ep_read_ptr;
- unsigned int writables;
-
- unsigned int free_entries;
- unsigned int busy_entries;
-
- struct list_head free_list;
- } async_header;
+struct hd_async_buf_context {
+ struct be_bus_address pa_base;
+ void *va_base;
+ void *ring_base;
+ struct hd_async_handle *handle_base;
+ u16 free_entries;
+ u32 buffer_size;
+ /**
+ * Once iSCSI layer finishes processing an async PDU, the
+ * handles used for the PDU are added to this list.
+ * They are posted back to FW in groups of 8.
+ */
+ struct list_head free_list;
+};
- struct {
- struct be_bus_address pa_base;
- void *va_base;
- void *ring_base;
- struct async_pdu_handle *handle_base;
-
- unsigned int host_write_ptr;
- unsigned int ep_read_ptr;
- unsigned int writables;
-
- unsigned int free_entries;
- unsigned int busy_entries;
- struct list_head free_list;
- } async_data;
-
- unsigned int buffer_size;
- unsigned int num_entries;
+/**
+ * hd_async_context is declared for each ULP supporting iSCSI function.
+ */
+struct hd_async_context {
+ struct hd_async_buf_context async_header;
+ struct hd_async_buf_context async_data;
+ u16 num_entries;
+ /**
+ * When unsol PDU is in, it needs to be chained till all the bytes are
+ * received and then processing is done. hd_async_entry is created
+ * based on the cid_count for each ULP. When unsol PDU comes in based
+ * on the conn_id it needs to be added to the correct async_entry wq.
+ * Below defined cid_to_async_cri_map is used to reterive the
+ * async_cri_map for a particular connection.
+ *
+ * This array is initialized after beiscsi_create_wrb_rings returns.
+ *
+ * - this method takes more memory space, fixed to 2K
+ * - any support for connections greater than this the array size needs
+ * to be incremented
+ */
#define BE_GET_ASYNC_CRI_FROM_CID(cid) (pasync_ctx->cid_to_async_cri_map[cid])
unsigned short cid_to_async_cri_map[BE_MAX_SESSION];
/**
- * This is a varying size list! Do not add anything
- * after this entry!!
+ * This is a variable size array. Don`t add anything after this field!!
*/
- struct hwi_async_entry *async_entry;
+ struct hd_async_entry *async_entry;
};
-#define PDUCQE_CODE_MASK 0x0000003F
-#define PDUCQE_DPL_MASK 0xFFFF0000
-#define PDUCQE_INDEX_MASK 0x0000FFFF
-
struct i_t_dpdu_cqe {
u32 dw[4];
} __packed;
@@ -845,7 +862,6 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
-void beiscsi_process_all_cqs(struct work_struct *work);
void beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
struct iscsi_task *task);
@@ -856,11 +872,6 @@ void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget);
void beiscsi_process_mcc_cq(struct beiscsi_hba *phba);
-static inline bool beiscsi_error(struct beiscsi_hba *phba)
-{
- return phba->ue_detected || phba->fw_timeout;
-}
-
struct pdu_nop_out {
u32 dw[12];
};
@@ -1067,11 +1078,18 @@ struct hwi_context_memory {
struct be_queue_info be_cq[MAX_CPUS - 1];
struct be_queue_info *be_wrbq;
+ /**
+ * Create array of ULP number for below entries as DEFQ
+ * will be created for both ULP if iSCSI Protocol is
+ * loaded on both ULP.
+ */
struct be_queue_info be_def_hdrq[BEISCSI_ULP_COUNT];
struct be_queue_info be_def_dataq[BEISCSI_ULP_COUNT];
- struct hwi_async_pdu_context *pasync_ctx[BEISCSI_ULP_COUNT];
+ struct hd_async_context *pasync_ctx[BEISCSI_ULP_COUNT];
};
+void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle);
+
/* Logging related definitions */
#define BEISCSI_LOG_INIT 0x0001 /* Initialization events */
#define BEISCSI_LOG_MBOX 0x0002 /* Mailbox Events */
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 83926e221f1e..aebc4ddb3060 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,10 +7,10 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com)
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -24,139 +24,9 @@
#include "be_iscsi.h"
#include "be_main.h"
-/* UE Status Low CSR */
-static const char * const desc_ue_status_low[] = {
- "CEV",
- "CTX",
- "DBUF",
- "ERX",
- "Host",
- "MPU",
- "NDMA",
- "PTC ",
- "RDMA ",
- "RXF ",
- "RXIPS ",
- "RXULP0 ",
- "RXULP1 ",
- "RXULP2 ",
- "TIM ",
- "TPOST ",
- "TPRE ",
- "TXIPS ",
- "TXULP0 ",
- "TXULP1 ",
- "UC ",
- "WDMA ",
- "TXULP2 ",
- "HOST1 ",
- "P0_OB_LINK ",
- "P1_OB_LINK ",
- "HOST_GPIO ",
- "MBOX ",
- "AXGMAC0",
- "AXGMAC1",
- "JTAG",
- "MPU_INTPEND"
-};
-
-/* UE Status High CSR */
-static const char * const desc_ue_status_hi[] = {
- "LPCMEMHOST",
- "MGMT_MAC",
- "PCS0ONLINE",
- "MPU_IRAM",
- "PCS1ONLINE",
- "PCTL0",
- "PCTL1",
- "PMEM",
- "RR",
- "TXPB",
- "RXPP",
- "XAUI",
- "TXP",
- "ARM",
- "IPC",
- "HOST2",
- "HOST3",
- "HOST4",
- "HOST5",
- "HOST6",
- "HOST7",
- "HOST8",
- "HOST9",
- "NETC",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown"
-};
-
-/*
- * beiscsi_ue_detec()- Detect Unrecoverable Error on adapter
- * @phba: Driver priv structure
- *
- * Read registers linked to UE and check for the UE status
- **/
-void beiscsi_ue_detect(struct beiscsi_hba *phba)
-{
- uint32_t ue_hi = 0, ue_lo = 0;
- uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
- uint8_t i = 0;
-
- if (phba->ue_detected)
- return;
-
- pci_read_config_dword(phba->pcidev,
- PCICFG_UE_STATUS_LOW, &ue_lo);
- pci_read_config_dword(phba->pcidev,
- PCICFG_UE_STATUS_MASK_LOW,
- &ue_mask_lo);
- pci_read_config_dword(phba->pcidev,
- PCICFG_UE_STATUS_HIGH,
- &ue_hi);
- pci_read_config_dword(phba->pcidev,
- PCICFG_UE_STATUS_MASK_HI,
- &ue_mask_hi);
-
- ue_lo = (ue_lo & ~ue_mask_lo);
- ue_hi = (ue_hi & ~ue_mask_hi);
-
-
- if (ue_lo || ue_hi) {
- phba->ue_detected = true;
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BG_%d : Error detected on the adapter\n");
- }
-
- if (ue_lo) {
- for (i = 0; ue_lo; ue_lo >>= 1, i++) {
- if (ue_lo & 1)
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG,
- "BG_%d : UE_LOW %s bit set\n",
- desc_ue_status_low[i]);
- }
- }
-
- if (ue_hi) {
- for (i = 0; ue_hi; ue_hi >>= 1, i++) {
- if (ue_hi & 1)
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG,
- "BG_%d : UE_HIGH %s bit set\n",
- desc_ue_status_hi[i]);
- }
- }
-}
-
-int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
- struct be_set_eqd *set_eqd, int num)
+int beiscsi_modify_eq_delay(struct beiscsi_hba *phba,
+ struct be_set_eqd *set_eqd,
+ int num)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
@@ -174,7 +44,7 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
+ OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
req->num_eq = cpu_to_le32(num);
for (i = 0; i < num; i++) {
@@ -184,386 +54,13 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
cpu_to_le32(set_eqd[i].delay_multiplier);
}
+ /* ignore the completion of this mbox command */
+ set_bit(MCC_TAG_STATE_IGNORE, &ctrl->ptag_state[tag].tag_state);
be_mcc_notify(phba, tag);
mutex_unlock(&ctrl->mbox_lock);
return tag;
}
-/**
- * mgmt_reopen_session()- Reopen a session based on reopen_type
- * @phba: Device priv structure instance
- * @reopen_type: Type of reopen_session FW should do.
- * @sess_handle: Session Handle of the session to be re-opened
- *
- * return
- * the TAG used for MBOX Command
- *
- **/
-unsigned int mgmt_reopen_session(struct beiscsi_hba *phba,
- unsigned int reopen_type,
- unsigned int sess_handle)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct be_cmd_reopen_session_req *req;
- unsigned int tag;
-
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BG_%d : In bescsi_get_boot_target\n");
-
- mutex_lock(&ctrl->mbox_lock);
- wrb = alloc_mcc_wrb(phba, &tag);
- if (!wrb) {
- mutex_unlock(&ctrl->mbox_lock);
- return 0;
- }
-
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
- OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS,
- sizeof(struct be_cmd_reopen_session_resp));
-
- /* set the reopen_type,sess_handle */
- req->reopen_type = reopen_type;
- req->session_handle = sess_handle;
-
- be_mcc_notify(phba, tag);
- mutex_unlock(&ctrl->mbox_lock);
- return tag;
-}
-
-unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct be_cmd_get_boot_target_req *req;
- unsigned int tag;
-
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BG_%d : In bescsi_get_boot_target\n");
-
- mutex_lock(&ctrl->mbox_lock);
- wrb = alloc_mcc_wrb(phba, &tag);
- if (!wrb) {
- mutex_unlock(&ctrl->mbox_lock);
- return 0;
- }
-
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
- OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
- sizeof(struct be_cmd_get_boot_target_resp));
-
- be_mcc_notify(phba, tag);
- mutex_unlock(&ctrl->mbox_lock);
- return tag;
-}
-
-unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
- u32 boot_session_handle,
- struct be_dma_mem *nonemb_cmd)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- unsigned int tag;
- struct be_cmd_get_session_req *req;
- struct be_cmd_get_session_resp *resp;
- struct be_sge *sge;
-
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BG_%d : In beiscsi_get_session_info\n");
-
- mutex_lock(&ctrl->mbox_lock);
- wrb = alloc_mcc_wrb(phba, &tag);
- if (!wrb) {
- mutex_unlock(&ctrl->mbox_lock);
- return 0;
- }
-
- nonemb_cmd->size = sizeof(*resp);
- req = nonemb_cmd->va;
- memset(req, 0, sizeof(*req));
- sge = nonembedded_sgl(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
- OPCODE_ISCSI_INI_SESSION_GET_A_SESSION,
- sizeof(*resp));
- req->session_handle = boot_session_handle;
- sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
- sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
- sge->len = cpu_to_le32(nonemb_cmd->size);
-
- be_mcc_notify(phba, tag);
- mutex_unlock(&ctrl->mbox_lock);
- return tag;
-}
-
-/**
- * mgmt_get_port_name()- Get port name for the function
- * @ctrl: ptr to Ctrl Info
- * @phba: ptr to the dev priv structure
- *
- * Get the alphanumeric character for port
- *
- **/
-int mgmt_get_port_name(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba)
-{
- int ret = 0;
- struct be_mcc_wrb *wrb;
- struct be_cmd_get_port_name *ioctl;
-
- mutex_lock(&ctrl->mbox_lock);
- wrb = wrb_from_mbox(&ctrl->mbox_mem);
- memset(wrb, 0, sizeof(*wrb));
- ioctl = embedded_payload(wrb);
-
- be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0);
- be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_GET_PORT_NAME,
- EMBED_MBX_MAX_PAYLOAD_SIZE);
- ret = be_mbox_notify(ctrl);
- phba->port_name = 0;
- if (!ret) {
- phba->port_name = ioctl->p.resp.port_names >>
- (phba->fw_config.phys_port * 8) & 0xff;
- } else {
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n",
- ret, ioctl->h.resp_hdr.status);
- }
-
- if (phba->port_name == 0)
- phba->port_name = '?';
-
- mutex_unlock(&ctrl->mbox_lock);
- return ret;
-}
-
-/**
- * mgmt_get_fw_config()- Get the FW config for the function
- * @ctrl: ptr to Ctrl Info
- * @phba: ptr to the dev priv structure
- *
- * Get the FW config and resources available for the function.
- * The resources are created based on the count received here.
- *
- * return
- * Success: 0
- * Failure: Non-Zero Value
- **/
-int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba)
-{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_fw_cfg *pfw_cfg = embedded_payload(wrb);
- uint32_t cid_count, icd_count;
- int status = -EINVAL;
- uint8_t ulp_num = 0;
-
- mutex_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
- be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0);
-
- be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
- EMBED_MBX_MAX_PAYLOAD_SIZE);
-
- if (be_mbox_notify(ctrl)) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : Failed in mgmt_get_fw_config\n");
- goto fail_init;
- }
-
- /* FW response formats depend on port id */
- phba->fw_config.phys_port = pfw_cfg->phys_port;
- if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : invalid physical port id %d\n",
- phba->fw_config.phys_port);
- goto fail_init;
- }
-
- /* populate and check FW config against min and max values */
- if (!is_chip_be2_be3r(phba)) {
- phba->fw_config.eqid_count = pfw_cfg->eqid_count;
- phba->fw_config.cqid_count = pfw_cfg->cqid_count;
- if (phba->fw_config.eqid_count == 0 ||
- phba->fw_config.eqid_count > 2048) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : invalid EQ count %d\n",
- phba->fw_config.eqid_count);
- goto fail_init;
- }
- if (phba->fw_config.cqid_count == 0 ||
- phba->fw_config.cqid_count > 4096) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : invalid CQ count %d\n",
- phba->fw_config.cqid_count);
- goto fail_init;
- }
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : EQ_Count : %d CQ_Count : %d\n",
- phba->fw_config.eqid_count,
- phba->fw_config.cqid_count);
- }
-
- /**
- * Check on which all ULP iSCSI Protocol is loaded.
- * Set the Bit for those ULP. This set flag is used
- * at all places in the code to check on which ULP
- * iSCSi Protocol is loaded
- **/
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
- if (pfw_cfg->ulp[ulp_num].ulp_mode &
- BEISCSI_ULP_ISCSI_INI_MODE) {
- set_bit(ulp_num, &phba->fw_config.ulp_supported);
-
- /* Get the CID, ICD and Chain count for each ULP */
- phba->fw_config.iscsi_cid_start[ulp_num] =
- pfw_cfg->ulp[ulp_num].sq_base;
- phba->fw_config.iscsi_cid_count[ulp_num] =
- pfw_cfg->ulp[ulp_num].sq_count;
-
- phba->fw_config.iscsi_icd_start[ulp_num] =
- pfw_cfg->ulp[ulp_num].icd_base;
- phba->fw_config.iscsi_icd_count[ulp_num] =
- pfw_cfg->ulp[ulp_num].icd_count;
-
- phba->fw_config.iscsi_chain_start[ulp_num] =
- pfw_cfg->chain_icd[ulp_num].chain_base;
- phba->fw_config.iscsi_chain_count[ulp_num] =
- pfw_cfg->chain_icd[ulp_num].chain_count;
-
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : Function loaded on ULP : %d\n"
- "\tiscsi_cid_count : %d\n"
- "\tiscsi_cid_start : %d\n"
- "\t iscsi_icd_count : %d\n"
- "\t iscsi_icd_start : %d\n",
- ulp_num,
- phba->fw_config.
- iscsi_cid_count[ulp_num],
- phba->fw_config.
- iscsi_cid_start[ulp_num],
- phba->fw_config.
- iscsi_icd_count[ulp_num],
- phba->fw_config.
- iscsi_icd_start[ulp_num]);
- }
- }
-
- if (phba->fw_config.ulp_supported == 0) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 %x\n",
- pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode,
- pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode);
- goto fail_init;
- }
-
- /**
- * ICD is shared among ULPs. Use icd_count of any one loaded ULP
- **/
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
- if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
- break;
- icd_count = phba->fw_config.iscsi_icd_count[ulp_num];
- if (icd_count == 0 || icd_count > 65536) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d: invalid ICD count %d\n", icd_count);
- goto fail_init;
- }
-
- cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) +
- BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1);
- if (cid_count == 0 || cid_count > 4096) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d: invalid CID count %d\n", cid_count);
- goto fail_init;
- }
-
- /**
- * Check FW is dual ULP aware i.e. can handle either
- * of the protocols.
- */
- phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
- BEISCSI_FUNC_DUA_MODE);
-
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : DUA Mode : 0x%x\n",
- phba->fw_config.dual_ulp_aware);
-
- /* all set, continue using this FW config */
- status = 0;
-fail_init:
- mutex_unlock(&ctrl->mbox_lock);
- return status;
-}
-
-int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba)
-{
- struct be_dma_mem nonemb_cmd;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_mgmt_controller_attributes *req;
- struct be_sge *sge = nonembedded_sgl(wrb);
- int status = 0;
-
- nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
- sizeof(struct be_mgmt_controller_attributes),
- &nonemb_cmd.dma);
- if (nonemb_cmd.va == NULL) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : Failed to allocate memory for "
- "mgmt_check_supported_fw\n");
- return -ENOMEM;
- }
- nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
- req = nonemb_cmd.va;
- memset(req, 0, sizeof(*req));
- mutex_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req));
- sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
- sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
- sge->len = cpu_to_le32(nonemb_cmd.size);
- status = be_mbox_notify(ctrl);
- if (!status) {
- struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va;
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : Firmware Version of CMD : %s\n"
- "Firmware Version is : %s\n"
- "Developer Build, not performing version check...\n",
- resp->params.hba_attribs
- .flashrom_version_string,
- resp->params.hba_attribs.
- firmware_version_string);
-
- phba->fw_config.iscsi_features =
- resp->params.hba_attribs.iscsi_features;
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BM_%d : phba->fw_config.iscsi_features = %d\n",
- phba->fw_config.iscsi_features);
- memcpy(phba->fw_ver_str, resp->params.hba_attribs.
- firmware_version_string, BEISCSI_VER_STRLEN);
- } else
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : Failed in mgmt_check_supported_fw\n");
- mutex_unlock(&ctrl->mbox_lock);
- if (nonemb_cmd.va)
- pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
-
- return status;
-}
-
unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba,
struct bsg_job *job,
@@ -609,7 +106,7 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
bsg_req->rqst_data.h_vendor.vendor_cmd[0]);
mutex_unlock(&ctrl->mbox_lock);
- return -ENOSYS;
+ return -EPERM;
}
wrb = alloc_mcc_wrb(phba, &tag);
@@ -631,48 +128,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
return tag;
}
-/**
- * mgmt_epfw_cleanup()- Inform FW to cleanup data structures.
- * @phba: pointer to dev priv structure
- * @ulp_num: ULP number.
- *
- * return
- * Success: 0
- * Failure: Non-Zero Value
- **/
-int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct iscsi_cleanup_req *req;
- unsigned int tag;
- int status;
-
- mutex_lock(&ctrl->mbox_lock);
- wrb = alloc_mcc_wrb(phba, &tag);
- if (!wrb) {
- mutex_unlock(&ctrl->mbox_lock);
- return -EBUSY;
- }
-
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
- OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
-
- req->chute = (1 << ulp_num);
- req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, ulp_num));
- req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, ulp_num));
-
- be_mcc_notify(phba, tag);
- status = be_mcc_compl_poll(phba, tag);
- if (status)
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT,
- "BG_%d : mgmt_epfw_cleanup , FAILED\n");
- mutex_unlock(&ctrl->mbox_lock);
- return status;
-}
-
unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct invalidate_command_table *inv_tbl,
unsigned int num_invalidate, unsigned int cid,
@@ -844,7 +299,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
nonemb_cmd->size);
if (dst_addr->sa_family == PF_INET) {
__be32 s_addr = daddr_in->sin_addr.s_addr;
- req->ip_address.ip_type = BE2_IPV4;
+ req->ip_address.ip_type = BEISCSI_IP_TYPE_V4;
req->ip_address.addr[0] = s_addr & 0x000000ff;
req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8;
req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16;
@@ -852,17 +307,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
req->tcp_port = ntohs(daddr_in->sin_port);
beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
- beiscsi_ep->ip_type = BE2_IPV4;
+ beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V4;
} else {
/* else its PF_INET6 family */
- req->ip_address.ip_type = BE2_IPV6;
+ req->ip_address.ip_type = BEISCSI_IP_TYPE_V6;
memcpy(&req->ip_address.addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
req->tcp_port = ntohs(daddr_in6->sin6_port);
beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port);
memcpy(&beiscsi_ep->dst6_addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
- beiscsi_ep->ip_type = BE2_IPV6;
+ beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V6;
}
req->cid = cid;
i = phba->nxt_cqid++;
@@ -883,7 +338,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
if (!is_chip_be2_be3r(phba)) {
req->hdr.version = MBX_CMD_VER1;
- req->tcp_window_size = 0;
+ req->tcp_window_size = 0x8000;
req->tcp_window_scale_count = 2;
}
@@ -892,44 +347,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
return tag;
}
-unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct be_cmd_get_all_if_id_req *req;
- struct be_cmd_get_all_if_id_req *pbe_allid;
- unsigned int tag;
- int status = 0;
-
- if (mutex_lock_interruptible(&ctrl->mbox_lock))
- return -EINTR;
- wrb = alloc_mcc_wrb(phba, &tag);
- if (!wrb) {
- mutex_unlock(&ctrl->mbox_lock);
- return -ENOMEM;
- }
-
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
- OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
- sizeof(*req));
- be_mcc_notify(phba, tag);
- mutex_unlock(&ctrl->mbox_lock);
-
- status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
- if (status) {
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BG_%d : Failed in mgmt_get_all_if_id\n");
- return -EBUSY;
- }
-
- pbe_allid = embedded_payload(wrb);
- phba->interface_handle = pbe_allid->if_hndl_list[0];
-
- return status;
-}
-
/*
* mgmt_exec_nonemb_cmd()- Execute Non Embedded MBX Cmd
* @phba: Driver priv structure
@@ -1001,72 +418,68 @@ static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd,
}
cmd->size = size;
be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size);
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BG_%d : subsystem iSCSI cmd %d size %d\n",
+ iscsi_cmd, size);
return 0;
}
-static int
-mgmt_static_ip_modify(struct beiscsi_hba *phba,
- struct be_cmd_get_if_info_resp *if_info,
- struct iscsi_iface_param_info *ip_param,
- struct iscsi_iface_param_info *subnet_param,
- uint32_t ip_action)
+unsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba)
{
- struct be_cmd_set_ip_addr_req *req;
- struct be_dma_mem nonemb_cmd;
- uint32_t ip_type;
- int rc;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_all_if_id_req *req;
+ struct be_cmd_get_all_if_id_req *pbe_allid;
+ unsigned int tag;
+ int status = 0;
- rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
- OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
- sizeof(*req));
- if (rc)
- return rc;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return -EINTR;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return -ENOMEM;
+ }
- ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
- BE2_IPV6 : BE2_IPV4 ;
+ req = embedded_payload(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
+ sizeof(*req));
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
- req = nonemb_cmd.va;
- req->ip_params.record_entry_count = 1;
- req->ip_params.ip_record.action = ip_action;
- req->ip_params.ip_record.interface_hndl =
- phba->interface_handle;
- req->ip_params.ip_record.ip_addr.size_of_structure =
- sizeof(struct be_ip_addr_subnet_format);
- req->ip_params.ip_record.ip_addr.ip_type = ip_type;
+ status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
+ if (status) {
+ beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
+ "BG_%d : %s failed: %d\n", __func__, status);
+ return -EBUSY;
+ }
- if (ip_action == IP_ACTION_ADD) {
- memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value,
- sizeof(req->ip_params.ip_record.ip_addr.addr));
+ pbe_allid = embedded_payload(wrb);
+ /* we now support only one interface per function */
+ phba->interface_handle = pbe_allid->if_hndl_list[0];
- if (subnet_param)
- memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
- subnet_param->value,
- sizeof(req->ip_params.ip_record.ip_addr.subnet_mask));
- } else {
- memcpy(req->ip_params.ip_record.ip_addr.addr,
- if_info->ip_addr.addr,
- sizeof(req->ip_params.ip_record.ip_addr.addr));
+ return status;
+}
- memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
- if_info->ip_addr.subnet_mask,
- sizeof(req->ip_params.ip_record.ip_addr.subnet_mask));
- }
+static inline bool beiscsi_if_zero_ip(u8 *ip, u32 ip_type)
+{
+ u32 len;
- rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
- if (rc < 0)
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BG_%d : Failed to Modify existing IP Address\n");
- return rc;
+ len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN;
+ while (len && !ip[len - 1])
+ len--;
+ return (len == 0);
}
-static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr,
- uint32_t gtway_action, uint32_t param_len)
+static int beiscsi_if_mod_gw(struct beiscsi_hba *phba,
+ u32 action, u32 ip_type, u8 *gw)
{
struct be_cmd_set_def_gateway_req *req;
struct be_dma_mem nonemb_cmd;
int rt_val;
-
rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY,
sizeof(*req));
@@ -1074,200 +487,300 @@ static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr,
return rt_val;
req = nonemb_cmd.va;
- req->action = gtway_action;
- req->ip_addr.ip_type = BE2_IPV4;
+ req->action = action;
+ req->ip_addr.ip_type = ip_type;
+ memcpy(req->ip_addr.addr, gw,
+ (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN);
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+}
- memcpy(req->ip_addr.addr, gt_addr, sizeof(req->ip_addr.addr));
+int beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw)
+{
+ struct be_cmd_get_def_gateway_resp gw_resp;
+ int rt_val;
- return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ memset(&gw_resp, 0, sizeof(gw_resp));
+ rt_val = beiscsi_if_get_gw(phba, ip_type, &gw_resp);
+ if (rt_val) {
+ beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
+ "BG_%d : Failed to Get Gateway Addr\n");
+ return rt_val;
+ }
+
+ if (!beiscsi_if_zero_ip(gw_resp.ip_addr.addr, ip_type)) {
+ rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, ip_type,
+ gw_resp.ip_addr.addr);
+ if (rt_val) {
+ beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
+ "BG_%d : Failed to clear Gateway Addr Set\n");
+ return rt_val;
+ }
+ }
+
+ rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_ADD, ip_type, gw);
+ if (rt_val)
+ beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
+ "BG_%d : Failed to Set Gateway Addr\n");
+
+ return rt_val;
}
-int mgmt_set_ip(struct beiscsi_hba *phba,
- struct iscsi_iface_param_info *ip_param,
- struct iscsi_iface_param_info *subnet_param,
- uint32_t boot_proto)
+int beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type,
+ struct be_cmd_get_def_gateway_resp *resp)
{
- struct be_cmd_get_def_gateway_resp gtway_addr_set;
- struct be_cmd_get_if_info_resp *if_info;
- struct be_cmd_set_dhcp_req *dhcpreq;
- struct be_cmd_rel_dhcp_req *reldhcp;
+ struct be_cmd_get_def_gateway_req *req;
struct be_dma_mem nonemb_cmd;
- uint8_t *gtway_addr;
- uint32_t ip_type;
int rc;
- rc = mgmt_get_all_if_id(phba);
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY,
+ sizeof(*resp));
if (rc)
return rc;
- ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
- BE2_IPV6 : BE2_IPV4 ;
+ req = nonemb_cmd.va;
+ req->ip_type = ip_type;
+
+ return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, resp,
+ sizeof(*resp));
+}
+
+static int
+beiscsi_if_clr_ip(struct beiscsi_hba *phba,
+ struct be_cmd_get_if_info_resp *if_info)
+{
+ struct be_cmd_set_ip_addr_req *req;
+ struct be_dma_mem nonemb_cmd;
+ int rc;
- rc = mgmt_get_if_info(phba, ip_type, &if_info);
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
+ sizeof(*req));
if (rc)
return rc;
- if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
- if (if_info->dhcp_state) {
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BG_%d : DHCP Already Enabled\n");
- goto exit;
- }
- /* The ip_param->len is 1 in DHCP case. Setting
- proper IP len as this it is used while
- freeing the Static IP.
- */
- ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
- IP_V6_LEN : IP_V4_LEN;
-
- } else {
- if (if_info->dhcp_state) {
+ req = nonemb_cmd.va;
+ req->ip_params.record_entry_count = 1;
+ req->ip_params.ip_record.action = IP_ACTION_DEL;
+ req->ip_params.ip_record.interface_hndl =
+ phba->interface_handle;
+ req->ip_params.ip_record.ip_addr.size_of_structure =
+ sizeof(struct be_ip_addr_subnet_format);
+ req->ip_params.ip_record.ip_addr.ip_type = if_info->ip_addr.ip_type;
+ memcpy(req->ip_params.ip_record.ip_addr.addr,
+ if_info->ip_addr.addr,
+ sizeof(if_info->ip_addr.addr));
+ memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
+ if_info->ip_addr.subnet_mask,
+ sizeof(if_info->ip_addr.subnet_mask));
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ if (rc < 0 || req->ip_params.ip_record.status) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BG_%d : failed to clear IP: rc %d status %d\n",
+ rc, req->ip_params.ip_record.status);
+ }
+ return rc;
+}
- memset(if_info, 0, sizeof(*if_info));
- rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
- OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR,
- sizeof(*reldhcp));
+static int
+beiscsi_if_set_ip(struct beiscsi_hba *phba, u8 *ip,
+ u8 *subnet, u32 ip_type)
+{
+ struct be_cmd_set_ip_addr_req *req;
+ struct be_dma_mem nonemb_cmd;
+ uint32_t ip_len;
+ int rc;
- if (rc)
- goto exit;
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR,
+ sizeof(*req));
+ if (rc)
+ return rc;
- reldhcp = nonemb_cmd.va;
- reldhcp->interface_hndl = phba->interface_handle;
- reldhcp->ip_type = ip_type;
+ req = nonemb_cmd.va;
+ req->ip_params.record_entry_count = 1;
+ req->ip_params.ip_record.action = IP_ACTION_ADD;
+ req->ip_params.ip_record.interface_hndl =
+ phba->interface_handle;
+ req->ip_params.ip_record.ip_addr.size_of_structure =
+ sizeof(struct be_ip_addr_subnet_format);
+ req->ip_params.ip_record.ip_addr.ip_type = ip_type;
+ ip_len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN;
+ memcpy(req->ip_params.ip_record.ip_addr.addr, ip, ip_len);
+ if (subnet)
+ memcpy(req->ip_params.ip_record.ip_addr.subnet_mask,
+ subnet, ip_len);
- rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
- if (rc < 0) {
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_CONFIG,
- "BG_%d : Failed to Delete existing dhcp\n");
- goto exit;
- }
- }
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ /**
+ * In some cases, host needs to look into individual record status
+ * even though FW reported success for that IOCTL.
+ */
+ if (rc < 0 || req->ip_params.ip_record.status) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BG_%d : failed to set IP: rc %d status %d\n",
+ rc, req->ip_params.ip_record.status);
+ if (req->ip_params.ip_record.status)
+ rc = -EINVAL;
}
+ return rc;
+}
- /* Delete the Static IP Set */
- if (if_info->ip_addr.addr[0]) {
- rc = mgmt_static_ip_modify(phba, if_info, ip_param, NULL,
- IP_ACTION_DEL);
+int beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type,
+ u8 *ip, u8 *subnet)
+{
+ struct be_cmd_get_if_info_resp *if_info;
+ struct be_cmd_rel_dhcp_req *reldhcp;
+ struct be_dma_mem nonemb_cmd;
+ int rc;
+
+ rc = beiscsi_if_get_info(phba, ip_type, &if_info);
+ if (rc)
+ return rc;
+
+ if (if_info->dhcp_state) {
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR,
+ sizeof(*reldhcp));
if (rc)
goto exit;
- }
- /* Delete the Gateway settings if mode change is to DHCP */
- if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
- memset(&gtway_addr_set, 0, sizeof(gtway_addr_set));
- rc = mgmt_get_gateway(phba, BE2_IPV4, &gtway_addr_set);
- if (rc) {
+ reldhcp = nonemb_cmd.va;
+ reldhcp->interface_hndl = phba->interface_handle;
+ reldhcp->ip_type = ip_type;
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
+ if (rc < 0) {
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BG_%d : Failed to Get Gateway Addr\n");
+ "BG_%d : failed to release existing DHCP: %d\n",
+ rc);
goto exit;
}
-
- if (gtway_addr_set.ip_addr.addr[0]) {
- gtway_addr = (uint8_t *)&gtway_addr_set.ip_addr.addr;
- rc = mgmt_modify_gateway(phba, gtway_addr,
- IP_ACTION_DEL, IP_V4_LEN);
-
- if (rc) {
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_CONFIG,
- "BG_%d : Failed to clear Gateway Addr Set\n");
- goto exit;
- }
- }
}
- /* Set Adapter to DHCP/Static Mode */
- if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
- rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
- OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR,
- sizeof(*dhcpreq));
+ /* first delete any IP set */
+ if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) {
+ rc = beiscsi_if_clr_ip(phba, if_info);
if (rc)
goto exit;
-
- dhcpreq = nonemb_cmd.va;
- dhcpreq->flags = BLOCKING;
- dhcpreq->retry_count = 1;
- dhcpreq->interface_hndl = phba->interface_handle;
- dhcpreq->ip_type = BE2_DHCP_V4;
-
- rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
- } else {
- rc = mgmt_static_ip_modify(phba, if_info, ip_param,
- subnet_param, IP_ACTION_ADD);
}
+ /* if ip == NULL then this is called just to release DHCP IP */
+ if (ip)
+ rc = beiscsi_if_set_ip(phba, ip, subnet, ip_type);
exit:
kfree(if_info);
return rc;
}
-int mgmt_set_gateway(struct beiscsi_hba *phba,
- struct iscsi_iface_param_info *gateway_param)
+int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type)
{
- struct be_cmd_get_def_gateway_resp gtway_addr_set;
- uint8_t *gtway_addr;
- int rt_val;
+ struct be_cmd_get_def_gateway_resp gw_resp;
+ struct be_cmd_get_if_info_resp *if_info;
+ struct be_cmd_set_dhcp_req *dhcpreq;
+ struct be_dma_mem nonemb_cmd;
+ u8 *gw;
+ int rc;
- memset(&gtway_addr_set, 0, sizeof(gtway_addr_set));
- rt_val = mgmt_get_gateway(phba, BE2_IPV4, &gtway_addr_set);
- if (rt_val) {
+ rc = beiscsi_if_get_info(phba, ip_type, &if_info);
+ if (rc)
+ return rc;
+
+ if (if_info->dhcp_state) {
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BG_%d : Failed to Get Gateway Addr\n");
- return rt_val;
+ "BG_%d : DHCP Already Enabled\n");
+ goto exit;
}
- if (gtway_addr_set.ip_addr.addr[0]) {
- gtway_addr = (uint8_t *)&gtway_addr_set.ip_addr.addr;
- rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL,
- gateway_param->len);
- if (rt_val) {
+ /* first delete any IP set */
+ if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) {
+ rc = beiscsi_if_clr_ip(phba, if_info);
+ if (rc)
+ goto exit;
+ }
+
+ /* delete gateway settings if mode change is to DHCP */
+ memset(&gw_resp, 0, sizeof(gw_resp));
+ /* use ip_type provided in if_info */
+ rc = beiscsi_if_get_gw(phba, if_info->ip_addr.ip_type, &gw_resp);
+ if (rc) {
+ beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
+ "BG_%d : Failed to Get Gateway Addr\n");
+ goto exit;
+ }
+ gw = (u8 *)&gw_resp.ip_addr.addr;
+ if (!beiscsi_if_zero_ip(gw, if_info->ip_addr.ip_type)) {
+ rc = beiscsi_if_mod_gw(phba, IP_ACTION_DEL,
+ if_info->ip_addr.ip_type, gw);
+ if (rc) {
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
"BG_%d : Failed to clear Gateway Addr Set\n");
- return rt_val;
+ goto exit;
}
}
- gtway_addr = (uint8_t *)&gateway_param->value;
- rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD,
- gateway_param->len);
+ rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+ OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR,
+ sizeof(*dhcpreq));
+ if (rc)
+ goto exit;
- if (rt_val)
- beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BG_%d : Failed to Set Gateway Addr\n");
+ dhcpreq = nonemb_cmd.va;
+ dhcpreq->flags = 1; /* 1 - blocking; 0 - non-blocking */
+ dhcpreq->retry_count = 1;
+ dhcpreq->interface_hndl = phba->interface_handle;
+ dhcpreq->ip_type = ip_type;
+ rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
- return rt_val;
+exit:
+ kfree(if_info);
+ return rc;
}
-int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
- struct be_cmd_get_def_gateway_resp *gateway)
+/**
+ * beiscsi_if_set_vlan()- Issue and wait for CMD completion
+ * @phba: device private structure instance
+ * @vlan_tag: VLAN tag
+ *
+ * Issue the MBX Cmd and wait for the completion of the
+ * command.
+ *
+ * returns
+ * Success: 0
+ * Failure: Non-Xero Value
+ **/
+int beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag)
{
- struct be_cmd_get_def_gateway_req *req;
- struct be_dma_mem nonemb_cmd;
int rc;
+ unsigned int tag;
- rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
- OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY,
- sizeof(*gateway));
- if (rc)
- return rc;
-
- req = nonemb_cmd.va;
- req->ip_type = ip_type;
+ tag = be_cmd_set_vlan(phba, vlan_tag);
+ if (!tag) {
+ beiscsi_log(phba, KERN_ERR,
+ (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
+ "BG_%d : VLAN Setting Failed\n");
+ return -EBUSY;
+ }
- return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway,
- sizeof(*gateway));
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
+ if (rc) {
+ beiscsi_log(phba, KERN_ERR,
+ (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
+ "BS_%d : VLAN MBX Cmd Failed\n");
+ return rc;
+ }
+ return rc;
}
-int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
- struct be_cmd_get_if_info_resp **if_info)
+
+int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_if_info_resp **if_info)
{
struct be_cmd_get_if_info_req *req;
struct be_dma_mem nonemb_cmd;
uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp);
int rc;
- rc = mgmt_get_all_if_id(phba);
+ rc = beiscsi_if_get_handle(phba);
if (rc)
return rc;
@@ -1364,123 +877,317 @@ unsigned int be_cmd_get_initname(struct beiscsi_hba *phba)
return tag;
}
+static void beiscsi_boot_process_compl(struct beiscsi_hba *phba,
+ unsigned int tag)
+{
+ struct be_cmd_get_boot_target_resp *boot_resp;
+ struct be_cmd_resp_logout_fw_sess *logo_resp;
+ struct be_cmd_get_session_resp *sess_resp;
+ struct be_mcc_wrb *wrb;
+ struct boot_struct *bs;
+ int boot_work, status;
+
+ if (!test_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BG_%d : %s no boot work %lx\n",
+ __func__, phba->state);
+ return;
+ }
+
+ if (phba->boot_struct.tag != tag) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BG_%d : %s tag mismatch %d:%d\n",
+ __func__, tag, phba->boot_struct.tag);
+ return;
+ }
+ bs = &phba->boot_struct;
+ boot_work = 1;
+ status = 0;
+ switch (bs->action) {
+ case BEISCSI_BOOT_REOPEN_SESS:
+ status = __beiscsi_mcc_compl_status(phba, tag, NULL, NULL);
+ if (!status)
+ bs->action = BEISCSI_BOOT_GET_SHANDLE;
+ else
+ bs->retry--;
+ break;
+ case BEISCSI_BOOT_GET_SHANDLE:
+ status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL);
+ if (!status) {
+ boot_resp = embedded_payload(wrb);
+ bs->s_handle = boot_resp->boot_session_handle;
+ }
+ if (bs->s_handle == BE_BOOT_INVALID_SHANDLE) {
+ bs->action = BEISCSI_BOOT_REOPEN_SESS;
+ bs->retry--;
+ } else {
+ bs->action = BEISCSI_BOOT_GET_SINFO;
+ }
+ break;
+ case BEISCSI_BOOT_GET_SINFO:
+ status = __beiscsi_mcc_compl_status(phba, tag, NULL,
+ &bs->nonemb_cmd);
+ if (!status) {
+ sess_resp = bs->nonemb_cmd.va;
+ memcpy(&bs->boot_sess, &sess_resp->session_info,
+ sizeof(struct mgmt_session_info));
+ bs->action = BEISCSI_BOOT_LOGOUT_SESS;
+ } else {
+ __beiscsi_log(phba, KERN_ERR,
+ "BG_%d : get boot session info error : 0x%x\n",
+ status);
+ boot_work = 0;
+ }
+ pci_free_consistent(phba->ctrl.pdev, bs->nonemb_cmd.size,
+ bs->nonemb_cmd.va, bs->nonemb_cmd.dma);
+ bs->nonemb_cmd.va = NULL;
+ break;
+ case BEISCSI_BOOT_LOGOUT_SESS:
+ status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL);
+ if (!status) {
+ logo_resp = embedded_payload(wrb);
+ if (logo_resp->session_status != BE_SESS_STATUS_CLOSE) {
+ __beiscsi_log(phba, KERN_ERR,
+ "BG_%d : FW boot session logout error : 0x%x\n",
+ logo_resp->session_status);
+ }
+ }
+ /* continue to create boot_kset even if logout failed? */
+ bs->action = BEISCSI_BOOT_CREATE_KSET;
+ break;
+ default:
+ break;
+ }
+
+ /* clear the tag so no other completion matches this tag */
+ bs->tag = 0;
+ if (!bs->retry) {
+ boot_work = 0;
+ __beiscsi_log(phba, KERN_ERR,
+ "BG_%d : failed to setup boot target: status %d action %d\n",
+ status, bs->action);
+ }
+ if (!boot_work) {
+ /* wait for next event to start boot_work */
+ clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state);
+ return;
+ }
+ schedule_work(&phba->boot_work);
+}
+
/**
- * be_mgmt_get_boot_shandle()- Get the session handle
- * @phba: device priv structure instance
- * @s_handle: session handle returned for boot session.
+ * beiscsi_boot_logout_sess()- Logout from boot FW session
+ * @phba: Device priv structure instance
*
- * Get the boot target session handle. In case of
- * crashdump mode driver has to issue and MBX Cmd
- * for FW to login to boot target
+ * return
+ * the TAG used for MBOX Command
+ *
+ */
+unsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_logout_fw_sess *req;
+ unsigned int tag;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
+ }
+
+ req = embedded_payload(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET,
+ sizeof(struct be_cmd_req_logout_fw_sess));
+ /* Use the session handle copied into boot_sess */
+ req->session_handle = phba->boot_struct.boot_sess.session_handle;
+
+ phba->boot_struct.tag = tag;
+ set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
+ ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
+
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
+
+ return tag;
+}
+/**
+ * beiscsi_boot_reopen_sess()- Reopen boot session
+ * @phba: Device priv structure instance
*
* return
- * Success: 0
- * Failure: Non-Zero value
+ * the TAG used for MBOX Command
*
**/
-int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
- unsigned int *s_handle)
+unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba)
{
- struct be_cmd_get_boot_target_resp *boot_resp;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
+ struct be_cmd_reopen_session_req *req;
unsigned int tag;
- uint8_t boot_retry = 3;
- int rc;
- do {
- /* Get the Boot Target Session Handle and Count*/
- tag = mgmt_get_boot_target(phba);
- if (!tag) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
- "BG_%d : Getting Boot Target Info Failed\n");
- return -EAGAIN;
- }
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
+ }
- rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
- if (rc) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d : MBX CMD get_boot_target Failed\n");
- return -EBUSY;
- }
+ req = embedded_payload(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS,
+ sizeof(struct be_cmd_reopen_session_resp));
+ req->reopen_type = BE_REOPEN_BOOT_SESSIONS;
+ req->session_handle = BE_BOOT_INVALID_SHANDLE;
- boot_resp = embedded_payload(wrb);
+ phba->boot_struct.tag = tag;
+ set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
+ ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
- /* Check if the there are any Boot targets configured */
- if (!boot_resp->boot_session_count) {
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d ;No boot targets configured\n");
- return -ENXIO;
- }
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
+ return tag;
+}
- /* FW returns the session handle of the boot session */
- if (boot_resp->boot_session_handle != INVALID_SESS_HANDLE) {
- *s_handle = boot_resp->boot_session_handle;
- return 0;
- }
- /* Issue MBX Cmd to FW to login to the boot target */
- tag = mgmt_reopen_session(phba, BE_REOPEN_BOOT_SESSIONS,
- INVALID_SESS_HANDLE);
- if (!tag) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d : mgmt_reopen_session Failed\n");
- return -EAGAIN;
- }
+/**
+ * beiscsi_boot_get_sinfo()- Get boot session info
+ * @phba: device priv structure instance
+ *
+ * Fetches the boot_struct.s_handle info from FW.
+ * return
+ * the TAG used for MBOX Command
+ *
+ **/
+unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_cmd_get_session_resp *resp;
+ struct be_cmd_get_session_req *req;
+ struct be_dma_mem *nonemb_cmd;
+ struct be_mcc_wrb *wrb;
+ struct be_sge *sge;
+ unsigned int tag;
- rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
- if (rc) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d : mgmt_reopen_session Failed");
- return rc;
- }
- } while (--boot_retry);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
+ }
- /* Couldn't log into the boot target */
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d : Login to Boot Target Failed\n");
- return -ENXIO;
+ nonemb_cmd = &phba->boot_struct.nonemb_cmd;
+ nonemb_cmd->size = sizeof(*resp);
+ nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev,
+ sizeof(nonemb_cmd->size),
+ &nonemb_cmd->dma);
+ if (!nonemb_cmd->va) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
+ }
+
+ req = nonemb_cmd->va;
+ memset(req, 0, sizeof(*req));
+ sge = nonembedded_sgl(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_SESSION_GET_A_SESSION,
+ sizeof(*resp));
+ req->session_handle = phba->boot_struct.s_handle;
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
+
+ phba->boot_struct.tag = tag;
+ set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
+ ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
+
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
+ return tag;
+}
+
+unsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_boot_target_req *req;
+ unsigned int tag;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
+ }
+
+ req = embedded_payload(wrb);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
+ sizeof(struct be_cmd_get_boot_target_resp));
+
+ if (async) {
+ phba->boot_struct.tag = tag;
+ set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state);
+ ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl;
+ }
+
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
+ return tag;
}
/**
- * mgmt_set_vlan()- Issue and wait for CMD completion
- * @phba: device private structure instance
- * @vlan_tag: VLAN tag
+ * beiscsi_boot_get_shandle()- Get boot session handle
+ * @phba: device priv structure instance
+ * @s_handle: session handle returned for boot session.
*
- * Issue the MBX Cmd and wait for the completion of the
- * command.
+ * return
+ * Success: 1
+ * Failure: negative
*
- * returns
- * Success: 0
- * Failure: Non-Xero Value
**/
-int mgmt_set_vlan(struct beiscsi_hba *phba,
- uint16_t vlan_tag)
+int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle)
{
- int rc;
+ struct be_cmd_get_boot_target_resp *boot_resp;
+ struct be_mcc_wrb *wrb;
unsigned int tag;
+ int rc;
- tag = be_cmd_set_vlan(phba, vlan_tag);
+ *s_handle = BE_BOOT_INVALID_SHANDLE;
+ /* get configured boot session count and handle */
+ tag = __beiscsi_boot_get_shandle(phba, 0);
if (!tag) {
beiscsi_log(phba, KERN_ERR,
- (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
- "BG_%d : VLAN Setting Failed\n");
- return -EBUSY;
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
+ "BG_%d : Getting Boot Target Info Failed\n");
+ return -EAGAIN;
}
- rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
- (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
- "BS_%d : VLAN MBX Cmd Failed\n");
- return rc;
+ BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
+ "BG_%d : MBX CMD get_boot_target Failed\n");
+ return -EBUSY;
}
- return rc;
+
+ boot_resp = embedded_payload(wrb);
+ /* check if there are any boot targets configured */
+ if (!boot_resp->boot_session_count) {
+ __beiscsi_log(phba, KERN_INFO,
+ "BG_%d : No boot targets configured\n");
+ return -ENXIO;
+ }
+
+ /* only if FW has logged in to the boot target, s_handle is valid */
+ *s_handle = boot_resp->boot_session_handle;
+ return 1;
}
/**
@@ -1645,7 +1352,6 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
{
struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
- memset(pwrb, 0, sizeof(*pwrb));
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
max_send_data_segment_length, pwrb,
params->dw[offsetof(struct amap_beiscsi_offload_params,
@@ -1717,8 +1423,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
{
struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
- memset(pwrb, 0, sizeof(*pwrb));
-
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
max_burst_length, pwrb, params->dw[offsetof
(struct amap_beiscsi_offload_params,
@@ -1790,70 +1494,3 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
(params->dw[offsetof(struct amap_beiscsi_offload_params,
exp_statsn) / 32] + 1));
}
-
-/**
- * beiscsi_logout_fw_sess()- Firmware Session Logout
- * @phba: Device priv structure instance
- * @fw_sess_handle: FW session handle
- *
- * Logout from the FW established sessions.
- * returns
- * Success: 0
- * Failure: Non-Zero Value
- *
- */
-int beiscsi_logout_fw_sess(struct beiscsi_hba *phba,
- uint32_t fw_sess_handle)
-{
- struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb;
- struct be_cmd_req_logout_fw_sess *req;
- struct be_cmd_resp_logout_fw_sess *resp;
- unsigned int tag;
- int rc;
-
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BG_%d : In bescsi_logout_fwboot_sess\n");
-
- mutex_lock(&ctrl->mbox_lock);
- wrb = alloc_mcc_wrb(phba, &tag);
- if (!wrb) {
- mutex_unlock(&ctrl->mbox_lock);
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BG_%d : MBX Tag Failure\n");
- return -EINVAL;
- }
-
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
- OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET,
- sizeof(struct be_cmd_req_logout_fw_sess));
-
- /* Set the session handle */
- req->session_handle = fw_sess_handle;
- be_mcc_notify(phba, tag);
- mutex_unlock(&ctrl->mbox_lock);
-
- rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
- if (rc) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d : MBX CMD FW_SESSION_LOGOUT_TARGET Failed\n");
- return -EBUSY;
- }
-
- resp = embedded_payload(wrb);
- if (resp->session_status !=
- BEISCSI_MGMT_SESSION_CLOSE) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
- "BG_%d : FW_SESSION_LOGOUT_TARGET resp : 0x%x\n",
- resp->session_status);
- rc = -EINVAL;
- }
-
- return rc;
-}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index f3a48a04b2ca..b897cfd57c72 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2015 Emulex
+ * Copyright (C) 2005 - 2016 Broadcom
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,10 +7,10 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohan.kallickal@avagotech.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@broadcom.com)
*
* Contact Information:
- * linux-drivers@avagotech.com
+ * linux-drivers@broadcom.com
*
* Emulex
* 3333 Susan Street
@@ -96,7 +96,6 @@ struct mcc_wrb {
struct mcc_wrb_payload payload;
};
-int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
int mgmt_open_connection(struct beiscsi_hba *phba,
struct sockaddr *dst_addr,
struct beiscsi_endpoint *beiscsi_ep,
@@ -266,50 +265,41 @@ struct beiscsi_endpoint {
u16 cid_vld;
};
-int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba);
-int mgmt_get_port_name(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba);
-
unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct beiscsi_endpoint *beiscsi_ep,
unsigned short cid,
unsigned short issue_reset,
unsigned short savecfg_flag);
-int mgmt_set_ip(struct beiscsi_hba *phba,
- struct iscsi_iface_param_info *ip_param,
- struct iscsi_iface_param_info *subnet_param,
- uint32_t boot_proto);
+int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type);
-unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba);
+int beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type,
+ u8 *ip, u8 *subnet);
-unsigned int mgmt_reopen_session(struct beiscsi_hba *phba,
- unsigned int reopen_type,
- unsigned sess_handle);
+int beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw);
-unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
- u32 boot_session_handle,
- struct be_dma_mem *nonemb_cmd);
+int beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type,
+ struct be_cmd_get_def_gateway_resp *resp);
int mgmt_get_nic_conf(struct beiscsi_hba *phba,
struct be_cmd_get_nic_conf_resp *mac);
-int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
- struct be_cmd_get_if_info_resp **if_info);
+int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type,
+ struct be_cmd_get_if_info_resp **if_info);
+
+unsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba);
+
+int beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
-int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
- struct be_cmd_get_def_gateway_resp *gateway);
+unsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba);
-int mgmt_set_gateway(struct beiscsi_hba *phba,
- struct iscsi_iface_param_info *gateway_param);
+unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba);
-int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
- unsigned int *s_handle);
+unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba);
-unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba);
+unsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async);
-int mgmt_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
+int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle);
ssize_t beiscsi_drvr_ver_disp(struct device *dev,
struct device_attribute *attr, char *buf);
@@ -339,7 +329,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
struct wrb_handle *pwrb_handle,
struct hwi_wrb_context *pwrb_context);
-void beiscsi_ue_detect(struct beiscsi_hba *phba);
int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
struct be_set_eqd *, int num);
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 7733ad5305d4..4ddda72f60e6 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -5827,13 +5827,13 @@ bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port)
bfa_port_speed_t max_speed = 0;
struct bfa_port_attr_s port_attr;
bfa_port_speed_t port_speed, rport_speed;
- bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa);
-
+ bfa_boolean_t trl_enabled;
if (port == NULL)
return 0;
fcs = port->fcs;
+ trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa);
/* Get Physical port's current speed */
bfa_fcport_get_attr(port->fcs->bfa, &port_attr);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c
index 5beea776b9f5..68ca518d34b0 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_els.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_els.c
@@ -254,7 +254,7 @@ int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp)
return rc;
}
-void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg)
+static void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg)
{
struct bnx2fc_mp_req *mp_req;
struct fc_frame_header *fc_hdr, *fh;
@@ -364,7 +364,7 @@ srr_compl_done:
kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
}
-void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg)
+static void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg)
{
struct bnx2fc_cmd *orig_io_req, *new_io_req;
struct bnx2fc_cmd *rec_req;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index a5052dd8d7e6..f9ddb6156f14 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -625,7 +625,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
*
* @arg: ptr to bnx2fc_percpu_info structure
*/
-int bnx2fc_percpu_io_thread(void *arg)
+static int bnx2fc_percpu_io_thread(void *arg)
{
struct bnx2fc_percpu_s *p = arg;
struct bnx2fc_work *work, *tmp;
@@ -1410,9 +1410,10 @@ bind_err:
return NULL;
}
-struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
- struct net_device *netdev,
- enum fip_state fip_mode)
+static struct bnx2fc_interface *
+bnx2fc_interface_create(struct bnx2fc_hba *hba,
+ struct net_device *netdev,
+ enum fip_state fip_mode)
{
struct fcoe_ctlr_device *ctlr_dev;
struct bnx2fc_interface *interface;
@@ -2765,8 +2766,7 @@ static void __exit bnx2fc_mod_exit(void)
* held.
*/
mutex_lock(&bnx2fc_dev_lock);
- list_splice(&adapter_list, &to_be_deleted);
- INIT_LIST_HEAD(&adapter_list);
+ list_splice_init(&adapter_list, &to_be_deleted);
adapter_count = 0;
mutex_unlock(&bnx2fc_dev_lock);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 28c671b609b2..5ff9f89c17c7 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -994,7 +994,7 @@ void bnx2fc_arm_cq(struct bnx2fc_rport *tgt)
}
-struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
+static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
{
struct bnx2fc_work *work;
work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 8f24d60f09d7..f501095f91ac 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1079,7 +1079,7 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
}
-int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
+static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
{
struct bnx2fc_rport *tgt = io_req->tgt;
int rc = SUCCESS;
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
index c2a6f9f29427..89a52b941ea8 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -1721,7 +1721,7 @@ out:
/* Wake up waiting threads */
csio_scsi_cmnd(req) = NULL;
- complete_all(&req->cmplobj);
+ complete(&req->cmplobj);
}
/*
@@ -1945,6 +1945,7 @@ csio_eh_abort_handler(struct scsi_cmnd *cmnd)
ready = csio_is_lnode_ready(ln);
tmo = CSIO_SCSI_ABRT_TMO_MS;
+ reinit_completion(&ioreq->cmplobj);
spin_lock_irq(&hw->lock);
rv = csio_do_abrt_cls(hw, ioreq, (ready ? SCSI_ABORT : SCSI_CLOSE));
spin_unlock_irq(&hw->lock);
@@ -1964,8 +1965,6 @@ csio_eh_abort_handler(struct scsi_cmnd *cmnd)
goto inval_scmnd;
}
- /* Wait for completion */
- init_completion(&ioreq->cmplobj);
wait_for_completion_timeout(&ioreq->cmplobj, msecs_to_jiffies(tmo));
/* FW didnt respond to abort within our timeout */
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 661bb94e2548..b301655f91cd 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -823,17 +823,6 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
}
/**
- * cxlflash_shutdown() - shutdown handler
- * @pdev: PCI device associated with the host.
- */
-static void cxlflash_shutdown(struct pci_dev *pdev)
-{
- struct cxlflash_cfg *cfg = pci_get_drvdata(pdev);
-
- notify_shutdown(cfg, false);
-}
-
-/**
* cxlflash_remove() - PCI entry point to tear down host
* @pdev: PCI device associated with the host.
*
@@ -844,6 +833,11 @@ static void cxlflash_remove(struct pci_dev *pdev)
struct cxlflash_cfg *cfg = pci_get_drvdata(pdev);
ulong lock_flags;
+ if (!pci_is_enabled(pdev)) {
+ pr_debug("%s: Device is disabled\n", __func__);
+ return;
+ }
+
/* If a Task Management Function is active, wait for it to complete
* before continuing with remove.
*/
@@ -1046,6 +1040,8 @@ static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
do {
msleep(delay_us / 1000);
status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]);
+ if (status == U64_MAX)
+ nretry /= 2;
} while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_ONLINE &&
nretry--);
@@ -1077,6 +1073,8 @@ static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
do {
msleep(delay_us / 1000);
status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]);
+ if (status == U64_MAX)
+ nretry /= 2;
} while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_OFFLINE &&
nretry--);
@@ -1095,42 +1093,25 @@ static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
* online. This toggling action can cause this routine to delay up to a few
* seconds. When configured to use the internal LUN feature of the AFU, a
* failure to come online is overridden.
- *
- * Return:
- * 0 when the WWPN is successfully written and the port comes back online
- * -1 when the port fails to go offline or come back up online
*/
-static int afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs,
- u64 wwpn)
+static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs,
+ u64 wwpn)
{
- int rc = 0;
-
set_port_offline(fc_regs);
-
if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
FC_PORT_STATUS_RETRY_CNT)) {
pr_debug("%s: wait on port %d to go offline timed out\n",
__func__, port);
- rc = -1; /* but continue on to leave the port back online */
}
- if (rc == 0)
- writeq_be(wwpn, &fc_regs[FC_PNAME / 8]);
-
- /* Always return success after programming WWPN */
- rc = 0;
+ writeq_be(wwpn, &fc_regs[FC_PNAME / 8]);
set_port_online(fc_regs);
-
if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
FC_PORT_STATUS_RETRY_CNT)) {
- pr_err("%s: wait on port %d to go online timed out\n",
- __func__, port);
+ pr_debug("%s: wait on port %d to go online timed out\n",
+ __func__, port);
}
-
- pr_debug("%s: returning rc=%d\n", __func__, rc);
-
- return rc;
}
/**
@@ -1187,7 +1168,7 @@ static const struct asyc_intr_info ainfo[] = {
{SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR},
{SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST},
{SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0},
- {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, SCAN_HOST},
+ {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0},
{SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
{SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
{SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
@@ -1195,7 +1176,7 @@ static const struct asyc_intr_info ainfo[] = {
{SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
{SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
{SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
- {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, SCAN_HOST},
+ {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0},
{0x0, "", 0, 0} /* terminator */
};
@@ -1631,15 +1612,10 @@ static int init_global(struct cxlflash_cfg *cfg)
[FC_CRC_THRESH / 8]);
/* Set WWPNs. If already programmed, wwpn[i] is 0 */
- if (wwpn[i] != 0 &&
- afu_set_wwpn(afu, i,
- &afu->afu_map->global.fc_regs[i][0],
- wwpn[i])) {
- dev_err(dev, "%s: failed to set WWPN on port %d\n",
- __func__, i);
- rc = -EIO;
- goto out;
- }
+ if (wwpn[i] != 0)
+ afu_set_wwpn(afu, i,
+ &afu->afu_map->global.fc_regs[i][0],
+ wwpn[i]);
/* Programming WWPN back to back causes additional
* offline/online transitions and a PLOGI
*/
@@ -2048,6 +2024,11 @@ retry:
* cxlflash_eh_host_reset_handler() - reset the host adapter
* @scp: SCSI command from stack identifying host.
*
+ * Following a reset, the state is evaluated again in case an EEH occurred
+ * during the reset. In such a scenario, the host reset will either yield
+ * until the EEH recovery is complete or return success or failure based
+ * upon the current device state.
+ *
* Return:
* SUCCESS as defined in scsi/scsi.h
* FAILED as defined in scsi/scsi.h
@@ -2080,7 +2061,8 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
} else
cfg->state = STATE_NORMAL;
wake_up_all(&cfg->reset_waitq);
- break;
+ ssleep(1);
+ /* fall through */
case STATE_RESET:
wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
if (cfg->state == STATE_NORMAL)
@@ -2596,6 +2578,9 @@ out_remove:
* @pdev: PCI device struct.
* @state: PCI channel state.
*
+ * When an EEH occurs during an active reset, wait until the reset is
+ * complete and then take action based upon the device state.
+ *
* Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
*/
static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,
@@ -2609,6 +2594,10 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,
switch (state) {
case pci_channel_io_frozen:
+ wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
+ if (cfg->state == STATE_FAILTERM)
+ return PCI_ERS_RESULT_DISCONNECT;
+
cfg->state = STATE_RESET;
scsi_block_requests(cfg->host);
drain_ioctls(cfg);
@@ -2685,7 +2674,7 @@ static struct pci_driver cxlflash_driver = {
.id_table = cxlflash_pci_table,
.probe = cxlflash_probe,
.remove = cxlflash_remove,
- .shutdown = cxlflash_shutdown,
+ .shutdown = cxlflash_remove,
.err_handler = &cxlflash_err_handler,
};
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index ce1507023132..9636970d9611 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -709,14 +709,13 @@ int cxlflash_disk_release(struct scsi_device *sdev,
* @cfg: Internal structure associated with the host.
* @ctxi: Context to release.
*
- * This routine is safe to be called with a a non-initialized context
- * and is tolerant of being called with the context's mutex held (it
- * will be unlocked if necessary before freeing). Also note that the
- * routine conditionally checks for the existence of the context control
- * map before clearing the RHT registers and context capabilities because
- * it is possible to destroy a context while the context is in the error
- * state (previous mapping was removed [so there is no need to worry about
- * clearing] and context is waiting for a new mapping).
+ * This routine is safe to be called with a a non-initialized context.
+ * Also note that the routine conditionally checks for the existence
+ * of the context control map before clearing the RHT registers and
+ * context capabilities because it is possible to destroy a context
+ * while the context is in the error state (previous mapping was
+ * removed [so there is no need to worry about clearing] and context
+ * is waiting for a new mapping).
*/
static void destroy_context(struct cxlflash_cfg *cfg,
struct ctx_info *ctxi)
@@ -732,9 +731,6 @@ static void destroy_context(struct cxlflash_cfg *cfg,
writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
writeq_be(0, &ctxi->ctrl_map->ctx_cap);
}
-
- if (mutex_is_locked(&ctxi->mutex))
- mutex_unlock(&ctxi->mutex);
}
/* Free memory associated with context */
@@ -792,32 +788,58 @@ err:
* @cfg: Internal structure associated with the host.
* @ctx: Previously obtained CXL context reference.
* @ctxid: Previously obtained process element associated with CXL context.
- * @adap_fd: Previously obtained adapter fd associated with CXL context.
* @file: Previously obtained file associated with CXL context.
* @perms: User-specified permissions.
- *
- * Upon return, the context is marked as initialized and the context's mutex
- * is locked.
*/
static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg,
- struct cxl_context *ctx, int ctxid, int adap_fd,
- struct file *file, u32 perms)
+ struct cxl_context *ctx, int ctxid, struct file *file,
+ u32 perms)
{
struct afu *afu = cfg->afu;
ctxi->rht_perms = perms;
ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl;
ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid);
- ctxi->lfd = adap_fd;
ctxi->pid = current->tgid; /* tgid = pid */
ctxi->ctx = ctx;
+ ctxi->cfg = cfg;
ctxi->file = file;
ctxi->initialized = true;
mutex_init(&ctxi->mutex);
+ kref_init(&ctxi->kref);
INIT_LIST_HEAD(&ctxi->luns);
INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
+}
+/**
+ * remove_context() - context kref release handler
+ * @kref: Kernel reference associated with context to be removed.
+ *
+ * When a context no longer has any references it can safely be removed
+ * from global access and destroyed. Note that it is assumed the thread
+ * relinquishing access to the context holds its mutex.
+ */
+static void remove_context(struct kref *kref)
+{
+ struct ctx_info *ctxi = container_of(kref, struct ctx_info, kref);
+ struct cxlflash_cfg *cfg = ctxi->cfg;
+ u64 ctxid = DECODE_CTXID(ctxi->ctxid);
+
+ /* Remove context from table/error list */
+ WARN_ON(!mutex_is_locked(&ctxi->mutex));
+ ctxi->unavail = true;
+ mutex_unlock(&ctxi->mutex);
+ mutex_lock(&cfg->ctx_tbl_list_mutex);
mutex_lock(&ctxi->mutex);
+
+ if (!list_empty(&ctxi->list))
+ list_del(&ctxi->list);
+ cfg->ctx_tbl[ctxid] = NULL;
+ mutex_unlock(&cfg->ctx_tbl_list_mutex);
+ mutex_unlock(&ctxi->mutex);
+
+ /* Context now completely uncoupled/unreachable */
+ destroy_context(cfg, ctxi);
}
/**
@@ -845,7 +867,6 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
int i;
int rc = 0;
- int lfd;
u64 ctxid = DECODE_CTXID(detach->context_id),
rctxid = detach->context_id;
@@ -887,40 +908,13 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
break;
}
- /* Tear down context following last LUN cleanup */
- if (list_empty(&ctxi->luns)) {
- ctxi->unavail = true;
- mutex_unlock(&ctxi->mutex);
- mutex_lock(&cfg->ctx_tbl_list_mutex);
- mutex_lock(&ctxi->mutex);
-
- /* Might not have been in error list so conditionally remove */
- if (!list_empty(&ctxi->list))
- list_del(&ctxi->list);
- cfg->ctx_tbl[ctxid] = NULL;
- mutex_unlock(&cfg->ctx_tbl_list_mutex);
- mutex_unlock(&ctxi->mutex);
-
- lfd = ctxi->lfd;
- destroy_context(cfg, ctxi);
- ctxi = NULL;
+ /*
+ * Release the context reference and the sdev reference that
+ * bound this LUN to the context.
+ */
+ if (kref_put(&ctxi->kref, remove_context))
put_ctx = false;
-
- /*
- * As a last step, clean up external resources when not
- * already on an external cleanup thread, i.e.: close(adap_fd).
- *
- * NOTE: this will free up the context from the CXL services,
- * allowing it to dole out the same context_id on a future
- * (or even currently in-flight) disk_attach operation.
- */
- if (lfd != -1)
- sys_close(lfd);
- }
-
- /* Release the sdev reference that bound this LUN to the context */
scsi_device_put(sdev);
-
out:
if (put_ctx)
put_context(ctxi);
@@ -941,34 +935,18 @@ static int cxlflash_disk_detach(struct scsi_device *sdev,
*
* This routine is the release handler for the fops registered with
* the CXL services on an initial attach for a context. It is called
- * when a close is performed on the adapter file descriptor returned
- * to the user. Programmatically, the user is not required to perform
- * the close, as it is handled internally via the detach ioctl when
- * a context is being removed. Note that nothing prevents the user
- * from performing a close, but the user should be aware that doing
- * so is considered catastrophic and subsequent usage of the superpipe
- * API with previously saved off tokens will fail.
- *
- * When initiated from an external close (either by the user or via
- * a process tear down), the routine derives the context reference
- * and calls detach for each LUN associated with the context. The
- * final detach operation will cause the context itself to be freed.
- * Note that the saved off lfd is reset prior to calling detach to
- * signify that the final detach should not perform a close.
- *
- * When initiated from a detach operation as part of the tear down
- * of a context, the context is first completely freed and then the
- * close is performed. This routine will fail to derive the context
- * reference (due to the context having already been freed) and then
- * call into the CXL release entry point.
+ * when a close (explicity by the user or as part of a process tear
+ * down) is performed on the adapter file descriptor returned to the
+ * user. The user should be aware that explicitly performing a close
+ * considered catastrophic and subsequent usage of the superpipe API
+ * with previously saved off tokens will fail.
*
- * Thus, with exception to when the CXL process element (context id)
- * lookup fails (a case that should theoretically never occur), every
- * call into this routine results in a complete freeing of a context.
- *
- * As part of the detach, all per-context resources associated with the LUN
- * are cleaned up. When detaching the last LUN for a context, the context
- * itself is cleaned up and released.
+ * This routine derives the context reference and calls detach for
+ * each LUN associated with the context.The final detach operation
+ * causes the context itself to be freed. With exception to when the
+ * CXL process element (context id) lookup fails (a case that should
+ * theoretically never occur), every call into this routine results
+ * in a complete freeing of a context.
*
* Return: 0 on success
*/
@@ -1006,11 +984,8 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file)
goto out;
}
- dev_dbg(dev, "%s: close(%d) for context %d\n",
- __func__, ctxi->lfd, ctxid);
+ dev_dbg(dev, "%s: close for context %d\n", __func__, ctxid);
- /* Reset the file descriptor to indicate we're on a close() thread */
- ctxi->lfd = -1;
detach.context_id = ctxi->ctxid;
list_for_each_entry_safe(lun_access, t, &ctxi->luns, list)
_cxlflash_disk_detach(lun_access->sdev, ctxi, &detach);
@@ -1110,8 +1085,7 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
goto err;
}
- dev_dbg(dev, "%s: fault(%d) for context %d\n",
- __func__, ctxi->lfd, ctxid);
+ dev_dbg(dev, "%s: fault for context %d\n", __func__, ctxid);
if (likely(!ctxi->err_recovery_active)) {
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
@@ -1186,8 +1160,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma)
goto out;
}
- dev_dbg(dev, "%s: mmap(%d) for context %d\n",
- __func__, ctxi->lfd, ctxid);
+ dev_dbg(dev, "%s: mmap for context %d\n", __func__, ctxid);
rc = cxl_fd_mmap(file, vma);
if (likely(!rc)) {
@@ -1377,12 +1350,12 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
lun_access->lli = lli;
lun_access->sdev = sdev;
- /* Non-NULL context indicates reuse */
+ /* Non-NULL context indicates reuse (another context reference) */
if (ctxi) {
dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n",
__func__, rctxid);
+ kref_get(&ctxi->kref);
list_add(&lun_access->list, &ctxi->luns);
- fd = ctxi->lfd;
goto out_attach;
}
@@ -1430,7 +1403,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
perms = SISL_RHT_PERM(attach->hdr.flags + 1);
/* Context mutex is locked upon return */
- init_context(ctxi, cfg, ctx, ctxid, fd, file, perms);
+ init_context(ctxi, cfg, ctx, ctxid, file, perms);
rc = afu_attach(cfg, ctxi);
if (unlikely(rc)) {
@@ -1445,7 +1418,6 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
* knows about us yet; we can be the only one holding our mutex.
*/
list_add(&lun_access->list, &ctxi->luns);
- mutex_unlock(&ctxi->mutex);
mutex_lock(&cfg->ctx_tbl_list_mutex);
mutex_lock(&ctxi->mutex);
cfg->ctx_tbl[ctxid] = ctxi;
@@ -1453,7 +1425,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
fd_install(fd, file);
out_attach:
- attach->hdr.return_flags = 0;
+ if (fd != -1)
+ attach->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD;
+ else
+ attach->hdr.return_flags = 0;
+
attach->context_id = ctxi->ctxid;
attach->block_size = gli->blk_len;
attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea);
@@ -1494,7 +1470,7 @@ err:
file = NULL;
}
- /* Cleanup our context; safe to call even with mutex locked */
+ /* Cleanup our context */
if (ctxi) {
destroy_context(cfg, ctxi);
ctxi = NULL;
@@ -1509,16 +1485,19 @@ err:
* recover_context() - recovers a context in error
* @cfg: Internal structure associated with the host.
* @ctxi: Context to release.
+ * @adap_fd: Adapter file descriptor associated with new/recovered context.
*
* Restablishes the state for a context-in-error.
*
* Return: 0 on success, -errno on failure
*/
-static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
+static int recover_context(struct cxlflash_cfg *cfg,
+ struct ctx_info *ctxi,
+ int *adap_fd)
{
struct device *dev = &cfg->dev->dev;
int rc = 0;
- int old_fd, fd = -1;
+ int fd = -1;
int ctxid = -1;
struct file *file;
struct cxl_context *ctx;
@@ -1566,9 +1545,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
* No error paths after this point. Once the fd is installed it's
* visible to user space and can't be undone safely on this thread.
*/
- old_fd = ctxi->lfd;
ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid);
- ctxi->lfd = fd;
ctxi->ctx = ctx;
ctxi->file = file;
@@ -1585,9 +1562,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
cfg->ctx_tbl[ctxid] = ctxi;
mutex_unlock(&cfg->ctx_tbl_list_mutex);
fd_install(fd, file);
-
- /* Release the original adapter fd and associated CXL resources */
- sys_close(old_fd);
+ *adap_fd = fd;
out:
dev_dbg(dev, "%s: returning ctxid=%d fd=%d rc=%d\n",
__func__, ctxid, fd, rc);
@@ -1646,6 +1621,7 @@ static int cxlflash_afu_recover(struct scsi_device *sdev,
rctxid = recover->context_id;
long reg;
int lretry = 20; /* up to 2 seconds */
+ int new_adap_fd = -1;
int rc = 0;
atomic_inc(&cfg->recovery_threads);
@@ -1675,7 +1651,7 @@ retry:
if (ctxi->err_recovery_active) {
retry_recover:
- rc = recover_context(cfg, ctxi);
+ rc = recover_context(cfg, ctxi, &new_adap_fd);
if (unlikely(rc)) {
dev_err(dev, "%s: Recovery failed for context %llu (rc=%d)\n",
__func__, ctxid, rc);
@@ -1697,9 +1673,9 @@ retry_recover:
ctxi->err_recovery_active = false;
recover->context_id = ctxi->ctxid;
- recover->adap_fd = ctxi->lfd;
+ recover->adap_fd = new_adap_fd;
recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea);
- recover->hdr.return_flags |=
+ recover->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD |
DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET;
goto out;
}
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index 5f9a091fda95..9e62ff304e4b 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -100,13 +100,14 @@ struct ctx_info {
struct cxl_ioctl_start_work work;
u64 ctxid;
- int lfd;
pid_t pid;
bool initialized;
bool unavail;
bool err_recovery_active;
struct mutex mutex; /* Context protection */
+ struct kref kref;
struct cxl_context *ctx;
+ struct cxlflash_cfg *cfg;
struct list_head luns; /* LUNs attached to this context */
const struct vm_operations_struct *cxl_mmap_vmops;
struct file *file;
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index 50f8e9300770..90c5d7f5278e 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -1135,14 +1135,13 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
ctxid_dst = DECODE_CTXID(clone->context_id_dst),
rctxid_src = clone->context_id_src,
rctxid_dst = clone->context_id_dst;
- int adap_fd_src = clone->adap_fd_src;
int i, j;
int rc = 0;
bool found;
LIST_HEAD(sidecar);
- pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu adap_fd_src=%d\n",
- __func__, ctxid_src, ctxid_dst, adap_fd_src);
+ pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu\n",
+ __func__, ctxid_src, ctxid_dst);
/* Do not clone yourself */
if (unlikely(rctxid_src == rctxid_dst)) {
@@ -1166,13 +1165,6 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
goto out;
}
- if (unlikely(adap_fd_src != ctxi_src->lfd)) {
- pr_debug("%s: Invalid source adapter fd! (%d)\n",
- __func__, adap_fd_src);
- rc = -EINVAL;
- goto out;
- }
-
/* Verify there is no open resource handle in the destination context */
for (i = 0; i < MAX_RHT_PER_CONTEXT; i++)
if (ctxi_dst->rht_start[i].nmask != 0) {
@@ -1257,7 +1249,6 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
out_success:
list_splice(&sidecar, &ctxi_dst->luns);
- sys_close(adap_fd_src);
/* fall through */
out:
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 752b5c9d1ab2..241829e59668 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -583,6 +583,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ kfree(buff);
return err;
}
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
deleted file mode 100644
index 459863f94e46..000000000000
--- a/drivers/scsi/dtc.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * DTC 3180/3280 driver, by
- * Ray Van Tassle rayvt@comm.mot.com
- *
- * taken from ...
- * Trantor T128/T128F/T228 driver by...
- *
- * Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 440-4894
- */
-
-/*
- * The card is detected and initialized in one of several ways :
- * 1. Autoprobe (default) - since the board is memory mapped,
- * a BIOS signature is scanned for to locate the registers.
- * An interrupt is triggered to autoprobe for the interrupt
- * line.
- *
- * 2. With command line overrides - dtc=address,irq may be
- * used on the LILO command line to override the defaults.
- *
-*/
-
-/*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
- where something crashed or gets stuck at */
-/* 1 = blue
- 2 = green
- 3 = cyan
- 4 = red
- 5 = magenta
- 6 = yellow
- 7 = white
-*/
-#if 0
-#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
-
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <scsi/scsi_host.h>
-
-#include "dtc.h"
-#include "NCR5380.h"
-
-/*
- * The DTC3180 & 3280 boards are memory mapped.
- *
- */
-
-/*
- */
-/* Offset from DTC_5380_OFFSET */
-#define DTC_CONTROL_REG 0x100 /* rw */
-#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */
-#define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */
-
-#define CSR_RESET 0x80 /* wo Resets 53c400 */
-#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */
-#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */
-#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */
-#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */
-#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */
-#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */
-#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */
-#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */
-#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR)
-
-
-#define DTC_BLK_CNT 0x101 /* rw
- * # of 128-byte blocks to transfer */
-
-
-#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */
-
-#define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */
-#define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer
- * after disconnect/reconnect*/
-
-#define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */
-
-/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */
-#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */
-
-static struct override {
- unsigned int address;
- int irq;
-} overrides
-#ifdef OVERRIDE
-[] __initdata = OVERRIDE;
-#else
-[4] __initdata = {
- { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }
-};
-#endif
-
-#define NO_OVERRIDES ARRAY_SIZE(overrides)
-
-static struct base {
- unsigned long address;
- int noauto;
-} bases[] __initdata = {
- { 0xcc000, 0 },
- { 0xc8000, 0 },
- { 0xdc000, 0 },
- { 0xd8000, 0 }
-};
-
-#define NO_BASES ARRAY_SIZE(bases)
-
-static const struct signature {
- const char *string;
- int offset;
-} signatures[] = {
- {"DATA TECHNOLOGY CORPORATION BIOS", 0x25},
-};
-
-#define NO_SIGNATURES ARRAY_SIZE(signatures)
-
-#ifndef MODULE
-/*
- * Function : dtc_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- */
-
-static int __init dtc_setup(char *str)
-{
- static int commandline_current;
- int i;
- int ints[10];
-
- get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] != 2)
- printk("dtc_setup: usage dtc=address,irq\n");
- else if (commandline_current < NO_OVERRIDES) {
- overrides[commandline_current].address = ints[1];
- overrides[commandline_current].irq = ints[2];
- for (i = 0; i < NO_BASES; ++i)
- if (bases[i].address == ints[1]) {
- bases[i].noauto = 1;
- break;
- }
- ++commandline_current;
- }
- return 1;
-}
-
-__setup("dtc=", dtc_setup);
-#endif
-
-/*
- * Function : int dtc_detect(struct scsi_host_template * tpnt)
- *
- * Purpose : detects and initializes DTC 3180/3280 controllers
- * that were autoprobed, overridden on the LILO command line,
- * or specified at compile time.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
-*/
-
-static int __init dtc_detect(struct scsi_host_template * tpnt)
-{
- static int current_override, current_base;
- struct Scsi_Host *instance;
- unsigned int addr;
- void __iomem *base;
- int sig, count;
-
- for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
- addr = 0;
- base = NULL;
-
- if (overrides[current_override].address) {
- addr = overrides[current_override].address;
- base = ioremap(addr, 0x2000);
- if (!base)
- addr = 0;
- } else
- for (; !addr && (current_base < NO_BASES); ++current_base) {
- dprintk(NDEBUG_INIT, "dtc: probing address 0x%08x\n",
- (unsigned int)bases[current_base].address);
- if (bases[current_base].noauto)
- continue;
- base = ioremap(bases[current_base].address, 0x2000);
- if (!base)
- continue;
- for (sig = 0; sig < NO_SIGNATURES; ++sig) {
- if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
- addr = bases[current_base].address;
- dprintk(NDEBUG_INIT, "dtc: detected board\n");
- goto found;
- }
- }
- iounmap(base);
- }
-
- dprintk(NDEBUG_INIT, "dtc: addr = 0x%08x\n", addr);
-
- if (!addr)
- break;
-
-found:
- instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
- if (instance == NULL)
- goto out_unmap;
-
- instance->base = addr;
- ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
-
- if (NCR5380_init(instance, FLAG_LATE_DMA_SETUP))
- goto out_unregister;
-
- NCR5380_maybe_reset_bus(instance);
-
- NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */
- if (overrides[current_override].irq != IRQ_AUTO)
- instance->irq = overrides[current_override].irq;
- else
- instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
-
- /* Compatibility with documented NCR5380 kernel parameters */
- if (instance->irq == 255)
- instance->irq = NO_IRQ;
-
- /* With interrupts enabled, it will sometimes hang when doing heavy
- * reads. So better not enable them until I finger it out. */
- instance->irq = NO_IRQ;
-
- if (instance->irq != NO_IRQ)
- if (request_irq(instance->irq, dtc_intr, 0,
- "dtc", instance)) {
- printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
- instance->irq = NO_IRQ;
- }
-
- if (instance->irq == NO_IRQ) {
- printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
- printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
- }
-
- dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
- instance->host_no, instance->irq);
-
- ++current_override;
- ++count;
- }
- return count;
-
-out_unregister:
- scsi_unregister(instance);
-out_unmap:
- iounmap(base);
- return count;
-}
-
-/*
- * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip)
- *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
- * the specified device / size.
- *
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- * major / minor, ip[] = {heads, sectors, cylinders}
- *
- * Returns : always 0 (success), initializes ip
- *
-*/
-
-/*
- * XXX Most SCSI boards use this mapping, I could be incorrect. Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
-*/
-
-static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev,
- sector_t capacity, int *ip)
-{
- int size = capacity;
-
- ip[0] = 64;
- ip[1] = 32;
- ip[2] = size >> 11;
- return 0;
-}
-
-
-/****************************************************************
- * Function : int NCR5380_pread (struct Scsi_Host *instance,
- * unsigned char *dst, int len)
- *
- * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to
- * dst
- *
- * Inputs : dst = destination, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog
- * timeout.
-*/
-
-static inline int dtc_pread(struct Scsi_Host *instance,
- unsigned char *dst, int len)
-{
- unsigned char *d = dst;
- int i; /* For counting time spent in the poll-loop */
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
-
- i = 0;
- if (instance->irq == NO_IRQ)
- NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
- else
- NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
- NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */
- rtrc(1);
- while (len > 0) {
- rtrc(2);
- while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
- ++i;
- rtrc(3);
- memcpy_fromio(d, hostdata->base + DTC_DATA_BUF, 128);
- d += 128;
- len -= 128;
- rtrc(7);
- /*** with int's on, it sometimes hangs after here.
- * Looks like something makes HBNR go away. */
- }
- rtrc(4);
- while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
- ++i;
- rtrc(0);
- return (0);
-}
-
-/****************************************************************
- * Function : int NCR5380_pwrite (struct Scsi_Host *instance,
- * unsigned char *src, int len)
- *
- * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
- * src
- *
- * Inputs : src = source, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog
- * timeout.
-*/
-
-static inline int dtc_pwrite(struct Scsi_Host *instance,
- unsigned char *src, int len)
-{
- int i;
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
-
- if (instance->irq == NO_IRQ)
- NCR5380_write(DTC_CONTROL_REG, 0);
- else
- NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
- NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */
- for (i = 0; len > 0; ++i) {
- rtrc(5);
- /* Poll until the host buffer can accept data. */
- while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
- ++i;
- rtrc(3);
- memcpy_toio(hostdata->base + DTC_DATA_BUF, src, 128);
- src += 128;
- len -= 128;
- }
- rtrc(4);
- while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
- ++i;
- rtrc(6);
- /* Wait until the last byte has been sent to the disk */
- while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
- ++i;
- rtrc(7);
- /* Check for parity error here. fixme. */
- rtrc(0);
- return (0);
-}
-
-static int dtc_dma_xfer_len(struct scsi_cmnd *cmd)
-{
- int transfersize = cmd->transfersize;
-
- /* Limit transfers to 32K, for xx400 & xx406
- * pseudoDMA that transfers in 128 bytes blocks.
- */
- if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
- !(cmd->SCp.this_residual % transfersize))
- transfersize = 32 * 1024;
-
- return transfersize;
-}
-
-MODULE_LICENSE("GPL");
-
-#include "NCR5380.c"
-
-static int dtc_release(struct Scsi_Host *shost)
-{
- struct NCR5380_hostdata *hostdata = shost_priv(shost);
-
- if (shost->irq != NO_IRQ)
- free_irq(shost->irq, shost);
- NCR5380_exit(shost);
- scsi_unregister(shost);
- iounmap(hostdata->base);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "DTC 3180/3280",
- .detect = dtc_detect,
- .release = dtc_release,
- .proc_name = "dtc3x80",
- .info = dtc_info,
- .queuecommand = dtc_queue_command,
- .eh_abort_handler = dtc_abort,
- .eh_bus_reset_handler = dtc_bus_reset,
- .bios_param = dtc_biosparam,
- .can_queue = 32,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING,
- .cmd_size = NCR5380_CMD_SIZE,
- .max_sectors = 128,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
deleted file mode 100644
index fcb0a8ea7bda..000000000000
--- a/drivers/scsi/dtc.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * DTC controller, taken from T128 driver by...
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 440-4894
- */
-
-#ifndef DTC3280_H
-#define DTC3280_H
-
-#define NCR5380_implementation_fields \
- void __iomem *base
-
-#define DTC_address(reg) \
- (((struct NCR5380_hostdata *)shost_priv(instance))->base + DTC_5380_OFFSET + reg)
-
-#define NCR5380_read(reg) (readb(DTC_address(reg)))
-#define NCR5380_write(reg, value) (writeb(value, DTC_address(reg)))
-
-#define NCR5380_dma_xfer_len(instance, cmd, phase) \
- dtc_dma_xfer_len(cmd)
-#define NCR5380_dma_recv_setup dtc_pread
-#define NCR5380_dma_send_setup dtc_pwrite
-#define NCR5380_dma_residual(instance) (0)
-
-#define NCR5380_intr dtc_intr
-#define NCR5380_queue_command dtc_queue_command
-#define NCR5380_abort dtc_abort
-#define NCR5380_bus_reset dtc_bus_reset
-#define NCR5380_info dtc_info
-
-#define NCR5380_io_delay(x) udelay(x)
-
-/* 15 12 11 10
- 1001 1100 0000 0000 */
-
-#define DTC_IRQS 0x9c00
-
-
-#endif /* DTC3280_H */
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
index 78ce4d61a69b..d6e53aee2295 100644
--- a/drivers/scsi/esas2r/esas2r_init.c
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -963,10 +963,6 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a,
/* initialize the allocated memory */
if (test_bit(AF_FIRST_INIT, &a->flags)) {
- memset(a->req_table, 0,
- (num_requests + num_ae_requests +
- 1) * sizeof(struct esas2r_request *));
-
esas2r_targ_db_initialize(a);
/* prime parts of the inbound list */
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
index 2aca4d16f39e..5092c821d088 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -194,7 +194,7 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj,
int length = min(sizeof(struct atto_ioctl), count);
if (!a->local_atto_ioctl) {
- a->local_atto_ioctl = kzalloc(sizeof(struct atto_ioctl),
+ a->local_atto_ioctl = kmalloc(sizeof(struct atto_ioctl),
GFP_KERNEL);
if (a->local_atto_ioctl == NULL) {
esas2r_log(ESAS2R_LOG_WARN,
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 7028dd37e5dd..375c536cbc68 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -83,6 +83,41 @@ static struct notifier_block libfcoe_notifier = {
.notifier_call = libfcoe_device_notification,
};
+static const struct {
+ u32 fc_port_speed;
+#define SPEED_2000 2000
+#define SPEED_4000 4000
+#define SPEED_8000 8000
+#define SPEED_16000 16000
+#define SPEED_32000 32000
+ u32 eth_port_speed;
+} fcoe_port_speed_mapping[] = {
+ { FC_PORTSPEED_1GBIT, SPEED_1000 },
+ { FC_PORTSPEED_2GBIT, SPEED_2000 },
+ { FC_PORTSPEED_4GBIT, SPEED_4000 },
+ { FC_PORTSPEED_8GBIT, SPEED_8000 },
+ { FC_PORTSPEED_10GBIT, SPEED_10000 },
+ { FC_PORTSPEED_16GBIT, SPEED_16000 },
+ { FC_PORTSPEED_20GBIT, SPEED_20000 },
+ { FC_PORTSPEED_25GBIT, SPEED_25000 },
+ { FC_PORTSPEED_32GBIT, SPEED_32000 },
+ { FC_PORTSPEED_40GBIT, SPEED_40000 },
+ { FC_PORTSPEED_50GBIT, SPEED_50000 },
+ { FC_PORTSPEED_100GBIT, SPEED_100000 },
+};
+
+static inline u32 eth2fc_speed(u32 eth_port_speed)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fcoe_port_speed_mapping); i++) {
+ if (fcoe_port_speed_mapping[i].eth_port_speed == eth_port_speed)
+ return fcoe_port_speed_mapping[i].fc_port_speed;
+ }
+
+ return FC_PORTSPEED_UNKNOWN;
+}
+
/**
* fcoe_link_speed_update() - Update the supported and actual link speeds
* @lport: The local port to update speeds for
@@ -126,23 +161,7 @@ int fcoe_link_speed_update(struct fc_lport *lport)
SUPPORTED_40000baseLR4_Full))
lport->link_supported_speeds |= FC_PORTSPEED_40GBIT;
- switch (ecmd.base.speed) {
- case SPEED_1000:
- lport->link_speed = FC_PORTSPEED_1GBIT;
- break;
- case SPEED_10000:
- lport->link_speed = FC_PORTSPEED_10GBIT;
- break;
- case SPEED_20000:
- lport->link_speed = FC_PORTSPEED_20GBIT;
- break;
- case SPEED_40000:
- lport->link_speed = FC_PORTSPEED_40GBIT;
- break;
- default:
- lport->link_speed = FC_PORTSPEED_UNKNOWN;
- break;
- }
+ lport->link_speed = eth2fc_speed(ecmd.base.speed);
return 0;
}
return -1;
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4731d3241323..72c98522bd26 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -23,7 +23,7 @@
#include <scsi/sas_ata.h>
#include <scsi/libsas.h>
-#define DRV_VERSION "v1.5"
+#define DRV_VERSION "v1.6"
#define HISI_SAS_MAX_PHYS 9
#define HISI_SAS_MAX_QUEUES 32
@@ -56,6 +56,11 @@ enum dev_status {
HISI_SAS_DEV_EH,
};
+enum {
+ HISI_SAS_INT_ABT_CMD = 0,
+ HISI_SAS_INT_ABT_DEV = 1,
+};
+
enum hisi_sas_dev_type {
HISI_SAS_DEV_TYPE_STP = 0,
HISI_SAS_DEV_TYPE_SSP,
@@ -89,6 +94,13 @@ struct hisi_sas_port {
struct hisi_sas_cq {
struct hisi_hba *hisi_hba;
+ int rd_point;
+ int id;
+};
+
+struct hisi_sas_dq {
+ struct hisi_hba *hisi_hba;
+ int wr_point;
int id;
};
@@ -146,6 +158,9 @@ struct hisi_sas_hw {
struct hisi_sas_slot *slot);
int (*prep_stp)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot);
+ int (*prep_abort)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ int device_id, int abort_flag, int tag_to_abort);
int (*slot_complete)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, int abort);
void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
@@ -185,6 +200,7 @@ struct hisi_hba {
struct Scsi_Host *shost;
struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_dq dq[HISI_SAS_MAX_QUEUES];
struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS];
struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 18dd5ea2c721..2f872f784e10 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -17,6 +17,10 @@
static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
u8 *lun, struct hisi_sas_tmf_task *tmf);
+static int
+hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ struct domain_device *device,
+ int abort_flag, int tag);
static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
{
@@ -93,7 +97,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
slot->task = NULL;
slot->port = NULL;
hisi_sas_slot_index_free(hisi_hba, slot->idx);
- memset(slot, 0, sizeof(*slot));
+ /* slot memory is fully zeroed when it is reused */
}
EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
@@ -116,6 +120,14 @@ static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
return hisi_hba->hw->prep_stp(hisi_hba, slot);
}
+static int hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ int device_id, int abort_flag, int tag_to_abort)
+{
+ return hisi_hba->hw->prep_abort(hisi_hba, slot,
+ device_id, abort_flag, tag_to_abort);
+}
+
/*
* This function will issue an abort TMF regardless of whether the
* task is in the sdev or not. Then it will do the task complete
@@ -192,27 +204,13 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
return rc;
}
port = device->port->lldd_port;
- if (port && !port->port_attached && !tmf) {
- if (sas_protocol_ata(task->task_proto)) {
- struct task_status_struct *ts = &task->task_status;
-
- dev_info(dev,
- "task prep: SATA/STP port%d not attach device\n",
- device->port->id);
- ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAS_PHY_DOWN;
- task->task_done(task);
- } else {
- struct task_status_struct *ts = &task->task_status;
-
- dev_info(dev,
- "task prep: SAS port%d does not attach device\n",
- device->port->id);
- ts->resp = SAS_TASK_UNDELIVERED;
- ts->stat = SAS_PHY_DOWN;
- task->task_done(task);
- }
- return 0;
+ if (port && !port->port_attached) {
+ dev_info(dev, "task prep: %s port%d not attach device\n",
+ (sas_protocol_ata(task->task_proto)) ?
+ "SATA/STP" : "SAS",
+ device->port->id);
+
+ return SAS_PHY_DOWN;
}
if (!sas_protocol_ata(task->task_proto)) {
@@ -609,6 +607,9 @@ static void hisi_sas_dev_gone(struct domain_device *device)
dev_info(dev, "found dev[%lld:%x] is gone\n",
sas_dev->device_id, sas_dev->dev_type);
+ hisi_sas_internal_task_abort(hisi_hba, device,
+ HISI_SAS_INT_ABT_DEV, 0);
+
hisi_hba->hw->free_device(hisi_hba, sas_dev);
device->lldd_dev = NULL;
memset(sas_dev, 0, sizeof(*sas_dev));
@@ -729,6 +730,12 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == TMF_RESP_FUNC_SUCC) {
+ res = TMF_RESP_FUNC_SUCC;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
task->task_status.stat == SAS_DATA_UNDERRUN) {
/* no error, but return the number of bytes of
* underrun
@@ -826,18 +833,22 @@ static int hisi_sas_abort_task(struct sas_task *task)
}
}
+ hisi_sas_internal_task_abort(hisi_hba, device,
+ HISI_SAS_INT_ABT_CMD, tag);
} else if (task->task_proto & SAS_PROTOCOL_SATA ||
task->task_proto & SAS_PROTOCOL_STP) {
if (task->dev->dev_type == SAS_SATA_DEV) {
- struct hisi_slot_info *slot = task->lldd_task;
-
- dev_notice(dev, "abort task: hba=%p task=%p slot=%p\n",
- hisi_hba, task, slot);
- task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ hisi_sas_internal_task_abort(hisi_hba, device,
+ HISI_SAS_INT_ABT_DEV, 0);
rc = TMF_RESP_FUNC_COMPLETE;
- goto out;
}
+ } else if (task->task_proto & SAS_PROTOCOL_SMP) {
+ /* SMP */
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+ hisi_sas_internal_task_abort(hisi_hba, device,
+ HISI_SAS_INT_ABT_CMD, tag);
}
out:
@@ -954,6 +965,157 @@ static int hisi_sas_query_task(struct sas_task *task)
return rc;
}
+static int
+hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
+ struct sas_task *task, int abort_flag,
+ int task_tag)
+{
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_cmd_hdr *cmd_hdr_base;
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+ if (!device->port)
+ return -1;
+
+ port = device->port->lldd_port;
+
+ /* simply get a slot and send abort command */
+ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+ if (rc)
+ goto err_out;
+ rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
+ &dlvry_queue_slot);
+ if (rc)
+ goto err_out_tag;
+
+ slot = &hisi_hba->slot_info[slot_idx];
+ memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+ slot->idx = slot_idx;
+ slot->n_elem = n_elem;
+ slot->dlvry_queue = dlvry_queue;
+ slot->dlvry_queue_slot = dlvry_queue_slot;
+ cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+ slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
+ slot->task = task;
+ slot->port = port;
+ task->lldd_task = slot;
+
+ memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+ rc = hisi_sas_task_prep_abort(hisi_hba, slot, device_id,
+ abort_flag, task_tag);
+ if (rc)
+ goto err_out_tag;
+
+ /* Port structure is static for the HBA, so
+ * even if the port is deformed it is ok
+ * to reference.
+ */
+ list_add_tail(&slot->entry, &port->list);
+ spin_lock(&task->task_state_lock);
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&task->task_state_lock);
+
+ hisi_hba->slot_prep = slot;
+
+ sas_dev->running_req++;
+ /* send abort command to our chip */
+ hisi_hba->hw->start_delivery(hisi_hba);
+
+ return 0;
+
+err_out_tag:
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
+err_out:
+ dev_err(dev, "internal abort task prep: failed[%d]!\n", rc);
+
+ return rc;
+}
+
+/**
+ * hisi_sas_internal_task_abort -- execute an internal
+ * abort command for single IO command or a device
+ * @hisi_hba: host controller struct
+ * @device: domain device
+ * @abort_flag: mode of operation, device or single IO
+ * @tag: tag of IO to be aborted (only relevant to single
+ * IO mode)
+ */
+static int
+hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+ struct domain_device *device,
+ int abort_flag, int tag)
+{
+ struct sas_task *task;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int res;
+ unsigned long flags;
+
+ if (!hisi_hba->hw->prep_abort)
+ return -EOPNOTSUPP;
+
+ task = sas_alloc_slow_task(GFP_KERNEL);
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = device;
+ task->task_proto = device->tproto;
+ task->task_done = hisi_sas_task_done;
+ task->slow_task->timer.data = (unsigned long)task;
+ task->slow_task->timer.function = hisi_sas_tmf_timedout;
+ task->slow_task->timer.expires = jiffies + 20*HZ;
+ add_timer(&task->slow_task->timer);
+
+ /* Lock as we are alloc'ing a slot, which cannot be interrupted */
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
+ task, abort_flag, tag);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ if (res) {
+ del_timer(&task->slow_task->timer);
+ dev_err(dev, "internal task abort: executing internal task failed: %d\n",
+ res);
+ goto exit;
+ }
+ wait_for_completion(&task->slow_task->completion);
+ res = TMF_RESP_FUNC_FAILED;
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
+ res = TMF_RESP_FUNC_COMPLETE;
+ goto exit;
+ }
+
+ /* TMF timed out, return direct. */
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ dev_err(dev, "internal task abort: timeout.\n");
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot = task->lldd_task;
+
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ }
+ }
+ }
+
+exit:
+ dev_info(dev, "internal task abort: task to dev %016llx task=%p "
+ "resp: 0x%x sts 0x%x\n",
+ SAS_ADDR(device->sas_addr),
+ task,
+ task->task_status.resp, /* 0 is complete, -1 is undelivered */
+ task->task_status.stat);
+ sas_free_task(task);
+
+ return res;
+}
+
static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
{
hisi_sas_port_notify_formed(sas_phy);
@@ -1063,11 +1225,16 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
for (i = 0; i < hisi_hba->queue_count; i++) {
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+ struct hisi_sas_dq *dq = &hisi_hba->dq[i];
/* Completion queue structure */
cq->id = i;
cq->hisi_hba = hisi_hba;
+ /* Delivery queue structure */
+ dq->id = i;
+ dq->hisi_hba = hisi_hba;
+
/* Delivery queue */
s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s,
@@ -1128,7 +1295,7 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
memset(hisi_hba->breakpoint, 0, s);
hisi_hba->slot_index_count = max_command_entries;
- s = hisi_hba->slot_index_count / sizeof(unsigned long);
+ s = hisi_hba->slot_index_count / BITS_PER_BYTE;
hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
if (!hisi_hba->slot_index_tags)
goto err_out;
@@ -1272,6 +1439,12 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
&hisi_hba->queue_count))
goto err_out;
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+ dev_err(dev, "No usable DMA addressing method\n");
+ goto err_out;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hisi_hba->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(hisi_hba->regs))
@@ -1319,13 +1492,6 @@ int hisi_sas_probe(struct platform_device *pdev,
hisi_hba = shost_priv(shost);
platform_set_drvdata(pdev, sha);
- if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
- dev_err(dev, "No usable DMA addressing method\n");
- rc = -EIO;
- goto err_out_ha;
- }
-
phy_nr = port_nr = hisi_hba->n_phy;
arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 1abbc2e162df..c0ac49d8bc8d 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -490,25 +490,17 @@ static void config_id_frame_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
__swab32(identify_buffer[0]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
- identify_buffer[2]);
+ __swab32(identify_buffer[1]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
- identify_buffer[1]);
+ __swab32(identify_buffer[2]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
- identify_buffer[4]);
+ __swab32(identify_buffer[3]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
- identify_buffer[3]);
+ __swab32(identify_buffer[4]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
__swab32(identify_buffer[5]));
}
-static void init_id_frame_v1_hw(struct hisi_hba *hisi_hba)
-{
- int i;
-
- for (i = 0; i < hisi_hba->n_phy; i++)
- config_id_frame_v1_hw(hisi_hba, i);
-}
-
static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_device *sas_dev)
{
@@ -774,8 +766,6 @@ static int hw_init_v1_hw(struct hisi_hba *hisi_hba)
msleep(100);
init_reg_v1_hw(hisi_hba);
- init_id_frame_v1_hw(hisi_hba);
-
return 0;
}
@@ -875,12 +865,13 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s)
{
struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_dq *dq;
u32 r, w;
int queue = hisi_hba->queue;
while (1) {
- w = hisi_sas_read32_relaxed(hisi_hba,
- DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ dq = &hisi_hba->dq[queue];
+ w = dq->wr_point;
r = hisi_sas_read32_relaxed(hisi_hba,
DLVRY_Q_0_RD_PTR + (queue * 0x14));
if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
@@ -903,10 +894,11 @@ static void start_delivery_v1_hw(struct hisi_hba *hisi_hba)
{
int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+ struct hisi_sas_dq *dq = &hisi_hba->dq[dlvry_queue];
- hisi_sas_write32(hisi_hba,
- DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
- ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+ dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+ dq->wr_point);
}
static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
@@ -1565,14 +1557,11 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
struct hisi_sas_complete_v1_hdr *complete_queue =
(struct hisi_sas_complete_v1_hdr *)
hisi_hba->complete_hdr[queue];
- u32 irq_value, rd_point, wr_point;
+ u32 irq_value, rd_point = cq->rd_point, wr_point;
irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
-
- rd_point = hisi_sas_read32(hisi_hba,
- COMPL_Q_0_RD_PTR + (0x14 * queue));
wr_point = hisi_sas_read32(hisi_hba,
COMPL_Q_0_WR_PTR + (0x14 * queue));
@@ -1600,6 +1589,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
}
/* update rd_point */
+ cq->rd_point = rd_point;
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
return IRQ_HANDLED;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index f96560431cf1..9825a3f49f53 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -117,6 +117,8 @@
#define SL_CONTROL (PORT_BASE + 0x94)
#define SL_CONTROL_NOTIFY_EN_OFF 0
#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define SL_CONTROL_CTA_OFF 17
+#define SL_CONTROL_CTA_MSK (0x1 << SL_CONTROL_CTA_OFF)
#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
@@ -124,6 +126,9 @@
#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define TXID_AUTO (PORT_BASE + 0xb8)
+#define TXID_AUTO_CT3_OFF 1
+#define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF)
#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
@@ -174,6 +179,10 @@
/* HW dma structures */
/* Delivery queue header */
/* dw0 */
+#define CMD_HDR_ABORT_FLAG_OFF 0
+#define CMD_HDR_ABORT_FLAG_MSK (0x3 << CMD_HDR_ABORT_FLAG_OFF)
+#define CMD_HDR_ABORT_DEVICE_TYPE_OFF 2
+#define CMD_HDR_ABORT_DEVICE_TYPE_MSK (0x1 << CMD_HDR_ABORT_DEVICE_TYPE_OFF)
#define CMD_HDR_RESP_REPORT_OFF 5
#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
#define CMD_HDR_TLR_CTRL_OFF 6
@@ -214,6 +223,8 @@
#define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
#define CMD_HDR_DATA_SGL_LEN_OFF 16
#define CMD_HDR_DATA_SGL_LEN_MSK (0xffff << CMD_HDR_DATA_SGL_LEN_OFF)
+#define CMD_HDR_ABORT_IPTT_OFF 16
+#define CMD_HDR_ABORT_IPTT_MSK (0xffff << CMD_HDR_ABORT_IPTT_OFF)
/* Completion header */
/* dw0 */
@@ -221,6 +232,13 @@
#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
#define CMPLT_HDR_ERX_OFF 12
#define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF)
+#define CMPLT_HDR_ABORT_STAT_OFF 13
+#define CMPLT_HDR_ABORT_STAT_MSK (0x7 << CMPLT_HDR_ABORT_STAT_OFF)
+/* abort_stat */
+#define STAT_IO_NOT_VALID 0x1
+#define STAT_IO_NO_DEVICE 0x2
+#define STAT_IO_COMPLETE 0x3
+#define STAT_IO_ABORTED 0x4
/* dw1 */
#define CMPLT_HDR_IPTT_OFF 0
#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
@@ -549,25 +567,17 @@ static void config_id_frame_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
__swab32(identify_buffer[0]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
- identify_buffer[2]);
+ __swab32(identify_buffer[1]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
- identify_buffer[1]);
+ __swab32(identify_buffer[2]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
- identify_buffer[4]);
+ __swab32(identify_buffer[3]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
- identify_buffer[3]);
+ __swab32(identify_buffer[4]));
hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
__swab32(identify_buffer[5]));
}
-static void init_id_frame_v2_hw(struct hisi_hba *hisi_hba)
-{
- int i;
-
- for (i = 0; i < hisi_hba->n_phy; i++)
- config_id_frame_v2_hw(hisi_hba, i);
-}
-
static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_device *sas_dev)
{
@@ -589,6 +599,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
break;
case SAS_SATA_DEV:
+ case SAS_SATA_PENDING:
if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
else
@@ -672,9 +683,7 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
else
reset_val = 0x7ffff;
- /* Disable all of the DQ */
- for (i = 0; i < HISI_SAS_MAX_QUEUES; i++)
- hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
/* Disable all of the PHYs */
for (i = 0; i < hisi_hba->n_phy; i++) {
@@ -810,6 +819,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+ hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x10);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
@@ -901,8 +912,6 @@ static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
msleep(100);
init_reg_v2_hw(hisi_hba);
- init_id_frame_v2_hw(hisi_hba);
-
return 0;
}
@@ -952,14 +961,8 @@ static void start_phys_v2_hw(unsigned long data)
static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
{
- int i;
struct timer_list *timer = &hisi_hba->timer;
- for (i = 0; i < hisi_hba->n_phy; i++) {
- hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
- hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
- }
-
setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba);
mod_timer(timer, jiffies + HZ);
}
@@ -1010,12 +1013,13 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s)
{
struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_dq *dq;
u32 r, w;
int queue = hisi_hba->queue;
while (1) {
- w = hisi_sas_read32_relaxed(hisi_hba,
- DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ dq = &hisi_hba->dq[queue];
+ w = dq->wr_point;
r = hisi_sas_read32_relaxed(hisi_hba,
DLVRY_Q_0_RD_PTR + (queue * 0x14));
if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
@@ -1038,9 +1042,11 @@ static void start_delivery_v2_hw(struct hisi_hba *hisi_hba)
{
int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+ struct hisi_sas_dq *dq = &hisi_hba->dq[dlvry_queue];
+ dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
- ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+ dq->wr_point);
}
static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
@@ -1563,6 +1569,30 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
goto out;
}
+ /* Use SAS+TMF status codes */
+ switch ((complete_hdr->dw0 & CMPLT_HDR_ABORT_STAT_MSK)
+ >> CMPLT_HDR_ABORT_STAT_OFF) {
+ case STAT_IO_ABORTED:
+ /* this io has been aborted by abort command */
+ ts->stat = SAS_ABORTED_TASK;
+ goto out;
+ case STAT_IO_COMPLETE:
+ /* internal abort command complete */
+ ts->stat = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ case STAT_IO_NO_DEVICE:
+ ts->stat = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ case STAT_IO_NOT_VALID:
+ /* abort single io, controller don't find
+ * the io need to abort
+ */
+ ts->stat = TMF_RESP_FUNC_FAILED;
+ goto out;
+ default:
+ break;
+ }
+
if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
(!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
@@ -1775,6 +1805,32 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
return 0;
}
+static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ int device_id, int abort_flag, int tag_to_abort)
+{
+ struct sas_task *task = slot->task;
+ struct domain_device *dev = task->dev;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct hisi_sas_port *port = slot->port;
+
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
+ (port->id << CMD_HDR_PORT_OFF) |
+ ((dev_is_sata(dev) ? 1:0) <<
+ CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
+ (abort_flag << CMD_HDR_ABORT_FLAG_OFF));
+
+ /* dw1 */
+ hdr->dw1 = cpu_to_le32(device_id << CMD_HDR_DEV_ID_OFF);
+
+ /* dw7 */
+ hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
+ hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+ return 0;
+}
+
static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
{
int i, res = 0;
@@ -1818,9 +1874,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
frame_rcvd[i] = __swab32(idaf);
}
- /* Get the linkrates */
- link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
- link_rate = (link_rate >> (phy_no * 4)) & 0xf;
sas_phy->linkrate = link_rate;
hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
HARD_PHY_LINKRATE);
@@ -1855,16 +1908,21 @@ end:
static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
{
int res = 0;
- u32 phy_cfg, phy_state;
+ u32 phy_state, sl_ctrl, txid_auto;
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
- phy_cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
-
phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
-
hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
+ sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL,
+ sl_ctrl & ~SL_CONTROL_CTA_MSK);
+
+ txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
+ txid_auto | TXID_AUTO_CT3_MSK);
+
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
@@ -1986,7 +2044,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
struct hisi_sas_slot *slot;
struct hisi_sas_itct *itct;
struct hisi_sas_complete_v2_hdr *complete_queue;
- u32 irq_value, rd_point, wr_point, dev_id;
+ u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id;
int queue = cq->id;
complete_queue = hisi_hba->complete_hdr[queue];
@@ -1994,8 +2052,6 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
- rd_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_RD_PTR +
- (0x14 * queue));
wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
(0x14 * queue));
@@ -2043,6 +2099,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
}
/* update rd_point */
+ cq->rd_point = rd_point;
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
return IRQ_HANDLED;
}
@@ -2239,6 +2296,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
.prep_smp = prep_smp_v2_hw,
.prep_ssp = prep_ssp_v2_hw,
.prep_stp = prep_ata_v2_hw,
+ .prep_abort = prep_abort_v2_hw,
.get_free_slot = get_free_slot_v2_hw,
.start_delivery = start_delivery_v2_hw,
.slot_complete = slot_complete_v2_hw,
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index ec6381e57eb7..258a3f9a2519 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -246,10 +246,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
shost->dma_dev = dma_dev;
- error = device_add(&shost->shost_gendev);
- if (error)
- goto out_destroy_freelist;
-
/*
* Increase usage count temporarily here so that calling
* scsi_autopm_put_host() will trigger runtime idle if there is
@@ -260,6 +256,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
pm_runtime_enable(&shost->shost_gendev);
device_enable_async_suspend(&shost->shost_gendev);
+ error = device_add(&shost->shost_gendev);
+ if (error)
+ goto out_destroy_freelist;
+
scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent);
@@ -309,6 +309,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
out_del_gendev:
device_del(&shost->shost_gendev);
out_destroy_freelist:
+ device_disable_async_suspend(&shost->shost_gendev);
+ pm_runtime_disable(&shost->shost_gendev);
+ pm_runtime_set_suspended(&shost->shost_gendev);
+ pm_runtime_put_noidle(&shost->shost_gendev);
scsi_destroy_command_freelist(shost);
out_destroy_tags:
if (shost_use_blk_mq(shost))
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 030d0023e1d2..d007ec18179a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -293,6 +293,8 @@ static int detect_controller_lockup(struct ctlr_info *h);
static void hpsa_disable_rld_caching(struct ctlr_info *h);
static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
struct ReportExtendedLUNdata *buf, int bufsize);
+static bool hpsa_vpd_page_supported(struct ctlr_info *h,
+ unsigned char scsi3addr[], u8 page);
static int hpsa_luns_changed(struct ctlr_info *h);
static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
struct hpsa_scsi_dev_t *dev,
@@ -2388,7 +2390,8 @@ static void hpsa_cmd_free_and_done(struct ctlr_info *h,
struct CommandList *c, struct scsi_cmnd *cmd)
{
hpsa_cmd_resolve_and_free(h, c);
- cmd->scsi_done(cmd);
+ if (cmd && cmd->scsi_done)
+ cmd->scsi_done(cmd);
}
static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c)
@@ -2489,7 +2492,17 @@ static void complete_scsi_command(struct CommandList *cp)
ei = cp->err_info;
cmd = cp->scsi_cmd;
h = cp->h;
+
+ if (!cmd->device) {
+ cmd->result = DID_NO_CONNECT << 16;
+ return hpsa_cmd_free_and_done(h, cp, cmd);
+ }
+
dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ return hpsa_cmd_free_and_done(h, cp, cmd);
+ }
c2 = &h->ioaccel2_cmd_pool[cp->cmdindex];
scsi_dma_unmap(cmd); /* undo the DMA mappings */
@@ -2504,8 +2517,15 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
- if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1)
- atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
+ if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) {
+ if (dev->physical_device && dev->expose_device &&
+ dev->removed) {
+ cmd->result = DID_NO_CONNECT << 16;
+ return hpsa_cmd_free_and_done(h, cp, cmd);
+ }
+ if (likely(cp->phys_disk != NULL))
+ atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
+ }
/*
* We check for lockup status here as it may be set for
@@ -3074,11 +3094,19 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0xC1, buf, 64);
+
+ if (!hpsa_vpd_page_supported(h, scsi3addr,
+ HPSA_VPD_LV_DEVICE_GEOMETRY))
+ goto exit;
+
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE |
+ HPSA_VPD_LV_DEVICE_GEOMETRY, buf, 64);
+
if (rc == 0)
*raid_level = buf[8];
if (*raid_level > RAID_UNKNOWN)
*raid_level = RAID_UNKNOWN;
+exit:
kfree(buf);
return;
}
@@ -3436,7 +3464,7 @@ static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr,
}
/* Get a device id from inquiry page 0x83 */
-static int hpsa_vpd_page_supported(struct ctlr_info *h,
+static bool hpsa_vpd_page_supported(struct ctlr_info *h,
unsigned char scsi3addr[], u8 page)
{
int rc;
@@ -3446,7 +3474,7 @@ static int hpsa_vpd_page_supported(struct ctlr_info *h,
buf = kzalloc(256, GFP_KERNEL);
if (!buf)
- return 0;
+ return false;
/* Get the size of the page list first */
rc = hpsa_scsi_do_inquiry(h, scsi3addr,
@@ -3473,10 +3501,10 @@ static int hpsa_vpd_page_supported(struct ctlr_info *h,
goto exit_supported;
exit_unsupported:
kfree(buf);
- return 0;
+ return false;
exit_supported:
kfree(buf);
- return 1;
+ return true;
}
static void hpsa_get_ioaccel_status(struct ctlr_info *h,
@@ -3525,18 +3553,25 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
int rc;
unsigned char *buf;
- if (buflen > 16)
- buflen = 16;
+ /* Does controller have VPD for device id? */
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_DEVICE_ID))
+ return 1; /* not supported */
+
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
- if (rc == 0)
- memcpy(device_id, &buf[index], buflen);
+
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE |
+ HPSA_VPD_LV_DEVICE_ID, buf, 64);
+ if (rc == 0) {
+ if (buflen > 16)
+ buflen = 16;
+ memcpy(device_id, &buf[8], buflen);
+ }
kfree(buf);
- return rc != 0;
+ return rc; /*0 - got id, otherwise, didn't */
}
static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
@@ -3807,8 +3842,15 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->model));
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
- hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
- sizeof(this_device->device_id));
+ if (hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
+ sizeof(this_device->device_id)))
+ dev_err(&h->pdev->dev,
+ "hpsa%d: %s: can't get device id for host %d:C0:T%d:L%d\t%s\t%.16s\n",
+ h->ctlr, __func__,
+ h->scsi_host->host_no,
+ this_device->target, this_device->lun,
+ scsi_device_type(this_device->devtype),
+ this_device->model);
if ((this_device->devtype == TYPE_DISK ||
this_device->devtype == TYPE_ZBC) &&
@@ -4034,7 +4076,17 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
struct bmic_identify_physical_device *id_phys)
{
int rc;
- struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+ struct ext_report_lun_entry *rle;
+
+ /*
+ * external targets don't support BMIC
+ */
+ if (dev->external) {
+ dev->queue_depth = 7;
+ return;
+ }
+
+ rle = &rlep->LUN[rle_index];
dev->ioaccel_handle = rle->ioaccel_handle;
if ((rle->device_flags & 0x08) && dev->ioaccel_handle)
@@ -4270,6 +4322,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
i, nphysicals, nlogicals, physdev_list, logdev_list);
+ /* Determine if this is a lun from an external target array */
+ tmpdevice->external =
+ figure_external_status(h, raid_ctlr_position, i,
+ nphysicals, nlocal_logicals);
+
/*
* Skip over some devices such as a spare.
*/
@@ -4295,11 +4352,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
continue;
}
- /* Determine if this is a lun from an external target array */
- tmpdevice->external =
- figure_external_status(h, raid_ctlr_position, i,
- nphysicals, nlocal_logicals);
-
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
@@ -4513,7 +4565,9 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
case READ_6:
case READ_12:
if (*cdb_len == 6) {
- block = get_unaligned_be16(&cdb[2]);
+ block = (((cdb[1] & 0x1F) << 16) |
+ (cdb[2] << 8) |
+ cdb[3]);
block_cnt = cdb[4];
if (block_cnt == 0)
block_cnt = 256;
@@ -4638,6 +4692,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
struct scsi_cmnd *cmd = c->scsi_cmd;
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ if (!dev)
+ return -1;
+
c->phys_disk = dev;
return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
@@ -4670,9 +4727,11 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h,
*/
switch (cmd->cmnd[0]) {
/* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
- case WRITE_6:
case READ_6:
- first_block = get_unaligned_be16(&cmd->cmnd[2]);
+ case WRITE_6:
+ first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
+ (cmd->cmnd[2] << 8) |
+ cmd->cmnd[3]);
break;
case WRITE_10:
case READ_10:
@@ -4714,6 +4773,12 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
u32 len;
u32 total_len = 0;
+ if (!cmd->device)
+ return -1;
+
+ if (!cmd->device->hostdata)
+ return -1;
+
BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
@@ -4822,6 +4887,12 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
{
+ if (!c->scsi_cmd->device)
+ return -1;
+
+ if (!c->scsi_cmd->device->hostdata)
+ return -1;
+
/* Try to honor the device's queue depth */
if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
phys_disk->queue_depth) {
@@ -4902,12 +4973,17 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
#endif
int offload_to_mirror;
+ if (!dev)
+ return -1;
+
/* check for valid opcode, get LBA and block count */
switch (cmd->cmnd[0]) {
case WRITE_6:
is_write = 1;
case READ_6:
- first_block = get_unaligned_be16(&cmd->cmnd[2]);
+ first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
+ (cmd->cmnd[2] << 8) |
+ cmd->cmnd[3]);
block_cnt = cmd->cmnd[4];
if (block_cnt == 0)
block_cnt = 256;
@@ -5314,6 +5390,9 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
int rc = IO_ACCEL_INELIGIBLE;
+ if (!dev)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
cmd->host_scribble = (unsigned char *) c;
if (dev->offload_enabled) {
@@ -5852,6 +5931,9 @@ static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h,
struct scsi_cmnd *scmd = command_to_abort->scsi_cmd;
struct hpsa_scsi_dev_t *dev = scmd->device->hostdata;
+ if (!dev)
+ return;
+
/*
* We're overlaying struct hpsa_tmf_struct on top of something which
* was allocated as a struct io_accel2_cmd, so we better be sure it
@@ -5935,7 +6017,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
"Reset as abort: Resetting physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
psa[0], psa[1], psa[2], psa[3],
psa[4], psa[5], psa[6], psa[7]);
- rc = hpsa_do_reset(h, dev, psa, HPSA_RESET_TYPE_TARGET, reply_queue);
+ rc = hpsa_do_reset(h, dev, psa, HPSA_PHYS_TARGET_RESET, reply_queue);
if (rc != 0) {
dev_warn(&h->pdev->dev,
"Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
@@ -5972,6 +6054,9 @@ static int hpsa_send_abort_ioaccel2(struct ctlr_info *h,
struct io_accel2_cmd *c2;
dev = abort->scsi_cmd->device->hostdata;
+ if (!dev)
+ return -1;
+
if (!dev->offload_enabled && !dev->hba_ioaccel_enabled)
return -1;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index a1487e67f7a1..82cdfad874f3 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -312,7 +312,6 @@ struct offline_device_entry {
#define HPSA_DEVICE_RESET_MSG 1
#define HPSA_RESET_TYPE_CONTROLLER 0x00
#define HPSA_RESET_TYPE_BUS 0x01
-#define HPSA_RESET_TYPE_TARGET 0x03
#define HPSA_RESET_TYPE_LUN 0x04
#define HPSA_PHYS_TARGET_RESET 0x99 /* not defined by cciss spec */
#define HPSA_MSG_SEND_RETRY_LIMIT 10
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index a5be153d92d4..a584cdf07058 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -157,6 +157,7 @@
/* VPD Inquiry types */
#define HPSA_VPD_SUPPORTED_PAGES 0x00
+#define HPSA_VPD_LV_DEVICE_ID 0x83
#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
#define HPSA_VPD_LV_IOACCEL_STATUS 0xC2
#define HPSA_VPD_LV_STATUS 0xC3
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index ab67ec4b6bd6..7e487c78279c 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -52,6 +52,7 @@ static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT;
static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS;
static unsigned int ibmvfc_debug = IBMVFC_DEBUG;
static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL;
+static unsigned int cls3_error = IBMVFC_CLS3_ERROR;
static LIST_HEAD(ibmvfc_head);
static DEFINE_SPINLOCK(ibmvfc_driver_lock);
static struct scsi_transport_template *ibmvfc_transport_template;
@@ -86,6 +87,9 @@ MODULE_PARM_DESC(debug, "Enable driver debug information. "
module_param_named(log_level, log_level, uint, 0);
MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. "
"[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]");
+module_param_named(cls3_error, cls3_error, uint, 0);
+MODULE_PARM_DESC(cls3_error, "Enable FC Class 3 Error Recovery. "
+ "[Default=" __stringify(IBMVFC_CLS3_ERROR) "]");
static const struct {
u16 status;
@@ -717,7 +721,6 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
spin_lock_irqsave(vhost->host->host_lock, flags);
vhost->state = IBMVFC_NO_CRQ;
vhost->logged_in = 0;
- ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
/* Clean out the queue */
memset(crq->msgs, 0, PAGE_SIZE);
@@ -1335,6 +1338,9 @@ static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd,
struct srp_direct_buf *data = &vfc_cmd->ioba;
struct ibmvfc_host *vhost = dev_get_drvdata(dev);
+ if (cls3_error)
+ vfc_cmd->flags |= cpu_to_be16(IBMVFC_CLASS_3_ERR);
+
sg_mapped = scsi_dma_map(scmd);
if (!sg_mapped) {
vfc_cmd->flags |= cpu_to_be16(IBMVFC_NO_MEM_DESC);
@@ -3381,6 +3387,10 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt)
prli->parms.type = IBMVFC_SCSI_FCP_TYPE;
prli->parms.flags = cpu_to_be16(IBMVFC_PRLI_EST_IMG_PAIR);
prli->parms.service_parms = cpu_to_be32(IBMVFC_PRLI_INITIATOR_FUNC);
+ prli->parms.service_parms |= cpu_to_be32(IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED);
+
+ if (cls3_error)
+ prli->parms.service_parms |= cpu_to_be32(IBMVFC_PRLI_RETRY);
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
if (ibmvfc_send_event(evt, vhost, default_timeout)) {
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 5c70a52ad346..9a0696f68f37 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -54,6 +54,7 @@
#define IBMVFC_DEV_LOSS_TMO (5 * 60)
#define IBMVFC_DEFAULT_LOG_LEVEL 2
#define IBMVFC_MAX_CDB_LEN 16
+#define IBMVFC_CLS3_ERROR 0
/*
* Ensure we have resources for ERP and initialization:
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index b29fef9d0f27..642b739ad0da 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -1606,8 +1606,6 @@ static void ibmvscsis_send_messages(struct scsi_info *vscsi)
if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
- pr_debug("send_messages cmd %p\n", cmd);
-
iue = cmd->iue;
crq->valid = VALID_CMD_RESP_EL;
@@ -1934,6 +1932,8 @@ static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
/*
* Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port
*/
+ target_wait_for_sess_cmds(se_sess);
+ transport_deregister_session_configfs(se_sess);
transport_deregister_session(se_sess);
tport->ibmv_nexus = NULL;
kfree(nexus);
@@ -1978,7 +1978,7 @@ static long ibmvscsis_srp_login(struct scsi_info *vscsi,
reason = SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED;
else if (fmt->buffers & (~SUPPORTED_FORMATS))
reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
- else if ((fmt->buffers | SUPPORTED_FORMATS) == 0)
+ else if ((fmt->buffers & SUPPORTED_FORMATS) == 0)
reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
if (vscsi->state == SRP_PROCESSING)
@@ -2554,10 +2554,6 @@ static void ibmvscsis_parse_cmd(struct scsi_info *vscsi,
srp->lun.scsi_lun[0] &= 0x3f;
- pr_debug("calling submit_cmd, se_cmd %p, lun 0x%llx, cdb 0x%x, attr:%d\n",
- &cmd->se_cmd, scsilun_to_int(&srp->lun), (int)srp->cdb[0],
- attr);
-
rc = target_submit_cmd(&cmd->se_cmd, nexus->se_sess, srp->cdb,
cmd->sense_buf, scsilun_to_int(&srp->lun),
data_len, attr, dir, 0);
@@ -3142,8 +3138,6 @@ static int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, struct scatterlist *sg,
long tx_len;
long rc = 0;
- pr_debug("rdma: dir %d, bytes 0x%x\n", dir, bytes);
-
if (bytes == 0)
return 0;
@@ -3192,12 +3186,6 @@ static int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, struct scatterlist *sg,
vscsi->dds.window[LOCAL].liobn,
server_ioba);
} else {
- /* write to client */
- struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
-
- if (!READ_CMD(srp->cdb))
- print_hex_dump_bytes(" data:", DUMP_PREFIX_NONE,
- sg_virt(sgp), buf_len);
/* The h_copy_rdma will cause phyp, running in another
* partition, to read memory, so we need to make sure
* the data has been written out, hence these syncs.
@@ -3322,12 +3310,9 @@ cmd_work:
rc = ibmvscsis_trans_event(vscsi, crq);
} else if (vscsi->flags & TRANS_EVENT) {
/*
- * if a tranport event has occurred leave
+ * if a transport event has occurred leave
* everything but transport events on the queue
- */
- pr_debug("handle_crq, ignoring\n");
-
- /*
+ *
* need to decrement the queue index so we can
* look at the elment again
*/
@@ -3461,6 +3446,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev,
vscsi->map_ioba = dma_map_single(&vdev->dev, vscsi->map_buf, PAGE_SIZE,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(&vdev->dev, vscsi->map_ioba)) {
+ rc = -ENOMEM;
dev_err(&vscsi->dev, "probe: error mapping command buffer\n");
goto free_buf;
}
@@ -3693,12 +3679,9 @@ static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
se_cmd);
struct scsi_info *vscsi = cmd->adapter;
- pr_debug("release_cmd %p, flags %d\n", se_cmd, cmd->flags);
-
spin_lock_bh(&vscsi->intr_lock);
/* Remove from active_q */
- list_del(&cmd->list);
- list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+ list_move_tail(&cmd->list, &vscsi->waiting_rsp);
ibmvscsis_send_messages(vscsi);
spin_unlock_bh(&vscsi->intr_lock);
}
@@ -3715,9 +3698,6 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
struct iu_entry *iue = cmd->iue;
int rc;
- pr_debug("write_pending, se_cmd %p, length 0x%x\n",
- se_cmd, se_cmd->data_length);
-
rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma,
1, 1);
if (rc) {
@@ -3756,9 +3736,6 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
uint len = 0;
int rc;
- pr_debug("queue_data_in, se_cmd %p, length 0x%x\n",
- se_cmd, se_cmd->data_length);
-
rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma, 1,
1);
if (rc) {
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
deleted file mode 100644
index 3882d9f519c8..000000000000
--- a/drivers/scsi/in2000.c
+++ /dev/null
@@ -1,2302 +0,0 @@
-/*
- * in2000.c - Linux device driver for the
- * Always IN2000 ISA SCSI card.
- *
- * Copyright (c) 1996 John Shifflett, GeoLog Consulting
- * john@geolog.com
- * jshiffle@netcom.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- *
- * Drew Eckhardt's excellent 'Generic NCR5380' sources provided
- * much of the inspiration and some of the code for this driver.
- * The Linux IN2000 driver distributed in the Linux kernels through
- * version 1.2.13 was an extremely valuable reference on the arcane
- * (and still mysterious) workings of the IN2000's fifo. It also
- * is where I lifted in2000_biosparam(), the gist of the card
- * detection scheme, and other bits of code. Many thanks to the
- * talented and courageous people who wrote, contributed to, and
- * maintained that driver (including Brad McLean, Shaun Savage,
- * Bill Earnest, Larry Doolittle, Roger Sunshine, John Luckey,
- * Matt Postiff, Peter Lu, zerucha@shell.portal.com, and Eric
- * Youngdale). I should also mention the driver written by
- * Hamish Macdonald for the (GASP!) Amiga A2091 card, included
- * in the Linux-m68k distribution; it gave me a good initial
- * understanding of the proper way to run a WD33c93 chip, and I
- * ended up stealing lots of code from it.
- *
- * _This_ driver is (I feel) an improvement over the old one in
- * several respects:
- * - All problems relating to the data size of a SCSI request are
- * gone (as far as I know). The old driver couldn't handle
- * swapping to partitions because that involved 4k blocks, nor
- * could it deal with the st.c tape driver unmodified, because
- * that usually involved 4k - 32k blocks. The old driver never
- * quite got away from a morbid dependence on 2k block sizes -
- * which of course is the size of the card's fifo.
- *
- * - Target Disconnection/Reconnection is now supported. Any
- * system with more than one device active on the SCSI bus
- * will benefit from this. The driver defaults to what I'm
- * calling 'adaptive disconnect' - meaning that each command
- * is evaluated individually as to whether or not it should
- * be run with the option to disconnect/reselect (if the
- * device chooses), or as a "SCSI-bus-hog".
- *
- * - Synchronous data transfers are now supported. Because there
- * are a few devices (and many improperly terminated systems)
- * that choke when doing sync, the default is sync DISABLED
- * for all devices. This faster protocol can (and should!)
- * be enabled on selected devices via the command-line.
- *
- * - Runtime operating parameters can now be specified through
- * either the LILO or the 'insmod' command line. For LILO do:
- * "in2000=blah,blah,blah"
- * and with insmod go like:
- * "insmod /usr/src/linux/modules/in2000.o setup_strings=blah,blah"
- * The defaults should be good for most people. See the comment
- * for 'setup_strings' below for more details.
- *
- * - The old driver relied exclusively on what the Western Digital
- * docs call "Combination Level 2 Commands", which are a great
- * idea in that the CPU is relieved of a lot of interrupt
- * overhead. However, by accepting a certain (user-settable)
- * amount of additional interrupts, this driver achieves
- * better control over the SCSI bus, and data transfers are
- * almost as fast while being much easier to define, track,
- * and debug.
- *
- * - You can force detection of a card whose BIOS has been disabled.
- *
- * - Multiple IN2000 cards might almost be supported. I've tried to
- * keep it in mind, but have no way to test...
- *
- *
- * TODO:
- * tagged queuing. multiple cards.
- *
- *
- * NOTE:
- * When using this or any other SCSI driver as a module, you'll
- * find that with the stock kernel, at most _two_ SCSI hard
- * drives will be linked into the device list (ie, usable).
- * If your IN2000 card has more than 2 disks on its bus, you
- * might want to change the define of 'SD_EXTRA_DEVS' in the
- * 'hosts.h' file from 2 to whatever is appropriate. It took
- * me a while to track down this surprisingly obscure and
- * undocumented little "feature".
- *
- *
- * People with bug reports, wish-lists, complaints, comments,
- * or improvements are asked to pah-leeez email me (John Shifflett)
- * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get
- * this thing into as good a shape as possible, and I'm positive
- * there are lots of lurking bugs and "Stupid Places".
- *
- * Updated for Linux 2.5 by Alan Cox <alan@lxorguk.ukuu.org.uk>
- * - Using new_eh handler
- * - Hopefully got all the locking right again
- * See "FIXME" notes for items that could do with more work
- */
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/ioport.h>
-#include <linux/stat.h>
-
-#include <asm/io.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-#define IN2000_VERSION "1.33-2.5"
-#define IN2000_DATE "2002/11/03"
-
-#include "in2000.h"
-
-
-/*
- * 'setup_strings' is a single string used to pass operating parameters and
- * settings from the kernel/module command-line to the driver. 'setup_args[]'
- * is an array of strings that define the compile-time default values for
- * these settings. If Linux boots with a LILO or insmod command-line, those
- * settings are combined with 'setup_args[]'. Note that LILO command-lines
- * are prefixed with "in2000=" while insmod uses a "setup_strings=" prefix.
- * The driver recognizes the following keywords (lower case required) and
- * arguments:
- *
- * - ioport:addr -Where addr is IO address of a (usually ROM-less) card.
- * - noreset -No optional args. Prevents SCSI bus reset at boot time.
- * - nosync:x -x is a bitmask where the 1st 7 bits correspond with
- * the 7 possible SCSI devices (bit 0 for device #0, etc).
- * Set a bit to PREVENT sync negotiation on that device.
- * The driver default is sync DISABLED on all devices.
- * - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer
- * period. Default is 500; acceptable values are 250 - 1000.
- * - disconnect:x -x = 0 to never allow disconnects, 2 to always allow them.
- * x = 1 does 'adaptive' disconnects, which is the default
- * and generally the best choice.
- * - debug:x -If 'DEBUGGING_ON' is defined, x is a bitmask that causes
- * various types of debug output to printed - see the DB_xxx
- * defines in in2000.h
- * - proc:x -If 'PROC_INTERFACE' is defined, x is a bitmask that
- * determines how the /proc interface works and what it
- * does - see the PR_xxx defines in in2000.h
- *
- * Syntax Notes:
- * - Numeric arguments can be decimal or the '0x' form of hex notation. There
- * _must_ be a colon between a keyword and its numeric argument, with no
- * spaces.
- * - Keywords are separated by commas, no spaces, in the standard kernel
- * command-line manner.
- * - A keyword in the 'nth' comma-separated command-line member will overwrite
- * the 'nth' element of setup_args[]. A blank command-line member (in
- * other words, a comma with no preceding keyword) will _not_ overwrite
- * the corresponding setup_args[] element.
- *
- * A few LILO examples (for insmod, use 'setup_strings' instead of 'in2000'):
- * - in2000=ioport:0x220,noreset
- * - in2000=period:250,disconnect:2,nosync:0x03
- * - in2000=debug:0x1e
- * - in2000=proc:3
- */
-
-/* Normally, no defaults are specified... */
-static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
-
-/* filled in by 'insmod' */
-static char *setup_strings;
-
-module_param(setup_strings, charp, 0);
-
-static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num)
-{
- write1_io(reg_num, IO_WD_ADDR);
- return read1_io(IO_WD_DATA);
-}
-
-
-#define READ_AUX_STAT() read1_io(IO_WD_ASR)
-
-
-static inline void write_3393(struct IN2000_hostdata *hostdata, uchar reg_num, uchar value)
-{
- write1_io(reg_num, IO_WD_ADDR);
- write1_io(value, IO_WD_DATA);
-}
-
-
-static inline void write_3393_cmd(struct IN2000_hostdata *hostdata, uchar cmd)
-{
-/* while (READ_AUX_STAT() & ASR_CIP)
- printk("|");*/
- write1_io(WD_COMMAND, IO_WD_ADDR);
- write1_io(cmd, IO_WD_DATA);
-}
-
-
-static uchar read_1_byte(struct IN2000_hostdata *hostdata)
-{
- uchar asr, x = 0;
-
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
- write_3393_cmd(hostdata, WD_CMD_TRANS_INFO | 0x80);
- do {
- asr = READ_AUX_STAT();
- if (asr & ASR_DBR)
- x = read_3393(hostdata, WD_DATA);
- } while (!(asr & ASR_INT));
- return x;
-}
-
-
-static void write_3393_count(struct IN2000_hostdata *hostdata, unsigned long value)
-{
- write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
- write1_io((value >> 16), IO_WD_DATA);
- write1_io((value >> 8), IO_WD_DATA);
- write1_io(value, IO_WD_DATA);
-}
-
-
-static unsigned long read_3393_count(struct IN2000_hostdata *hostdata)
-{
- unsigned long value;
-
- write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
- value = read1_io(IO_WD_DATA) << 16;
- value |= read1_io(IO_WD_DATA) << 8;
- value |= read1_io(IO_WD_DATA);
- return value;
-}
-
-
-/* The 33c93 needs to be told which direction a command transfers its
- * data; we use this function to figure it out. Returns true if there
- * will be a DATA_OUT phase with this command, false otherwise.
- * (Thanks to Joerg Dorchain for the research and suggestion.)
- */
-static int is_dir_out(Scsi_Cmnd * cmd)
-{
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_LONG:
- case WRITE_SAME:
- case WRITE_BUFFER:
- case WRITE_VERIFY:
- case WRITE_VERIFY_12:
- case COMPARE:
- case COPY:
- case COPY_VERIFY:
- case SEARCH_EQUAL:
- case SEARCH_HIGH:
- case SEARCH_LOW:
- case SEARCH_EQUAL_12:
- case SEARCH_HIGH_12:
- case SEARCH_LOW_12:
- case FORMAT_UNIT:
- case REASSIGN_BLOCKS:
- case RESERVE:
- case MODE_SELECT:
- case MODE_SELECT_10:
- case LOG_SELECT:
- case SEND_DIAGNOSTIC:
- case CHANGE_DEFINITION:
- case UPDATE_BLOCK:
- case SET_WINDOW:
- case MEDIUM_SCAN:
- case SEND_VOLUME_TAG:
- case 0xea:
- return 1;
- default:
- return 0;
- }
-}
-
-
-
-static struct sx_period sx_table[] = {
- {1, 0x20},
- {252, 0x20},
- {376, 0x30},
- {500, 0x40},
- {624, 0x50},
- {752, 0x60},
- {876, 0x70},
- {1000, 0x00},
- {0, 0}
-};
-
-static int round_period(unsigned int period)
-{
- int x;
-
- for (x = 1; sx_table[x].period_ns; x++) {
- if ((period <= sx_table[x - 0].period_ns) && (period > sx_table[x - 1].period_ns)) {
- return x;
- }
- }
- return 7;
-}
-
-static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
-{
- uchar result;
-
- period *= 4; /* convert SDTR code to ns */
- result = sx_table[round_period(period)].reg_value;
- result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
- return result;
-}
-
-
-
-static void in2000_execute(struct Scsi_Host *instance);
-
-static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
- struct Scsi_Host *instance;
- struct IN2000_hostdata *hostdata;
- Scsi_Cmnd *tmp;
-
- instance = cmd->device->host;
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
-
- DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x(", cmd->cmnd[0]))
-
-/* Set up a few fields in the Scsi_Cmnd structure for our own use:
- * - host_scribble is the pointer to the next cmd in the input queue
- * - scsi_done points to the routine we call when a cmd is finished
- * - result is what you'd expect
- */
- cmd->host_scribble = NULL;
- cmd->scsi_done = done;
- cmd->result = 0;
-
-/* We use the Scsi_Pointer structure that's included with each command
- * as a scratchpad (as it's intended to be used!). The handy thing about
- * the SCp.xxx fields is that they're always associated with a given
- * cmd, and are preserved across disconnect-reselect. This means we
- * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages
- * if we keep all the critical pointers and counters in SCp:
- * - SCp.ptr is the pointer into the RAM buffer
- * - SCp.this_residual is the size of that buffer
- * - SCp.buffer points to the current scatter-gather buffer
- * - SCp.buffers_residual tells us how many S.G. buffers there are
- * - SCp.have_data_in helps keep track of >2048 byte transfers
- * - SCp.sent_command is not used
- * - SCp.phase records this command's SRCID_ER bit setting
- */
-
- if (scsi_bufflen(cmd)) {
- cmd->SCp.buffer = scsi_sglist(cmd);
- cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- } else {
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = NULL;
- cmd->SCp.this_residual = 0;
- }
- cmd->SCp.have_data_in = 0;
-
-/* We don't set SCp.phase here - that's done in in2000_execute() */
-
-/* WD docs state that at the conclusion of a "LEVEL2" command, the
- * status byte can be retrieved from the LUN register. Apparently,
- * this is the case only for *uninterrupted* LEVEL2 commands! If
- * there are any unexpected phases entered, even if they are 100%
- * legal (different devices may choose to do things differently),
- * the LEVEL2 command sequence is exited. This often occurs prior
- * to receiving the status byte, in which case the driver does a
- * status phase interrupt and gets the status byte on its own.
- * While such a command can then be "resumed" (ie restarted to
- * finish up as a LEVEL2 command), the LUN register will NOT be
- * a valid status byte at the command's conclusion, and we must
- * use the byte obtained during the earlier interrupt. Here, we
- * preset SCp.Status to an illegal value (0xff) so that when
- * this command finally completes, we can tell where the actual
- * status byte is stored.
- */
-
- cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
-
-/* We need to disable interrupts before messing with the input
- * queue and calling in2000_execute().
- */
-
- /*
- * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE
- * commands are added to the head of the queue so that the desired
- * sense data is not lost before REQUEST_SENSE executes.
- */
-
- if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- cmd->host_scribble = (uchar *) hostdata->input_Q;
- hostdata->input_Q = cmd;
- } else { /* find the end of the queue */
- for (tmp = (Scsi_Cmnd *) hostdata->input_Q; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
- tmp->host_scribble = (uchar *) cmd;
- }
-
-/* We know that there's at least one command in 'input_Q' now.
- * Go see if any of them are runnable!
- */
-
- in2000_execute(cmd->device->host);
-
- DB(DB_QUEUE_COMMAND, printk(")Q "))
- return 0;
-}
-
-static DEF_SCSI_QCMD(in2000_queuecommand)
-
-
-
-/*
- * This routine attempts to start a scsi command. If the host_card is
- * already connected, we give up immediately. Otherwise, look through
- * the input_Q, using the first command we find that's intended
- * for a currently non-busy target/lun.
- * Note that this function is always called with interrupts already
- * disabled (either from in2000_queuecommand() or in2000_intr()).
- */
-static void in2000_execute(struct Scsi_Host *instance)
-{
- struct IN2000_hostdata *hostdata;
- Scsi_Cmnd *cmd, *prev;
- int i;
- unsigned short *sp;
- unsigned short f;
- unsigned short flushbuf[16];
-
-
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
-
- DB(DB_EXECUTE, printk("EX("))
-
- if (hostdata->selecting || hostdata->connected) {
-
- DB(DB_EXECUTE, printk(")EX-0 "))
-
- return;
- }
-
- /*
- * Search through the input_Q for a command destined
- * for an idle target/lun.
- */
-
- cmd = (Scsi_Cmnd *) hostdata->input_Q;
- prev = NULL;
- while (cmd) {
- if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)))
- break;
- prev = cmd;
- cmd = (Scsi_Cmnd *) cmd->host_scribble;
- }
-
- /* quit if queue empty or all possible targets are busy */
-
- if (!cmd) {
-
- DB(DB_EXECUTE, printk(")EX-1 "))
-
- return;
- }
-
- /* remove command from queue */
-
- if (prev)
- prev->host_scribble = cmd->host_scribble;
- else
- hostdata->input_Q = (Scsi_Cmnd *) cmd->host_scribble;
-
-#ifdef PROC_STATISTICS
- hostdata->cmd_cnt[cmd->device->id]++;
-#endif
-
-/*
- * Start the selection process
- */
-
- if (is_dir_out(cmd))
- write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id);
- else
- write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
-
-/* Now we need to figure out whether or not this command is a good
- * candidate for disconnect/reselect. We guess to the best of our
- * ability, based on a set of hierarchical rules. When several
- * devices are operating simultaneously, disconnects are usually
- * an advantage. In a single device system, or if only 1 device
- * is being accessed, transfers usually go faster if disconnects
- * are not allowed:
- *
- * + Commands should NEVER disconnect if hostdata->disconnect =
- * DIS_NEVER (this holds for tape drives also), and ALWAYS
- * disconnect if hostdata->disconnect = DIS_ALWAYS.
- * + Tape drive commands should always be allowed to disconnect.
- * + Disconnect should be allowed if disconnected_Q isn't empty.
- * + Commands should NOT disconnect if input_Q is empty.
- * + Disconnect should be allowed if there are commands in input_Q
- * for a different target/lun. In this case, the other commands
- * should be made disconnect-able, if not already.
- *
- * I know, I know - this code would flunk me out of any
- * "C Programming 101" class ever offered. But it's easy
- * to change around and experiment with for now.
- */
-
- cmd->SCp.phase = 0; /* assume no disconnect */
- if (hostdata->disconnect == DIS_NEVER)
- goto no;
- if (hostdata->disconnect == DIS_ALWAYS)
- goto yes;
- if (cmd->device->type == 1) /* tape drive? */
- goto yes;
- if (hostdata->disconnected_Q) /* other commands disconnected? */
- goto yes;
- if (!(hostdata->input_Q)) /* input_Q empty? */
- goto no;
- for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble) {
- if ((prev->device->id != cmd->device->id) || (prev->device->lun != cmd->device->lun)) {
- for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble)
- prev->SCp.phase = 1;
- goto yes;
- }
- }
- goto no;
-
- yes:
- cmd->SCp.phase = 1;
-
-#ifdef PROC_STATISTICS
- hostdata->disc_allowed_cnt[cmd->device->id]++;
-#endif
-
- no:
- write_3393(hostdata, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0));
-
- write_3393(hostdata, WD_TARGET_LUN, cmd->device->lun);
- write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]);
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-
- if ((hostdata->level2 <= L2_NONE) || (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) {
-
- /*
- * Do a 'Select-With-ATN' command. This will end with
- * one of the following interrupts:
- * CSR_RESEL_AM: failure - can try again later.
- * CSR_TIMEOUT: failure - give up.
- * CSR_SELECT: success - proceed.
- */
-
- hostdata->selecting = cmd;
-
-/* Every target has its own synchronous transfer setting, kept in
- * the sync_xfer array, and a corresponding status byte in sync_stat[].
- * Each target's sync_stat[] entry is initialized to SS_UNSET, and its
- * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET
- * means that the parameters are undetermined as yet, and that we
- * need to send an SDTR message to this device after selection is
- * complete. We set SS_FIRST to tell the interrupt routine to do so,
- * unless we don't want to even _try_ synchronous transfers: In this
- * case we set SS_SET to make the defaults final.
- */
- if (hostdata->sync_stat[cmd->device->id] == SS_UNSET) {
- if (hostdata->sync_off & (1 << cmd->device->id))
- hostdata->sync_stat[cmd->device->id] = SS_SET;
- else
- hostdata->sync_stat[cmd->device->id] = SS_FIRST;
- }
- hostdata->state = S_SELECTING;
- write_3393_count(hostdata, 0); /* this guarantees a DATA_PHASE interrupt */
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN);
- }
-
- else {
-
- /*
- * Do a 'Select-With-ATN-Xfer' command. This will end with
- * one of the following interrupts:
- * CSR_RESEL_AM: failure - can try again later.
- * CSR_TIMEOUT: failure - give up.
- * anything else: success - proceed.
- */
-
- hostdata->connected = cmd;
- write_3393(hostdata, WD_COMMAND_PHASE, 0);
-
- /* copy command_descriptor_block into WD chip
- * (take advantage of auto-incrementing)
- */
-
- write1_io(WD_CDB_1, IO_WD_ADDR);
- for (i = 0; i < cmd->cmd_len; i++)
- write1_io(cmd->cmnd[i], IO_WD_DATA);
-
- /* The wd33c93 only knows about Group 0, 1, and 5 commands when
- * it's doing a 'select-and-transfer'. To be safe, we write the
- * size of the CDB into the OWN_ID register for every case. This
- * way there won't be problems with vendor-unique, audio, etc.
- */
-
- write_3393(hostdata, WD_OWN_ID, cmd->cmd_len);
-
- /* When doing a non-disconnect command, we can save ourselves a DATA
- * phase interrupt later by setting everything up now. With writes we
- * need to pre-fill the fifo; if there's room for the 32 flush bytes,
- * put them in there too - that'll avoid a fifo interrupt. Reads are
- * somewhat simpler.
- * KLUDGE NOTE: It seems that you can't completely fill the fifo here:
- * This results in the IO_FIFO_COUNT register rolling over to zero,
- * and apparently the gate array logic sees this as empty, not full,
- * so the 3393 chip is never signalled to start reading from the
- * fifo. Or maybe it's seen as a permanent fifo interrupt condition.
- * Regardless, we fix this by temporarily pretending that the fifo
- * is 16 bytes smaller. (I see now that the old driver has a comment
- * about "don't fill completely" in an analogous place - must be the
- * same deal.) This results in CDROM, swap partitions, and tape drives
- * needing an extra interrupt per write command - I think we can live
- * with that!
- */
-
- if (!(cmd->SCp.phase)) {
- write_3393_count(hostdata, cmd->SCp.this_residual);
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
- write1_io(0, IO_FIFO_WRITE); /* clear fifo counter, write mode */
-
- if (is_dir_out(cmd)) {
- hostdata->fifo = FI_FIFO_WRITING;
- if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16))
- i = IN2000_FIFO_SIZE - 16;
- cmd->SCp.have_data_in = i; /* this much data in fifo */
- i >>= 1; /* Gulp. Assuming modulo 2. */
- sp = (unsigned short *) cmd->SCp.ptr;
- f = hostdata->io_base + IO_FIFO;
-
-#ifdef FAST_WRITE_IO
-
- FAST_WRITE2_IO();
-#else
- while (i--)
- write2_io(*sp++, IO_FIFO);
-
-#endif
-
- /* Is there room for the flush bytes? */
-
- if (cmd->SCp.have_data_in <= ((IN2000_FIFO_SIZE - 16) - 32)) {
- sp = flushbuf;
- i = 16;
-
-#ifdef FAST_WRITE_IO
-
- FAST_WRITE2_IO();
-#else
- while (i--)
- write2_io(0, IO_FIFO);
-
-#endif
-
- }
- }
-
- else {
- write1_io(0, IO_FIFO_READ); /* put fifo in read mode */
- hostdata->fifo = FI_FIFO_READING;
- cmd->SCp.have_data_in = 0; /* nothing transferred yet */
- }
-
- } else {
- write_3393_count(hostdata, 0); /* this guarantees a DATA_PHASE interrupt */
- }
- hostdata->state = S_RUNNING_LEVEL2;
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- }
-
- /*
- * Since the SCSI bus can handle only 1 connection at a time,
- * we get out of here now. If the selection fails, or when
- * the command disconnects, we'll come back to this routine
- * to search the input_Q again...
- */
-
- DB(DB_EXECUTE, printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : ""))
-
-}
-
-
-
-static void transfer_pio(uchar * buf, int cnt, int data_in_dir, struct IN2000_hostdata *hostdata)
-{
- uchar asr;
-
- DB(DB_TRANSFER, printk("(%p,%d,%s)", buf, cnt, data_in_dir ? "in" : "out"))
-
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
- write_3393_count(hostdata, cnt);
- write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
- if (data_in_dir) {
- do {
- asr = READ_AUX_STAT();
- if (asr & ASR_DBR)
- *buf++ = read_3393(hostdata, WD_DATA);
- } while (!(asr & ASR_INT));
- } else {
- do {
- asr = READ_AUX_STAT();
- if (asr & ASR_DBR)
- write_3393(hostdata, WD_DATA, *buf++);
- } while (!(asr & ASR_INT));
- }
-
- /* Note: we are returning with the interrupt UN-cleared.
- * Since (presumably) an entire I/O operation has
- * completed, the bus phase is probably different, and
- * the interrupt routine will discover this when it
- * responds to the uncleared int.
- */
-
-}
-
-
-
-static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
-{
- struct IN2000_hostdata *hostdata;
- unsigned short *sp;
- unsigned short f;
- int i;
-
- hostdata = (struct IN2000_hostdata *) cmd->device->host->hostdata;
-
-/* Normally, you'd expect 'this_residual' to be non-zero here.
- * In a series of scatter-gather transfers, however, this
- * routine will usually be called with 'this_residual' equal
- * to 0 and 'buffers_residual' non-zero. This means that a
- * previous transfer completed, clearing 'this_residual', and
- * now we need to setup the next scatter-gather buffer as the
- * source or destination for THIS transfer.
- */
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- }
-
-/* Set up hardware registers */
-
- write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]);
- write_3393_count(hostdata, cmd->SCp.this_residual);
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
- write1_io(0, IO_FIFO_WRITE); /* zero counter, assume write */
-
-/* Reading is easy. Just issue the command and return - we'll
- * get an interrupt later when we have actual data to worry about.
- */
-
- if (data_in_dir) {
- write1_io(0, IO_FIFO_READ);
- if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
- write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- hostdata->state = S_RUNNING_LEVEL2;
- } else
- write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
- hostdata->fifo = FI_FIFO_READING;
- cmd->SCp.have_data_in = 0;
- return;
- }
-
-/* Writing is more involved - we'll start the WD chip and write as
- * much data to the fifo as we can right now. Later interrupts will
- * write any bytes that don't make it at this stage.
- */
-
- if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
- write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- hostdata->state = S_RUNNING_LEVEL2;
- } else
- write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
- hostdata->fifo = FI_FIFO_WRITING;
- sp = (unsigned short *) cmd->SCp.ptr;
-
- if ((i = cmd->SCp.this_residual) > IN2000_FIFO_SIZE)
- i = IN2000_FIFO_SIZE;
- cmd->SCp.have_data_in = i;
- i >>= 1; /* Gulp. We assume this_residual is modulo 2 */
- f = hostdata->io_base + IO_FIFO;
-
-#ifdef FAST_WRITE_IO
-
- FAST_WRITE2_IO();
-#else
- while (i--)
- write2_io(*sp++, IO_FIFO);
-
-#endif
-
-}
-
-
-/* We need to use spin_lock_irqsave() & spin_unlock_irqrestore() in this
- * function in order to work in an SMP environment. (I'd be surprised
- * if the driver is ever used by anyone on a real multi-CPU motherboard,
- * but it _does_ need to be able to compile and run in an SMP kernel.)
- */
-
-static irqreturn_t in2000_intr(int irqnum, void *dev_id)
-{
- struct Scsi_Host *instance = dev_id;
- struct IN2000_hostdata *hostdata;
- Scsi_Cmnd *patch, *cmd;
- uchar asr, sr, phs, id, lun, *ucp, msg;
- int i, j;
- unsigned long length;
- unsigned short *sp;
- unsigned short f;
- unsigned long flags;
-
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
-
-/* Get the spin_lock and disable further ints, for SMP */
-
- spin_lock_irqsave(instance->host_lock, flags);
-
-#ifdef PROC_STATISTICS
- hostdata->int_cnt++;
-#endif
-
-/* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the
- * WD3393 chip and the 2k fifo (which is actually a dual-port RAM combined
- * with a big logic array, so it's a little different than what you might
- * expect). As far as I know, there's no reason that BOTH can't be active
- * at the same time, but there's a problem: while we can read the 3393
- * to tell if _it_ wants an interrupt, I don't know of a way to ask the
- * fifo the same question. The best we can do is check the 3393 and if
- * it _isn't_ the source of the interrupt, then we can be pretty sure
- * that the fifo is the culprit.
- * UPDATE: I have it on good authority (Bill Earnest) that bit 0 of the
- * IO_FIFO_COUNT register mirrors the fifo interrupt state. I
- * assume that bit clear means interrupt active. As it turns
- * out, the driver really doesn't need to check for this after
- * all, so my remarks above about a 'problem' can safely be
- * ignored. The way the logic is set up, there's no advantage
- * (that I can see) to worrying about it.
- *
- * It seems that the fifo interrupt signal is negated when we extract
- * bytes during read or write bytes during write.
- * - fifo will interrupt when data is moving from it to the 3393, and
- * there are 31 (or less?) bytes left to go. This is sort of short-
- * sighted: what if you don't WANT to do more? In any case, our
- * response is to push more into the fifo - either actual data or
- * dummy bytes if need be. Note that we apparently have to write at
- * least 32 additional bytes to the fifo after an interrupt in order
- * to get it to release the ones it was holding on to - writing fewer
- * than 32 will result in another fifo int.
- * UPDATE: Again, info from Bill Earnest makes this more understandable:
- * 32 bytes = two counts of the fifo counter register. He tells
- * me that the fifo interrupt is a non-latching signal derived
- * from a straightforward boolean interpretation of the 7
- * highest bits of the fifo counter and the fifo-read/fifo-write
- * state. Who'd a thought?
- */
-
- write1_io(0, IO_LED_ON);
- asr = READ_AUX_STAT();
- if (!(asr & ASR_INT)) { /* no WD33c93 interrupt? */
-
-/* Ok. This is definitely a FIFO-only interrupt.
- *
- * If FI_FIFO_READING is set, there are up to 2048 bytes waiting to be read,
- * maybe more to come from the SCSI bus. Read as many as we can out of the
- * fifo and into memory at the location of SCp.ptr[SCp.have_data_in], and
- * update have_data_in afterwards.
- *
- * If we have FI_FIFO_WRITING, the FIFO has almost run out of bytes to move
- * into the WD3393 chip (I think the interrupt happens when there are 31
- * bytes left, but it may be fewer...). The 3393 is still waiting, so we
- * shove some more into the fifo, which gets things moving again. If the
- * original SCSI command specified more than 2048 bytes, there may still
- * be some of that data left: fine - use it (from SCp.ptr[SCp.have_data_in]).
- * Don't forget to update have_data_in. If we've already written out the
- * entire buffer, feed 32 dummy bytes to the fifo - they're needed to
- * push out the remaining real data.
- * (Big thanks to Bill Earnest for getting me out of the mud in here.)
- */
-
- cmd = (Scsi_Cmnd *) hostdata->connected; /* assume we're connected */
- CHECK_NULL(cmd, "fifo_int")
-
- if (hostdata->fifo == FI_FIFO_READING) {
-
- DB(DB_FIFO, printk("{R:%02x} ", read1_io(IO_FIFO_COUNT)))
-
- sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
- i = read1_io(IO_FIFO_COUNT) & 0xfe;
- i <<= 2; /* # of words waiting in the fifo */
- f = hostdata->io_base + IO_FIFO;
-
-#ifdef FAST_READ_IO
-
- FAST_READ2_IO();
-#else
- while (i--)
- *sp++ = read2_io(IO_FIFO);
-
-#endif
-
- i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
- i <<= 1;
- cmd->SCp.have_data_in += i;
- }
-
- else if (hostdata->fifo == FI_FIFO_WRITING) {
-
- DB(DB_FIFO, printk("{W:%02x} ", read1_io(IO_FIFO_COUNT)))
-
-/* If all bytes have been written to the fifo, flush out the stragglers.
- * Note that while writing 16 dummy words seems arbitrary, we don't
- * have another choice that I can see. What we really want is to read
- * the 3393 transfer count register (that would tell us how many bytes
- * needed flushing), but the TRANSFER_INFO command hasn't completed
- * yet (not enough bytes!) and that register won't be accessible. So,
- * we use 16 words - a number obtained through trial and error.
- * UPDATE: Bill says this is exactly what Always does, so there.
- * More thanks due him for help in this section.
- */
- if (cmd->SCp.this_residual == cmd->SCp.have_data_in) {
- i = 16;
- while (i--) /* write 32 dummy bytes */
- write2_io(0, IO_FIFO);
- }
-
-/* If there are still bytes left in the SCSI buffer, write as many as we
- * can out to the fifo.
- */
-
- else {
- sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
- i = cmd->SCp.this_residual - cmd->SCp.have_data_in; /* bytes yet to go */
- j = read1_io(IO_FIFO_COUNT) & 0xfe;
- j <<= 2; /* how many words the fifo has room for */
- if ((j << 1) > i)
- j = (i >> 1);
- while (j--)
- write2_io(*sp++, IO_FIFO);
-
- i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
- i <<= 1;
- cmd->SCp.have_data_in += i;
- }
- }
-
- else {
- printk("*** Spurious FIFO interrupt ***");
- }
-
- write1_io(0, IO_LED_OFF);
-
-/* release the SMP spin_lock and restore irq state */
- spin_unlock_irqrestore(instance->host_lock, flags);
- return IRQ_HANDLED;
- }
-
-/* This interrupt was triggered by the WD33c93 chip. The fifo interrupt
- * may also be asserted, but we don't bother to check it: we get more
- * detailed info from FIFO_READING and FIFO_WRITING (see below).
- */
-
- cmd = (Scsi_Cmnd *) hostdata->connected; /* assume we're connected */
- sr = read_3393(hostdata, WD_SCSI_STATUS); /* clear the interrupt */
- phs = read_3393(hostdata, WD_COMMAND_PHASE);
-
- if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) {
- printk("\nNR:wd-intr-1\n");
- write1_io(0, IO_LED_OFF);
-
-/* release the SMP spin_lock and restore irq state */
- spin_unlock_irqrestore(instance->host_lock, flags);
- return IRQ_HANDLED;
- }
-
- DB(DB_INTR, printk("{%02x:%02x-", asr, sr))
-
-/* After starting a FIFO-based transfer, the next _WD3393_ interrupt is
- * guaranteed to be in response to the completion of the transfer.
- * If we were reading, there's probably data in the fifo that needs
- * to be copied into RAM - do that here. Also, we have to update
- * 'this_residual' and 'ptr' based on the contents of the
- * TRANSFER_COUNT register, in case the device decided to do an
- * intermediate disconnect (a device may do this if it has to
- * do a seek, or just to be nice and let other devices have
- * some bus time during long transfers).
- * After doing whatever is necessary with the fifo, we go on and
- * service the WD3393 interrupt normally.
- */
- if (hostdata->fifo == FI_FIFO_READING) {
-
-/* buffer index = start-of-buffer + #-of-bytes-already-read */
-
- sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
-
-/* bytes remaining in fifo = (total-wanted - #-not-got) - #-already-read */
-
- i = (cmd->SCp.this_residual - read_3393_count(hostdata)) - cmd->SCp.have_data_in;
- i >>= 1; /* Gulp. We assume this will always be modulo 2 */
- f = hostdata->io_base + IO_FIFO;
-
-#ifdef FAST_READ_IO
-
- FAST_READ2_IO();
-#else
- while (i--)
- *sp++ = read2_io(IO_FIFO);
-
-#endif
-
- hostdata->fifo = FI_FIFO_UNUSED;
- length = cmd->SCp.this_residual;
- cmd->SCp.this_residual = read_3393_count(hostdata);
- cmd->SCp.ptr += (length - cmd->SCp.this_residual);
-
- DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))
-
- }
-
- else if (hostdata->fifo == FI_FIFO_WRITING) {
- hostdata->fifo = FI_FIFO_UNUSED;
- length = cmd->SCp.this_residual;
- cmd->SCp.this_residual = read_3393_count(hostdata);
- cmd->SCp.ptr += (length - cmd->SCp.this_residual);
-
- DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))
-
- }
-
-/* Respond to the specific WD3393 interrupt - there are quite a few! */
-
- switch (sr) {
-
- case CSR_TIMEOUT:
- DB(DB_INTR, printk("TIMEOUT"))
-
- if (hostdata->state == S_RUNNING_LEVEL2)
- hostdata->connected = NULL;
- else {
- cmd = (Scsi_Cmnd *) hostdata->selecting; /* get a valid cmd */
- CHECK_NULL(cmd, "csr_timeout")
- hostdata->selecting = NULL;
- }
-
- cmd->result = DID_NO_CONNECT << 16;
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- hostdata->state = S_UNCONNECTED;
- cmd->scsi_done(cmd);
-
-/* We are not connected to a target - check to see if there
- * are commands waiting to be executed.
- */
-
- in2000_execute(instance);
- break;
-
-
-/* Note: this interrupt should not occur in a LEVEL2 command */
-
- case CSR_SELECT:
- DB(DB_INTR, printk("SELECT"))
- hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting;
- CHECK_NULL(cmd, "csr_select")
- hostdata->selecting = NULL;
-
- /* construct an IDENTIFY message with correct disconnect bit */
-
- hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun);
- if (cmd->SCp.phase)
- hostdata->outgoing_msg[0] |= 0x40;
-
- if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {
-#ifdef SYNC_DEBUG
- printk(" sending SDTR ");
-#endif
-
- hostdata->sync_stat[cmd->device->id] = SS_WAITING;
-
- /* tack on a 2nd message to ask about synchronous transfers */
-
- hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
- hostdata->outgoing_msg[2] = 3;
- hostdata->outgoing_msg[3] = EXTENDED_SDTR;
- hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;
- hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
- hostdata->outgoing_len = 6;
- } else
- hostdata->outgoing_len = 1;
-
- hostdata->state = S_CONNECTED;
- break;
-
-
- case CSR_XFER_DONE | PHS_DATA_IN:
- case CSR_UNEXP | PHS_DATA_IN:
- case CSR_SRV_REQ | PHS_DATA_IN:
- DB(DB_INTR, printk("IN-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))
- transfer_bytes(cmd, DATA_IN_DIR);
- if (hostdata->state != S_RUNNING_LEVEL2)
- hostdata->state = S_CONNECTED;
- break;
-
-
- case CSR_XFER_DONE | PHS_DATA_OUT:
- case CSR_UNEXP | PHS_DATA_OUT:
- case CSR_SRV_REQ | PHS_DATA_OUT:
- DB(DB_INTR, printk("OUT-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))
- transfer_bytes(cmd, DATA_OUT_DIR);
- if (hostdata->state != S_RUNNING_LEVEL2)
- hostdata->state = S_CONNECTED;
- break;
-
-
-/* Note: this interrupt should not occur in a LEVEL2 command */
-
- case CSR_XFER_DONE | PHS_COMMAND:
- case CSR_UNEXP | PHS_COMMAND:
- case CSR_SRV_REQ | PHS_COMMAND:
- DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0]))
- transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
- hostdata->state = S_CONNECTED;
- break;
-
-
- case CSR_XFER_DONE | PHS_STATUS:
- case CSR_UNEXP | PHS_STATUS:
- case CSR_SRV_REQ | PHS_STATUS:
- DB(DB_INTR, printk("STATUS="))
-
- cmd->SCp.Status = read_1_byte(hostdata);
- DB(DB_INTR, printk("%02x", cmd->SCp.Status))
- if (hostdata->level2 >= L2_BASIC) {
- sr = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */
- hostdata->state = S_RUNNING_LEVEL2;
- write_3393(hostdata, WD_COMMAND_PHASE, 0x50);
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- } else {
- hostdata->state = S_CONNECTED;
- }
- break;
-
-
- case CSR_XFER_DONE | PHS_MESS_IN:
- case CSR_UNEXP | PHS_MESS_IN:
- case CSR_SRV_REQ | PHS_MESS_IN:
- DB(DB_INTR, printk("MSG_IN="))
-
- msg = read_1_byte(hostdata);
- sr = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */
-
- hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
- if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
- msg = EXTENDED_MESSAGE;
- else
- hostdata->incoming_ptr = 0;
-
- cmd->SCp.Message = msg;
- switch (msg) {
-
- case COMMAND_COMPLETE:
- DB(DB_INTR, printk("CCMP"))
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_PRE_CMP_DISC;
- break;
-
- case SAVE_POINTERS:
- DB(DB_INTR, printk("SDP"))
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- break;
-
- case RESTORE_POINTERS:
- DB(DB_INTR, printk("RDP"))
- if (hostdata->level2 >= L2_BASIC) {
- write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- hostdata->state = S_RUNNING_LEVEL2;
- } else {
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- }
- break;
-
- case DISCONNECT:
- DB(DB_INTR, printk("DIS"))
- cmd->device->disconnect = 1;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_PRE_TMP_DISC;
- break;
-
- case MESSAGE_REJECT:
- DB(DB_INTR, printk("REJ"))
-#ifdef SYNC_DEBUG
- printk("-REJ-");
-#endif
- if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)
- hostdata->sync_stat[cmd->device->id] = SS_SET;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- break;
-
- case EXTENDED_MESSAGE:
- DB(DB_INTR, printk("EXT"))
-
- ucp = hostdata->incoming_msg;
-
-#ifdef SYNC_DEBUG
- printk("%02x", ucp[hostdata->incoming_ptr]);
-#endif
- /* Is this the last byte of the extended message? */
-
- if ((hostdata->incoming_ptr >= 2) && (hostdata->incoming_ptr == (ucp[1] + 1))) {
-
- switch (ucp[2]) { /* what's the EXTENDED code? */
- case EXTENDED_SDTR:
- id = calc_sync_xfer(ucp[3], ucp[4]);
- if (hostdata->sync_stat[cmd->device->id] != SS_WAITING) {
-
-/* A device has sent an unsolicited SDTR message; rather than go
- * through the effort of decoding it and then figuring out what
- * our reply should be, we're just gonna say that we have a
- * synchronous fifo depth of 0. This will result in asynchronous
- * transfers - not ideal but so much easier.
- * Actually, this is OK because it assures us that if we don't
- * specifically ask for sync transfers, we won't do any.
- */
-
- write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
- hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
- hostdata->outgoing_msg[1] = 3;
- hostdata->outgoing_msg[2] = EXTENDED_SDTR;
- hostdata->outgoing_msg[3] = hostdata->default_sx_per / 4;
- hostdata->outgoing_msg[4] = 0;
- hostdata->outgoing_len = 5;
- hostdata->sync_xfer[cmd->device->id] = calc_sync_xfer(hostdata->default_sx_per / 4, 0);
- } else {
- hostdata->sync_xfer[cmd->device->id] = id;
- }
-#ifdef SYNC_DEBUG
- printk("sync_xfer=%02x", hostdata->sync_xfer[cmd->device->id]);
-#endif
- hostdata->sync_stat[cmd->device->id] = SS_SET;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- break;
- case EXTENDED_WDTR:
- write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
- printk("sending WDTR ");
- hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
- hostdata->outgoing_msg[1] = 2;
- hostdata->outgoing_msg[2] = EXTENDED_WDTR;
- hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */
- hostdata->outgoing_len = 4;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- break;
- default:
- write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
- printk("Rejecting Unknown Extended Message(%02x). ", ucp[2]);
- hostdata->outgoing_msg[0] = MESSAGE_REJECT;
- hostdata->outgoing_len = 1;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- break;
- }
- hostdata->incoming_ptr = 0;
- }
-
- /* We need to read more MESS_IN bytes for the extended message */
-
- else {
- hostdata->incoming_ptr++;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- }
- break;
-
- default:
- printk("Rejecting Unknown Message(%02x) ", msg);
- write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */
- hostdata->outgoing_msg[0] = MESSAGE_REJECT;
- hostdata->outgoing_len = 1;
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- hostdata->state = S_CONNECTED;
- }
- break;
-
-
-/* Note: this interrupt will occur only after a LEVEL2 command */
-
- case CSR_SEL_XFER_DONE:
-
-/* Make sure that reselection is enabled at this point - it may
- * have been turned off for the command that just completed.
- */
-
- write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
- if (phs == 0x60) {
- DB(DB_INTR, printk("SX-DONE"))
- cmd->SCp.Message = COMMAND_COMPLETE;
- lun = read_3393(hostdata, WD_TARGET_LUN);
- DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
- hostdata->connected = NULL;
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- hostdata->state = S_UNCONNECTED;
- if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
- cmd->SCp.Status = lun;
- if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- else
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- cmd->scsi_done(cmd);
-
-/* We are no longer connected to a target - check to see if
- * there are commands waiting to be executed.
- */
-
- in2000_execute(instance);
- } else {
- printk("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs);
- }
- break;
-
-
-/* Note: this interrupt will occur only after a LEVEL2 command */
-
- case CSR_SDP:
- DB(DB_INTR, printk("SDP"))
- hostdata->state = S_RUNNING_LEVEL2;
- write_3393(hostdata, WD_COMMAND_PHASE, 0x41);
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- break;
-
-
- case CSR_XFER_DONE | PHS_MESS_OUT:
- case CSR_UNEXP | PHS_MESS_OUT:
- case CSR_SRV_REQ | PHS_MESS_OUT:
- DB(DB_INTR, printk("MSG_OUT="))
-
-/* To get here, we've probably requested MESSAGE_OUT and have
- * already put the correct bytes in outgoing_msg[] and filled
- * in outgoing_len. We simply send them out to the SCSI bus.
- * Sometimes we get MESSAGE_OUT phase when we're not expecting
- * it - like when our SDTR message is rejected by a target. Some
- * targets send the REJECT before receiving all of the extended
- * message, and then seem to go back to MESSAGE_OUT for a byte
- * or two. Not sure why, or if I'm doing something wrong to
- * cause this to happen. Regardless, it seems that sending
- * NOP messages in these situations results in no harm and
- * makes everyone happy.
- */
- if (hostdata->outgoing_len == 0) {
- hostdata->outgoing_len = 1;
- hostdata->outgoing_msg[0] = NOP;
- }
- transfer_pio(hostdata->outgoing_msg, hostdata->outgoing_len, DATA_OUT_DIR, hostdata);
- DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))
- hostdata->outgoing_len = 0;
- hostdata->state = S_CONNECTED;
- break;
-
-
- case CSR_UNEXP_DISC:
-
-/* I think I've seen this after a request-sense that was in response
- * to an error condition, but not sure. We certainly need to do
- * something when we get this interrupt - the question is 'what?'.
- * Let's think positively, and assume some command has finished
- * in a legal manner (like a command that provokes a request-sense),
- * so we treat it as a normal command-complete-disconnect.
- */
-
-
-/* Make sure that reselection is enabled at this point - it may
- * have been turned off for the command that just completed.
- */
-
- write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
- if (cmd == NULL) {
- printk(" - Already disconnected! ");
- hostdata->state = S_UNCONNECTED;
-
-/* release the SMP spin_lock and restore irq state */
- spin_unlock_irqrestore(instance->host_lock, flags);
- return IRQ_HANDLED;
- }
- DB(DB_INTR, printk("UNEXP_DISC"))
- hostdata->connected = NULL;
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- hostdata->state = S_UNCONNECTED;
- if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- else
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- cmd->scsi_done(cmd);
-
-/* We are no longer connected to a target - check to see if
- * there are commands waiting to be executed.
- */
-
- in2000_execute(instance);
- break;
-
-
- case CSR_DISC:
-
-/* Make sure that reselection is enabled at this point - it may
- * have been turned off for the command that just completed.
- */
-
- write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
- DB(DB_INTR, printk("DISC"))
- if (cmd == NULL) {
- printk(" - Already disconnected! ");
- hostdata->state = S_UNCONNECTED;
- }
- switch (hostdata->state) {
- case S_PRE_CMP_DISC:
- hostdata->connected = NULL;
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- hostdata->state = S_UNCONNECTED;
- DB(DB_INTR, printk(":%d", cmd->SCp.Status))
- if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- else
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- cmd->scsi_done(cmd);
- break;
- case S_PRE_TMP_DISC:
- case S_RUNNING_LEVEL2:
- cmd->host_scribble = (uchar *) hostdata->disconnected_Q;
- hostdata->disconnected_Q = cmd;
- hostdata->connected = NULL;
- hostdata->state = S_UNCONNECTED;
-
-#ifdef PROC_STATISTICS
- hostdata->disc_done_cnt[cmd->device->id]++;
-#endif
-
- break;
- default:
- printk("*** Unexpected DISCONNECT interrupt! ***");
- hostdata->state = S_UNCONNECTED;
- }
-
-/* We are no longer connected to a target - check to see if
- * there are commands waiting to be executed.
- */
-
- in2000_execute(instance);
- break;
-
-
- case CSR_RESEL_AM:
- DB(DB_INTR, printk("RESEL"))
-
- /* First we have to make sure this reselection didn't */
- /* happen during Arbitration/Selection of some other device. */
- /* If yes, put losing command back on top of input_Q. */
- if (hostdata->level2 <= L2_NONE) {
-
- if (hostdata->selecting) {
- cmd = (Scsi_Cmnd *) hostdata->selecting;
- hostdata->selecting = NULL;
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- cmd->host_scribble = (uchar *) hostdata->input_Q;
- hostdata->input_Q = cmd;
- }
- }
-
- else {
-
- if (cmd) {
- if (phs == 0x00) {
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- cmd->host_scribble = (uchar *) hostdata->input_Q;
- hostdata->input_Q = cmd;
- } else {
- printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---", asr, sr, phs);
- while (1)
- printk("\r");
- }
- }
-
- }
-
- /* OK - find out which device reselected us. */
-
- id = read_3393(hostdata, WD_SOURCE_ID);
- id &= SRCID_MASK;
-
- /* and extract the lun from the ID message. (Note that we don't
- * bother to check for a valid message here - I guess this is
- * not the right way to go, but....)
- */
-
- lun = read_3393(hostdata, WD_DATA);
- if (hostdata->level2 < L2_RESELECT)
- write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
- lun &= 7;
-
- /* Now we look for the command that's reconnecting. */
-
- cmd = (Scsi_Cmnd *) hostdata->disconnected_Q;
- patch = NULL;
- while (cmd) {
- if (id == cmd->device->id && lun == cmd->device->lun)
- break;
- patch = cmd;
- cmd = (Scsi_Cmnd *) cmd->host_scribble;
- }
-
- /* Hmm. Couldn't find a valid command.... What to do? */
-
- if (!cmd) {
- printk("---TROUBLE: target %d.%d not in disconnect queue---", id, lun);
- break;
- }
-
- /* Ok, found the command - now start it up again. */
-
- if (patch)
- patch->host_scribble = cmd->host_scribble;
- else
- hostdata->disconnected_Q = (Scsi_Cmnd *) cmd->host_scribble;
- hostdata->connected = cmd;
-
- /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
- * because these things are preserved over a disconnect.
- * But we DO need to fix the DPD bit so it's correct for this command.
- */
-
- if (is_dir_out(cmd))
- write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id);
- else
- write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
- if (hostdata->level2 >= L2_RESELECT) {
- write_3393_count(hostdata, 0); /* we want a DATA_PHASE interrupt */
- write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
- write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
- hostdata->state = S_RUNNING_LEVEL2;
- } else
- hostdata->state = S_CONNECTED;
-
- break;
-
- default:
- printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
- }
-
- write1_io(0, IO_LED_OFF);
-
- DB(DB_INTR, printk("} "))
-
-/* release the SMP spin_lock and restore irq state */
- spin_unlock_irqrestore(instance->host_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-
-#define RESET_CARD 0
-#define RESET_CARD_AND_BUS 1
-#define B_FLAG 0x80
-
-/*
- * Caller must hold instance lock!
- */
-
-static int reset_hardware(struct Scsi_Host *instance, int type)
-{
- struct IN2000_hostdata *hostdata;
- int qt, x;
-
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
-
- write1_io(0, IO_LED_ON);
- if (type == RESET_CARD_AND_BUS) {
- write1_io(0, IO_CARD_RESET);
- x = read1_io(IO_HARDWARE);
- }
- x = read_3393(hostdata, WD_SCSI_STATUS); /* clear any WD intrpt */
- write_3393(hostdata, WD_OWN_ID, instance->this_id | OWNID_EAF | OWNID_RAF | OWNID_FS_8);
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
- write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, DEFAULT_SX_OFF));
-
- write1_io(0, IO_FIFO_WRITE); /* clear fifo counter */
- write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */
- write_3393(hostdata, WD_COMMAND, WD_CMD_RESET);
- /* FIXME: timeout ?? */
- while (!(READ_AUX_STAT() & ASR_INT))
- cpu_relax(); /* wait for RESET to complete */
-
- x = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */
-
- write_3393(hostdata, WD_QUEUE_TAG, 0xa5); /* any random number */
- qt = read_3393(hostdata, WD_QUEUE_TAG);
- if (qt == 0xa5) {
- x |= B_FLAG;
- write_3393(hostdata, WD_QUEUE_TAG, 0);
- }
- write_3393(hostdata, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
- write1_io(0, IO_LED_OFF);
- return x;
-}
-
-
-
-static int in2000_bus_reset(Scsi_Cmnd * cmd)
-{
- struct Scsi_Host *instance;
- struct IN2000_hostdata *hostdata;
- int x;
- unsigned long flags;
-
- instance = cmd->device->host;
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
-
- printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no);
-
- spin_lock_irqsave(instance->host_lock, flags);
-
- /* do scsi-reset here */
- reset_hardware(instance, RESET_CARD_AND_BUS);
- for (x = 0; x < 8; x++) {
- hostdata->busy[x] = 0;
- hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
- hostdata->sync_stat[x] = SS_UNSET; /* using default sync values */
- }
- hostdata->input_Q = NULL;
- hostdata->selecting = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_Q = NULL;
- hostdata->state = S_UNCONNECTED;
- hostdata->fifo = FI_FIFO_UNUSED;
- hostdata->incoming_ptr = 0;
- hostdata->outgoing_len = 0;
-
- cmd->result = DID_RESET << 16;
-
- spin_unlock_irqrestore(instance->host_lock, flags);
- return SUCCESS;
-}
-
-static int __in2000_abort(Scsi_Cmnd * cmd)
-{
- struct Scsi_Host *instance;
- struct IN2000_hostdata *hostdata;
- Scsi_Cmnd *tmp, *prev;
- uchar sr, asr;
- unsigned long timeout;
-
- instance = cmd->device->host;
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
-
- printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no);
- printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ", READ_AUX_STAT(), read_3393_count(hostdata), cmd->SCp.this_residual, cmd->SCp.buffers_residual, cmd->SCp.have_data_in, read1_io(IO_FIFO_COUNT));
-
-/*
- * Case 1 : If the command hasn't been issued yet, we simply remove it
- * from the inout_Q.
- */
-
- tmp = (Scsi_Cmnd *) hostdata->input_Q;
- prev = NULL;
- while (tmp) {
- if (tmp == cmd) {
- if (prev)
- prev->host_scribble = cmd->host_scribble;
- cmd->host_scribble = NULL;
- cmd->result = DID_ABORT << 16;
- printk(KERN_WARNING "scsi%d: Abort - removing command from input_Q. ", instance->host_no);
- cmd->scsi_done(cmd);
- return SUCCESS;
- }
- prev = tmp;
- tmp = (Scsi_Cmnd *) tmp->host_scribble;
- }
-
-/*
- * Case 2 : If the command is connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
-
- if (hostdata->connected == cmd) {
-
- printk(KERN_WARNING "scsi%d: Aborting connected command - ", instance->host_no);
-
- printk("sending wd33c93 ABORT command - ");
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
- write_3393_cmd(hostdata, WD_CMD_ABORT);
-
-/* Now we have to attempt to flush out the FIFO... */
-
- printk("flushing fifo - ");
- timeout = 1000000;
- do {
- asr = READ_AUX_STAT();
- if (asr & ASR_DBR)
- read_3393(hostdata, WD_DATA);
- } while (!(asr & ASR_INT) && timeout-- > 0);
- sr = read_3393(hostdata, WD_SCSI_STATUS);
- printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", asr, sr, read_3393_count(hostdata), timeout);
-
- /*
- * Abort command processed.
- * Still connected.
- * We must disconnect.
- */
-
- printk("sending wd33c93 DISCONNECT command - ");
- write_3393_cmd(hostdata, WD_CMD_DISCONNECT);
-
- timeout = 1000000;
- asr = READ_AUX_STAT();
- while ((asr & ASR_CIP) && timeout-- > 0)
- asr = READ_AUX_STAT();
- sr = read_3393(hostdata, WD_SCSI_STATUS);
- printk("asr=%02x, sr=%02x.", asr, sr);
-
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- hostdata->connected = NULL;
- hostdata->state = S_UNCONNECTED;
- cmd->result = DID_ABORT << 16;
- cmd->scsi_done(cmd);
-
- in2000_execute(instance);
-
- return SUCCESS;
- }
-
-/*
- * Case 3: If the command is currently disconnected from the bus,
- * we're not going to expend much effort here: Let's just return
- * an ABORT_SNOOZE and hope for the best...
- */
-
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_Q; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no);
- return FAILED;
- }
-
-/*
- * Case 4 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
-
- in2000_execute(instance);
-
- printk("scsi%d: warning : SCSI command probably completed successfully" " before abortion. ", instance->host_no);
- return SUCCESS;
-}
-
-static int in2000_abort(Scsi_Cmnd * cmd)
-{
- int rc;
-
- spin_lock_irq(cmd->device->host->host_lock);
- rc = __in2000_abort(cmd);
- spin_unlock_irq(cmd->device->host->host_lock);
-
- return rc;
-}
-
-
-#define MAX_IN2000_HOSTS 3
-#define MAX_SETUP_ARGS ARRAY_SIZE(setup_args)
-#define SETUP_BUFFER_SIZE 200
-static char setup_buffer[SETUP_BUFFER_SIZE];
-static char setup_used[MAX_SETUP_ARGS];
-static int done_setup = 0;
-
-static void __init in2000_setup(char *str, int *ints)
-{
- int i;
- char *p1, *p2;
-
- strlcpy(setup_buffer, str, SETUP_BUFFER_SIZE);
- p1 = setup_buffer;
- i = 0;
- while (*p1 && (i < MAX_SETUP_ARGS)) {
- p2 = strchr(p1, ',');
- if (p2) {
- *p2 = '\0';
- if (p1 != p2)
- setup_args[i] = p1;
- p1 = p2 + 1;
- i++;
- } else {
- setup_args[i] = p1;
- break;
- }
- }
- for (i = 0; i < MAX_SETUP_ARGS; i++)
- setup_used[i] = 0;
- done_setup = 1;
-}
-
-
-/* check_setup_args() returns index if key found, 0 if not
- */
-
-static int __init check_setup_args(char *key, int *val, char *buf)
-{
- int x;
- char *cp;
-
- for (x = 0; x < MAX_SETUP_ARGS; x++) {
- if (setup_used[x])
- continue;
- if (!strncmp(setup_args[x], key, strlen(key)))
- break;
- }
- if (x == MAX_SETUP_ARGS)
- return 0;
- setup_used[x] = 1;
- cp = setup_args[x] + strlen(key);
- *val = -1;
- if (*cp != ':')
- return ++x;
- cp++;
- if ((*cp >= '0') && (*cp <= '9')) {
- *val = simple_strtoul(cp, NULL, 0);
- }
- return ++x;
-}
-
-
-
-/* The "correct" (ie portable) way to access memory-mapped hardware
- * such as the IN2000 EPROM and dip switch is through the use of
- * special macros declared in 'asm/io.h'. We use readb() and readl()
- * when reading from the card's BIOS area in in2000_detect().
- */
-static u32 bios_tab[] in2000__INITDATA = {
- 0xc8000,
- 0xd0000,
- 0xd8000,
- 0
-};
-
-static unsigned short base_tab[] in2000__INITDATA = {
- 0x220,
- 0x200,
- 0x110,
- 0x100,
-};
-
-static int int_tab[] in2000__INITDATA = {
- 15,
- 14,
- 11,
- 10
-};
-
-static int probe_bios(u32 addr, u32 *s1, uchar *switches)
-{
- void __iomem *p = ioremap(addr, 0x34);
- if (!p)
- return 0;
- *s1 = readl(p + 0x10);
- if (*s1 == 0x41564f4e || readl(p + 0x30) == 0x61776c41) {
- /* Read the switch image that's mapped into EPROM space */
- *switches = ~readb(p + 0x20);
- iounmap(p);
- return 1;
- }
- iounmap(p);
- return 0;
-}
-
-static int __init in2000_detect(struct scsi_host_template * tpnt)
-{
- struct Scsi_Host *instance;
- struct IN2000_hostdata *hostdata;
- int detect_count;
- int bios;
- int x;
- unsigned short base;
- uchar switches;
- uchar hrev;
- unsigned long flags;
- int val;
- char buf[32];
-
-/* Thanks to help from Bill Earnest, probing for IN2000 cards is a
- * pretty straightforward and fool-proof operation. There are 3
- * possible locations for the IN2000 EPROM in memory space - if we
- * find a BIOS signature, we can read the dip switch settings from
- * the byte at BIOS+32 (shadowed in by logic on the card). From 2
- * of the switch bits we get the card's address in IO space. There's
- * an image of the dip switch there, also, so we have a way to back-
- * check that this really is an IN2000 card. Very nifty. Use the
- * 'ioport:xx' command-line parameter if your BIOS EPROM is absent
- * or disabled.
- */
-
- if (!done_setup && setup_strings)
- in2000_setup(setup_strings, NULL);
-
- detect_count = 0;
- for (bios = 0; bios_tab[bios]; bios++) {
- u32 s1 = 0;
- if (check_setup_args("ioport", &val, buf)) {
- base = val;
- switches = ~inb(base + IO_SWITCHES) & 0xff;
- printk("Forcing IN2000 detection at IOport 0x%x ", base);
- bios = 2;
- }
-/*
- * There have been a couple of BIOS versions with different layouts
- * for the obvious ID strings. We look for the 2 most common ones and
- * hope that they cover all the cases...
- */
- else if (probe_bios(bios_tab[bios], &s1, &switches)) {
- printk("Found IN2000 BIOS at 0x%x ", (unsigned int) bios_tab[bios]);
-
-/* Find out where the IO space is */
-
- x = switches & (SW_ADDR0 | SW_ADDR1);
- base = base_tab[x];
-
-/* Check for the IN2000 signature in IO space. */
-
- x = ~inb(base + IO_SWITCHES) & 0xff;
- if (x != switches) {
- printk("Bad IO signature: %02x vs %02x.\n", x, switches);
- continue;
- }
- } else
- continue;
-
-/* OK. We have a base address for the IO ports - run a few safety checks */
-
- if (!(switches & SW_BIT7)) { /* I _think_ all cards do this */
- printk("There is no IN-2000 SCSI card at IOport 0x%03x!\n", base);
- continue;
- }
-
-/* Let's assume any hardware version will work, although the driver
- * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll
- * print out the rev number for reference later, but accept them all.
- */
-
- hrev = inb(base + IO_HARDWARE);
-
- /* Bit 2 tells us if interrupts are disabled */
- if (switches & SW_DISINT) {
- printk("The IN-2000 SCSI card at IOport 0x%03x ", base);
- printk("is not configured for interrupt operation!\n");
- printk("This driver requires an interrupt: cancelling detection.\n");
- continue;
- }
-
-/* Ok. We accept that there's an IN2000 at ioaddr 'base'. Now
- * initialize it.
- */
-
- tpnt->proc_name = "in2000";
- instance = scsi_register(tpnt, sizeof(struct IN2000_hostdata));
- if (instance == NULL)
- continue;
- detect_count++;
- hostdata = (struct IN2000_hostdata *) instance->hostdata;
- instance->io_port = hostdata->io_base = base;
- hostdata->dip_switch = switches;
- hostdata->hrev = hrev;
-
- write1_io(0, IO_FIFO_WRITE); /* clear fifo counter */
- write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */
- write1_io(0, IO_INTR_MASK); /* allow all ints */
- x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
- if (request_irq(x, in2000_intr, 0, "in2000", instance)) {
- printk("in2000_detect: Unable to allocate IRQ.\n");
- detect_count--;
- continue;
- }
- instance->irq = x;
- instance->n_io_port = 13;
- request_region(base, 13, "in2000"); /* lock in this IO space for our use */
-
- for (x = 0; x < 8; x++) {
- hostdata->busy[x] = 0;
- hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
- hostdata->sync_stat[x] = SS_UNSET; /* using default sync values */
-#ifdef PROC_STATISTICS
- hostdata->cmd_cnt[x] = 0;
- hostdata->disc_allowed_cnt[x] = 0;
- hostdata->disc_done_cnt[x] = 0;
-#endif
- }
- hostdata->input_Q = NULL;
- hostdata->selecting = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_Q = NULL;
- hostdata->state = S_UNCONNECTED;
- hostdata->fifo = FI_FIFO_UNUSED;
- hostdata->level2 = L2_BASIC;
- hostdata->disconnect = DIS_ADAPTIVE;
- hostdata->args = DEBUG_DEFAULTS;
- hostdata->incoming_ptr = 0;
- hostdata->outgoing_len = 0;
- hostdata->default_sx_per = DEFAULT_SX_PER;
-
-/* Older BIOS's had a 'sync on/off' switch - use its setting */
-
- if (s1 == 0x41564f4e && (switches & SW_SYNC_DOS5))
- hostdata->sync_off = 0x00; /* sync defaults to on */
- else
- hostdata->sync_off = 0xff; /* sync defaults to off */
-
-#ifdef PROC_INTERFACE
- hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;
-#ifdef PROC_STATISTICS
- hostdata->int_cnt = 0;
-#endif
-#endif
-
- if (check_setup_args("nosync", &val, buf))
- hostdata->sync_off = val;
-
- if (check_setup_args("period", &val, buf))
- hostdata->default_sx_per = sx_table[round_period((unsigned int) val)].period_ns;
-
- if (check_setup_args("disconnect", &val, buf)) {
- if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
- hostdata->disconnect = val;
- else
- hostdata->disconnect = DIS_ADAPTIVE;
- }
-
- if (check_setup_args("noreset", &val, buf))
- hostdata->args ^= A_NO_SCSI_RESET;
-
- if (check_setup_args("level2", &val, buf))
- hostdata->level2 = val;
-
- if (check_setup_args("debug", &val, buf))
- hostdata->args = (val & DB_MASK);
-
-#ifdef PROC_INTERFACE
- if (check_setup_args("proc", &val, buf))
- hostdata->proc = val;
-#endif
-
-
- /* FIXME: not strictly needed I think but the called code expects
- to be locked */
- spin_lock_irqsave(instance->host_lock, flags);
- x = reset_hardware(instance, (hostdata->args & A_NO_SCSI_RESET) ? RESET_CARD : RESET_CARD_AND_BUS);
- spin_unlock_irqrestore(instance->host_lock, flags);
-
- hostdata->microcode = read_3393(hostdata, WD_CDB_1);
- if (x & 0x01) {
- if (x & B_FLAG)
- hostdata->chip = C_WD33C93B;
- else
- hostdata->chip = C_WD33C93A;
- } else
- hostdata->chip = C_WD33C93;
-
- printk("dip_switch=%02x irq=%d ioport=%02x floppy=%s sync/DOS5=%s ", (switches & 0x7f), instance->irq, hostdata->io_base, (switches & SW_FLOPPY) ? "Yes" : "No", (switches & SW_SYNC_DOS5) ? "Yes" : "No");
- printk("hardware_ver=%02x chip=%s microcode=%02x\n", hrev, (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip == C_WD33C93A) ? "WD33c93A" : (hostdata->chip == C_WD33C93B) ? "WD33c93B" : "unknown", hostdata->microcode);
-#ifdef DEBUGGING_ON
- printk("setup_args = ");
- for (x = 0; x < MAX_SETUP_ARGS; x++)
- printk("%s,", setup_args[x]);
- printk("\n");
-#endif
- if (hostdata->sync_off == 0xff)
- printk("Sync-transfer DISABLED on all devices: ENABLE from command-line\n");
- printk("IN2000 driver version %s - %s\n", IN2000_VERSION, IN2000_DATE);
- }
-
- return detect_count;
-}
-
-static int in2000_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- return 0;
-}
-
-/* NOTE: I lifted this function straight out of the old driver,
- * and have not tested it. Presumably it does what it's
- * supposed to do...
- */
-
-static int in2000_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *iinfo)
-{
- int size;
-
- size = capacity;
- iinfo[0] = 64;
- iinfo[1] = 32;
- iinfo[2] = size >> 11;
-
-/* This should approximate the large drive handling that the DOS ASPI manager
- uses. Drives very near the boundaries may not be handled correctly (i.e.
- near 2.0 Gb and 4.0 Gb) */
-
- if (iinfo[2] > 1024) {
- iinfo[0] = 64;
- iinfo[1] = 63;
- iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
- }
- if (iinfo[2] > 1024) {
- iinfo[0] = 128;
- iinfo[1] = 63;
- iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
- }
- if (iinfo[2] > 1024) {
- iinfo[0] = 255;
- iinfo[1] = 63;
- iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
- }
- return 0;
-}
-
-
-static int in2000_write_info(struct Scsi_Host *instance, char *buf, int len)
-{
-
-#ifdef PROC_INTERFACE
-
- char *bp;
- struct IN2000_hostdata *hd;
- int x, i;
-
- hd = (struct IN2000_hostdata *) instance->hostdata;
-
- buf[len] = '\0';
- bp = buf;
- if (!strncmp(bp, "debug:", 6)) {
- bp += 6;
- hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
- } else if (!strncmp(bp, "disconnect:", 11)) {
- bp += 11;
- x = simple_strtoul(bp, NULL, 0);
- if (x < DIS_NEVER || x > DIS_ALWAYS)
- x = DIS_ADAPTIVE;
- hd->disconnect = x;
- } else if (!strncmp(bp, "period:", 7)) {
- bp += 7;
- x = simple_strtoul(bp, NULL, 0);
- hd->default_sx_per = sx_table[round_period((unsigned int) x)].period_ns;
- } else if (!strncmp(bp, "resync:", 7)) {
- bp += 7;
- x = simple_strtoul(bp, NULL, 0);
- for (i = 0; i < 7; i++)
- if (x & (1 << i))
- hd->sync_stat[i] = SS_UNSET;
- } else if (!strncmp(bp, "proc:", 5)) {
- bp += 5;
- hd->proc = simple_strtoul(bp, NULL, 0);
- } else if (!strncmp(bp, "level2:", 7)) {
- bp += 7;
- hd->level2 = simple_strtoul(bp, NULL, 0);
- }
-#endif
- return len;
-}
-
-static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance)
-{
-
-#ifdef PROC_INTERFACE
- unsigned long flags;
- struct IN2000_hostdata *hd;
- Scsi_Cmnd *cmd;
- int x;
-
- hd = (struct IN2000_hostdata *) instance->hostdata;
-
- spin_lock_irqsave(instance->host_lock, flags);
- if (hd->proc & PR_VERSION)
- seq_printf(m, "\nVersion %s - %s.", IN2000_VERSION, IN2000_DATE);
-
- if (hd->proc & PR_INFO) {
- seq_printf(m, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No");
- seq_puts(m, "\nsync_xfer[] = ");
- for (x = 0; x < 7; x++)
- seq_printf(m, "\t%02x", hd->sync_xfer[x]);
- seq_puts(m, "\nsync_stat[] = ");
- for (x = 0; x < 7; x++)
- seq_printf(m, "\t%02x", hd->sync_stat[x]);
- }
-#ifdef PROC_STATISTICS
- if (hd->proc & PR_STATISTICS) {
- seq_puts(m, "\ncommands issued: ");
- for (x = 0; x < 7; x++)
- seq_printf(m, "\t%ld", hd->cmd_cnt[x]);
- seq_puts(m, "\ndisconnects allowed:");
- for (x = 0; x < 7; x++)
- seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]);
- seq_puts(m, "\ndisconnects done: ");
- for (x = 0; x < 7; x++)
- seq_printf(m, "\t%ld", hd->disc_done_cnt[x]);
- seq_printf(m, "\ninterrupts: \t%ld", hd->int_cnt);
- }
-#endif
- if (hd->proc & PR_CONNECTED) {
- seq_puts(m, "\nconnected: ");
- if (hd->connected) {
- cmd = (Scsi_Cmnd *) hd->connected;
- seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- }
- }
- if (hd->proc & PR_INPUTQ) {
- seq_puts(m, "\ninput_Q: ");
- cmd = (Scsi_Cmnd *) hd->input_Q;
- while (cmd) {
- seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- cmd = (Scsi_Cmnd *) cmd->host_scribble;
- }
- }
- if (hd->proc & PR_DISCQ) {
- seq_puts(m, "\ndisconnected_Q:");
- cmd = (Scsi_Cmnd *) hd->disconnected_Q;
- while (cmd) {
- seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- cmd = (Scsi_Cmnd *) cmd->host_scribble;
- }
- }
- if (hd->proc & PR_TEST) {
- ; /* insert your own custom function here */
- }
- seq_putc(m, '\n');
- spin_unlock_irqrestore(instance->host_lock, flags);
-#endif /* PROC_INTERFACE */
- return 0;
-}
-
-MODULE_LICENSE("GPL");
-
-
-static struct scsi_host_template driver_template = {
- .proc_name = "in2000",
- .write_info = in2000_write_info,
- .show_info = in2000_show_info,
- .name = "Always IN2000",
- .detect = in2000_detect,
- .release = in2000_release,
- .queuecommand = in2000_queuecommand,
- .eh_abort_handler = in2000_abort,
- .eh_bus_reset_handler = in2000_bus_reset,
- .bios_param = in2000_biosparam,
- .can_queue = IN2000_CAN_Q,
- .this_id = IN2000_HOST_ID,
- .sg_tablesize = IN2000_SG,
- .cmd_per_lun = IN2000_CPL,
- .use_clustering = DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
deleted file mode 100644
index 5821e1fbce08..000000000000
--- a/drivers/scsi/in2000.h
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * in2000.h - Linux device driver definitions for the
- * Always IN2000 ISA SCSI card.
- *
- * IMPORTANT: This file is for version 1.33 - 26/Aug/1998
- *
- * Copyright (c) 1996 John Shifflett, GeoLog Consulting
- * john@geolog.com
- * jshiffle@netcom.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef IN2000_H
-#define IN2000_H
-
-#include <asm/io.h>
-
-#define PROC_INTERFACE /* add code for /proc/scsi/in2000/xxx interface */
-#ifdef PROC_INTERFACE
-#define PROC_STATISTICS /* add code for keeping various real time stats */
-#endif
-
-#define SYNC_DEBUG /* extra info on sync negotiation printed */
-#define DEBUGGING_ON /* enable command-line debugging bitmask */
-#define DEBUG_DEFAULTS 0 /* default bitmask - change from command-line */
-
-#ifdef __i386__
-#define FAST_READ_IO /* No problems with these on my machine */
-#define FAST_WRITE_IO
-#endif
-
-#ifdef DEBUGGING_ON
-#define DB(f,a) if (hostdata->args & (f)) a;
-#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */
-#else
-#define DB(f,a)
-#define CHECK_NULL(p,s)
-#endif
-
-#define uchar unsigned char
-
-#define read1_io(a) (inb(hostdata->io_base+(a)))
-#define read2_io(a) (inw(hostdata->io_base+(a)))
-#define write1_io(b,a) (outb((b),hostdata->io_base+(a)))
-#define write2_io(w,a) (outw((w),hostdata->io_base+(a)))
-
-#ifdef __i386__
-/* These inline assembly defines are derived from a patch
- * sent to me by Bill Earnest. He's done a lot of very
- * valuable thinking, testing, and coding during his effort
- * to squeeze more speed out of this driver. I really think
- * that we are doing IO at close to the maximum now with
- * the fifo. (And yes, insw uses 'edi' while outsw uses
- * 'esi'. Thanks Bill!)
- */
-
-#define FAST_READ2_IO() \
-({ \
-int __dummy_1,__dummy_2; \
- __asm__ __volatile__ ("\n \
- cld \n \
- orl %%ecx, %%ecx \n \
- jz 1f \n \
- rep \n \
- insw (%%dx),%%es:(%%edi) \n \
-1: " \
- : "=D" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2) /* output */ \
- : "2" (f), "0" (sp), "1" (i) /* input */ \
- ); /* trashed */ \
-})
-
-#define FAST_WRITE2_IO() \
-({ \
-int __dummy_1,__dummy_2; \
- __asm__ __volatile__ ("\n \
- cld \n \
- orl %%ecx, %%ecx \n \
- jz 1f \n \
- rep \n \
- outsw %%ds:(%%esi),(%%dx) \n \
-1: " \
- : "=S" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2)/* output */ \
- : "2" (f), "0" (sp), "1" (i) /* input */ \
- ); /* trashed */ \
-})
-#endif
-
-/* IN2000 io_port offsets */
-#define IO_WD_ASR 0x00 /* R - 3393 auxstat reg */
-#define ASR_INT 0x80
-#define ASR_LCI 0x40
-#define ASR_BSY 0x20
-#define ASR_CIP 0x10
-#define ASR_PE 0x02
-#define ASR_DBR 0x01
-#define IO_WD_ADDR 0x00 /* W - 3393 address reg */
-#define IO_WD_DATA 0x01 /* R/W - rest of 3393 regs */
-#define IO_FIFO 0x02 /* R/W - in2000 dual-port fifo (16 bits) */
-#define IN2000_FIFO_SIZE 2048 /* fifo capacity in bytes */
-#define IO_CARD_RESET 0x03 /* W - in2000 start master reset */
-#define IO_FIFO_COUNT 0x04 /* R - in2000 fifo counter */
-#define IO_FIFO_WRITE 0x05 /* W - clear fifo counter, start write */
-#define IO_FIFO_READ 0x07 /* W - start fifo read */
-#define IO_LED_OFF 0x08 /* W - turn off in2000 activity LED */
-#define IO_SWITCHES 0x08 /* R - read in2000 dip switch */
-#define SW_ADDR0 0x01 /* bit 0 = bit 0 of index to io addr */
-#define SW_ADDR1 0x02 /* bit 1 = bit 1 of index io addr */
-#define SW_DISINT 0x04 /* bit 2 true if ints disabled */
-#define SW_INT0 0x08 /* bit 3 = bit 0 of index to interrupt */
-#define SW_INT1 0x10 /* bit 4 = bit 1 of index to interrupt */
-#define SW_INT_SHIFT 3 /* shift right this amount to right justify int bits */
-#define SW_SYNC_DOS5 0x20 /* bit 5 used by Always BIOS */
-#define SW_FLOPPY 0x40 /* bit 6 true if floppy enabled */
-#define SW_BIT7 0x80 /* bit 7 hardwired true (ground) */
-#define IO_LED_ON 0x09 /* W - turn on in2000 activity LED */
-#define IO_HARDWARE 0x0a /* R - read in2000 hardware rev, stop reset */
-#define IO_INTR_MASK 0x0c /* W - in2000 interrupt mask reg */
-#define IMASK_WD 0x01 /* WD33c93 interrupt mask */
-#define IMASK_FIFO 0x02 /* FIFO interrupt mask */
-
-/* wd register names */
-#define WD_OWN_ID 0x00
-#define WD_CONTROL 0x01
-#define WD_TIMEOUT_PERIOD 0x02
-#define WD_CDB_1 0x03
-#define WD_CDB_2 0x04
-#define WD_CDB_3 0x05
-#define WD_CDB_4 0x06
-#define WD_CDB_5 0x07
-#define WD_CDB_6 0x08
-#define WD_CDB_7 0x09
-#define WD_CDB_8 0x0a
-#define WD_CDB_9 0x0b
-#define WD_CDB_10 0x0c
-#define WD_CDB_11 0x0d
-#define WD_CDB_12 0x0e
-#define WD_TARGET_LUN 0x0f
-#define WD_COMMAND_PHASE 0x10
-#define WD_SYNCHRONOUS_TRANSFER 0x11
-#define WD_TRANSFER_COUNT_MSB 0x12
-#define WD_TRANSFER_COUNT 0x13
-#define WD_TRANSFER_COUNT_LSB 0x14
-#define WD_DESTINATION_ID 0x15
-#define WD_SOURCE_ID 0x16
-#define WD_SCSI_STATUS 0x17
-#define WD_COMMAND 0x18
-#define WD_DATA 0x19
-#define WD_QUEUE_TAG 0x1a
-#define WD_AUXILIARY_STATUS 0x1f
-
-/* WD commands */
-#define WD_CMD_RESET 0x00
-#define WD_CMD_ABORT 0x01
-#define WD_CMD_ASSERT_ATN 0x02
-#define WD_CMD_NEGATE_ACK 0x03
-#define WD_CMD_DISCONNECT 0x04
-#define WD_CMD_RESELECT 0x05
-#define WD_CMD_SEL_ATN 0x06
-#define WD_CMD_SEL 0x07
-#define WD_CMD_SEL_ATN_XFER 0x08
-#define WD_CMD_SEL_XFER 0x09
-#define WD_CMD_RESEL_RECEIVE 0x0a
-#define WD_CMD_RESEL_SEND 0x0b
-#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
-#define WD_CMD_TRANS_ADDR 0x18
-#define WD_CMD_TRANS_INFO 0x20
-#define WD_CMD_TRANSFER_PAD 0x21
-#define WD_CMD_SBT_MODE 0x80
-
-/* SCSI Bus Phases */
-#define PHS_DATA_OUT 0x00
-#define PHS_DATA_IN 0x01
-#define PHS_COMMAND 0x02
-#define PHS_STATUS 0x03
-#define PHS_MESS_OUT 0x06
-#define PHS_MESS_IN 0x07
-
-/* Command Status Register definitions */
-
- /* reset state interrupts */
-#define CSR_RESET 0x00
-#define CSR_RESET_AF 0x01
-
- /* successful completion interrupts */
-#define CSR_RESELECT 0x10
-#define CSR_SELECT 0x11
-#define CSR_SEL_XFER_DONE 0x16
-#define CSR_XFER_DONE 0x18
-
- /* paused or aborted interrupts */
-#define CSR_MSGIN 0x20
-#define CSR_SDP 0x21
-#define CSR_SEL_ABORT 0x22
-#define CSR_RESEL_ABORT 0x25
-#define CSR_RESEL_ABORT_AM 0x27
-#define CSR_ABORT 0x28
-
- /* terminated interrupts */
-#define CSR_INVALID 0x40
-#define CSR_UNEXP_DISC 0x41
-#define CSR_TIMEOUT 0x42
-#define CSR_PARITY 0x43
-#define CSR_PARITY_ATN 0x44
-#define CSR_BAD_STATUS 0x45
-#define CSR_UNEXP 0x48
-
- /* service required interrupts */
-#define CSR_RESEL 0x80
-#define CSR_RESEL_AM 0x81
-#define CSR_DISC 0x85
-#define CSR_SRV_REQ 0x88
-
- /* Own ID/CDB Size register */
-#define OWNID_EAF 0x08
-#define OWNID_EHP 0x10
-#define OWNID_RAF 0x20
-#define OWNID_FS_8 0x00
-#define OWNID_FS_12 0x40
-#define OWNID_FS_16 0x80
-
- /* Control register */
-#define CTRL_HSP 0x01
-#define CTRL_HA 0x02
-#define CTRL_IDI 0x04
-#define CTRL_EDI 0x08
-#define CTRL_HHP 0x10
-#define CTRL_POLLED 0x00
-#define CTRL_BURST 0x20
-#define CTRL_BUS 0x40
-#define CTRL_DMA 0x80
-
- /* Timeout Period register */
-#define TIMEOUT_PERIOD_VALUE 20 /* results in 200 ms. */
-
- /* Synchronous Transfer Register */
-#define STR_FSS 0x80
-
- /* Destination ID register */
-#define DSTID_DPD 0x40
-#define DATA_OUT_DIR 0
-#define DATA_IN_DIR 1
-#define DSTID_SCC 0x80
-
- /* Source ID register */
-#define SRCID_MASK 0x07
-#define SRCID_SIV 0x08
-#define SRCID_DSP 0x20
-#define SRCID_ES 0x40
-#define SRCID_ER 0x80
-
-
-
-#define ILLEGAL_STATUS_BYTE 0xff
-
-
-#define DEFAULT_SX_PER 500 /* (ns) fairly safe */
-#define DEFAULT_SX_OFF 0 /* aka async */
-
-#define OPTIMUM_SX_PER 252 /* (ns) best we can do (mult-of-4) */
-#define OPTIMUM_SX_OFF 12 /* size of in2000 fifo */
-
-struct sx_period {
- unsigned int period_ns;
- uchar reg_value;
- };
-
-
-struct IN2000_hostdata {
- struct Scsi_Host *next;
- uchar chip; /* what kind of wd33c93 chip? */
- uchar microcode; /* microcode rev if 'B' */
- unsigned short io_base; /* IO port base */
- unsigned int dip_switch; /* dip switch settings */
- unsigned int hrev; /* hardware revision of card */
- volatile uchar busy[8]; /* index = target, bit = lun */
- volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */
- volatile Scsi_Cmnd *selecting; /* trying to select this command */
- volatile Scsi_Cmnd *connected; /* currently connected command */
- volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */
- uchar state; /* what we are currently doing */
- uchar fifo; /* what the FIFO is up to */
- uchar level2; /* extent to which Level-2 commands are used */
- uchar disconnect; /* disconnect/reselect policy */
- unsigned int args; /* set from command-line argument */
- uchar incoming_msg[8]; /* filled during message_in phase */
- int incoming_ptr; /* mainly used with EXTENDED messages */
- uchar outgoing_msg[8]; /* send this during next message_out */
- int outgoing_len; /* length of outgoing message */
- unsigned int default_sx_per; /* default transfer period for SCSI bus */
- uchar sync_xfer[8]; /* sync_xfer reg settings per target */
- uchar sync_stat[8]; /* status of sync negotiation per target */
- uchar sync_off; /* bit mask: don't use sync with these targets */
-#ifdef PROC_INTERFACE
- uchar proc; /* bit mask: what's in proc output */
-#ifdef PROC_STATISTICS
- unsigned long cmd_cnt[8]; /* # of commands issued per target */
- unsigned long int_cnt; /* # of interrupts serviced */
- unsigned long disc_allowed_cnt[8]; /* # of disconnects allowed per target */
- unsigned long disc_done_cnt[8]; /* # of disconnects done per target*/
-#endif
-#endif
- };
-
-
-/* defines for hostdata->chip */
-
-#define C_WD33C93 0
-#define C_WD33C93A 1
-#define C_WD33C93B 2
-#define C_UNKNOWN_CHIP 100
-
-/* defines for hostdata->state */
-
-#define S_UNCONNECTED 0
-#define S_SELECTING 1
-#define S_RUNNING_LEVEL2 2
-#define S_CONNECTED 3
-#define S_PRE_TMP_DISC 4
-#define S_PRE_CMP_DISC 5
-
-/* defines for hostdata->fifo */
-
-#define FI_FIFO_UNUSED 0
-#define FI_FIFO_READING 1
-#define FI_FIFO_WRITING 2
-
-/* defines for hostdata->level2 */
-/* NOTE: only the first 3 are trustworthy at this point -
- * having trouble when more than 1 device is reading/writing
- * at the same time...
- */
-
-#define L2_NONE 0 /* no combination commands - we get lots of ints */
-#define L2_SELECT 1 /* start with SEL_ATN_XFER, but never resume it */
-#define L2_BASIC 2 /* resume after STATUS ints & RDP messages */
-#define L2_DATA 3 /* resume after DATA_IN/OUT ints */
-#define L2_MOST 4 /* resume after anything except a RESELECT int */
-#define L2_RESELECT 5 /* resume after everything, including RESELECT ints */
-#define L2_ALL 6 /* always resume */
-
-/* defines for hostdata->disconnect */
-
-#define DIS_NEVER 0
-#define DIS_ADAPTIVE 1
-#define DIS_ALWAYS 2
-
-/* defines for hostdata->args */
-
-#define DB_TEST 1<<0
-#define DB_FIFO 1<<1
-#define DB_QUEUE_COMMAND 1<<2
-#define DB_EXECUTE 1<<3
-#define DB_INTR 1<<4
-#define DB_TRANSFER 1<<5
-#define DB_MASK 0x3f
-
-#define A_NO_SCSI_RESET 1<<15
-
-
-/* defines for hostdata->sync_xfer[] */
-
-#define SS_UNSET 0
-#define SS_FIRST 1
-#define SS_WAITING 2
-#define SS_SET 3
-
-/* defines for hostdata->proc */
-
-#define PR_VERSION 1<<0
-#define PR_INFO 1<<1
-#define PR_STATISTICS 1<<2
-#define PR_CONNECTED 1<<3
-#define PR_INPUTQ 1<<4
-#define PR_DISCQ 1<<5
-#define PR_TEST 1<<6
-#define PR_STOP 1<<7
-
-
-# include <linux/init.h>
-# include <linux/spinlock.h>
-# define in2000__INITFUNC(function) __initfunc(function)
-# define in2000__INIT __init
-# define in2000__INITDATA __initdata
-# define CLISPIN_LOCK(host,flags) spin_lock_irqsave(host->host_lock, flags)
-# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \
- flags)
-
-static int in2000_detect(struct scsi_host_template *) in2000__INIT;
-static int in2000_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-static int in2000_abort(Scsi_Cmnd *);
-static void in2000_setup(char *, int *) in2000__INIT;
-static int in2000_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int *);
-static int in2000_bus_reset(Scsi_Cmnd *);
-
-
-#define IN2000_CAN_Q 16
-#define IN2000_SG SG_ALL
-#define IN2000_CPL 2
-#define IN2000_HOST_ID 7
-
-#endif /* IN2000_H */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 17d04c702e1b..a8762a3efeef 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -493,15 +493,15 @@ struct ipr_error_table_t ipr_error_table[] = {
"9072: Link not operational transition"},
{0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL,
"9032: Array exposed but still protected"},
- {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1,
+ {0x066B8300, 0, IPR_DEBUG_LOG_LEVEL,
"70DD: Device forced failed by disrupt device command"},
{0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL,
"4061: Multipath redundancy level got better"},
{0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL,
"4060: Multipath redundancy level got worse"},
- {0x06808100, 0, IPR_DEFAULT_LOG_LEVEL,
+ {0x06808100, 0, IPR_DEBUG_LOG_LEVEL,
"9083: Device raw mode enabled"},
- {0x06808200, 0, IPR_DEFAULT_LOG_LEVEL,
+ {0x06808200, 0, IPR_DEBUG_LOG_LEVEL,
"9084: Device raw mode disabled"},
{0x07270000, 0, 0,
"Failure due to other device"},
@@ -1473,7 +1473,7 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
- list_del(&hostrcb->queue);
+ list_del_init(&hostrcb->queue);
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
if (ioasc) {
@@ -2552,6 +2552,23 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
}
}
+static struct ipr_hostrcb *ipr_get_free_hostrcb(struct ipr_ioa_cfg *ioa)
+{
+ struct ipr_hostrcb *hostrcb;
+
+ hostrcb = list_first_entry_or_null(&ioa->hostrcb_free_q,
+ struct ipr_hostrcb, queue);
+
+ if (unlikely(!hostrcb)) {
+ dev_info(&ioa->pdev->dev, "Reclaiming async error buffers.");
+ hostrcb = list_first_entry_or_null(&ioa->hostrcb_report_q,
+ struct ipr_hostrcb, queue);
+ }
+
+ list_del_init(&hostrcb->queue);
+ return hostrcb;
+}
+
/**
* ipr_process_error - Op done function for an adapter error log.
* @ipr_cmd: ipr command struct
@@ -2569,13 +2586,14 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
u32 fd_ioasc;
+ char *envp[] = { "ASYNC_ERR_LOG=1", NULL };
if (ioa_cfg->sis64)
fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
else
fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
- list_del(&hostrcb->queue);
+ list_del_init(&hostrcb->queue);
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
if (!ioasc) {
@@ -2588,6 +2606,10 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
"Host RCB failed with IOASC: 0x%08X\n", ioasc);
}
+ list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_report_q);
+ hostrcb = ipr_get_free_hostrcb(ioa_cfg);
+ kobject_uevent_env(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE, envp);
+
ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
}
@@ -4095,6 +4117,64 @@ static struct device_attribute ipr_ioa_fw_type_attr = {
.show = ipr_show_fw_type
};
+static ssize_t ipr_read_async_err_log(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *cdev = container_of(kobj, struct device, kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+ struct ipr_hostrcb *hostrcb;
+ unsigned long lock_flags = 0;
+ int ret;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ hostrcb = list_first_entry_or_null(&ioa_cfg->hostrcb_report_q,
+ struct ipr_hostrcb, queue);
+ if (!hostrcb) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return 0;
+ }
+ ret = memory_read_from_buffer(buf, count, &off, &hostrcb->hcam,
+ sizeof(hostrcb->hcam));
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return ret;
+}
+
+static ssize_t ipr_next_async_err_log(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *cdev = container_of(kobj, struct device, kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+ struct ipr_hostrcb *hostrcb;
+ unsigned long lock_flags = 0;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ hostrcb = list_first_entry_or_null(&ioa_cfg->hostrcb_report_q,
+ struct ipr_hostrcb, queue);
+ if (!hostrcb) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return count;
+ }
+
+ /* Reclaim hostrcb before exit */
+ list_move_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return count;
+}
+
+static struct bin_attribute ipr_ioa_async_err_log = {
+ .attr = {
+ .name = "async_err_log",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = 0,
+ .read = ipr_read_async_err_log,
+ .write = ipr_next_async_err_log
+};
+
static struct device_attribute *ipr_ioa_attrs[] = {
&ipr_fw_version_attr,
&ipr_log_level_attr,
@@ -7026,8 +7106,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct ipr_resource_entry *res;
- struct ipr_hostrcb *hostrcb, *temp;
- int i = 0, j;
+ int j;
ENTER;
ioa_cfg->in_reset_reload = 0;
@@ -7048,12 +7127,16 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
}
schedule_work(&ioa_cfg->work_q);
- list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) {
- list_del(&hostrcb->queue);
- if (i++ < IPR_NUM_LOG_HCAMS)
- ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
+ for (j = 0; j < IPR_NUM_HCAMS; j++) {
+ list_del_init(&ioa_cfg->hostrcb[j]->queue);
+ if (j < IPR_NUM_LOG_HCAMS)
+ ipr_send_hcam(ioa_cfg,
+ IPR_HCAM_CDB_OP_CODE_LOG_DATA,
+ ioa_cfg->hostrcb[j]);
else
- ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
+ ipr_send_hcam(ioa_cfg,
+ IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE,
+ ioa_cfg->hostrcb[j]);
}
scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS);
@@ -7966,7 +8049,8 @@ static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd)
ENTER;
ipr_cmd->job_step = ipr_ioafp_std_inquiry;
- dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n");
+ if (ioa_cfg->identify_hrrq_index == 0)
+ dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n");
if (ioa_cfg->identify_hrrq_index < ioa_cfg->hrrq_num) {
hrrq = &ioa_cfg->hrrq[ioa_cfg->identify_hrrq_index];
@@ -8335,7 +8419,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
struct ipr_hostrcb, queue);
- list_del(&hostrcb->queue);
+ list_del_init(&hostrcb->queue);
memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
rc = ipr_get_ldump_data_section(ioa_cfg,
@@ -9332,7 +9416,7 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
dma_free_coherent(&ioa_cfg->pdev->dev, ioa_cfg->cfg_table_size,
ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma);
- for (i = 0; i < IPR_NUM_HCAMS; i++) {
+ for (i = 0; i < IPR_MAX_HCAMS; i++) {
dma_free_coherent(&ioa_cfg->pdev->dev,
sizeof(struct ipr_hostrcb),
ioa_cfg->hostrcb[i],
@@ -9572,7 +9656,7 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
if (!ioa_cfg->u.cfg_table)
goto out_free_host_rrq;
- for (i = 0; i < IPR_NUM_HCAMS; i++) {
+ for (i = 0; i < IPR_MAX_HCAMS; i++) {
ioa_cfg->hostrcb[i] = dma_alloc_coherent(&pdev->dev,
sizeof(struct ipr_hostrcb),
&ioa_cfg->hostrcb_dma[i],
@@ -9714,6 +9798,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q);
INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
+ INIT_LIST_HEAD(&ioa_cfg->hostrcb_report_q);
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
@@ -10352,6 +10437,8 @@ static void ipr_remove(struct pci_dev *pdev)
&ipr_trace_attr);
ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj,
&ipr_dump_attr);
+ sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj,
+ &ipr_ioa_async_err_log);
scsi_remove_host(ioa_cfg->host);
__ipr_remove(pdev);
@@ -10400,10 +10487,25 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
return rc;
}
+ rc = sysfs_create_bin_file(&ioa_cfg->host->shost_dev.kobj,
+ &ipr_ioa_async_err_log);
+
+ if (rc) {
+ ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj,
+ &ipr_dump_attr);
+ ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj,
+ &ipr_trace_attr);
+ scsi_remove_host(ioa_cfg->host);
+ __ipr_remove(pdev);
+ return rc;
+ }
+
rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj,
&ipr_dump_attr);
if (rc) {
+ sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj,
+ &ipr_ioa_async_err_log);
ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj,
&ipr_trace_attr);
scsi_remove_host(ioa_cfg->host);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index cdb51960b53c..8995053d01b3 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -154,7 +154,9 @@
#define IPR_DEFAULT_MAX_ERROR_DUMP 984
#define IPR_NUM_LOG_HCAMS 2
#define IPR_NUM_CFG_CHG_HCAMS 2
+#define IPR_NUM_HCAM_QUEUE 12
#define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
+#define IPR_MAX_HCAMS (IPR_NUM_HCAMS + IPR_NUM_HCAM_QUEUE)
#define IPR_MAX_SIS64_TARGETS_PER_BUS 1024
#define IPR_MAX_SIS64_LUNS_PER_TARGET 0xffffffff
@@ -1504,6 +1506,7 @@ struct ipr_ioa_cfg {
u8 log_level;
#define IPR_MAX_LOG_LEVEL 4
#define IPR_DEFAULT_LOG_LEVEL 2
+#define IPR_DEBUG_LOG_LEVEL 3
#define IPR_NUM_TRACE_INDEX_BITS 8
#define IPR_NUM_TRACE_ENTRIES (1 << IPR_NUM_TRACE_INDEX_BITS)
@@ -1532,10 +1535,11 @@ struct ipr_ioa_cfg {
char ipr_hcam_label[8];
#define IPR_HCAM_LABEL "hcams"
- struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS];
- dma_addr_t hostrcb_dma[IPR_NUM_HCAMS];
+ struct ipr_hostrcb *hostrcb[IPR_MAX_HCAMS];
+ dma_addr_t hostrcb_dma[IPR_MAX_HCAMS];
struct list_head hostrcb_free_q;
struct list_head hostrcb_pending_q;
+ struct list_head hostrcb_report_q;
struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM];
u32 hrrq_num;
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index e72673b0a8fb..16ca31ad5ec0 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1837,7 +1837,6 @@ static void fc_exch_reset(struct fc_exch *ep)
int rc = 1;
spin_lock_bh(&ep->ex_lock);
- fc_exch_abort_locked(ep, 0);
ep->state |= FC_EX_RST_CLEANUP;
fc_exch_timer_cancel(ep);
if (ep->esb_stat & ESB_ST_REC_QUAL)
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 93f596182145..97aeaddd600d 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -457,6 +457,9 @@ static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
*/
static int fc_rport_logoff(struct fc_rport_priv *rdata)
{
+ struct fc_lport *lport = rdata->local_port;
+ u32 port_id = rdata->ids.port_id;
+
mutex_lock(&rdata->rp_mutex);
FC_RPORT_DBG(rdata, "Remove port\n");
@@ -466,6 +469,15 @@ static int fc_rport_logoff(struct fc_rport_priv *rdata)
FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
goto out;
}
+ /*
+ * FC-LS states:
+ * To explicitly Logout, the initiating Nx_Port shall terminate
+ * other open Sequences that it initiated with the destination
+ * Nx_Port prior to performing Logout.
+ */
+ lport->tt.exch_mgr_reset(lport, 0, port_id);
+ lport->tt.exch_mgr_reset(lport, port_id, 0);
+
fc_rport_enter_logo(rdata);
/*
@@ -547,16 +559,24 @@ static void fc_rport_timeout(struct work_struct *work)
*/
static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
{
+ struct fc_lport *lport = rdata->local_port;
+
FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
IS_ERR(fp) ? -PTR_ERR(fp) : 0,
fc_rport_state(rdata), rdata->retries);
switch (rdata->rp_state) {
case RPORT_ST_FLOGI:
- case RPORT_ST_PLOGI:
rdata->flags &= ~FC_RP_STARTED;
fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
break;
+ case RPORT_ST_PLOGI:
+ if (lport->point_to_multipoint) {
+ rdata->flags &= ~FC_RP_STARTED;
+ fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
+ } else
+ fc_rport_enter_logo(rdata);
+ break;
case RPORT_ST_RTV:
fc_rport_enter_ready(rdata);
break;
@@ -1877,7 +1897,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
spp->spp_type_ext = rspp->spp_type_ext;
spp->spp_flags = FC_SPP_RESP_ACK;
- fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+ fc_rport_enter_prli(rdata);
fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
lport->tt.frame_send(lport, fp);
@@ -1915,7 +1935,7 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
fc_rport_state(rdata));
- fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+ fc_rport_enter_delete(rdata, RPORT_EV_STOP);
mutex_unlock(&rdata->rp_mutex);
kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
} else
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 63e48d4277b0..4ac03b16d17f 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1535,7 +1535,7 @@ lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
}
/* Routines for all individual HBA attributes */
-int
+static int
lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
{
struct lpfc_fdmi_attr_entry *ae;
@@ -1551,7 +1551,7 @@ lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
ad->AttrType = cpu_to_be16(RHBA_NODENAME);
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1573,7 +1573,7 @@ lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
{
struct lpfc_hba *phba = vport->phba;
@@ -1594,7 +1594,7 @@ lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1615,7 +1615,7 @@ lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1637,7 +1637,7 @@ lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1669,7 +1669,7 @@ lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1690,7 +1690,7 @@ lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1715,7 +1715,7 @@ lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1736,7 +1736,7 @@ lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1759,7 +1759,7 @@ lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1775,7 +1775,7 @@ lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1794,7 +1794,7 @@ lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1811,7 +1811,7 @@ lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1828,7 +1828,7 @@ lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1846,7 +1846,7 @@ lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1867,7 +1867,7 @@ lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1884,7 +1884,7 @@ lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1906,7 +1906,7 @@ lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
}
/* Routines for all individual PORT attributes */
-int
+static int
lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1925,7 +1925,7 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -1975,7 +1975,7 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2039,7 +2039,7 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2059,7 +2059,7 @@ lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2081,7 +2081,7 @@ lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2102,7 +2102,7 @@ lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2120,7 +2120,7 @@ lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2138,7 +2138,7 @@ lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2156,7 +2156,7 @@ lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2175,7 +2175,7 @@ lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2190,7 +2190,7 @@ lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2208,7 +2208,7 @@ lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2227,7 +2227,7 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2243,7 +2243,7 @@ lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2259,7 +2259,7 @@ lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2274,7 +2274,7 @@ lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2295,7 +2295,7 @@ lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2316,7 +2316,7 @@ lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2337,7 +2337,7 @@ lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2358,7 +2358,7 @@ lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2378,7 +2378,7 @@ lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
@@ -2393,7 +2393,7 @@ lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
return size;
}
-int
+static int
lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c0af32f24954..b7d54bfb1df9 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -4617,7 +4617,7 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
return sentplogi;
}
-uint32_t
+static uint32_t
lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc,
uint32_t word0)
{
@@ -4629,7 +4629,7 @@ lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc,
return sizeof(struct fc_rdp_link_service_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc,
uint8_t *page_a0, uint8_t *page_a2)
{
@@ -4694,7 +4694,7 @@ lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc,
return sizeof(struct fc_rdp_sfp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
READ_LNK_VAR *stat)
{
@@ -4723,7 +4723,7 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
return sizeof(struct fc_rdp_link_error_status_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat,
struct lpfc_vport *vport)
{
@@ -4748,7 +4748,7 @@ lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat,
return sizeof(struct fc_rdp_bbc_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba,
struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2)
{
@@ -4776,7 +4776,7 @@ lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba,
return sizeof(struct fc_rdp_oed_sfp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba,
struct fc_rdp_oed_sfp_desc *desc,
uint8_t *page_a2)
@@ -4805,7 +4805,7 @@ lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba,
return sizeof(struct fc_rdp_oed_sfp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba,
struct fc_rdp_oed_sfp_desc *desc,
uint8_t *page_a2)
@@ -4834,7 +4834,7 @@ lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba,
return sizeof(struct fc_rdp_oed_sfp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba,
struct fc_rdp_oed_sfp_desc *desc,
uint8_t *page_a2)
@@ -4864,7 +4864,7 @@ lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba,
}
-uint32_t
+static uint32_t
lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba,
struct fc_rdp_oed_sfp_desc *desc,
uint8_t *page_a2)
@@ -4893,7 +4893,7 @@ lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba,
return sizeof(struct fc_rdp_oed_sfp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc,
uint8_t *page_a0, struct lpfc_vport *vport)
{
@@ -4907,7 +4907,7 @@ lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc,
return sizeof(struct fc_rdp_opd_sfp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
{
if (bf_get(lpfc_read_link_stat_gec2, stat) == 0)
@@ -4924,7 +4924,7 @@ lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
return sizeof(struct fc_fec_rdp_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
{
uint16_t rdp_cap = 0;
@@ -4986,7 +4986,7 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
return sizeof(struct fc_rdp_port_speed_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc,
struct lpfc_hba *phba)
{
@@ -5003,7 +5003,7 @@ lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc,
return sizeof(struct fc_rdp_port_name_desc);
}
-uint32_t
+static uint32_t
lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc,
struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
@@ -5027,7 +5027,7 @@ lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc,
return sizeof(struct fc_rdp_port_name_desc);
}
-void
+static void
lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
int status)
{
@@ -5165,7 +5165,7 @@ free_rdp_context:
kfree(rdp_context);
}
-int
+static int
lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context)
{
LPFC_MBOXQ_t *mbox = NULL;
@@ -7995,7 +7995,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
-void
+static void
lpfc_start_fdmi(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 12dbe99ccc50..b234c50c255f 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2260,7 +2260,7 @@ lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
return 0;
}
-void
+static void
lpfc_mbx_cmpl_rdp_link_stat(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
MAILBOX_t *mb;
@@ -2281,7 +2281,7 @@ mbx_failed:
rdp_context->cmpl(phba, rdp_context, rc);
}
-void
+static void
lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
{
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) mbox->context1;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 7080ce2920fd..c5326055beee 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -5689,7 +5689,7 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type)
return rc;
}
-void
+static void
lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
uint32_t feature)
{
@@ -8968,7 +8968,7 @@ lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
* Since ABORTS must go on the same WQ of the command they are
* aborting, we use command's fcp_wqidx.
*/
-int
+static int
lpfc_sli_calc_ring(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb)
{
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index c1ed25adb17e..9ff57dee72d7 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -189,25 +189,12 @@ u32
megasas_build_and_issue_cmd(struct megasas_instance *instance,
struct scsi_cmnd *scmd);
static void megasas_complete_cmd_dpc(unsigned long instance_addr);
-void
-megasas_release_fusion(struct megasas_instance *instance);
-int
-megasas_ioc_init_fusion(struct megasas_instance *instance);
-void
-megasas_free_cmds_fusion(struct megasas_instance *instance);
-u8
-megasas_get_map_info(struct megasas_instance *instance);
-int
-megasas_sync_map_info(struct megasas_instance *instance);
int
wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
int seconds);
-void megasas_reset_reply_desc(struct megasas_instance *instance);
void megasas_fusion_ocr_wq(struct work_struct *work);
static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
int initial);
-int megasas_check_mpio_paths(struct megasas_instance *instance,
- struct scsi_cmnd *scmd);
int
megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
@@ -5036,7 +5023,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
/* Find first memory bar */
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
- instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
+ instance->bar = find_first_bit(&bar_list, BITS_PER_LONG);
if (pci_request_selected_regions(instance->pdev, 1<<instance->bar,
"megasas: LSI")) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n");
@@ -5782,7 +5769,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
&instance->consumer_h);
if (!instance->producer || !instance->consumer) {
- dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate"
+ dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate "
"memory for producer, consumer\n");
goto fail_alloc_dma_buf;
}
@@ -6711,14 +6698,9 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
unsigned long flags;
u32 wait_time = MEGASAS_RESET_WAIT_TIME;
- ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
- if (!ioc)
- return -ENOMEM;
-
- if (copy_from_user(ioc, user_ioc, sizeof(*ioc))) {
- error = -EFAULT;
- goto out_kfree_ioc;
- }
+ ioc = memdup_user(user_ioc, sizeof(*ioc));
+ if (IS_ERR(ioc))
+ return PTR_ERR(ioc);
instance = megasas_lookup_instance(ioc->host_no);
if (!instance) {
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 80eaee22f5bc..e3bee04c1eb1 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -991,5 +991,14 @@ union desc_value {
} u;
};
+void megasas_free_cmds_fusion(struct megasas_instance *instance);
+int megasas_ioc_init_fusion(struct megasas_instance *instance);
+u8 megasas_get_map_info(struct megasas_instance *instance);
+int megasas_sync_map_info(struct megasas_instance *instance);
+void megasas_release_fusion(struct megasas_instance *instance);
+void megasas_reset_reply_desc(struct megasas_instance *instance);
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd);
+void megasas_fusion_ocr_wq(struct work_struct *work);
#endif /* _MEGARAID_SAS_FUSION_H_ */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 750f82c339d4..a1a5ceb42ce6 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -98,7 +98,7 @@ MODULE_PARM_DESC(mpt3sas_fwfault_debug,
" enable detection of firmware fault and halt firmware - (default=0)");
static int
-_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag);
+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
/**
* _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
@@ -218,8 +218,7 @@ _base_fault_reset_work(struct work_struct *work)
ioc->non_operational_loop = 0;
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
- rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
pr_warn(MPT3SAS_FMT "%s: hard reset: %s\n", ioc->name,
__func__, (rc == 0) ? "success" : "failed");
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
@@ -2040,7 +2039,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
* mpt3sas_base_unmap_resources - free controller resources
* @ioc: per adapter object
*/
-void
+static void
mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
{
struct pci_dev *pdev = ioc->pdev;
@@ -2145,7 +2144,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
_base_mask_interrupts(ioc);
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+ r = _base_get_ioc_facts(ioc);
if (r)
goto out_fail;
@@ -3183,12 +3182,11 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
/**
* _base_allocate_memory_pools - allocate start of day memory pools
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 success, anything else error
*/
static int
-_base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
{
struct mpt3sas_facts *facts;
u16 max_sge_elements;
@@ -3658,29 +3656,25 @@ mpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked)
* _base_wait_on_iocstate - waiting on a particular ioc state
* @ioc_state: controller state { READY, OPERATIONAL, or RESET }
* @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
- int sleep_flag)
+_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout)
{
u32 count, cntdn;
u32 current_state;
count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+ cntdn = 1000 * timeout;
do {
current_state = mpt3sas_base_get_iocstate(ioc, 1);
if (current_state == ioc_state)
return 0;
if (count && current_state == MPI2_IOC_STATE_FAULT)
break;
- if (sleep_flag == CAN_SLEEP)
- usleep_range(1000, 1500);
- else
- udelay(500);
+
+ usleep_range(1000, 1500);
count++;
} while (--cntdn);
@@ -3692,24 +3686,22 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
* a write to the doorbell)
* @ioc: per adapter object
* @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*
* Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
*/
static int
-_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag);
+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc);
static int
-_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
+_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
{
u32 cntdn, count;
u32 int_status;
count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+ cntdn = 1000 * timeout;
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
@@ -3718,10 +3710,35 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
ioc->name, __func__, count, timeout));
return 0;
}
- if (sleep_flag == CAN_SLEEP)
- usleep_range(1000, 1500);
- else
- udelay(500);
+
+ usleep_range(1000, 1500);
+ count++;
+ } while (--cntdn);
+
+ pr_err(MPT3SAS_FMT
+ "%s: failed due to timeout count(%d), int_status(%x)!\n",
+ ioc->name, __func__, count, int_status);
+ return -EFAULT;
+}
+
+static int
+_base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
+{
+ u32 cntdn, count;
+ u32 int_status;
+
+ count = 0;
+ cntdn = 2000 * timeout;
+ do {
+ int_status = readl(&ioc->chip->HostInterruptStatus);
+ if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+ dhsprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: successful count(%d), timeout(%d)\n",
+ ioc->name, __func__, count, timeout));
+ return 0;
+ }
+
+ udelay(500);
count++;
} while (--cntdn);
@@ -3729,13 +3746,13 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
"%s: failed due to timeout count(%d), int_status(%x)!\n",
ioc->name, __func__, count, int_status);
return -EFAULT;
+
}
/**
* _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
* @ioc: per adapter object
* @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*
@@ -3743,15 +3760,14 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
* doorbell.
*/
static int
-_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
+_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout)
{
u32 cntdn, count;
u32 int_status;
u32 doorbell;
count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+ cntdn = 1000 * timeout;
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
@@ -3769,10 +3785,7 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout,
} else if (int_status == 0xFFFFFFFF)
goto out;
- if (sleep_flag == CAN_SLEEP)
- usleep_range(1000, 1500);
- else
- udelay(500);
+ usleep_range(1000, 1500);
count++;
} while (--cntdn);
@@ -3787,20 +3800,18 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout,
* _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
* @ioc: per adapter object
* @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*
*/
static int
-_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
+_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout)
{
u32 cntdn, count;
u32 doorbell_reg;
count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+ cntdn = 1000 * timeout;
do {
doorbell_reg = readl(&ioc->chip->Doorbell);
if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
@@ -3809,10 +3820,8 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout,
ioc->name, __func__, count, timeout));
return 0;
}
- if (sleep_flag == CAN_SLEEP)
- usleep_range(1000, 1500);
- else
- udelay(500);
+
+ usleep_range(1000, 1500);
count++;
} while (--cntdn);
@@ -3827,13 +3836,11 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout,
* @ioc: per adapter object
* @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
* @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout,
- int sleep_flag)
+_base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
{
u32 ioc_state;
int r = 0;
@@ -3852,12 +3859,11 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout,
writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
&ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) {
+ if ((_base_wait_for_doorbell_ack(ioc, 15))) {
r = -EFAULT;
goto out;
}
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
- timeout, sleep_flag);
+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
if (ioc_state) {
pr_err(MPT3SAS_FMT
"%s: failed going to ready state (ioc_state=0x%x)\n",
@@ -3879,18 +3885,16 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout,
* @reply_bytes: reply length
* @reply: pointer to reply payload
* @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
- u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+ u32 *request, int reply_bytes, u16 *reply, int timeout)
{
MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
int i;
u8 failed;
- u16 dummy;
__le32 *mfp;
/* make sure doorbell is not in use */
@@ -3911,7 +3915,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
&ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
+ if ((_base_spin_on_doorbell_int(ioc, 5))) {
pr_err(MPT3SAS_FMT
"doorbell handshake int failed (line=%d)\n",
ioc->name, __LINE__);
@@ -3919,7 +3923,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
}
writel(0, &ioc->chip->HostInterruptStatus);
- if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+ if ((_base_wait_for_doorbell_ack(ioc, 5))) {
pr_err(MPT3SAS_FMT
"doorbell handshake ack failed (line=%d)\n",
ioc->name, __LINE__);
@@ -3929,7 +3933,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
/* send message 32-bits at a time */
for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+ if ((_base_wait_for_doorbell_ack(ioc, 5)))
failed = 1;
}
@@ -3941,7 +3945,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
}
/* now wait for the reply */
- if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+ if ((_base_wait_for_doorbell_int(ioc, timeout))) {
pr_err(MPT3SAS_FMT
"doorbell handshake int failed (line=%d)\n",
ioc->name, __LINE__);
@@ -3952,7 +3956,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
& MPI2_DOORBELL_DATA_MASK);
writel(0, &ioc->chip->HostInterruptStatus);
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+ if ((_base_wait_for_doorbell_int(ioc, 5))) {
pr_err(MPT3SAS_FMT
"doorbell handshake int failed (line=%d)\n",
ioc->name, __LINE__);
@@ -3963,22 +3967,22 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
writel(0, &ioc->chip->HostInterruptStatus);
for (i = 2; i < default_reply->MsgLength * 2; i++) {
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+ if ((_base_wait_for_doorbell_int(ioc, 5))) {
pr_err(MPT3SAS_FMT
"doorbell handshake int failed (line=%d)\n",
ioc->name, __LINE__);
return -EFAULT;
}
if (i >= reply_bytes/2) /* overflow case */
- dummy = readl(&ioc->chip->Doorbell);
+ readl(&ioc->chip->Doorbell);
else
reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
& MPI2_DOORBELL_DATA_MASK);
writel(0, &ioc->chip->HostInterruptStatus);
}
- _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
- if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
+ _base_wait_for_doorbell_int(ioc, 5);
+ if (_base_wait_for_doorbell_not_used(ioc, 5) != 0) {
dhsprintk(ioc, pr_info(MPT3SAS_FMT
"doorbell is in use (line=%d)\n", ioc->name, __LINE__));
}
@@ -4015,7 +4019,6 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
{
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
bool issue_reset = false;
int rc;
void *request;
@@ -4068,7 +4071,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
ioc->ioc_link_reset_in_progress = 1;
init_completion(&ioc->base_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+ wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) &&
@@ -4093,8 +4096,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
ioc->base_cmds.status = MPT3_CMD_NOT_USED;
rc = -EFAULT;
out:
@@ -4119,7 +4121,6 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
{
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
bool issue_reset = false;
int rc;
void *request;
@@ -4170,7 +4171,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
init_completion(&ioc->base_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+ wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -4191,8 +4192,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
ioc->base_cmds.status = MPT3_CMD_NOT_USED;
rc = -EFAULT;
out:
@@ -4203,12 +4203,11 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
/**
* _base_get_port_facts - obtain port facts reply and save in ioc
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag)
+_base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port)
{
Mpi2PortFactsRequest_t mpi_request;
Mpi2PortFactsReply_t mpi_reply;
@@ -4224,7 +4223,7 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag)
mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
mpi_request.PortNumber = port;
r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
- (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+ (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5);
if (r != 0) {
pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
@@ -4247,13 +4246,11 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag)
* _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL
* @ioc: per adapter object
* @timeout:
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
+_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout)
{
u32 ioc_state;
int rc;
@@ -4287,8 +4284,7 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout,
goto issue_diag_reset;
}
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
- timeout, sleep_flag);
+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
if (ioc_state) {
dfailprintk(ioc, printk(MPT3SAS_FMT
"%s: failed going to ready state (ioc_state=0x%x)\n",
@@ -4297,19 +4293,18 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout,
}
issue_diag_reset:
- rc = _base_diag_reset(ioc, sleep_flag);
+ rc = _base_diag_reset(ioc);
return rc;
}
/**
* _base_get_ioc_facts - obtain ioc facts reply and save in ioc
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2IOCFactsRequest_t mpi_request;
Mpi2IOCFactsReply_t mpi_reply;
@@ -4319,7 +4314,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
- r = _base_wait_for_iocstate(ioc, 10, sleep_flag);
+ r = _base_wait_for_iocstate(ioc, 10);
if (r) {
dfailprintk(ioc, printk(MPT3SAS_FMT
"%s: failed getting to correct state\n",
@@ -4331,7 +4326,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
memset(&mpi_request, 0, mpi_request_sz);
mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
- (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+ (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5);
if (r != 0) {
pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
@@ -4391,12 +4386,11 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/**
* _base_send_ioc_init - send ioc_init to firmware
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2IOCInitRequest_t mpi_request;
Mpi2IOCInitReply_t mpi_reply;
@@ -4479,8 +4473,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
r = _base_handshake_req_reply_wait(ioc,
sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
- sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10,
- sleep_flag);
+ sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10);
if (r != 0) {
pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
@@ -4555,16 +4548,14 @@ mpt3sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/**
* _base_send_port_enable - send port_enable(discovery stuff) to firmware
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_port_enable(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2PortEnableRequest_t *mpi_request;
Mpi2PortEnableReply_t *mpi_reply;
- unsigned long timeleft;
int r = 0;
u16 smid;
u16 ioc_status;
@@ -4592,8 +4583,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
init_completion(&ioc->port_enable_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done,
- 300*HZ);
+ wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
ioc->name, __func__);
@@ -4737,15 +4727,13 @@ _base_unmask_events(struct MPT3SAS_ADAPTER *ioc, u16 event)
/**
* _base_event_notification - send event notification
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_event_notification(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_event_notification(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2EventNotificationRequest_t *mpi_request;
- unsigned long timeleft;
u16 smid;
int r = 0;
int i;
@@ -4777,7 +4765,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
cpu_to_le32(ioc->event_masks[i]);
init_completion(&ioc->base_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
+ wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
ioc->name, __func__);
@@ -4827,19 +4815,18 @@ mpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type)
return;
mutex_lock(&ioc->base_cmds.mutex);
- _base_event_notification(ioc, CAN_SLEEP);
+ _base_event_notification(ioc);
mutex_unlock(&ioc->base_cmds.mutex);
}
/**
* _base_diag_reset - the "big hammer" start of day reset
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
{
u32 host_diagnostic;
u32 ioc_state;
@@ -4867,10 +4854,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
/* wait 100 msec */
- if (sleep_flag == CAN_SLEEP)
- msleep(100);
- else
- mdelay(100);
+ msleep(100);
if (count++ > 20)
goto out;
@@ -4890,10 +4874,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
&ioc->chip->HostDiagnostic);
/*This delay allows the chip PCIe hardware time to finish reset tasks*/
- if (sleep_flag == CAN_SLEEP)
- msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
- else
- mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
+ msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
/* Approximately 300 second max wait */
for (count = 0; count < (300000000 /
@@ -4906,13 +4887,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
break;
- /* Wait to pass the second read delay window */
- if (sleep_flag == CAN_SLEEP)
- msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
- / 1000);
- else
- mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
- / 1000);
+ msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC / 1000);
}
if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
@@ -4941,8 +4916,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
drsprintk(ioc, pr_info(MPT3SAS_FMT
"Wait for FW to go to the READY state\n", ioc->name));
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
- sleep_flag);
+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20);
if (ioc_state) {
pr_err(MPT3SAS_FMT
"%s: failed going to ready state (ioc_state=0x%x)\n",
@@ -4961,14 +4935,12 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/**
* _base_make_ioc_ready - put controller in READY state
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
* @type: FORCE_BIG_HAMMER or SOFT_RESET
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type)
+_base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
{
u32 ioc_state;
int rc;
@@ -4995,10 +4967,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
ioc->name, __func__, ioc_state);
return -EFAULT;
}
- if (sleep_flag == CAN_SLEEP)
- ssleep(1);
- else
- mdelay(1000);
+ ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
}
}
@@ -5024,24 +4993,23 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
if (!(_base_send_ioc_reset(ioc,
- MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) {
+ MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15))) {
return 0;
}
issue_diag_reset:
- rc = _base_diag_reset(ioc, CAN_SLEEP);
+ rc = _base_diag_reset(ioc);
return rc;
}
/**
* _base_make_ioc_operational - put controller in OPERATIONAL state
* @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
{
int r, i, index;
unsigned long flags;
@@ -5160,7 +5128,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
}
skip_init_reply_post_free_queue:
- r = _base_send_ioc_init(ioc, sleep_flag);
+ r = _base_send_ioc_init(ioc);
if (r)
return r;
@@ -5186,13 +5154,11 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
skip_init_reply_post_host_index:
_base_unmask_interrupts(ioc);
- r = _base_event_notification(ioc, sleep_flag);
+ r = _base_event_notification(ioc);
if (r)
return r;
- if (sleep_flag == CAN_SLEEP)
- _base_static_config_pages(ioc);
-
+ _base_static_config_pages(ioc);
if (ioc->is_driver_loading) {
@@ -5211,7 +5177,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
return r; /* scan_start and scan_finished support */
}
- r = _base_send_port_enable(ioc, sleep_flag);
+ r = _base_send_port_enable(ioc);
if (r)
return r;
@@ -5235,7 +5201,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
if (ioc->chip_phys && ioc->chip) {
_base_mask_interrupts(ioc);
ioc->shost_recovery = 1;
- _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+ _base_make_ioc_ready(ioc, SOFT_RESET);
ioc->shost_recovery = 0;
}
@@ -5292,7 +5258,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
goto out_free_resources;
pci_set_drvdata(ioc->pdev, ioc->shost);
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+ r = _base_get_ioc_facts(ioc);
if (r)
goto out_free_resources;
@@ -5326,7 +5292,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->build_sg_mpi = &_base_build_sg;
ioc->build_zero_len_sge_mpi = &_base_build_zero_len_sge;
- r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+ r = _base_make_ioc_ready(ioc, SOFT_RESET);
if (r)
goto out_free_resources;
@@ -5338,12 +5304,12 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
}
for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
- r = _base_get_port_facts(ioc, i, CAN_SLEEP);
+ r = _base_get_port_facts(ioc, i);
if (r)
goto out_free_resources;
}
- r = _base_allocate_memory_pools(ioc, CAN_SLEEP);
+ r = _base_allocate_memory_pools(ioc);
if (r)
goto out_free_resources;
@@ -5429,7 +5395,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
if (ioc->hba_mpi_version_belonged == MPI26_VERSION)
_base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION);
- r = _base_make_ioc_operational(ioc, CAN_SLEEP);
+ r = _base_make_ioc_operational(ioc);
if (r)
goto out_free_resources;
@@ -5565,21 +5531,18 @@ _base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
/**
* _wait_for_commands_to_complete - reset controller
* @ioc: Pointer to MPT_ADAPTER structure
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* This function waiting(3s) for all pending commands to complete
* prior to putting controller in reset.
*/
static void
-_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc)
{
u32 ioc_state;
unsigned long flags;
u16 i;
ioc->pending_io_count = 0;
- if (sleep_flag != CAN_SLEEP)
- return;
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL)
@@ -5602,13 +5565,12 @@ _wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/**
* mpt3sas_base_hard_reset_handler - reset controller
* @ioc: Pointer to MPT_ADAPTER structure
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
* @type: FORCE_BIG_HAMMER or SOFT_RESET
*
* Returns 0 for success, non-zero for failure.
*/
int
-mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
+mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
enum reset_type type)
{
int r;
@@ -5629,13 +5591,6 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
if (mpt3sas_fwfault_debug)
mpt3sas_halt_firmware(ioc);
- /* TODO - What we really should be doing is pulling
- * out all the code associated with NO_SLEEP; its never used.
- * That is legacy code from mpt fusion driver, ported over.
- * I will leave this BUG_ON here for now till its been resolved.
- */
- BUG_ON(sleep_flag == NO_SLEEP);
-
/* wait for an active reset in progress to complete */
if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
do {
@@ -5660,9 +5615,9 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
is_fault = 1;
}
_base_reset_handler(ioc, MPT3_IOC_PRE_RESET);
- _wait_for_commands_to_complete(ioc, sleep_flag);
+ _wait_for_commands_to_complete(ioc);
_base_mask_interrupts(ioc);
- r = _base_make_ioc_ready(ioc, sleep_flag, type);
+ r = _base_make_ioc_ready(ioc, type);
if (r)
goto out;
_base_reset_handler(ioc, MPT3_IOC_AFTER_RESET);
@@ -5675,7 +5630,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
r = -EFAULT;
goto out;
}
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+ r = _base_get_ioc_facts(ioc);
if (r)
goto out;
@@ -5684,7 +5639,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
"Please reboot the system and ensure that the correct"
" firmware version is running\n", ioc->name);
- r = _base_make_ioc_operational(ioc, sleep_flag);
+ r = _base_make_ioc_operational(ioc);
if (!r)
_base_reset_handler(ioc, MPT3_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 892c9be008b5..3e71bc1b4a80 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -119,10 +119,6 @@
#define MPT_MAX_CALLBACKS 32
-
-#define CAN_SLEEP 1
-#define NO_SLEEP 0
-
#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
/* reserved for issuing internally framed scsi io cmds */
#define INTERNAL_SCSIIO_CMDS_COUNT 3
@@ -478,7 +474,7 @@ struct _sas_device {
u8 pfa_led_on;
u8 pend_sas_rphy_add;
u8 enclosure_level;
- u8 connector_name[4];
+ u8 connector_name[5];
struct kref refcount;
};
@@ -794,16 +790,6 @@ struct reply_post_struct {
dma_addr_t reply_post_free_dma;
};
-/**
- * enum mutex_type - task management mutex type
- * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
- * @TM_MUTEX_ON: mutex is required
- */
-enum mutex_type {
- TM_MUTEX_OFF = 0,
- TM_MUTEX_ON = 1,
-};
-
typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
/**
* struct MPT3SAS_ADAPTER - per adapter struct
@@ -1229,7 +1215,7 @@ int mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc);
int mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc);
-int mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
+int mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
enum reset_type type);
void *mpt3sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid);
@@ -1291,7 +1277,11 @@ void mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase);
int mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
uint channel, uint id, uint lun, u8 type, u16 smid_task,
- ulong timeout, enum mutex_type m_type);
+ ulong timeout);
+int mpt3sas_scsih_issue_locked_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
+ uint channel, uint id, uint lun, u8 type, u16 smid_task,
+ ulong timeout);
+
void mpt3sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle);
void mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle);
void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index a6914ec99cc0..cebfd734fd76 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -285,7 +285,6 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
{
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
Mpi2ConfigRequest_t *config_request;
int r;
u8 retry_count, issue_host_reset = 0;
@@ -386,8 +385,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
_config_display_some_debug(ioc, smid, "config_request", NULL);
init_completion(&ioc->config_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
- timeout*HZ);
+ wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
ioc->name, __func__);
@@ -491,8 +489,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
mutex_unlock(&ioc->config_cmds.mutex);
if (issue_host_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
return r;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 7d00f09666b6..26cdc127ac89 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -518,7 +518,7 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
*
* Called when application request fasyn callback handler.
*/
-int
+static int
_ctl_fasync(int fd, struct file *filep, int mode)
{
return fasync_helper(fd, filep, mode, &async_queue);
@@ -530,7 +530,7 @@ _ctl_fasync(int fd, struct file *filep, int mode)
* @wait -
*
*/
-unsigned int
+static unsigned int
_ctl_poll(struct file *filep, poll_table *wait)
{
struct MPT3SAS_ADAPTER *ioc;
@@ -641,9 +641,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
MPI2RequestHeader_t *mpi_request = NULL, *request;
MPI2DefaultReply_t *mpi_reply;
u32 ioc_state;
- u16 ioc_status;
u16 smid;
- unsigned long timeout, timeleft;
+ unsigned long timeout;
u8 issue_reset;
u32 sz;
void *psge;
@@ -914,8 +913,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
timeout = MPT3_IOCTL_DEFAULT_TIMEOUT;
else
timeout = karg.timeout;
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- timeout*HZ);
+ wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ);
if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
Mpi2SCSITaskManagementRequest_t *tm_request =
(Mpi2SCSITaskManagementRequest_t *)mpi_request;
@@ -938,7 +936,6 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
}
mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
(ioc->logging_level & MPT_DEBUG_TM)) {
@@ -1001,13 +998,11 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
ioc->name,
le16_to_cpu(mpi_request->FunctionDependent1));
mpt3sas_halt_firmware(ioc);
- mpt3sas_scsih_issue_tm(ioc,
+ mpt3sas_scsih_issue_locked_tm(ioc,
le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,
- 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30,
- TM_MUTEX_ON);
+ 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
} else
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
}
out:
@@ -1220,8 +1215,7 @@ _ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
__func__));
- retval = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
pr_info(MPT3SAS_FMT "host reset: %s\n",
ioc->name, ((!retval) ? "SUCCESS" : "FAILED"));
return 0;
@@ -1381,7 +1375,6 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
Mpi2DiagBufferPostRequest_t *mpi_request;
Mpi2DiagBufferPostReply_t *mpi_reply;
u8 buffer_type;
- unsigned long timeleft;
u16 smid;
u16 ioc_status;
u32 ioc_state;
@@ -1499,7 +1492,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
init_completion(&ioc->ctl_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+ wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1538,8 +1531,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
out:
@@ -1800,7 +1792,6 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
u16 ioc_status;
u32 ioc_state;
int rc;
- unsigned long timeleft;
dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
@@ -1848,7 +1839,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
init_completion(&ioc->ctl_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+ wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1974,8 +1965,7 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
rc = mpt3sas_send_diag_release(ioc, buffer_type, &issue_reset);
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
return rc;
}
@@ -1995,7 +1985,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
Mpi2DiagBufferPostReply_t *mpi_reply;
int rc, i;
u8 buffer_type;
- unsigned long timeleft, request_size, copy_size;
+ unsigned long request_size, copy_size;
u16 smid;
u16 ioc_status;
u8 issue_reset = 0;
@@ -2116,7 +2106,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
init_completion(&ioc->ctl_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
+ wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -2155,8 +2145,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
out:
@@ -2352,7 +2341,7 @@ out_unlock_pciaccess:
* @cmd - ioctl opcode
* @arg -
*/
-long
+static long
_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
@@ -2372,7 +2361,7 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
* @cmd - ioctl opcode
* @arg -
*/
-long
+static long
_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
@@ -2392,7 +2381,7 @@ _ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*
* This routine handles 32 bit applications in 64bit os.
*/
-long
+static long
_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
@@ -2410,7 +2399,7 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
*
* This routine handles 32 bit applications in 64bit os.
*/
-long
+static long
_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index cd91a684c945..209a969a979d 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -1195,7 +1195,7 @@ _scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id,
*
* Returns queue depth.
*/
-int
+static int
scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
@@ -1244,7 +1244,7 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-int
+static int
scsih_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
@@ -1311,7 +1311,7 @@ scsih_target_alloc(struct scsi_target *starget)
*
* Returns nothing.
*/
-void
+static void
scsih_target_destroy(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
@@ -1320,7 +1320,6 @@ scsih_target_destroy(struct scsi_target *starget)
struct _sas_device *sas_device;
struct _raid_device *raid_device;
unsigned long flags;
- struct sas_rphy *rphy;
sas_target_priv_data = starget->hostdata;
if (!sas_target_priv_data)
@@ -1339,7 +1338,6 @@ scsih_target_destroy(struct scsi_target *starget)
}
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- rphy = dev_to_rphy(starget->dev.parent);
sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
if (sas_device && (sas_device->starget == starget) &&
(sas_device->id == starget->id) &&
@@ -1369,7 +1367,7 @@ scsih_target_destroy(struct scsi_target *starget)
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-int
+static int
scsih_slave_alloc(struct scsi_device *sdev)
{
struct Scsi_Host *shost;
@@ -1434,7 +1432,7 @@ scsih_slave_alloc(struct scsi_device *sdev)
*
* Returns nothing.
*/
-void
+static void
scsih_slave_destroy(struct scsi_device *sdev)
{
struct MPT3SAS_TARGET *sas_target_priv_data;
@@ -1527,7 +1525,7 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc,
* scsih_is_raid - return boolean indicating device is raid volume
* @dev the device struct object
*/
-int
+static int
scsih_is_raid(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -1542,7 +1540,7 @@ scsih_is_raid(struct device *dev)
* scsih_get_resync - get raid volume resync percent complete
* @dev the device struct object
*/
-void
+static void
scsih_get_resync(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -1603,7 +1601,7 @@ scsih_get_resync(struct device *dev)
* scsih_get_state - get raid volume level
* @dev the device struct object
*/
-void
+static void
scsih_get_state(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -1805,7 +1803,7 @@ _scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev)
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-int
+static int
scsih_slave_configure(struct scsi_device *sdev)
{
struct Scsi_Host *shost = sdev->host;
@@ -2021,7 +2019,7 @@ scsih_slave_configure(struct scsi_device *sdev)
*
* Return nothing.
*/
-int
+static int
scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int params[])
{
@@ -2201,7 +2199,6 @@ mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle)
* @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
* @smid_task: smid assigned to the task
* @timeout: timeout in seconds
- * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
* Context: user
*
* A generic API for sending task management requests to firmware.
@@ -2212,60 +2209,51 @@ mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle)
*/
int
mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
- uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
- enum mutex_type m_type)
+ uint id, uint lun, u8 type, u16 smid_task, ulong timeout)
{
Mpi2SCSITaskManagementRequest_t *mpi_request;
Mpi2SCSITaskManagementReply_t *mpi_reply;
u16 smid = 0;
u32 ioc_state;
- unsigned long timeleft;
struct scsiio_tracker *scsi_lookup = NULL;
int rc;
u16 msix_task = 0;
- if (m_type == TM_MUTEX_ON)
- mutex_lock(&ioc->tm_cmds.mutex);
+ lockdep_assert_held(&ioc->tm_cmds.mutex);
+
if (ioc->tm_cmds.status != MPT3_CMD_NOT_USED) {
pr_info(MPT3SAS_FMT "%s: tm_cmd busy!!!\n",
__func__, ioc->name);
- rc = FAILED;
- goto err_out;
+ return FAILED;
}
if (ioc->shost_recovery || ioc->remove_host ||
ioc->pci_error_recovery) {
pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
- rc = FAILED;
- goto err_out;
+ return FAILED;
}
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
if (ioc_state & MPI2_DOORBELL_USED) {
dhsprintk(ioc, pr_info(MPT3SAS_FMT
"unexpected doorbell active!\n", ioc->name));
- rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- goto err_out;
+ rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
+ return (!rc) ? SUCCESS : FAILED;
}
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
mpt3sas_base_fault_info(ioc, ioc_state &
MPI2_DOORBELL_DATA_MASK);
- rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- goto err_out;
+ rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
+ return (!rc) ? SUCCESS : FAILED;
}
smid = mpt3sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
if (!smid) {
pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
- rc = FAILED;
- goto err_out;
+ return FAILED;
}
if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
@@ -2292,19 +2280,17 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
else
msix_task = 0;
mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
- timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
+ wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
ioc->name, __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SCSITaskManagementRequest_t)/4);
if (!(ioc->tm_cmds.status & MPT3_CMD_RESET)) {
- rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ rc = mpt3sas_base_hard_reset_handler(ioc,
+ FORCE_BIG_HAMMER);
rc = (!rc) ? SUCCESS : FAILED;
- ioc->tm_cmds.status = MPT3_CMD_NOT_USED;
- mpt3sas_scsih_clear_tm_flag(ioc, handle);
- goto err_out;
+ goto out;
}
}
@@ -2356,17 +2342,23 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
break;
}
+out:
mpt3sas_scsih_clear_tm_flag(ioc, handle);
ioc->tm_cmds.status = MPT3_CMD_NOT_USED;
- if (m_type == TM_MUTEX_ON)
- mutex_unlock(&ioc->tm_cmds.mutex);
-
return rc;
+}
- err_out:
- if (m_type == TM_MUTEX_ON)
- mutex_unlock(&ioc->tm_cmds.mutex);
- return rc;
+int mpt3sas_scsih_issue_locked_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
+ uint channel, uint id, uint lun, u8 type, u16 smid_task, ulong timeout)
+{
+ int ret;
+
+ mutex_lock(&ioc->tm_cmds.mutex);
+ ret = mpt3sas_scsih_issue_tm(ioc, handle, channel, id, lun, type,
+ smid_task, timeout);
+ mutex_unlock(&ioc->tm_cmds.mutex);
+
+ return ret;
}
/**
@@ -2439,7 +2431,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
*
* Returns SUCCESS if command aborted else FAILED
*/
-int
+static int
scsih_abort(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
@@ -2482,9 +2474,9 @@ scsih_abort(struct scsi_cmnd *scmd)
mpt3sas_halt_firmware(ioc);
handle = sas_device_priv_data->sas_target->handle;
- r = mpt3sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
+ r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->channel,
scmd->device->id, scmd->device->lun,
- MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON);
+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
out:
sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
@@ -2498,7 +2490,7 @@ scsih_abort(struct scsi_cmnd *scmd)
*
* Returns SUCCESS if command aborted else FAILED
*/
-int
+static int
scsih_dev_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
@@ -2541,9 +2533,9 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
goto out;
}
- r = mpt3sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
+ r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->channel,
scmd->device->id, scmd->device->lun,
- MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON);
+ MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30);
out:
sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
@@ -2561,7 +2553,7 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
*
* Returns SUCCESS if command aborted else FAILED
*/
-int
+static int
scsih_target_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
@@ -2603,9 +2595,9 @@ scsih_target_reset(struct scsi_cmnd *scmd)
goto out;
}
- r = mpt3sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
+ r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->channel,
scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
- 30, TM_MUTEX_ON);
+ 30);
out:
starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
@@ -2624,7 +2616,7 @@ scsih_target_reset(struct scsi_cmnd *scmd)
*
* Returns SUCCESS if command aborted else FAILED
*/
-int
+static int
scsih_host_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
@@ -2641,8 +2633,7 @@ scsih_host_reset(struct scsi_cmnd *scmd)
goto out;
}
- retval = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
r = (retval < 0) ? FAILED : SUCCESS;
out:
pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n",
@@ -3455,7 +3446,7 @@ _scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
*
* Context - processed in interrupt context.
*/
-void
+static void
_scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
u32 event_context)
{
@@ -3494,7 +3485,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
*
* Context - processed in interrupt context.
*/
-void
+static void
_scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
u16 smid, u16 handle)
{
@@ -4032,7 +4023,7 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
* SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
* SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
*/
-int
+static int
scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -4701,7 +4692,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le16_to_cpu(mpi_reply->DevHandle));
mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq);
- if (!(ioc->logging_level & MPT_DEBUG_REPLY) &&
+ if ((ioc->logging_level & MPT_DEBUG_REPLY) &&
((scmd->sense_buffer[2] == UNIT_ATTENTION) ||
(scmd->sense_buffer[2] == MEDIUM_ERROR) ||
(scmd->sense_buffer[2] == HARDWARE_ERROR)))
@@ -5380,8 +5371,9 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
sas_device->enclosure_level =
le16_to_cpu(sas_device_pg0.EnclosureLevel);
- memcpy(&sas_device->connector_name[0],
- &sas_device_pg0.ConnectorName[0], 4);
+ memcpy(sas_device->connector_name,
+ sas_device_pg0.ConnectorName, 4);
+ sas_device->connector_name[4] = '\0';
} else {
sas_device->enclosure_level = 0;
sas_device->connector_name[0] = '\0';
@@ -5508,8 +5500,9 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
if (sas_device_pg0.Flags & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
sas_device->enclosure_level =
le16_to_cpu(sas_device_pg0.EnclosureLevel);
- memcpy(&sas_device->connector_name[0],
- &sas_device_pg0.ConnectorName[0], 4);
+ memcpy(sas_device->connector_name,
+ sas_device_pg0.ConnectorName, 4);
+ sas_device->connector_name[4] = '\0';
} else {
sas_device->enclosure_level = 0;
sas_device->connector_name[0] = '\0';
@@ -6087,8 +6080,7 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
r = mpt3sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
- MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30,
- TM_MUTEX_OFF);
+ MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
if (r == FAILED) {
sdev_printk(KERN_WARNING, sdev,
"mpt3sas_scsih_issue_tm: FAILED when sending "
@@ -6128,8 +6120,8 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
goto out_no_lock;
r = mpt3sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
- sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
- TM_MUTEX_OFF);
+ sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid,
+ 30);
if (r == FAILED) {
sdev_printk(KERN_WARNING, sdev,
"mpt3sas_scsih_issue_tm: ABORT_TASK: FAILED : "
@@ -6297,8 +6289,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
mutex_unlock(&ioc->scsih_cmds.mutex);
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
return rc;
}
@@ -6311,11 +6302,10 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
static void
_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
{
- int rc;
sdev->no_uld_attach = no_uld_attach ? 1 : 0;
sdev_printk(KERN_INFO, sdev, "%s raid component\n",
sdev->no_uld_attach ? "hidding" : "exposing");
- rc = scsi_device_reprobe(sdev);
+ WARN_ON(scsi_device_reprobe(sdev));
}
/**
@@ -8137,7 +8127,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
* Routine called when unloading the driver.
* Return nothing.
*/
-void scsih_remove(struct pci_dev *pdev)
+static void scsih_remove(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8210,7 +8200,7 @@ void scsih_remove(struct pci_dev *pdev)
*
* Return nothing.
*/
-void
+static void
scsih_shutdown(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -8451,7 +8441,7 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc)
* of scanning the entire bus. In our implemention, we will kick off
* firmware discovery.
*/
-void
+static void
scsih_scan_start(struct Scsi_Host *shost)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8478,7 +8468,7 @@ scsih_scan_start(struct Scsi_Host *shost)
* scsi_host and the elapsed time of the scan in jiffies. In our implemention,
* we wait for firmware discovery to complete, then return 1.
*/
-int
+static int
scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8608,7 +8598,7 @@ static struct raid_function_template mpt3sas_raid_functions = {
* MPI25_VERSION for SAS 3.0 HBA devices, and
* MPI26 VERSION for Cutlass & Invader SAS 3.0 HBA devices
*/
-u16
+static u16
_scsih_determine_hba_mpi_version(struct pci_dev *pdev)
{
@@ -8660,7 +8650,7 @@ _scsih_determine_hba_mpi_version(struct pci_dev *pdev)
*
* Returns 0 success, anything else error.
*/
-int
+static int
_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct MPT3SAS_ADAPTER *ioc;
@@ -8869,7 +8859,7 @@ out_add_shost_fail:
*
* Returns 0 success, anything else error.
*/
-int
+static int
scsih_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -8896,7 +8886,7 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state)
*
* Returns 0 success, anything else error.
*/
-int
+static int
scsih_resume(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -8916,7 +8906,7 @@ scsih_resume(struct pci_dev *pdev)
if (r)
return r;
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
+ mpt3sas_base_hard_reset_handler(ioc, SOFT_RESET);
scsi_unblock_requests(shost);
mpt3sas_base_start_watchdog(ioc);
return 0;
@@ -8933,7 +8923,7 @@ scsih_resume(struct pci_dev *pdev)
* Return value:
* PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
*/
-pci_ers_result_t
+static pci_ers_result_t
scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -8970,7 +8960,7 @@ scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
* code after the PCI slot has been reset, just before we
* should resume normal operations.
*/
-pci_ers_result_t
+static pci_ers_result_t
scsih_pci_slot_reset(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -8987,8 +8977,7 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
if (rc)
return PCI_ERS_RESULT_DISCONNECT;
- rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
pr_warn(MPT3SAS_FMT "hard reset: %s\n", ioc->name,
(rc == 0) ? "success" : "failed");
@@ -9007,7 +8996,7 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
* OK to resume normal operation. Use completion to allow
* halted scsi ops to resume.
*/
-void
+static void
scsih_pci_resume(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -9024,7 +9013,7 @@ scsih_pci_resume(struct pci_dev *pdev)
* scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
* @pdev: pointer to PCI device
*/
-pci_ers_result_t
+static pci_ers_result_t
scsih_pci_mmio_enabled(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -9152,7 +9141,7 @@ static struct pci_driver mpt3sas_driver = {
*
* Returns 0 success, anything else error.
*/
-int
+static int
scsih_init(void)
{
mpt2_ids = 0;
@@ -9202,7 +9191,7 @@ scsih_init(void)
*
* Returns 0 success, anything else error.
*/
-void
+static void
scsih_exit(void)
{
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index ff93286bc32f..b74faf1a69b2 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -300,7 +300,6 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
int rc;
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
void *psge;
u8 issue_reset = 0;
void *data_out = NULL;
@@ -394,8 +393,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
ioc->name, (unsigned long long)sas_address));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
+ wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -446,8 +444,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
if (data_out)
@@ -1107,7 +1104,6 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
int rc;
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
void *psge;
u8 issue_reset = 0;
void *data_out = NULL;
@@ -1203,8 +1199,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
phy->number));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
+ wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -1253,8 +1248,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
if (data_out)
@@ -1421,7 +1415,6 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
int rc;
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
void *psge;
u8 issue_reset = 0;
void *data_out = NULL;
@@ -1522,8 +1515,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
phy->number, phy_operation));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
+ wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -1564,8 +1556,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset)
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
if (data_out)
@@ -1899,7 +1890,6 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
int rc;
u16 smid;
u32 ioc_state;
- unsigned long timeleft;
void *psge;
u8 issue_reset = 0;
dma_addr_t dma_addr_in = 0;
@@ -2043,8 +2033,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
+ wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s : timeout\n",
@@ -2103,8 +2092,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
issue_host_reset:
if (issue_reset) {
- mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
rc = -ETIMEDOUT;
}
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c
index 8bb06995adfb..b757d389e32f 100644
--- a/drivers/scsi/mvsas/mv_64xx.c
+++ b/drivers/scsi/mvsas/mv_64xx.c
@@ -136,7 +136,8 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
}
}
-void mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
+static void
+mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
{
void __iomem *regs = mvi->regs;
u32 tmp;
@@ -563,7 +564,7 @@ static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
return MVS_ID_NOT_MAPPED;
}
-void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
+static void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
{
int i;
struct scatterlist *sg;
@@ -633,7 +634,7 @@ static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i)
mvs_write_port_vsr_data(mvi, i, tmp);
}
-void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
+static void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
struct sas_phy_linkrates *rates)
{
u32 lrmin = 0, lrmax = 0;
@@ -668,20 +669,20 @@ static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
}
-u32 mvs_64xx_spi_read_data(struct mvs_info *mvi)
+static u32 mvs_64xx_spi_read_data(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs_ex;
return ior32(SPI_DATA_REG_64XX);
}
-void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data)
+static void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data)
{
void __iomem *regs = mvi->regs_ex;
iow32(SPI_DATA_REG_64XX, data);
}
-int mvs_64xx_spi_buildcmd(struct mvs_info *mvi,
+static int mvs_64xx_spi_buildcmd(struct mvs_info *mvi,
u32 *dwCmd,
u8 cmd,
u8 read,
@@ -705,7 +706,7 @@ int mvs_64xx_spi_buildcmd(struct mvs_info *mvi,
}
-int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
+static int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
{
void __iomem *regs = mvi->regs_ex;
int retry;
@@ -720,7 +721,7 @@ int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
return 0;
}
-int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
+static int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
{
void __iomem *regs = mvi->regs_ex;
u32 i, dwTmp;
@@ -735,7 +736,7 @@ int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
return -1;
}
-void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
+static void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
int buf_len, int from, void *prd)
{
int i;
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
index f6fc4a705924..4c57d9abce7b 100644
--- a/drivers/scsi/mvsas/mv_94xx.c
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -48,8 +48,8 @@ static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i)
}
}
-void set_phy_tuning(struct mvs_info *mvi, int phy_id,
- struct phy_tuning phy_tuning)
+static void set_phy_tuning(struct mvs_info *mvi, int phy_id,
+ struct phy_tuning phy_tuning)
{
u32 tmp, setting_0 = 0, setting_1 = 0;
u8 i;
@@ -110,8 +110,8 @@ void set_phy_tuning(struct mvs_info *mvi, int phy_id,
}
}
-void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id,
- struct ffe_control ffe)
+static void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id,
+ struct ffe_control ffe)
{
u32 tmp;
@@ -177,7 +177,7 @@ void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id,
}
/*Notice: this function must be called when phy is disabled*/
-void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate)
+static void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate)
{
union reg_phy_cfg phy_cfg, phy_cfg_tmp;
mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
@@ -679,7 +679,8 @@ static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
}
}
-void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
+static void
+mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
{
void __iomem *regs = mvi->regs;
u32 tmp;
@@ -906,8 +907,8 @@ static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i,
}
-void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
- struct sas_phy_linkrates *rates)
+static void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
+ struct sas_phy_linkrates *rates)
{
u32 lrmax = 0;
u32 tmp;
@@ -936,25 +937,25 @@ static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi)
}
-u32 mvs_94xx_spi_read_data(struct mvs_info *mvi)
+static u32 mvs_94xx_spi_read_data(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs_ex - 0x10200;
return mr32(SPI_RD_DATA_REG_94XX);
}
-void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data)
+static void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data)
{
void __iomem *regs = mvi->regs_ex - 0x10200;
mw32(SPI_RD_DATA_REG_94XX, data);
}
-int mvs_94xx_spi_buildcmd(struct mvs_info *mvi,
- u32 *dwCmd,
- u8 cmd,
- u8 read,
- u8 length,
- u32 addr
+static int mvs_94xx_spi_buildcmd(struct mvs_info *mvi,
+ u32 *dwCmd,
+ u8 cmd,
+ u8 read,
+ u8 length,
+ u32 addr
)
{
void __iomem *regs = mvi->regs_ex - 0x10200;
@@ -974,7 +975,7 @@ int mvs_94xx_spi_buildcmd(struct mvs_info *mvi,
}
-int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
+static int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
{
void __iomem *regs = mvi->regs_ex - 0x10200;
mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX);
@@ -982,7 +983,7 @@ int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
return 0;
}
-int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
+static int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
{
void __iomem *regs = mvi->regs_ex - 0x10200;
u32 i, dwTmp;
@@ -997,8 +998,8 @@ int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
return -1;
}
-void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
- int buf_len, int from, void *prd)
+static void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
+ int buf_len, int from, void *prd)
{
int i;
struct mvs_prd *buf_prd = prd;
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 5b9fcff6cd94..86eb19902bac 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -74,7 +74,7 @@ void mvs_tag_init(struct mvs_info *mvi)
mvs_tag_clear(mvi, i);
}
-struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
+static struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
{
unsigned long i = 0, j = 0, hi = 0;
struct sas_ha_struct *sha = dev->port->ha;
@@ -102,7 +102,7 @@ struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
}
-int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
+static int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
{
unsigned long i = 0, j = 0, n = 0, num = 0;
struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
@@ -1158,7 +1158,7 @@ void mvs_port_deformed(struct asd_sas_phy *sas_phy)
mvs_port_notify_deformed(sas_phy, 1);
}
-struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
+static struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
{
u32 dev;
for (dev = 0; dev < MVS_MAX_DEVICES; dev++) {
@@ -1175,7 +1175,7 @@ struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
return NULL;
}
-void mvs_free_dev(struct mvs_device *mvi_dev)
+static void mvs_free_dev(struct mvs_device *mvi_dev)
{
u32 id = mvi_dev->device_id;
memset(mvi_dev, 0, sizeof(*mvi_dev));
@@ -1185,7 +1185,7 @@ void mvs_free_dev(struct mvs_device *mvi_dev)
mvi_dev->taskfileset = MVS_ID_NOT_MAPPED;
}
-int mvs_dev_found_notify(struct domain_device *dev, int lock)
+static int mvs_dev_found_notify(struct domain_device *dev, int lock)
{
unsigned long flags = 0;
int res = 0;
@@ -1241,7 +1241,7 @@ int mvs_dev_found(struct domain_device *dev)
return mvs_dev_found_notify(dev, 1);
}
-void mvs_dev_gone_notify(struct domain_device *dev)
+static void mvs_dev_gone_notify(struct domain_device *dev)
{
unsigned long flags = 0;
struct mvs_device *mvi_dev = dev->lldd_dev;
@@ -1611,7 +1611,7 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
return stat;
}
-void mvs_set_sense(u8 *buffer, int len, int d_sense,
+static void mvs_set_sense(u8 *buffer, int len, int d_sense,
int key, int asc, int ascq)
{
memset(buffer, 0, len);
@@ -1650,7 +1650,7 @@ void mvs_set_sense(u8 *buffer, int len, int d_sense,
return;
}
-void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
+static void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
u8 key, u8 asc, u8 asc_q)
{
iu->datapres = 2;
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
deleted file mode 100644
index 2f689ae7a803..000000000000
--- a/drivers/scsi/pas16.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * This driver adapted from Drew Eckhardt's Trantor T128 driver
- *
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
- *
- * ( Based on T128 - DISTRIBUTION RELEASE 3. )
- *
- * Modified to work with the Pro Audio Spectrum/Studio 16
- * by John Weidman.
- *
- *
- * For more information, please consult
- *
- * Media Vision
- * (510) 770-8600
- * (800) 348-7116
- */
-
-/*
- * The card is detected and initialized in one of several ways :
- * 1. Autoprobe (default) - There are many different models of
- * the Pro Audio Spectrum/Studio 16, and I only have one of
- * them, so this may require a little tweaking. An interrupt
- * is triggered to autoprobe for the interrupt line. Note:
- * with the newer model boards, the interrupt is set via
- * software after reset using the default_irq for the
- * current board number.
- *
- * 2. With command line overrides - pas16=port,irq may be
- * used on the LILO command line to override the defaults.
- *
- * 3. With the PAS16_OVERRIDE compile time define. This is
- * specified as an array of address, irq tuples. Ie, for
- * one board at the default 0x388 address, IRQ10, I could say
- * -DPAS16_OVERRIDE={{0x388, 10}}
- * NOTE: Untested.
- *
- * 4. When included as a module, with arguments passed on the command line:
- * pas16_irq=xx the interrupt
- * pas16_addr=xx the port
- * e.g. "modprobe pas16 pas16_addr=0x388 pas16_irq=5"
- *
- * Note that if the override methods are used, place holders must
- * be specified for other boards in the system.
- *
- *
- * Configuration notes :
- * The current driver does not support interrupt sharing with the
- * sound portion of the card. If you use the same irq for the
- * scsi port and sound you will have problems. Either use
- * a different irq for the scsi port or don't use interrupts
- * for the scsi port.
- *
- * If you have problems with your card not being recognized, use
- * the LILO command line override. Try to get it recognized without
- * interrupts. Ie, for a board at the default 0x388 base port,
- * boot: linux pas16=0x388,0
- *
- * NO_IRQ (0) should be specified for no interrupt,
- * IRQ_AUTO (254) to autoprobe for an IRQ line if overridden
- * on the command line.
- */
-
-#include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <scsi/scsi_host.h>
-#include "pas16.h"
-#include "NCR5380.h"
-
-
-static unsigned short pas16_addr;
-static int pas16_irq;
-
-
-static const int scsi_irq_translate[] =
- { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
-
-/* The default_irqs array contains values used to set the irq into the
- * board via software (as must be done on newer model boards without
- * irq jumpers on the board). The first value in the array will be
- * assigned to logical board 0, the next to board 1, etc.
- */
-static int default_irqs[] __initdata =
- { PAS16_DEFAULT_BOARD_1_IRQ,
- PAS16_DEFAULT_BOARD_2_IRQ,
- PAS16_DEFAULT_BOARD_3_IRQ,
- PAS16_DEFAULT_BOARD_4_IRQ
- };
-
-static struct override {
- unsigned short io_port;
- int irq;
-} overrides
-#ifdef PAS16_OVERRIDE
- [] __initdata = PAS16_OVERRIDE;
-#else
- [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
- {0,IRQ_AUTO}};
-#endif
-
-#define NO_OVERRIDES ARRAY_SIZE(overrides)
-
-static struct base {
- unsigned short io_port;
- int noauto;
-} bases[] __initdata =
- { {PAS16_DEFAULT_BASE_1, 0},
- {PAS16_DEFAULT_BASE_2, 0},
- {PAS16_DEFAULT_BASE_3, 0},
- {PAS16_DEFAULT_BASE_4, 0}
- };
-
-#define NO_BASES ARRAY_SIZE(bases)
-
-static const unsigned short pas16_offset[ 8 ] =
- {
- 0x1c00, /* OUTPUT_DATA_REG */
- 0x1c01, /* INITIATOR_COMMAND_REG */
- 0x1c02, /* MODE_REG */
- 0x1c03, /* TARGET_COMMAND_REG */
- 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */
- 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
- 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
- * START_DMA_TARGET_RECEIVE_REG wo
- */
- 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro,
- * START_DMA_INITIATOR_RECEIVE_REG wo
- */
- };
-
-
-/*
- * Function : enable_board( int board_num, unsigned short port )
- *
- * Purpose : set address in new model board
- *
- * Inputs : board_num - logical board number 0-3, port - base address
- *
- */
-
-static void __init
- enable_board( int board_num, unsigned short port )
-{
- outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
- outb( port >> 2, MASTER_ADDRESS_PTR );
-}
-
-
-
-/*
- * Function : init_board( unsigned short port, int irq )
- *
- * Purpose : Set the board up to handle the SCSI interface
- *
- * Inputs : port - base address of the board,
- * irq - irq to assign to the SCSI port
- * force_irq - set it even if it conflicts with sound driver
- *
- */
-
-static void __init
- init_board( unsigned short io_port, int irq, int force_irq )
-{
- unsigned int tmp;
- unsigned int pas_irq_code;
-
- /* Initialize the SCSI part of the board */
-
- outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */
- outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
- outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
-
- inb(io_port + pas16_offset[RESET_PARITY_INTERRUPT_REG]);
-
- /* Set the SCSI interrupt pointer without mucking up the sound
- * interrupt pointer in the same byte.
- */
- pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0;
- tmp = inb( io_port + IO_CONFIG_3 );
-
- if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0
- && !force_irq )
- {
- printk( "pas16: WARNING: Can't use same irq as sound "
- "driver -- interrupts disabled\n" );
- /* Set up the drive parameters, disable 5380 interrupts */
- outb( 0x4d, io_port + SYS_CONFIG_4 );
- }
- else
- {
- tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 );
- outb( tmp, io_port + IO_CONFIG_3 );
-
- /* Set up the drive parameters and enable 5380 interrupts */
- outb( 0x6d, io_port + SYS_CONFIG_4 );
- }
-}
-
-
-/*
- * Function : pas16_hw_detect( unsigned short board_num )
- *
- * Purpose : determine if a pas16 board is present
- *
- * Inputs : board_num - logical board number ( 0 - 3 )
- *
- * Returns : 0 if board not found, 1 if found.
- */
-
-static int __init
- pas16_hw_detect( unsigned short board_num )
-{
- unsigned char board_rev, tmp;
- unsigned short io_port = bases[ board_num ].io_port;
-
- /* See if we can find a PAS16 board at the address associated
- * with this logical board number.
- */
-
- /* First, attempt to take a newer model board out of reset and
- * give it a base address. This shouldn't affect older boards.
- */
- enable_board( board_num, io_port );
-
- /* Now see if it looks like a PAS16 board */
- board_rev = inb( io_port + PCB_CONFIG );
-
- if( board_rev == 0xff )
- return 0;
-
- tmp = board_rev ^ 0xe0;
-
- outb( tmp, io_port + PCB_CONFIG );
- tmp = inb( io_port + PCB_CONFIG );
- outb( board_rev, io_port + PCB_CONFIG );
-
- if( board_rev != tmp ) /* Not a PAS-16 */
- return 0;
-
- if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
- return 0; /* return if no SCSI interface found */
-
- /* Mediavision has some new model boards that return ID bits
- * that indicate a SCSI interface, but they're not (LMS). We'll
- * put in an additional test to try to weed them out.
- */
-
- outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */
- outb(0x20, io_port + pas16_offset[MODE_REG]); /* Is it really SCSI? */
- if (inb(io_port + pas16_offset[MODE_REG]) != 0x20) /* Write to a reg. */
- return 0; /* and try to read */
- outb(0x00, io_port + pas16_offset[MODE_REG]); /* it back. */
- if (inb(io_port + pas16_offset[MODE_REG]) != 0x00)
- return 0;
-
- return 1;
-}
-
-
-#ifndef MODULE
-/*
- * Function : pas16_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- */
-
-static int __init pas16_setup(char *str)
-{
- static int commandline_current;
- int i;
- int ints[10];
-
- get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] != 2)
- printk("pas16_setup : usage pas16=io_port,irq\n");
- else
- if (commandline_current < NO_OVERRIDES) {
- overrides[commandline_current].io_port = (unsigned short) ints[1];
- overrides[commandline_current].irq = ints[2];
- for (i = 0; i < NO_BASES; ++i)
- if (bases[i].io_port == (unsigned short) ints[1]) {
- bases[i].noauto = 1;
- break;
- }
- ++commandline_current;
- }
- return 1;
-}
-
-__setup("pas16=", pas16_setup);
-#endif
-
-/*
- * Function : int pas16_detect(struct scsi_host_template * tpnt)
- *
- * Purpose : detects and initializes PAS16 controllers
- * that were autoprobed, overridden on the LILO command line,
- * or specified at compile time.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
- */
-
-static int __init pas16_detect(struct scsi_host_template *tpnt)
-{
- static int current_override;
- static unsigned short current_base;
- struct Scsi_Host *instance;
- unsigned short io_port;
- int count;
-
- if (pas16_addr != 0) {
- overrides[0].io_port = pas16_addr;
- /*
- * This is how we avoid seeing more than
- * one host adapter at the same I/O port.
- * Cribbed shamelessly from pas16_setup().
- */
- for (count = 0; count < NO_BASES; ++count)
- if (bases[count].io_port == pas16_addr) {
- bases[count].noauto = 1;
- break;
- }
- }
- if (pas16_irq != 0)
- overrides[0].irq = pas16_irq;
-
- for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
- io_port = 0;
-
- if (overrides[current_override].io_port)
- {
- io_port = overrides[current_override].io_port;
- enable_board( current_override, io_port );
- init_board( io_port, overrides[current_override].irq, 1 );
- }
- else
- for (; !io_port && (current_base < NO_BASES); ++current_base) {
- dprintk(NDEBUG_INIT, "pas16: probing io_port 0x%04x\n",
- (unsigned int)bases[current_base].io_port);
- if ( !bases[current_base].noauto &&
- pas16_hw_detect( current_base ) ){
- io_port = bases[current_base].io_port;
- init_board( io_port, default_irqs[ current_base ], 0 );
- dprintk(NDEBUG_INIT, "pas16: detected board\n");
- }
- }
-
- dprintk(NDEBUG_INIT, "pas16: io_port = 0x%04x\n",
- (unsigned int)io_port);
-
- if (!io_port)
- break;
-
- instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
- if(instance == NULL)
- goto out;
-
- instance->io_port = io_port;
-
- if (NCR5380_init(instance, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP))
- goto out_unregister;
-
- NCR5380_maybe_reset_bus(instance);
-
- if (overrides[current_override].irq != IRQ_AUTO)
- instance->irq = overrides[current_override].irq;
- else
- instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
-
- /* Compatibility with documented NCR5380 kernel parameters */
- if (instance->irq == 255)
- instance->irq = NO_IRQ;
-
- if (instance->irq != NO_IRQ)
- if (request_irq(instance->irq, pas16_intr, 0,
- "pas16", instance)) {
- printk("scsi%d : IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = NO_IRQ;
- }
-
- if (instance->irq == NO_IRQ) {
- printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
- printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
- /* Disable 5380 interrupts, leave drive params the same */
- outb( 0x4d, io_port + SYS_CONFIG_4 );
- outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
- }
-
- dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
- instance->host_no, instance->irq);
-
- ++current_override;
- ++count;
- }
- return count;
-
-out_unregister:
- scsi_unregister(instance);
-out:
- return count;
-}
-
-/*
- * Function : int pas16_biosparam(Disk *disk, struct block_device *dev, int *ip)
- *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
- * the specified device / size.
- *
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- * major / minor, ip[] = {heads, sectors, cylinders}
- *
- * Returns : always 0 (success), initializes ip
- *
- */
-
-/*
- * XXX Most SCSI boards use this mapping, I could be incorrect. Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
- */
-
-static int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev,
- sector_t capacity, int *ip)
-{
- int size = capacity;
- ip[0] = 64;
- ip[1] = 32;
- ip[2] = size >> 11; /* I think I have it as /(32*64) */
- if( ip[2] > 1024 ) { /* yes, >, not >= */
- ip[0]=255;
- ip[1]=63;
- ip[2]=size/(63*255);
- if( ip[2] > 1023 ) /* yes >1023... */
- ip[2] = 1023;
- }
-
- return 0;
-}
-
-/*
- * Function : int pas16_pread (struct Scsi_Host *instance,
- * unsigned char *dst, int len)
- *
- * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to
- * dst
- *
- * Inputs : dst = destination, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog
- * timeout.
- */
-
-static inline int pas16_pread(struct Scsi_Host *instance,
- unsigned char *dst, int len)
-{
- register unsigned char *d = dst;
- register unsigned short reg = (unsigned short) (instance->io_port +
- P_DATA_REG_OFFSET);
- register int i = len;
- int ii = 0;
-
- while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
- ++ii;
-
- insb( reg, d, i );
-
- if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
- outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
- printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
- instance->host_no);
- return -1;
- }
- return 0;
-}
-
-/*
- * Function : int pas16_pwrite (struct Scsi_Host *instance,
- * unsigned char *src, int len)
- *
- * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
- * src
- *
- * Inputs : src = source, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog
- * timeout.
- */
-
-static inline int pas16_pwrite(struct Scsi_Host *instance,
- unsigned char *src, int len)
-{
- register unsigned char *s = src;
- register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
- register int i = len;
- int ii = 0;
-
- while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
- ++ii;
-
- outsb( reg, s, i );
-
- if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
- outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
- printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
- instance->host_no);
- return -1;
- }
- return 0;
-}
-
-#include "NCR5380.c"
-
-static int pas16_release(struct Scsi_Host *shost)
-{
- if (shost->irq != NO_IRQ)
- free_irq(shost->irq, shost);
- NCR5380_exit(shost);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "Pro Audio Spectrum-16 SCSI",
- .detect = pas16_detect,
- .release = pas16_release,
- .proc_name = "pas16",
- .info = pas16_info,
- .queuecommand = pas16_queue_command,
- .eh_abort_handler = pas16_abort,
- .eh_bus_reset_handler = pas16_bus_reset,
- .bios_param = pas16_biosparam,
- .can_queue = 32,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING,
- .cmd_size = NCR5380_CMD_SIZE,
- .max_sectors = 128,
-};
-#include "scsi_module.c"
-
-#ifdef MODULE
-module_param(pas16_addr, ushort, 0);
-module_param(pas16_irq, int, 0);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
deleted file mode 100644
index 9fe7f33660b4..000000000000
--- a/drivers/scsi/pas16.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * This driver adapted from Drew Eckhardt's Trantor T128 driver
- *
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
- *
- * ( Based on T128 - DISTRIBUTION RELEASE 3. )
- *
- * Modified to work with the Pro Audio Spectrum/Studio 16
- * by John Weidman.
- *
- *
- * For more information, please consult
- *
- * Media Vision
- * (510) 770-8600
- * (800) 348-7116
- */
-
-
-#ifndef PAS16_H
-#define PAS16_H
-
-#define PAS16_DEFAULT_BASE_1 0x388
-#define PAS16_DEFAULT_BASE_2 0x384
-#define PAS16_DEFAULT_BASE_3 0x38c
-#define PAS16_DEFAULT_BASE_4 0x288
-
-#define PAS16_DEFAULT_BOARD_1_IRQ 10
-#define PAS16_DEFAULT_BOARD_2_IRQ 12
-#define PAS16_DEFAULT_BOARD_3_IRQ 14
-#define PAS16_DEFAULT_BOARD_4_IRQ 15
-
-
-/*
- * The Pro Audio Spectrum boards are I/O mapped. They use a Zilog 5380
- * SCSI controller, which is the equivalent of NCR's 5380. "Pseudo-DMA"
- * architecture is used, where a PAL drives the DMA signals on the 5380
- * allowing fast, blind transfers with proper handshaking.
- */
-
-
-/* The Time-out Counter register is used to safe-guard against a stuck
- * bus (in the case of RDY driven handshake) or a stuck byte (if 16-Bit
- * DMA conversion is used). The counter uses a 28.224MHz clock
- * divided by 14 as its clock source. In the case of a stuck byte in
- * the holding register, an interrupt is generated (and mixed with the
- * one with the drive) using the CD-ROM interrupt pointer.
- */
-
-#define P_TIMEOUT_COUNTER_REG 0x4000
-#define P_TC_DISABLE 0x80 /* Set to 0 to enable timeout int. */
- /* Bits D6-D0 contain timeout count */
-
-
-#define P_TIMEOUT_STATUS_REG_OFFSET 0x4001
-#define P_TS_TIM 0x80 /* check timeout status */
- /* Bits D6-D4 N/U */
-#define P_TS_ARM_DRQ_INT 0x08 /* Arm DRQ Int. When set high,
- * the next rising edge will
- * cause a CD-ROM interrupt.
- * When set low, the interrupt
- * will be cleared. There is
- * no status available for
- * this interrupt.
- */
-#define P_TS_ENABLE_TO_ERR_INTERRUPT /* Enable timeout error int. */
-#define P_TS_ENABLE_WAIT /* Enable Wait */
-
-#define P_TS_CT 0x01 /* clear timeout. Note: writing
- * to this register clears the
- * timeout error int. or status
- */
-
-
-/*
- * The data register reads/writes to/from the 5380 in pseudo-DMA mode
- */
-
-#define P_DATA_REG_OFFSET 0x5c00 /* rw */
-
-#define P_STATUS_REG_OFFSET 0x5c01 /* ro */
-#define P_ST_RDY 0x80 /* 5380 DDRQ Status */
-
-#define P_IRQ_STATUS 0x5c03
-#define P_IS_IRQ 0x80 /* DIRQ status */
-
-#define PCB_CONFIG 0x803
-#define MASTER_ADDRESS_PTR 0x9a01 /* Fixed position - no relo */
-#define SYS_CONFIG_4 0x8003
-#define WAIT_STATE 0xbc00
-#define OPERATION_MODE_1 0xec03
-#define IO_CONFIG_3 0xf002
-
-#define NCR5380_implementation_fields /* none */
-
-#define PAS16_io_port(reg) (instance->io_port + pas16_offset[(reg)])
-
-#define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) )
-#define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) )
-
-#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
-#define NCR5380_dma_recv_setup pas16_pread
-#define NCR5380_dma_send_setup pas16_pwrite
-#define NCR5380_dma_residual(instance) (0)
-
-#define NCR5380_intr pas16_intr
-#define NCR5380_queue_command pas16_queue_command
-#define NCR5380_abort pas16_abort
-#define NCR5380_bus_reset pas16_bus_reset
-#define NCR5380_info pas16_info
-
-/* 15 14 12 10 7 5 3
- 1101 0100 1010 1000 */
-
-#define PAS16_IRQS 0xd4a8
-
-#endif /* PAS16_H */
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 04e67a190652..10546faac58c 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -4492,8 +4492,8 @@ pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
* @num: the inbound queue number
* @phy_id: the phy id which we wanted to start up.
*/
-int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
- u8 phy_id)
+static int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
+ u8 phy_id)
{
struct phy_stop_req payload;
struct inbound_queue_table *circularQ;
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index dc33dfa8f994..ce584c31d36e 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -527,7 +527,7 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
* pm8001_alloc_dev - find a empty pm8001_device
* @pm8001_ha: our hba card information
*/
-struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha)
+static struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha)
{
u32 dev;
for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) {
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index b2a88200fe54..68a5c347fae9 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -306,7 +306,7 @@ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth)
* Return Value
* None
*/
-void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
+static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
{
struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb);
dma_addr_t dma_addr = cmd->ioa_cb_bus_addr;
@@ -401,7 +401,7 @@ static struct pmcraid_cmd *pmcraid_get_free_cmd(
* Return Value:
* nothing
*/
-void pmcraid_return_cmd(struct pmcraid_cmd *cmd)
+static void pmcraid_return_cmd(struct pmcraid_cmd *cmd)
{
struct pmcraid_instance *pinstance = cmd->drv_inst;
unsigned long lock_flags;
@@ -1710,7 +1710,7 @@ static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc)
* @ioasc: ioasc code
* @cmd: pointer to command that resulted in 'ioasc'
*/
-void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd)
+static void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd)
{
struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc);
@@ -3137,7 +3137,7 @@ static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd)
* returns pointer pmcraid_ioadl_desc, initialized to point to internal
* or external IOADLs
*/
-struct pmcraid_ioadl_desc *
+static struct pmcraid_ioadl_desc *
pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount)
{
struct pmcraid_ioadl_desc *ioadl;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index ae4a74756128..73b12e41d992 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -279,16 +279,6 @@ struct req_que;
struct qla_tgt_sess;
/*
- * (sd.h is not exported, hence local inclusion)
- * Data Integrity Field tuple.
- */
-struct sd_dif_tuple {
- __be16 guard_tag; /* Checksum */
- __be16 app_tag; /* Opaque storage */
- __be32 ref_tag; /* Target LBA or indirect LBA */
-};
-
-/*
* SCSI Request Block
*/
struct srb_cmd {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 987f1c729e9c..068c4e47fac9 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1828,7 +1828,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
if (scsi_prot_sg_count(cmd)) {
uint32_t i, j = 0, k = 0, num_ent;
struct scatterlist *sg;
- struct sd_dif_tuple *spt;
+ struct t10_pi_tuple *spt;
/* Patch the corresponding protection tags */
scsi_for_each_prot_sg(cmd, sg,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2674f4c16bc3..ace65db1d2a2 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -899,12 +899,12 @@ qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- while (((qla2x00_reset_active(vha)) || ha->dpc_active ||
- ha->flags.mbox_busy) ||
- test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
- test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) {
- if (test_bit(UNLOADING, &base_vha->dpc_flags))
- break;
+ while ((qla2x00_reset_active(vha) || ha->dpc_active ||
+ ha->flags.mbox_busy) ||
+ test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
+ test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) {
+ if (test_bit(UNLOADING, &base_vha->dpc_flags))
+ break;
msleep(1000);
}
}
@@ -4694,7 +4694,7 @@ retry_unlock:
qla83xx_wait_logic();
retry++;
ql_dbg(ql_dbg_p3p, base_vha, 0xb064,
- "Failed to release IDC lock, retyring=%d\n", retry);
+ "Failed to release IDC lock, retrying=%d\n", retry);
goto retry_unlock;
}
} else if (retry < 10) {
@@ -4702,7 +4702,7 @@ retry_unlock:
qla83xx_wait_logic();
retry++;
ql_dbg(ql_dbg_p3p, base_vha, 0xb065,
- "Failed to read drv-lockid, retyring=%d\n", retry);
+ "Failed to read drv-lockid, retrying=%d\n", retry);
goto retry_unlock;
}
@@ -4718,7 +4718,7 @@ retry_unlock2:
qla83xx_wait_logic();
retry++;
ql_dbg(ql_dbg_p3p, base_vha, 0xb066,
- "Failed to release IDC lock, retyring=%d\n", retry);
+ "Failed to release IDC lock, retrying=%d\n", retry);
goto retry_unlock2;
}
}
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index ae87d6c19f17..06ddd13cb7cc 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -1843,7 +1843,7 @@ static uint32_t ql4_84xx_poll_wait_for_ready(struct scsi_qla_host *ha,
return rval;
}
-uint32_t ql4_84xx_ipmdio_rd_reg(struct scsi_qla_host *ha, uint32_t addr1,
+static uint32_t ql4_84xx_ipmdio_rd_reg(struct scsi_qla_host *ha, uint32_t addr1,
uint32_t addr3, uint32_t mask, uint32_t addr,
uint32_t *data_ptr)
{
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 6a219a0844d3..c905709707f0 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -42,6 +42,7 @@
#include <linux/atomic.h>
#include <linux/hrtimer.h>
#include <linux/uuid.h>
+#include <linux/t10-pi.h>
#include <net/checksum.h>
@@ -627,7 +628,7 @@ static LIST_HEAD(sdebug_host_list);
static DEFINE_SPINLOCK(sdebug_host_list_lock);
static unsigned char *fake_storep; /* ramdisk storage */
-static struct sd_dif_tuple *dif_storep; /* protection info */
+static struct t10_pi_tuple *dif_storep; /* protection info */
static void *map_storep; /* provisioning map */
static unsigned long map_size;
@@ -682,7 +683,7 @@ static void *fake_store(unsigned long long lba)
return fake_storep + lba * sdebug_sector_size;
}
-static struct sd_dif_tuple *dif_store(sector_t sector)
+static struct t10_pi_tuple *dif_store(sector_t sector)
{
sector = sector_div(sector, sdebug_store_sectors);
@@ -1349,7 +1350,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
} else if (0x86 == cmd[2]) { /* extended inquiry */
arr[1] = cmd[2]; /*sanity */
arr[3] = 0x3c; /* number of following entries */
- if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
+ if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
arr[4] = 0x4; /* SPT: GRD_CHK:1 */
else if (have_dif_prot)
arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
@@ -2430,7 +2431,7 @@ static __be16 dif_compute_csum(const void *buf, int len)
return csum;
}
-static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
+static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
sector_t sector, u32 ei_lba)
{
__be16 csum = dif_compute_csum(data, sdebug_sector_size);
@@ -2442,13 +2443,13 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
be16_to_cpu(csum));
return 0x01;
}
- if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
+ if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
pr_err("REF check failed on sector %lu\n",
(unsigned long)sector);
return 0x03;
}
- if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
+ if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
be32_to_cpu(sdt->ref_tag) != ei_lba) {
pr_err("REF check failed on sector %lu\n",
(unsigned long)sector);
@@ -2504,7 +2505,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
unsigned int sectors, u32 ei_lba)
{
unsigned int i;
- struct sd_dif_tuple *sdt;
+ struct t10_pi_tuple *sdt;
sector_t sector;
for (i = 0; i < sectors; i++, ei_lba++) {
@@ -2580,13 +2581,13 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
break;
}
if (unlikely(have_dif_prot && check_prot)) {
- if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
+ if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
(cmd[1] & 0xe0)) {
mk_sense_invalid_opcode(scp);
return check_condition_result;
}
- if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
- sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
+ sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
(cmd[1] & 0xe0) == 0)
sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
"to DIF device\n");
@@ -2696,7 +2697,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
unsigned int sectors, u32 ei_lba)
{
int ret;
- struct sd_dif_tuple *sdt;
+ struct t10_pi_tuple *sdt;
void *daddr;
sector_t sector = start_sec;
int ppage_offset;
@@ -2722,7 +2723,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
}
for (ppage_offset = 0; ppage_offset < piter.length;
- ppage_offset += sizeof(struct sd_dif_tuple)) {
+ ppage_offset += sizeof(struct t10_pi_tuple)) {
/* If we're at the end of the current
* data page advance to the next one
*/
@@ -2893,13 +2894,13 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
break;
}
if (unlikely(have_dif_prot && check_prot)) {
- if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
+ if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
(cmd[1] & 0xe0)) {
mk_sense_invalid_opcode(scp);
return check_condition_result;
}
- if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
- sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
+ sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
(cmd[1] & 0xe0) == 0)
sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
"to DIF device\n");
@@ -3135,13 +3136,13 @@ static int resp_comp_write(struct scsi_cmnd *scp,
num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
if (0 == num)
return 0; /* degenerate case, not an error */
- if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
+ if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
(cmd[1] & 0xe0)) {
mk_sense_invalid_opcode(scp);
return check_condition_result;
}
- if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
- sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
+ sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
(cmd[1] & 0xe0) == 0)
sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
"to DIF device\n");
@@ -4939,12 +4940,11 @@ static int __init scsi_debug_init(void)
}
switch (sdebug_dif) {
-
- case SD_DIF_TYPE0_PROTECTION:
+ case T10_PI_TYPE0_PROTECTION:
break;
- case SD_DIF_TYPE1_PROTECTION:
- case SD_DIF_TYPE2_PROTECTION:
- case SD_DIF_TYPE3_PROTECTION:
+ case T10_PI_TYPE1_PROTECTION:
+ case T10_PI_TYPE2_PROTECTION:
+ case T10_PI_TYPE3_PROTECTION:
have_dif_prot = true;
break;
@@ -5026,7 +5026,7 @@ static int __init scsi_debug_init(void)
if (sdebug_dix) {
int dif_size;
- dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
+ dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
dif_storep = vmalloc(dif_size);
pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
@@ -5480,19 +5480,19 @@ static int sdebug_driver_probe(struct device * dev)
switch (sdebug_dif) {
- case SD_DIF_TYPE1_PROTECTION:
+ case T10_PI_TYPE1_PROTECTION:
hprot = SHOST_DIF_TYPE1_PROTECTION;
if (sdebug_dix)
hprot |= SHOST_DIX_TYPE1_PROTECTION;
break;
- case SD_DIF_TYPE2_PROTECTION:
+ case T10_PI_TYPE2_PROTECTION:
hprot = SHOST_DIF_TYPE2_PROTECTION;
if (sdebug_dix)
hprot |= SHOST_DIX_TYPE2_PROTECTION;
break;
- case SD_DIF_TYPE3_PROTECTION:
+ case T10_PI_TYPE3_PROTECTION:
hprot = SHOST_DIF_TYPE3_PROTECTION;
if (sdebug_dix)
hprot |= SHOST_DIX_TYPE3_PROTECTION;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index c71344aebdbb..2cca9cffc63f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2077,7 +2077,6 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
}
static struct blk_mq_ops scsi_mq_ops = {
- .map_queue = blk_mq_map_queue,
.queue_rq = scsi_queue_rq,
.complete = scsi_softirq_done,
.timeout = scsi_timeout,
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 85c8a51bc563..193636a59adf 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -86,12 +86,14 @@ extern void scsi_device_unbusy(struct scsi_device *sdev);
extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
+extern void scsi_requeue_run_queue(struct work_struct *work);
extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
extern struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev);
extern int scsi_mq_setup_tags(struct Scsi_Host *shost);
extern void scsi_mq_destroy_tags(struct Scsi_Host *shost);
extern int scsi_init_queue(void);
extern void scsi_exit_queue(void);
+extern void scsi_evt_thread(struct work_struct *work);
struct request_queue;
struct request;
extern struct kmem_cache *scsi_sdb_cache;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index e0a78f53d809..212e98d940bc 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -217,8 +217,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
struct scsi_device *sdev;
int display_failure_msg = 1, ret;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- extern void scsi_evt_thread(struct work_struct *work);
- extern void scsi_requeue_run_queue(struct work_struct *work);
sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
GFP_ATOMIC);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d3e852ad5aa3..51e56296f465 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -52,6 +52,7 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/pr.h>
+#include <linux/t10-pi.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
@@ -314,7 +315,7 @@ protection_type_store(struct device *dev, struct device_attribute *attr,
if (err)
return err;
- if (val >= 0 && val <= SD_DIF_TYPE3_PROTECTION)
+ if (val >= 0 && val <= T10_PI_TYPE3_PROTECTION)
sdkp->protection_type = val;
return count;
@@ -332,7 +333,7 @@ protection_mode_show(struct device *dev, struct device_attribute *attr,
dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
dix = scsi_host_dix_capable(sdp->host, sdkp->protection_type);
- if (!dix && scsi_host_dix_capable(sdp->host, SD_DIF_TYPE0_PROTECTION)) {
+ if (!dix && scsi_host_dix_capable(sdp->host, T10_PI_TYPE0_PROTECTION)) {
dif = 0;
dix = 1;
}
@@ -608,7 +609,7 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
scmd->prot_flags |= SCSI_PROT_GUARD_CHECK;
}
- if (dif != SD_DIF_TYPE3_PROTECTION) { /* DIX/DIF Type 0, 1, 2 */
+ if (dif != T10_PI_TYPE3_PROTECTION) { /* DIX/DIF Type 0, 1, 2 */
scmd->prot_flags |= SCSI_PROT_REF_INCREMENT;
if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
@@ -1031,7 +1032,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
else
protect = 0;
- if (protect && sdkp->protection_type == SD_DIF_TYPE2_PROTECTION) {
+ if (protect && sdkp->protection_type == T10_PI_TYPE2_PROTECTION) {
SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);
if (unlikely(SCpnt->cmnd == NULL)) {
@@ -1997,7 +1998,7 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer
type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
- if (type > SD_DIF_TYPE3_PROTECTION)
+ if (type > T10_PI_TYPE3_PROTECTION)
ret = -ENODEV;
else if (scsi_host_dif_capable(sdp->host, type))
ret = 1;
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 765a6f1ac1b7..c8d986368da9 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -157,27 +157,6 @@ static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t b
}
/*
- * A DIF-capable target device can be formatted with different
- * protection schemes. Currently 0 through 3 are defined:
- *
- * Type 0 is regular (unprotected) I/O
- *
- * Type 1 defines the contents of the guard and reference tags
- *
- * Type 2 defines the contents of the guard and reference tags and
- * uses 32-byte commands to seed the latter
- *
- * Type 3 defines the contents of the guard tag only
- */
-
-enum sd_dif_target_protection_types {
- SD_DIF_TYPE0_PROTECTION = 0x0,
- SD_DIF_TYPE1_PROTECTION = 0x1,
- SD_DIF_TYPE2_PROTECTION = 0x2,
- SD_DIF_TYPE3_PROTECTION = 0x3,
-};
-
-/*
* Look up the DIX operation based on whether the command is read or
* write and whether dix and dif are enabled.
*/
@@ -239,15 +218,6 @@ static inline unsigned int sd_prot_flag_mask(unsigned int prot_op)
return flag_mask[prot_op];
}
-/*
- * Data Integrity Field tuple.
- */
-struct sd_dif_tuple {
- __be16 guard_tag; /* Checksum */
- __be16 app_tag; /* Opaque storage */
- __be32 ref_tag; /* Target LBA or indirect LBA */
-};
-
#ifdef CONFIG_BLK_DEV_INTEGRITY
extern void sd_dif_config_host(struct scsi_disk *);
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 987bf392c336..9035380c0dda 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -60,14 +60,14 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
/* Enable DMA of protection information */
if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) {
- if (type == SD_DIF_TYPE3_PROTECTION)
+ if (type == T10_PI_TYPE3_PROTECTION)
bi.profile = &t10_pi_type3_ip;
else
bi.profile = &t10_pi_type1_ip;
bi.flags |= BLK_INTEGRITY_IP_CHECKSUM;
} else
- if (type == SD_DIF_TYPE3_PROTECTION)
+ if (type == T10_PI_TYPE3_PROTECTION)
bi.profile = &t10_pi_type3_crc;
else
bi.profile = &t10_pi_type1_crc;
@@ -82,7 +82,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
if (!sdkp->ATO)
goto out;
- if (type == SD_DIF_TYPE3_PROTECTION)
+ if (type == T10_PI_TYPE3_PROTECTION)
bi.tag_size = sizeof(u16) + sizeof(u32);
else
bi.tag_size = sizeof(u16);
@@ -121,7 +121,7 @@ void sd_dif_prepare(struct scsi_cmnd *scmd)
sdkp = scsi_disk(scmd->request->rq_disk);
- if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION)
+ if (sdkp->protection_type == T10_PI_TYPE3_PROTECTION)
return;
phys = scsi_prot_ref_tag(scmd);
@@ -172,7 +172,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
sdkp = scsi_disk(scmd->request->rq_disk);
- if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0)
+ if (sdkp->protection_type == T10_PI_TYPE3_PROTECTION || good_bytes == 0)
return;
intervals = good_bytes / scsi_prot_interval(scmd);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ae7d9bdf409c..070332eb41f3 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -79,18 +79,7 @@ static void sg_proc_cleanup(void);
*/
#define SG_MAX_CDB_SIZE 252
-/*
- * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d)
- * Then when using 32 bit integers x * m may overflow during the calculation.
- * Replacing muldiv(x) by muldiv(x)=((x % d) * m) / d + int(x / d) * m
- * calculates the same, but prevents the overflow when both m and d
- * are "small" numbers (like HZ and USER_HZ).
- * Of course an overflow is inavoidable if the result of muldiv doesn't fit
- * in 32 bits.
- */
-#define MULDIV(X,MUL,DIV) ((((X % DIV) * MUL) / DIV) + ((X / DIV) * MUL))
-
-#define SG_DEFAULT_TIMEOUT MULDIV(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
+#define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
int sg_big_buff = SG_DEF_RESERVED_SIZE;
/* N.B. This variable is readable and writeable via
@@ -884,10 +873,11 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
return result;
if (val < 0)
return -EIO;
- if (val >= MULDIV (INT_MAX, USER_HZ, HZ))
- val = MULDIV (INT_MAX, USER_HZ, HZ);
+ if (val >= mult_frac((s64)INT_MAX, USER_HZ, HZ))
+ val = min_t(s64, mult_frac((s64)INT_MAX, USER_HZ, HZ),
+ INT_MAX);
sfp->timeout_user = val;
- sfp->timeout = MULDIV (val, HZ, USER_HZ);
+ sfp->timeout = mult_frac(val, HZ, USER_HZ);
return 0;
case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */
diff --git a/drivers/scsi/smartpqi/Kconfig b/drivers/scsi/smartpqi/Kconfig
new file mode 100644
index 000000000000..97e159c2cecd
--- /dev/null
+++ b/drivers/scsi/smartpqi/Kconfig
@@ -0,0 +1,54 @@
+#
+# Kernel configuration file for the SMARTPQI
+#
+# Copyright (c) 2016 Microsemi Corporation
+# Copyright (c) 2016 PMC-Sierra, Inc.
+# (mailto:esc.storagedev@microsemi.com)
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# NO WARRANTY
+# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+# solely responsible for determining the appropriateness of using and
+# distributing the Program and assumes all risks associated with its
+# exercise of rights under this Agreement, including but not limited to
+# the risks and costs of program errors, damage to or loss of data,
+# programs or equipment, and unavailability or interruption of operations.
+
+# DISCLAIMER OF LIABILITY
+# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+config SCSI_SMARTPQI
+ tristate "Microsemi PQI Driver"
+ depends on PCI && SCSI && !S390
+ select SCSI_SAS_ATTRS
+ select RAID_ATTRS
+ ---help---
+ This driver supports Microsemi PQI controllers.
+
+ <http://www.microsemi.com>
+
+ To compile this driver as a module, choose M here: the
+ module will be called smartpqi.
+
+ Note: the aacraid driver will not manage a smartpqi
+ controller. You need to enable smartpqi for smartpqi
+ controllers. For more information, please see
+ Documentation/scsi/smartpqi.txt
diff --git a/drivers/scsi/smartpqi/Makefile b/drivers/scsi/smartpqi/Makefile
new file mode 100644
index 000000000000..0f42a225a664
--- /dev/null
+++ b/drivers/scsi/smartpqi/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -I.
+obj-m += smartpqi.o
+smartpqi-objs := smartpqi_init.o smartpqi_sis.o smartpqi_sas_transport.o
diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
new file mode 100644
index 000000000000..07b6444d3e0a
--- /dev/null
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -0,0 +1,1136 @@
+/*
+ * driver for Microsemi PQI-based storage controllers
+ * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016 PMC-Sierra, 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; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ *
+ */
+
+#if !defined(_SMARTPQI_H)
+#define _SMARTPQI_H
+
+#pragma pack(1)
+
+#define PQI_DEVICE_SIGNATURE "PQI DREG"
+
+/* This structure is defined by the PQI specification. */
+struct pqi_device_registers {
+ __le64 signature;
+ u8 function_and_status_code;
+ u8 reserved[7];
+ u8 max_admin_iq_elements;
+ u8 max_admin_oq_elements;
+ u8 admin_iq_element_length; /* in 16-byte units */
+ u8 admin_oq_element_length; /* in 16-byte units */
+ __le16 max_reset_timeout; /* in 100-millisecond units */
+ u8 reserved1[2];
+ __le32 legacy_intx_status;
+ __le32 legacy_intx_mask_set;
+ __le32 legacy_intx_mask_clear;
+ u8 reserved2[28];
+ __le32 device_status;
+ u8 reserved3[4];
+ __le64 admin_iq_pi_offset;
+ __le64 admin_oq_ci_offset;
+ __le64 admin_iq_element_array_addr;
+ __le64 admin_oq_element_array_addr;
+ __le64 admin_iq_ci_addr;
+ __le64 admin_oq_pi_addr;
+ u8 admin_iq_num_elements;
+ u8 admin_oq_num_elements;
+ __le16 admin_queue_int_msg_num;
+ u8 reserved4[4];
+ __le32 device_error;
+ u8 reserved5[4];
+ __le64 error_details;
+ __le32 device_reset;
+ __le32 power_action;
+ u8 reserved6[104];
+};
+
+/*
+ * controller registers
+ *
+ * These are defined by the PMC implementation.
+ *
+ * Some registers (those named sis_*) are only used when in
+ * legacy SIS mode before we transition the controller into
+ * PQI mode. There are a number of other SIS mode registers,
+ * but we don't use them, so only the SIS registers that we
+ * care about are defined here. The offsets mentioned in the
+ * comments are the offsets from the PCIe BAR 0.
+ */
+struct pqi_ctrl_registers {
+ u8 reserved[0x20];
+ __le32 sis_host_to_ctrl_doorbell; /* 20h */
+ u8 reserved1[0x34 - (0x20 + sizeof(__le32))];
+ __le32 sis_interrupt_mask; /* 34h */
+ u8 reserved2[0x9c - (0x34 + sizeof(__le32))];
+ __le32 sis_ctrl_to_host_doorbell; /* 9Ch */
+ u8 reserved3[0xa0 - (0x9c + sizeof(__le32))];
+ __le32 sis_ctrl_to_host_doorbell_clear; /* A0h */
+ u8 reserved4[0xb0 - (0xa0 + sizeof(__le32))];
+ __le32 sis_driver_scratch; /* B0h */
+ u8 reserved5[0xbc - (0xb0 + sizeof(__le32))];
+ __le32 sis_firmware_status; /* BCh */
+ u8 reserved6[0x1000 - (0xbc + sizeof(__le32))];
+ __le32 sis_mailbox[8]; /* 1000h */
+ u8 reserved7[0x4000 - (0x1000 + (sizeof(__le32) * 8))];
+ /*
+ * The PQI spec states that the PQI registers should be at
+ * offset 0 from the PCIe BAR 0. However, we can't map
+ * them at offset 0 because that would break compatibility
+ * with the SIS registers. So we map them at offset 4000h.
+ */
+ struct pqi_device_registers pqi_registers; /* 4000h */
+};
+
+#define PQI_DEVICE_REGISTERS_OFFSET 0x4000
+
+enum pqi_io_path {
+ RAID_PATH = 0,
+ AIO_PATH = 1
+};
+
+struct pqi_sg_descriptor {
+ __le64 address;
+ __le32 length;
+ __le32 flags;
+};
+
+/* manifest constants for the flags field of pqi_sg_descriptor */
+#define CISS_SG_LAST 0x40000000
+#define CISS_SG_CHAIN 0x80000000
+
+struct pqi_iu_header {
+ u8 iu_type;
+ u8 reserved;
+ __le16 iu_length; /* in bytes - does not include the length */
+ /* of this header */
+ __le16 response_queue_id; /* specifies the OQ where the */
+ /* response IU is to be delivered */
+ u8 work_area[2]; /* reserved for driver use */
+};
+
+/*
+ * According to the PQI spec, the IU header is only the first 4 bytes of our
+ * pqi_iu_header structure.
+ */
+#define PQI_REQUEST_HEADER_LENGTH 4
+
+struct pqi_general_admin_request {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ u8 function_code;
+ union {
+ struct {
+ u8 reserved[33];
+ __le32 buffer_length;
+ struct pqi_sg_descriptor sg_descriptor;
+ } report_device_capability;
+
+ struct {
+ u8 reserved;
+ __le16 queue_id;
+ u8 reserved1[2];
+ __le64 element_array_addr;
+ __le64 ci_addr;
+ __le16 num_elements;
+ __le16 element_length;
+ u8 queue_protocol;
+ u8 reserved2[23];
+ __le32 vendor_specific;
+ } create_operational_iq;
+
+ struct {
+ u8 reserved;
+ __le16 queue_id;
+ u8 reserved1[2];
+ __le64 element_array_addr;
+ __le64 pi_addr;
+ __le16 num_elements;
+ __le16 element_length;
+ u8 queue_protocol;
+ u8 reserved2[3];
+ __le16 int_msg_num;
+ __le16 coalescing_count;
+ __le32 min_coalescing_time;
+ __le32 max_coalescing_time;
+ u8 reserved3[8];
+ __le32 vendor_specific;
+ } create_operational_oq;
+
+ struct {
+ u8 reserved;
+ __le16 queue_id;
+ u8 reserved1[50];
+ } delete_operational_queue;
+
+ struct {
+ u8 reserved;
+ __le16 queue_id;
+ u8 reserved1[46];
+ __le32 vendor_specific;
+ } change_operational_iq_properties;
+
+ } data;
+};
+
+struct pqi_general_admin_response {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ u8 function_code;
+ u8 status;
+ union {
+ struct {
+ u8 status_descriptor[4];
+ __le64 iq_pi_offset;
+ u8 reserved[40];
+ } create_operational_iq;
+
+ struct {
+ u8 status_descriptor[4];
+ __le64 oq_ci_offset;
+ u8 reserved[40];
+ } create_operational_oq;
+ } data;
+};
+
+struct pqi_iu_layer_descriptor {
+ u8 inbound_spanning_supported : 1;
+ u8 reserved : 7;
+ u8 reserved1[5];
+ __le16 max_inbound_iu_length;
+ u8 outbound_spanning_supported : 1;
+ u8 reserved2 : 7;
+ u8 reserved3[5];
+ __le16 max_outbound_iu_length;
+};
+
+struct pqi_device_capability {
+ __le16 data_length;
+ u8 reserved[6];
+ u8 iq_arbitration_priority_support_bitmask;
+ u8 maximum_aw_a;
+ u8 maximum_aw_b;
+ u8 maximum_aw_c;
+ u8 max_arbitration_burst : 3;
+ u8 reserved1 : 4;
+ u8 iqa : 1;
+ u8 reserved2[2];
+ u8 iq_freeze : 1;
+ u8 reserved3 : 7;
+ __le16 max_inbound_queues;
+ __le16 max_elements_per_iq;
+ u8 reserved4[4];
+ __le16 max_iq_element_length;
+ __le16 min_iq_element_length;
+ u8 reserved5[2];
+ __le16 max_outbound_queues;
+ __le16 max_elements_per_oq;
+ __le16 intr_coalescing_time_granularity;
+ __le16 max_oq_element_length;
+ __le16 min_oq_element_length;
+ u8 reserved6[24];
+ struct pqi_iu_layer_descriptor iu_layer_descriptors[32];
+};
+
+#define PQI_MAX_EMBEDDED_SG_DESCRIPTORS 4
+
+struct pqi_raid_path_request {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ __le16 nexus_id;
+ __le32 buffer_length;
+ u8 lun_number[8];
+ __le16 protocol_specific;
+ u8 data_direction : 2;
+ u8 partial : 1;
+ u8 reserved1 : 4;
+ u8 fence : 1;
+ __le16 error_index;
+ u8 reserved2;
+ u8 task_attribute : 3;
+ u8 command_priority : 4;
+ u8 reserved3 : 1;
+ u8 reserved4 : 2;
+ u8 additional_cdb_bytes_usage : 3;
+ u8 reserved5 : 3;
+ u8 cdb[32];
+ struct pqi_sg_descriptor
+ sg_descriptors[PQI_MAX_EMBEDDED_SG_DESCRIPTORS];
+};
+
+struct pqi_aio_path_request {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ u8 reserved1[2];
+ __le32 nexus_id;
+ __le32 buffer_length;
+ u8 data_direction : 2;
+ u8 partial : 1;
+ u8 memory_type : 1;
+ u8 fence : 1;
+ u8 encryption_enable : 1;
+ u8 reserved2 : 2;
+ u8 task_attribute : 3;
+ u8 command_priority : 4;
+ u8 reserved3 : 1;
+ __le16 data_encryption_key_index;
+ __le32 encrypt_tweak_lower;
+ __le32 encrypt_tweak_upper;
+ u8 cdb[16];
+ __le16 error_index;
+ u8 num_sg_descriptors;
+ u8 cdb_length;
+ u8 lun_number[8];
+ u8 reserved4[4];
+ struct pqi_sg_descriptor
+ sg_descriptors[PQI_MAX_EMBEDDED_SG_DESCRIPTORS];
+};
+
+struct pqi_io_response {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ __le16 error_index;
+ u8 reserved2[4];
+};
+
+struct pqi_general_management_request {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ union {
+ struct {
+ u8 reserved[2];
+ __le32 buffer_length;
+ struct pqi_sg_descriptor sg_descriptors[3];
+ } report_event_configuration;
+
+ struct {
+ __le16 global_event_oq_id;
+ __le32 buffer_length;
+ struct pqi_sg_descriptor sg_descriptors[3];
+ } set_event_configuration;
+ } data;
+};
+
+struct pqi_event_descriptor {
+ u8 event_type;
+ u8 reserved;
+ __le16 oq_id;
+};
+
+struct pqi_event_config {
+ u8 reserved[2];
+ u8 num_event_descriptors;
+ u8 reserved1;
+ struct pqi_event_descriptor descriptors[1];
+};
+
+#define PQI_MAX_EVENT_DESCRIPTORS 255
+
+struct pqi_event_response {
+ struct pqi_iu_header header;
+ u8 event_type;
+ u8 reserved2 : 7;
+ u8 request_acknowlege : 1;
+ __le16 event_id;
+ __le32 additional_event_id;
+ u8 data[16];
+};
+
+struct pqi_event_acknowledge_request {
+ struct pqi_iu_header header;
+ u8 event_type;
+ u8 reserved2;
+ __le16 event_id;
+ __le32 additional_event_id;
+};
+
+struct pqi_task_management_request {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ __le16 nexus_id;
+ u8 reserved[4];
+ u8 lun_number[8];
+ __le16 protocol_specific;
+ __le16 outbound_queue_id_to_manage;
+ __le16 request_id_to_manage;
+ u8 task_management_function;
+ u8 reserved2 : 7;
+ u8 fence : 1;
+};
+
+#define SOP_TASK_MANAGEMENT_LUN_RESET 0x8
+
+struct pqi_task_management_response {
+ struct pqi_iu_header header;
+ __le16 request_id;
+ __le16 nexus_id;
+ u8 additional_response_info[3];
+ u8 response_code;
+};
+
+struct pqi_aio_error_info {
+ u8 status;
+ u8 service_response;
+ u8 data_present;
+ u8 reserved;
+ __le32 residual_count;
+ __le16 data_length;
+ __le16 reserved1;
+ u8 data[256];
+};
+
+struct pqi_raid_error_info {
+ u8 data_in_result;
+ u8 data_out_result;
+ u8 reserved[3];
+ u8 status;
+ __le16 status_qualifier;
+ __le16 sense_data_length;
+ __le16 response_data_length;
+ __le32 data_in_transferred;
+ __le32 data_out_transferred;
+ u8 data[256];
+};
+
+#define PQI_REQUEST_IU_TASK_MANAGEMENT 0x13
+#define PQI_REQUEST_IU_RAID_PATH_IO 0x14
+#define PQI_REQUEST_IU_AIO_PATH_IO 0x15
+#define PQI_REQUEST_IU_GENERAL_ADMIN 0x60
+#define PQI_REQUEST_IU_REPORT_VENDOR_EVENT_CONFIG 0x72
+#define PQI_REQUEST_IU_SET_VENDOR_EVENT_CONFIG 0x73
+#define PQI_REQUEST_IU_ACKNOWLEDGE_VENDOR_EVENT 0xf6
+
+#define PQI_RESPONSE_IU_GENERAL_MANAGEMENT 0x81
+#define PQI_RESPONSE_IU_TASK_MANAGEMENT 0x93
+#define PQI_RESPONSE_IU_GENERAL_ADMIN 0xe0
+#define PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS 0xf0
+#define PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS 0xf1
+#define PQI_RESPONSE_IU_RAID_PATH_IO_ERROR 0xf2
+#define PQI_RESPONSE_IU_AIO_PATH_IO_ERROR 0xf3
+#define PQI_RESPONSE_IU_AIO_PATH_DISABLED 0xf4
+#define PQI_RESPONSE_IU_VENDOR_EVENT 0xf5
+
+#define PQI_GENERAL_ADMIN_FUNCTION_REPORT_DEVICE_CAPABILITY 0x0
+#define PQI_GENERAL_ADMIN_FUNCTION_CREATE_IQ 0x10
+#define PQI_GENERAL_ADMIN_FUNCTION_CREATE_OQ 0x11
+#define PQI_GENERAL_ADMIN_FUNCTION_DELETE_IQ 0x12
+#define PQI_GENERAL_ADMIN_FUNCTION_DELETE_OQ 0x13
+#define PQI_GENERAL_ADMIN_FUNCTION_CHANGE_IQ_PROPERTY 0x14
+
+#define PQI_GENERAL_ADMIN_STATUS_SUCCESS 0x0
+
+#define PQI_IQ_PROPERTY_IS_AIO_QUEUE 0x1
+
+#define PQI_GENERAL_ADMIN_IU_LENGTH 0x3c
+#define PQI_PROTOCOL_SOP 0x0
+
+#define PQI_DATA_IN_OUT_GOOD 0x0
+#define PQI_DATA_IN_OUT_UNDERFLOW 0x1
+#define PQI_DATA_IN_OUT_BUFFER_ERROR 0x40
+#define PQI_DATA_IN_OUT_BUFFER_OVERFLOW 0x41
+#define PQI_DATA_IN_OUT_BUFFER_OVERFLOW_DESCRIPTOR_AREA 0x42
+#define PQI_DATA_IN_OUT_BUFFER_OVERFLOW_BRIDGE 0x43
+#define PQI_DATA_IN_OUT_PCIE_FABRIC_ERROR 0x60
+#define PQI_DATA_IN_OUT_PCIE_COMPLETION_TIMEOUT 0x61
+#define PQI_DATA_IN_OUT_PCIE_COMPLETER_ABORT_RECEIVED 0x62
+#define PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST_RECEIVED 0x63
+#define PQI_DATA_IN_OUT_PCIE_ECRC_CHECK_FAILED 0x64
+#define PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST 0x65
+#define PQI_DATA_IN_OUT_PCIE_ACS_VIOLATION 0x66
+#define PQI_DATA_IN_OUT_PCIE_TLP_PREFIX_BLOCKED 0x67
+#define PQI_DATA_IN_OUT_PCIE_POISONED_MEMORY_READ 0x6F
+#define PQI_DATA_IN_OUT_ERROR 0xf0
+#define PQI_DATA_IN_OUT_PROTOCOL_ERROR 0xf1
+#define PQI_DATA_IN_OUT_HARDWARE_ERROR 0xf2
+#define PQI_DATA_IN_OUT_UNSOLICITED_ABORT 0xf3
+#define PQI_DATA_IN_OUT_ABORTED 0xf4
+#define PQI_DATA_IN_OUT_TIMEOUT 0xf5
+
+#define CISS_CMD_STATUS_SUCCESS 0x0
+#define CISS_CMD_STATUS_TARGET_STATUS 0x1
+#define CISS_CMD_STATUS_DATA_UNDERRUN 0x2
+#define CISS_CMD_STATUS_DATA_OVERRUN 0x3
+#define CISS_CMD_STATUS_INVALID 0x4
+#define CISS_CMD_STATUS_PROTOCOL_ERROR 0x5
+#define CISS_CMD_STATUS_HARDWARE_ERROR 0x6
+#define CISS_CMD_STATUS_CONNECTION_LOST 0x7
+#define CISS_CMD_STATUS_ABORTED 0x8
+#define CISS_CMD_STATUS_ABORT_FAILED 0x9
+#define CISS_CMD_STATUS_UNSOLICITED_ABORT 0xa
+#define CISS_CMD_STATUS_TIMEOUT 0xb
+#define CISS_CMD_STATUS_UNABORTABLE 0xc
+#define CISS_CMD_STATUS_TMF 0xd
+#define CISS_CMD_STATUS_AIO_DISABLED 0xe
+
+#define PQI_NUM_EVENT_QUEUE_ELEMENTS 32
+#define PQI_EVENT_OQ_ELEMENT_LENGTH sizeof(struct pqi_event_response)
+
+#define PQI_EVENT_TYPE_HOTPLUG 0x1
+#define PQI_EVENT_TYPE_HARDWARE 0x2
+#define PQI_EVENT_TYPE_PHYSICAL_DEVICE 0x4
+#define PQI_EVENT_TYPE_LOGICAL_DEVICE 0x5
+#define PQI_EVENT_TYPE_AIO_STATE_CHANGE 0xfd
+#define PQI_EVENT_TYPE_AIO_CONFIG_CHANGE 0xfe
+#define PQI_EVENT_TYPE_HEARTBEAT 0xff
+
+#pragma pack()
+
+#define PQI_ERROR_BUFFER_ELEMENT_LENGTH \
+ sizeof(struct pqi_raid_error_info)
+
+/* these values are based on our implementation */
+#define PQI_ADMIN_IQ_NUM_ELEMENTS 8
+#define PQI_ADMIN_OQ_NUM_ELEMENTS 20
+#define PQI_ADMIN_IQ_ELEMENT_LENGTH 64
+#define PQI_ADMIN_OQ_ELEMENT_LENGTH 64
+
+#define PQI_OPERATIONAL_IQ_ELEMENT_LENGTH 128
+#define PQI_OPERATIONAL_OQ_ELEMENT_LENGTH 16
+
+#define PQI_MIN_MSIX_VECTORS 1
+#define PQI_MAX_MSIX_VECTORS 64
+
+/* these values are defined by the PQI spec */
+#define PQI_MAX_NUM_ELEMENTS_ADMIN_QUEUE 255
+#define PQI_MAX_NUM_ELEMENTS_OPERATIONAL_QUEUE 65535
+#define PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT 64
+#define PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT 16
+#define PQI_ADMIN_INDEX_ALIGNMENT 64
+#define PQI_OPERATIONAL_INDEX_ALIGNMENT 4
+
+#define PQI_MIN_OPERATIONAL_QUEUE_ID 1
+#define PQI_MAX_OPERATIONAL_QUEUE_ID 65535
+
+#define PQI_AIO_SERV_RESPONSE_COMPLETE 0
+#define PQI_AIO_SERV_RESPONSE_FAILURE 1
+#define PQI_AIO_SERV_RESPONSE_TMF_COMPLETE 2
+#define PQI_AIO_SERV_RESPONSE_TMF_SUCCEEDED 3
+#define PQI_AIO_SERV_RESPONSE_TMF_REJECTED 4
+#define PQI_AIO_SERV_RESPONSE_TMF_INCORRECT_LUN 5
+
+#define PQI_AIO_STATUS_IO_ERROR 0x1
+#define PQI_AIO_STATUS_IO_ABORTED 0x2
+#define PQI_AIO_STATUS_NO_PATH_TO_DEVICE 0x3
+#define PQI_AIO_STATUS_INVALID_DEVICE 0x4
+#define PQI_AIO_STATUS_AIO_PATH_DISABLED 0xe
+#define PQI_AIO_STATUS_UNDERRUN 0x51
+#define PQI_AIO_STATUS_OVERRUN 0x75
+
+typedef u32 pqi_index_t;
+
+/* SOP data direction flags */
+#define SOP_NO_DIRECTION_FLAG 0
+#define SOP_WRITE_FLAG 1 /* host writes data to Data-Out */
+ /* buffer */
+#define SOP_READ_FLAG 2 /* host receives data from Data-In */
+ /* buffer */
+#define SOP_BIDIRECTIONAL 3 /* data is transferred from the */
+ /* Data-Out buffer and data is */
+ /* transferred to the Data-In buffer */
+
+#define SOP_TASK_ATTRIBUTE_SIMPLE 0
+#define SOP_TASK_ATTRIBUTE_HEAD_OF_QUEUE 1
+#define SOP_TASK_ATTRIBUTE_ORDERED 2
+#define SOP_TASK_ATTRIBUTE_ACA 4
+
+#define SOP_TMF_COMPLETE 0x0
+#define SOP_TMF_FUNCTION_SUCCEEDED 0x8
+
+/* additional CDB bytes usage field codes */
+#define SOP_ADDITIONAL_CDB_BYTES_0 0 /* 16-byte CDB */
+#define SOP_ADDITIONAL_CDB_BYTES_4 1 /* 20-byte CDB */
+#define SOP_ADDITIONAL_CDB_BYTES_8 2 /* 24-byte CDB */
+#define SOP_ADDITIONAL_CDB_BYTES_12 3 /* 28-byte CDB */
+#define SOP_ADDITIONAL_CDB_BYTES_16 4 /* 32-byte CDB */
+
+/*
+ * The purpose of this structure is to obtain proper alignment of objects in
+ * an admin queue pair.
+ */
+struct pqi_admin_queues_aligned {
+ __aligned(PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT)
+ u8 iq_element_array[PQI_ADMIN_IQ_ELEMENT_LENGTH]
+ [PQI_ADMIN_IQ_NUM_ELEMENTS];
+ __aligned(PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT)
+ u8 oq_element_array[PQI_ADMIN_OQ_ELEMENT_LENGTH]
+ [PQI_ADMIN_OQ_NUM_ELEMENTS];
+ __aligned(PQI_ADMIN_INDEX_ALIGNMENT) pqi_index_t iq_ci;
+ __aligned(PQI_ADMIN_INDEX_ALIGNMENT) pqi_index_t oq_pi;
+};
+
+struct pqi_admin_queues {
+ void *iq_element_array;
+ void *oq_element_array;
+ volatile pqi_index_t *iq_ci;
+ volatile pqi_index_t *oq_pi;
+ dma_addr_t iq_element_array_bus_addr;
+ dma_addr_t oq_element_array_bus_addr;
+ dma_addr_t iq_ci_bus_addr;
+ dma_addr_t oq_pi_bus_addr;
+ __le32 __iomem *iq_pi;
+ pqi_index_t iq_pi_copy;
+ __le32 __iomem *oq_ci;
+ pqi_index_t oq_ci_copy;
+ struct task_struct *task;
+ u16 int_msg_num;
+};
+
+struct pqi_queue_group {
+ struct pqi_ctrl_info *ctrl_info; /* backpointer */
+ u16 iq_id[2];
+ u16 oq_id;
+ u16 int_msg_num;
+ void *iq_element_array[2];
+ void *oq_element_array;
+ dma_addr_t iq_element_array_bus_addr[2];
+ dma_addr_t oq_element_array_bus_addr;
+ __le32 __iomem *iq_pi[2];
+ pqi_index_t iq_pi_copy[2];
+ volatile pqi_index_t *iq_ci[2];
+ volatile pqi_index_t *oq_pi;
+ dma_addr_t iq_ci_bus_addr[2];
+ dma_addr_t oq_pi_bus_addr;
+ __le32 __iomem *oq_ci;
+ pqi_index_t oq_ci_copy;
+ spinlock_t submit_lock[2]; /* protect submission queue */
+ struct list_head request_list[2];
+};
+
+struct pqi_event_queue {
+ u16 oq_id;
+ u16 int_msg_num;
+ void *oq_element_array;
+ volatile pqi_index_t *oq_pi;
+ dma_addr_t oq_element_array_bus_addr;
+ dma_addr_t oq_pi_bus_addr;
+ __le32 __iomem *oq_ci;
+ pqi_index_t oq_ci_copy;
+};
+
+#define PQI_DEFAULT_QUEUE_GROUP 0
+#define PQI_MAX_QUEUE_GROUPS PQI_MAX_MSIX_VECTORS
+
+struct pqi_encryption_info {
+ u16 data_encryption_key_index;
+ u32 encrypt_tweak_lower;
+ u32 encrypt_tweak_upper;
+};
+
+#define PQI_MAX_OUTSTANDING_REQUESTS ((u32)~0)
+#define PQI_MAX_TRANSFER_SIZE (4 * 1024U * 1024U)
+
+#define RAID_MAP_MAX_ENTRIES 1024
+
+#define PQI_PHYSICAL_DEVICE_BUS 0
+#define PQI_RAID_VOLUME_BUS 1
+#define PQI_HBA_BUS 2
+#define PQI_MAX_BUS PQI_HBA_BUS
+
+#pragma pack(1)
+
+struct report_lun_header {
+ __be32 list_length;
+ u8 extended_response;
+ u8 reserved[3];
+};
+
+struct report_log_lun_extended_entry {
+ u8 lunid[8];
+ u8 volume_id[16];
+};
+
+struct report_log_lun_extended {
+ struct report_lun_header header;
+ struct report_log_lun_extended_entry lun_entries[1];
+};
+
+struct report_phys_lun_extended_entry {
+ u8 lunid[8];
+ __be64 wwid;
+ u8 device_type;
+ u8 device_flags;
+ u8 lun_count; /* number of LUNs in a multi-LUN device */
+ u8 redundant_paths;
+ u32 aio_handle;
+};
+
+/* for device_flags field of struct report_phys_lun_extended_entry */
+#define REPORT_PHYS_LUN_DEV_FLAG_NON_DISK 0x1
+#define REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED 0x8
+
+struct report_phys_lun_extended {
+ struct report_lun_header header;
+ struct report_phys_lun_extended_entry lun_entries[1];
+};
+
+struct raid_map_disk_data {
+ u32 aio_handle;
+ u8 xor_mult[2];
+ u8 reserved[2];
+};
+
+/* constants for flags field of RAID map */
+#define RAID_MAP_ENCRYPTION_ENABLED 0x1
+
+struct raid_map {
+ __le32 structure_size; /* size of entire structure in bytes */
+ __le32 volume_blk_size; /* bytes / block in the volume */
+ __le64 volume_blk_cnt; /* logical blocks on the volume */
+ u8 phys_blk_shift; /* shift factor to convert between */
+ /* units of logical blocks and */
+ /* physical disk blocks */
+ u8 parity_rotation_shift; /* shift factor to convert between */
+ /* units of logical stripes and */
+ /* physical stripes */
+ __le16 strip_size; /* blocks used on each disk / stripe */
+ __le64 disk_starting_blk; /* first disk block used in volume */
+ __le64 disk_blk_cnt; /* disk blocks used by volume / disk */
+ __le16 data_disks_per_row; /* data disk entries / row in the map */
+ __le16 metadata_disks_per_row; /* mirror/parity disk entries / row */
+ /* in the map */
+ __le16 row_cnt; /* rows in each layout map */
+ __le16 layout_map_count; /* layout maps (1 map per */
+ /* mirror parity group) */
+ __le16 flags;
+ __le16 data_encryption_key_index;
+ u8 reserved[16];
+ struct raid_map_disk_data disk_data[RAID_MAP_MAX_ENTRIES];
+};
+
+#pragma pack()
+
+#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
+
+struct pqi_scsi_dev {
+ int devtype; /* as reported by INQUIRY commmand */
+ u8 device_type; /* as reported by */
+ /* BMIC_IDENTIFY_PHYSICAL_DEVICE */
+ /* only valid for devtype = TYPE_DISK */
+ int bus;
+ int target;
+ int lun;
+ u8 scsi3addr[8];
+ __be64 wwid;
+ u8 volume_id[16];
+ u8 is_physical_device : 1;
+ u8 target_lun_valid : 1;
+ u8 expose_device : 1;
+ u8 no_uld_attach : 1;
+ u8 aio_enabled : 1; /* only valid for physical disks */
+ u8 device_gone : 1;
+ u8 new_device : 1;
+ u8 keep_device : 1;
+ u8 volume_offline : 1;
+ u8 vendor[8]; /* bytes 8-15 of inquiry data */
+ u8 model[16]; /* bytes 16-31 of inquiry data */
+ u64 sas_address;
+ u8 raid_level;
+ u16 queue_depth; /* max. queue_depth for this device */
+ u16 advertised_queue_depth;
+ u32 aio_handle;
+ u8 volume_status;
+ u8 active_path_index;
+ u8 path_map;
+ u8 bay;
+ u8 box[8];
+ u16 phys_connector[8];
+ int offload_configured; /* I/O accel RAID offload configured */
+ int offload_enabled; /* I/O accel RAID offload enabled */
+ int offload_enabled_pending;
+ int offload_to_mirror; /* Send next I/O accelerator RAID */
+ /* offload request to mirror drive. */
+ struct raid_map *raid_map; /* I/O accelerator RAID map */
+
+ struct pqi_sas_port *sas_port;
+ struct scsi_device *sdev;
+
+ struct list_head scsi_device_list_entry;
+ struct list_head new_device_list_entry;
+ struct list_head add_list_entry;
+ struct list_head delete_list_entry;
+};
+
+/* VPD inquiry pages */
+#define SCSI_VPD_SUPPORTED_PAGES 0x0 /* standard page */
+#define SCSI_VPD_DEVICE_ID 0x83 /* standard page */
+#define CISS_VPD_LV_DEVICE_GEOMETRY 0xc1 /* vendor-specific page */
+#define CISS_VPD_LV_OFFLOAD_STATUS 0xc2 /* vendor-specific page */
+#define CISS_VPD_LV_STATUS 0xc3 /* vendor-specific page */
+
+#define VPD_PAGE (1 << 8)
+
+#pragma pack(1)
+
+/* structure for CISS_VPD_LV_STATUS */
+struct ciss_vpd_logical_volume_status {
+ u8 peripheral_info;
+ u8 page_code;
+ u8 reserved;
+ u8 page_length;
+ u8 volume_status;
+ u8 reserved2[3];
+ __be32 flags;
+};
+
+#pragma pack()
+
+/* constants for volume_status field of ciss_vpd_logical_volume_status */
+#define CISS_LV_OK 0
+#define CISS_LV_FAILED 1
+#define CISS_LV_NOT_CONFIGURED 2
+#define CISS_LV_DEGRADED 3
+#define CISS_LV_READY_FOR_RECOVERY 4
+#define CISS_LV_UNDERGOING_RECOVERY 5
+#define CISS_LV_WRONG_PHYSICAL_DRIVE_REPLACED 6
+#define CISS_LV_PHYSICAL_DRIVE_CONNECTION_PROBLEM 7
+#define CISS_LV_HARDWARE_OVERHEATING 8
+#define CISS_LV_HARDWARE_HAS_OVERHEATED 9
+#define CISS_LV_UNDERGOING_EXPANSION 10
+#define CISS_LV_NOT_AVAILABLE 11
+#define CISS_LV_QUEUED_FOR_EXPANSION 12
+#define CISS_LV_DISABLED_SCSI_ID_CONFLICT 13
+#define CISS_LV_EJECTED 14
+#define CISS_LV_UNDERGOING_ERASE 15
+/* state 16 not used */
+#define CISS_LV_READY_FOR_PREDICTIVE_SPARE_REBUILD 17
+#define CISS_LV_UNDERGOING_RPI 18
+#define CISS_LV_PENDING_RPI 19
+#define CISS_LV_ENCRYPTED_NO_KEY 20
+/* state 21 not used */
+#define CISS_LV_UNDERGOING_ENCRYPTION 22
+#define CISS_LV_UNDERGOING_ENCRYPTION_REKEYING 23
+#define CISS_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER 24
+#define CISS_LV_PENDING_ENCRYPTION 25
+#define CISS_LV_PENDING_ENCRYPTION_REKEYING 26
+#define CISS_LV_NOT_SUPPORTED 27
+#define CISS_LV_STATUS_UNAVAILABLE 255
+
+/* constants for flags field of ciss_vpd_logical_volume_status */
+#define CISS_LV_FLAGS_NO_HOST_IO 0x1 /* volume not available for */
+ /* host I/O */
+
+/* for SAS hosts and SAS expanders */
+struct pqi_sas_node {
+ struct device *parent_dev;
+ struct list_head port_list_head;
+};
+
+struct pqi_sas_port {
+ struct list_head port_list_entry;
+ u64 sas_address;
+ struct sas_port *port;
+ int next_phy_index;
+ struct list_head phy_list_head;
+ struct pqi_sas_node *parent_node;
+ struct sas_rphy *rphy;
+};
+
+struct pqi_sas_phy {
+ struct list_head phy_list_entry;
+ struct sas_phy *phy;
+ struct pqi_sas_port *parent_port;
+ bool added_to_port;
+};
+
+struct pqi_io_request {
+ atomic_t refcount;
+ u16 index;
+ void (*io_complete_callback)(struct pqi_io_request *io_request,
+ void *context);
+ void *context;
+ int status;
+ struct scsi_cmnd *scmd;
+ void *error_info;
+ struct pqi_sg_descriptor *sg_chain_buffer;
+ dma_addr_t sg_chain_buffer_dma_handle;
+ void *iu;
+ struct list_head request_list_entry;
+};
+
+/* for indexing into the pending_events[] field of struct pqi_ctrl_info */
+#define PQI_EVENT_HEARTBEAT 0
+#define PQI_EVENT_HOTPLUG 1
+#define PQI_EVENT_HARDWARE 2
+#define PQI_EVENT_PHYSICAL_DEVICE 3
+#define PQI_EVENT_LOGICAL_DEVICE 4
+#define PQI_EVENT_AIO_STATE_CHANGE 5
+#define PQI_EVENT_AIO_CONFIG_CHANGE 6
+#define PQI_NUM_SUPPORTED_EVENTS 7
+
+struct pqi_event {
+ bool pending;
+ u8 event_type;
+ __le16 event_id;
+ __le32 additional_event_id;
+};
+
+#define PQI_RESERVED_IO_SLOTS_LUN_RESET 1
+#define PQI_RESERVED_IO_SLOTS_EVENT_ACK PQI_NUM_SUPPORTED_EVENTS
+#define PQI_RESERVED_IO_SLOTS_SYNCHRONOUS_REQUESTS 3
+#define PQI_RESERVED_IO_SLOTS \
+ (PQI_RESERVED_IO_SLOTS_LUN_RESET + PQI_RESERVED_IO_SLOTS_EVENT_ACK + \
+ PQI_RESERVED_IO_SLOTS_SYNCHRONOUS_REQUESTS)
+
+struct pqi_ctrl_info {
+ unsigned int ctrl_id;
+ struct pci_dev *pci_dev;
+ char firmware_version[11];
+ void __iomem *iomem_base;
+ struct pqi_ctrl_registers __iomem *registers;
+ struct pqi_device_registers __iomem *pqi_registers;
+ u32 max_sg_entries;
+ u32 config_table_offset;
+ u32 config_table_length;
+ u16 max_inbound_queues;
+ u16 max_elements_per_iq;
+ u16 max_iq_element_length;
+ u16 max_outbound_queues;
+ u16 max_elements_per_oq;
+ u16 max_oq_element_length;
+ u32 max_transfer_size;
+ u32 max_outstanding_requests;
+ u32 max_io_slots;
+ unsigned int scsi_ml_can_queue;
+ unsigned short sg_tablesize;
+ unsigned int max_sectors;
+ u32 error_buffer_length;
+ void *error_buffer;
+ dma_addr_t error_buffer_dma_handle;
+ size_t sg_chain_buffer_length;
+ unsigned int num_queue_groups;
+ unsigned int num_active_queue_groups;
+ u16 num_elements_per_iq;
+ u16 num_elements_per_oq;
+ u16 max_inbound_iu_length_per_firmware;
+ u16 max_inbound_iu_length;
+ unsigned int max_sg_per_iu;
+ void *admin_queue_memory_base;
+ u32 admin_queue_memory_length;
+ dma_addr_t admin_queue_memory_base_dma_handle;
+ void *queue_memory_base;
+ u32 queue_memory_length;
+ dma_addr_t queue_memory_base_dma_handle;
+ struct pqi_admin_queues admin_queues;
+ struct pqi_queue_group queue_groups[PQI_MAX_QUEUE_GROUPS];
+ struct pqi_event_queue event_queue;
+ int max_msix_vectors;
+ int num_msix_vectors_enabled;
+ int num_msix_vectors_initialized;
+ u32 msix_vectors[PQI_MAX_MSIX_VECTORS];
+ void *intr_data[PQI_MAX_MSIX_VECTORS];
+ int event_irq;
+ struct Scsi_Host *scsi_host;
+
+ struct mutex scan_mutex;
+ u8 inbound_spanning_supported : 1;
+ u8 outbound_spanning_supported : 1;
+ u8 pqi_mode_enabled : 1;
+ u8 controller_online : 1;
+ u8 heartbeat_timer_started : 1;
+
+ struct list_head scsi_device_list;
+ spinlock_t scsi_device_list_lock;
+
+ struct delayed_work rescan_work;
+ struct delayed_work update_time_work;
+
+ struct pqi_sas_node *sas_host;
+ u64 sas_address;
+
+ struct pqi_io_request *io_request_pool;
+ u16 next_io_request_slot;
+
+ struct pqi_event pending_events[PQI_NUM_SUPPORTED_EVENTS];
+ struct work_struct event_work;
+
+ atomic_t num_interrupts;
+ int previous_num_interrupts;
+ unsigned int num_heartbeats_requested;
+ struct timer_list heartbeat_timer;
+
+ struct semaphore sync_request_sem;
+ struct semaphore lun_reset_sem;
+};
+
+enum pqi_ctrl_mode {
+ UNKNOWN,
+ PQI_MODE
+};
+
+/*
+ * assume worst case: SATA queue depth of 31 minus 4 internal firmware commands
+ */
+#define PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH 27
+
+/* 0 = no limit */
+#define PQI_LOGICAL_DRIVE_DEFAULT_MAX_QUEUE_DEPTH 0
+
+/* CISS commands */
+#define CISS_READ 0xc0
+#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */
+#define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */
+#define CISS_GET_RAID_MAP 0xc8
+
+/* constants for CISS_REPORT_LOG/CISS_REPORT_PHYS commands */
+#define CISS_REPORT_LOG_EXTENDED 0x1
+#define CISS_REPORT_PHYS_EXTENDED 0x2
+
+/* BMIC commands */
+#define BMIC_IDENTIFY_CONTROLLER 0x11
+#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15
+#define BMIC_READ 0x26
+#define BMIC_WRITE 0x27
+#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
+#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
+#define BMIC_WRITE_HOST_WELLNESS 0xa5
+#define BMIC_CACHE_FLUSH 0xc2
+
+#define SA_CACHE_FLUSH 0x01
+
+#define MASKED_DEVICE(lunid) ((lunid)[3] & 0xc0)
+#define CISS_GET_BUS(lunid) ((lunid)[7] & 0x3f)
+#define CISS_GET_LEVEL_2_TARGET(lunid) ((lunid)[6])
+#define CISS_GET_DRIVE_NUMBER(lunid) \
+ (((CISS_GET_BUS((lunid)) - 1) << 8) + \
+ CISS_GET_LEVEL_2_TARGET((lunid)))
+
+#define NO_TIMEOUT ((unsigned long) -1)
+
+#pragma pack(1)
+
+struct bmic_identify_controller {
+ u8 configured_logical_drive_count;
+ __le32 configuration_signature;
+ u8 firmware_version[4];
+ u8 reserved[145];
+ __le16 extended_logical_unit_count;
+ u8 reserved1[34];
+ __le16 firmware_build_number;
+ u8 reserved2[100];
+ u8 controller_mode;
+ u8 reserved3[32];
+};
+
+struct bmic_identify_physical_device {
+ u8 scsi_bus; /* SCSI Bus number on controller */
+ u8 scsi_id; /* SCSI ID on this bus */
+ __le16 block_size; /* sector size in bytes */
+ __le32 total_blocks; /* number for sectors on drive */
+ __le32 reserved_blocks; /* controller reserved (RIS) */
+ u8 model[40]; /* Physical Drive Model */
+ u8 serial_number[40]; /* Drive Serial Number */
+ u8 firmware_revision[8]; /* drive firmware revision */
+ u8 scsi_inquiry_bits; /* inquiry byte 7 bits */
+ u8 compaq_drive_stamp; /* 0 means drive not stamped */
+ u8 last_failure_reason;
+ u8 flags;
+ u8 more_flags;
+ u8 scsi_lun; /* SCSI LUN for phys drive */
+ u8 yet_more_flags;
+ u8 even_more_flags;
+ __le32 spi_speed_rules;
+ u8 phys_connector[2]; /* connector number on controller */
+ u8 phys_box_on_bus; /* phys enclosure this drive resides */
+ u8 phys_bay_in_box; /* phys drv bay this drive resides */
+ __le32 rpm; /* drive rotational speed in RPM */
+ u8 device_type; /* type of drive */
+ u8 sata_version; /* only valid when device_type = */
+ /* BMIC_DEVICE_TYPE_SATA */
+ __le64 big_total_block_count;
+ __le64 ris_starting_lba;
+ __le32 ris_size;
+ u8 wwid[20];
+ u8 controller_phy_map[32];
+ __le16 phy_count;
+ u8 phy_connected_dev_type[256];
+ u8 phy_to_drive_bay_num[256];
+ __le16 phy_to_attached_dev_index[256];
+ u8 box_index;
+ u8 reserved;
+ __le16 extra_physical_drive_flags;
+ u8 negotiated_link_rate[256];
+ u8 phy_to_phy_map[256];
+ u8 redundant_path_present_map;
+ u8 redundant_path_failure_map;
+ u8 active_path_number;
+ __le16 alternate_paths_phys_connector[8];
+ u8 alternate_paths_phys_box_on_port[8];
+ u8 multi_lun_device_lun_count;
+ u8 minimum_good_fw_revision[8];
+ u8 unique_inquiry_bytes[20];
+ u8 current_temperature_degreesC;
+ u8 temperature_threshold_degreesC;
+ u8 max_temperature_degreesC;
+ u8 logical_blocks_per_phys_block_exp;
+ __le16 current_queue_depth_limit;
+ u8 switch_name[10];
+ __le16 switch_port;
+ u8 alternate_paths_switch_name[40];
+ u8 alternate_paths_switch_port[8];
+ __le16 power_on_hours;
+ __le16 percent_endurance_used;
+ u8 drive_authentication;
+ u8 smart_carrier_authentication;
+ u8 smart_carrier_app_fw_version;
+ u8 smart_carrier_bootloader_fw_version;
+ u8 encryption_key_name[64];
+ __le32 misc_drive_flags;
+ __le16 dek_index;
+ u8 padding[112];
+};
+
+#pragma pack()
+
+int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info);
+void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info);
+int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
+ struct pqi_scsi_dev *device);
+void pqi_remove_sas_device(struct pqi_scsi_dev *device);
+struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
+ struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy);
+
+extern struct sas_function_template pqi_sas_transport_functions;
+
+#if !defined(readq)
+#define readq readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+ u32 lower32;
+ u32 upper32;
+
+ lower32 = readl(addr);
+ upper32 = readl(addr + 4);
+
+ return ((u64)upper32 << 32) | lower32;
+}
+#endif
+
+#if !defined(writeq)
+#define writeq writeq
+static inline void writeq(u64 value, volatile void __iomem *addr)
+{
+ u32 lower32;
+ u32 upper32;
+
+ lower32 = lower_32_bits(value);
+ upper32 = upper_32_bits(value);
+
+ writel(lower32, addr);
+ writel(upper32, addr + 4);
+}
+#endif
+
+#endif /* _SMARTPQI_H */
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
new file mode 100644
index 000000000000..a535b2661f38
--- /dev/null
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -0,0 +1,6303 @@
+/*
+ * driver for Microsemi PQI-based storage controllers
+ * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016 PMC-Sierra, 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; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/cciss_ioctl.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport_sas.h>
+#include <asm/unaligned.h>
+#include "smartpqi.h"
+#include "smartpqi_sis.h"
+
+#if !defined(BUILD_TIMESTAMP)
+#define BUILD_TIMESTAMP
+#endif
+
+#define DRIVER_VERSION "0.9.13-370"
+#define DRIVER_MAJOR 0
+#define DRIVER_MINOR 9
+#define DRIVER_RELEASE 13
+#define DRIVER_REVISION 370
+
+#define DRIVER_NAME "Microsemi PQI Driver (v" DRIVER_VERSION ")"
+#define DRIVER_NAME_SHORT "smartpqi"
+
+MODULE_AUTHOR("Microsemi");
+MODULE_DESCRIPTION("Driver for Microsemi Smart Family Controller version "
+ DRIVER_VERSION);
+MODULE_SUPPORTED_DEVICE("Microsemi Smart Family Controllers");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+#define PQI_ENABLE_MULTI_QUEUE_SUPPORT 0
+
+static char *hpe_branded_controller = "HPE Smart Array Controller";
+static char *microsemi_branded_controller = "Microsemi Smart Family Controller";
+
+static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);
+static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info);
+static void pqi_scan_start(struct Scsi_Host *shost);
+static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_queue_group *queue_group, enum pqi_io_path path,
+ struct pqi_io_request *io_request);
+static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_iu_header *request, unsigned int flags,
+ struct pqi_raid_error_info *error_info, unsigned long timeout_msecs);
+static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
+ struct scsi_cmnd *scmd, u32 aio_handle, u8 *cdb,
+ unsigned int cdb_length, struct pqi_queue_group *queue_group,
+ struct pqi_encryption_info *encryption_info);
+
+/* for flags argument to pqi_submit_raid_request_synchronous() */
+#define PQI_SYNC_FLAGS_INTERRUPTABLE 0x1
+
+static struct scsi_transport_template *pqi_sas_transport_template;
+
+static atomic_t pqi_controller_count = ATOMIC_INIT(0);
+
+static int pqi_disable_device_id_wildcards;
+module_param_named(disable_device_id_wildcards,
+ pqi_disable_device_id_wildcards, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_device_id_wildcards,
+ "Disable device ID wildcards.");
+
+static char *raid_levels[] = {
+ "RAID-0",
+ "RAID-4",
+ "RAID-1(1+0)",
+ "RAID-5",
+ "RAID-5+1",
+ "RAID-ADG",
+ "RAID-1(ADM)",
+};
+
+static char *pqi_raid_level_to_string(u8 raid_level)
+{
+ if (raid_level < ARRAY_SIZE(raid_levels))
+ return raid_levels[raid_level];
+
+ return "";
+}
+
+#define SA_RAID_0 0
+#define SA_RAID_4 1
+#define SA_RAID_1 2 /* also used for RAID 10 */
+#define SA_RAID_5 3 /* also used for RAID 50 */
+#define SA_RAID_51 4
+#define SA_RAID_6 5 /* also used for RAID 60 */
+#define SA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
+#define SA_RAID_MAX SA_RAID_ADM
+#define SA_RAID_UNKNOWN 0xff
+
+static inline void pqi_scsi_done(struct scsi_cmnd *scmd)
+{
+ scmd->scsi_done(scmd);
+}
+
+static inline bool pqi_scsi3addr_equal(u8 *scsi3addr1, u8 *scsi3addr2)
+{
+ return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
+}
+
+static inline struct pqi_ctrl_info *shost_to_hba(struct Scsi_Host *shost)
+{
+ void *hostdata = shost_priv(shost);
+
+ return *((struct pqi_ctrl_info **)hostdata);
+}
+
+static inline bool pqi_is_logical_device(struct pqi_scsi_dev *device)
+{
+ return !device->is_physical_device;
+}
+
+static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
+{
+ return !ctrl_info->controller_online;
+}
+
+static inline void pqi_check_ctrl_health(struct pqi_ctrl_info *ctrl_info)
+{
+ if (ctrl_info->controller_online)
+ if (!sis_is_firmware_running(ctrl_info))
+ pqi_take_ctrl_offline(ctrl_info);
+}
+
+static inline bool pqi_is_hba_lunid(u8 *scsi3addr)
+{
+ return pqi_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID);
+}
+
+static inline enum pqi_ctrl_mode pqi_get_ctrl_mode(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ return sis_read_driver_scratch(ctrl_info);
+}
+
+static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info *ctrl_info,
+ enum pqi_ctrl_mode mode)
+{
+ sis_write_driver_scratch(ctrl_info, mode);
+}
+
+#define PQI_RESCAN_WORK_INTERVAL (10 * HZ)
+
+static inline void pqi_schedule_rescan_worker(struct pqi_ctrl_info *ctrl_info)
+{
+ schedule_delayed_work(&ctrl_info->rescan_work,
+ PQI_RESCAN_WORK_INTERVAL);
+}
+
+static int pqi_map_single(struct pci_dev *pci_dev,
+ struct pqi_sg_descriptor *sg_descriptor, void *buffer,
+ size_t buffer_length, int data_direction)
+{
+ dma_addr_t bus_address;
+
+ if (!buffer || buffer_length == 0 || data_direction == PCI_DMA_NONE)
+ return 0;
+
+ bus_address = pci_map_single(pci_dev, buffer, buffer_length,
+ data_direction);
+ if (pci_dma_mapping_error(pci_dev, bus_address))
+ return -ENOMEM;
+
+ put_unaligned_le64((u64)bus_address, &sg_descriptor->address);
+ put_unaligned_le32(buffer_length, &sg_descriptor->length);
+ put_unaligned_le32(CISS_SG_LAST, &sg_descriptor->flags);
+
+ return 0;
+}
+
+static void pqi_pci_unmap(struct pci_dev *pci_dev,
+ struct pqi_sg_descriptor *descriptors, int num_descriptors,
+ int data_direction)
+{
+ int i;
+
+ if (data_direction == PCI_DMA_NONE)
+ return;
+
+ for (i = 0; i < num_descriptors; i++)
+ pci_unmap_single(pci_dev,
+ (dma_addr_t)get_unaligned_le64(&descriptors[i].address),
+ get_unaligned_le32(&descriptors[i].length),
+ data_direction);
+}
+
+static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_raid_path_request *request, u8 cmd,
+ u8 *scsi3addr, void *buffer, size_t buffer_length,
+ u16 vpd_page, int *pci_direction)
+{
+ u8 *cdb;
+ int pci_dir;
+
+ memset(request, 0, sizeof(*request));
+
+ request->header.iu_type = PQI_REQUEST_IU_RAID_PATH_IO;
+ put_unaligned_le16(offsetof(struct pqi_raid_path_request,
+ sg_descriptors[1]) - PQI_REQUEST_HEADER_LENGTH,
+ &request->header.iu_length);
+ put_unaligned_le32(buffer_length, &request->buffer_length);
+ memcpy(request->lun_number, scsi3addr, sizeof(request->lun_number));
+ request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
+ request->additional_cdb_bytes_usage = SOP_ADDITIONAL_CDB_BYTES_0;
+
+ cdb = request->cdb;
+
+ switch (cmd) {
+ case INQUIRY:
+ request->data_direction = SOP_READ_FLAG;
+ cdb[0] = INQUIRY;
+ if (vpd_page & VPD_PAGE) {
+ cdb[1] = 0x1;
+ cdb[2] = (u8)vpd_page;
+ }
+ cdb[4] = (u8)buffer_length;
+ break;
+ case CISS_REPORT_LOG:
+ case CISS_REPORT_PHYS:
+ request->data_direction = SOP_READ_FLAG;
+ cdb[0] = cmd;
+ if (cmd == CISS_REPORT_PHYS)
+ cdb[1] = CISS_REPORT_PHYS_EXTENDED;
+ else
+ cdb[1] = CISS_REPORT_LOG_EXTENDED;
+ put_unaligned_be32(buffer_length, &cdb[6]);
+ break;
+ case CISS_GET_RAID_MAP:
+ request->data_direction = SOP_READ_FLAG;
+ cdb[0] = CISS_READ;
+ cdb[1] = CISS_GET_RAID_MAP;
+ put_unaligned_be32(buffer_length, &cdb[6]);
+ break;
+ case SA_CACHE_FLUSH:
+ request->data_direction = SOP_WRITE_FLAG;
+ cdb[0] = BMIC_WRITE;
+ cdb[6] = BMIC_CACHE_FLUSH;
+ put_unaligned_be16(buffer_length, &cdb[7]);
+ break;
+ case BMIC_IDENTIFY_CONTROLLER:
+ case BMIC_IDENTIFY_PHYSICAL_DEVICE:
+ request->data_direction = SOP_READ_FLAG;
+ cdb[0] = BMIC_READ;
+ cdb[6] = cmd;
+ put_unaligned_be16(buffer_length, &cdb[7]);
+ break;
+ case BMIC_WRITE_HOST_WELLNESS:
+ request->data_direction = SOP_WRITE_FLAG;
+ cdb[0] = BMIC_WRITE;
+ cdb[6] = cmd;
+ put_unaligned_be16(buffer_length, &cdb[7]);
+ break;
+ default:
+ dev_err(&ctrl_info->pci_dev->dev, "unknown command 0x%c\n",
+ cmd);
+ WARN_ON(cmd);
+ break;
+ }
+
+ switch (request->data_direction) {
+ case SOP_READ_FLAG:
+ pci_dir = PCI_DMA_FROMDEVICE;
+ break;
+ case SOP_WRITE_FLAG:
+ pci_dir = PCI_DMA_TODEVICE;
+ break;
+ case SOP_NO_DIRECTION_FLAG:
+ pci_dir = PCI_DMA_NONE;
+ break;
+ default:
+ pci_dir = PCI_DMA_BIDIRECTIONAL;
+ break;
+ }
+
+ *pci_direction = pci_dir;
+
+ return pqi_map_single(ctrl_info->pci_dev, &request->sg_descriptors[0],
+ buffer, buffer_length, pci_dir);
+}
+
+static struct pqi_io_request *pqi_alloc_io_request(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ struct pqi_io_request *io_request;
+ u16 i = ctrl_info->next_io_request_slot; /* benignly racy */
+
+ while (1) {
+ io_request = &ctrl_info->io_request_pool[i];
+ if (atomic_inc_return(&io_request->refcount) == 1)
+ break;
+ atomic_dec(&io_request->refcount);
+ i = (i + 1) % ctrl_info->max_io_slots;
+ }
+
+ /* benignly racy */
+ ctrl_info->next_io_request_slot = (i + 1) % ctrl_info->max_io_slots;
+
+ io_request->scmd = NULL;
+ io_request->status = 0;
+ io_request->error_info = NULL;
+
+ return io_request;
+}
+
+static void pqi_free_io_request(struct pqi_io_request *io_request)
+{
+ atomic_dec(&io_request->refcount);
+}
+
+static int pqi_identify_controller(struct pqi_ctrl_info *ctrl_info,
+ struct bmic_identify_controller *buffer)
+{
+ int rc;
+ int pci_direction;
+ struct pqi_raid_path_request request;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ BMIC_IDENTIFY_CONTROLLER, RAID_CTLR_LUNID, buffer,
+ sizeof(*buffer), 0, &pci_direction);
+ if (rc)
+ return rc;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
+ NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+ return rc;
+}
+
+static int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info,
+ u8 *scsi3addr, u16 vpd_page, void *buffer, size_t buffer_length)
+{
+ int rc;
+ int pci_direction;
+ struct pqi_raid_path_request request;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ INQUIRY, scsi3addr, buffer, buffer_length, vpd_page,
+ &pci_direction);
+ if (rc)
+ return rc;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
+ NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+ return rc;
+}
+
+static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device,
+ struct bmic_identify_physical_device *buffer,
+ size_t buffer_length)
+{
+ int rc;
+ int pci_direction;
+ u16 bmic_device_index;
+ struct pqi_raid_path_request request;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ BMIC_IDENTIFY_PHYSICAL_DEVICE, RAID_CTLR_LUNID, buffer,
+ buffer_length, 0, &pci_direction);
+ if (rc)
+ return rc;
+
+ bmic_device_index = CISS_GET_DRIVE_NUMBER(device->scsi3addr);
+ request.cdb[2] = (u8)bmic_device_index;
+ request.cdb[9] = (u8)(bmic_device_index >> 8);
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
+ 0, NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+ return rc;
+}
+
+#define SA_CACHE_FLUSH_BUFFER_LENGTH 4
+
+static int pqi_flush_cache(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct pqi_raid_path_request request;
+ int pci_direction;
+ u8 *buffer;
+
+ /*
+ * Don't bother trying to flush the cache if the controller is
+ * locked up.
+ */
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+
+ buffer = kzalloc(SA_CACHE_FLUSH_BUFFER_LENGTH, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ SA_CACHE_FLUSH, RAID_CTLR_LUNID, buffer,
+ SA_CACHE_FLUSH_BUFFER_LENGTH, 0, &pci_direction);
+ if (rc)
+ goto out;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
+ 0, NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+out:
+ kfree(buffer);
+
+ return rc;
+}
+
+static int pqi_write_host_wellness(struct pqi_ctrl_info *ctrl_info,
+ void *buffer, size_t buffer_length)
+{
+ int rc;
+ struct pqi_raid_path_request request;
+ int pci_direction;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ BMIC_WRITE_HOST_WELLNESS, RAID_CTLR_LUNID, buffer,
+ buffer_length, 0, &pci_direction);
+ if (rc)
+ return rc;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
+ 0, NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+ return rc;
+}
+
+#pragma pack(1)
+
+struct bmic_host_wellness_driver_version {
+ u8 start_tag[4];
+ u8 driver_version_tag[2];
+ __le16 driver_version_length;
+ char driver_version[32];
+ u8 end_tag[2];
+};
+
+#pragma pack()
+
+static int pqi_write_driver_version_to_host_wellness(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct bmic_host_wellness_driver_version *buffer;
+ size_t buffer_length;
+
+ buffer_length = sizeof(*buffer);
+
+ buffer = kmalloc(buffer_length, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ buffer->start_tag[0] = '<';
+ buffer->start_tag[1] = 'H';
+ buffer->start_tag[2] = 'W';
+ buffer->start_tag[3] = '>';
+ buffer->driver_version_tag[0] = 'D';
+ buffer->driver_version_tag[1] = 'V';
+ put_unaligned_le16(sizeof(buffer->driver_version),
+ &buffer->driver_version_length);
+ strncpy(buffer->driver_version, DRIVER_VERSION,
+ sizeof(buffer->driver_version) - 1);
+ buffer->driver_version[sizeof(buffer->driver_version) - 1] = '\0';
+ buffer->end_tag[0] = 'Z';
+ buffer->end_tag[1] = 'Z';
+
+ rc = pqi_write_host_wellness(ctrl_info, buffer, buffer_length);
+
+ kfree(buffer);
+
+ return rc;
+}
+
+#pragma pack(1)
+
+struct bmic_host_wellness_time {
+ u8 start_tag[4];
+ u8 time_tag[2];
+ __le16 time_length;
+ u8 time[8];
+ u8 dont_write_tag[2];
+ u8 end_tag[2];
+};
+
+#pragma pack()
+
+static int pqi_write_current_time_to_host_wellness(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct bmic_host_wellness_time *buffer;
+ size_t buffer_length;
+ time64_t local_time;
+ unsigned int year;
+ struct timeval time;
+ struct rtc_time tm;
+
+ buffer_length = sizeof(*buffer);
+
+ buffer = kmalloc(buffer_length, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ buffer->start_tag[0] = '<';
+ buffer->start_tag[1] = 'H';
+ buffer->start_tag[2] = 'W';
+ buffer->start_tag[3] = '>';
+ buffer->time_tag[0] = 'T';
+ buffer->time_tag[1] = 'D';
+ put_unaligned_le16(sizeof(buffer->time),
+ &buffer->time_length);
+
+ do_gettimeofday(&time);
+ local_time = time.tv_sec - (sys_tz.tz_minuteswest * 60);
+ rtc_time64_to_tm(local_time, &tm);
+ year = tm.tm_year + 1900;
+
+ buffer->time[0] = bin2bcd(tm.tm_hour);
+ buffer->time[1] = bin2bcd(tm.tm_min);
+ buffer->time[2] = bin2bcd(tm.tm_sec);
+ buffer->time[3] = 0;
+ buffer->time[4] = bin2bcd(tm.tm_mon + 1);
+ buffer->time[5] = bin2bcd(tm.tm_mday);
+ buffer->time[6] = bin2bcd(year / 100);
+ buffer->time[7] = bin2bcd(year % 100);
+
+ buffer->dont_write_tag[0] = 'D';
+ buffer->dont_write_tag[1] = 'W';
+ buffer->end_tag[0] = 'Z';
+ buffer->end_tag[1] = 'Z';
+
+ rc = pqi_write_host_wellness(ctrl_info, buffer, buffer_length);
+
+ kfree(buffer);
+
+ return rc;
+}
+
+#define PQI_UPDATE_TIME_WORK_INTERVAL (24UL * 60 * 60 * HZ)
+
+static void pqi_update_time_worker(struct work_struct *work)
+{
+ int rc;
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = container_of(to_delayed_work(work), struct pqi_ctrl_info,
+ update_time_work);
+
+ rc = pqi_write_current_time_to_host_wellness(ctrl_info);
+ if (rc)
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "error updating time on controller\n");
+
+ schedule_delayed_work(&ctrl_info->update_time_work,
+ PQI_UPDATE_TIME_WORK_INTERVAL);
+}
+
+static inline void pqi_schedule_update_time_worker(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ schedule_delayed_work(&ctrl_info->update_time_work, 0);
+}
+
+static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
+ void *buffer, size_t buffer_length)
+{
+ int rc;
+ int pci_direction;
+ struct pqi_raid_path_request request;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ cmd, RAID_CTLR_LUNID, buffer, buffer_length, 0, &pci_direction);
+ if (rc)
+ return rc;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
+ NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+ return rc;
+}
+
+static int pqi_report_phys_logical_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
+ void **buffer)
+{
+ int rc;
+ size_t lun_list_length;
+ size_t lun_data_length;
+ size_t new_lun_list_length;
+ void *lun_data = NULL;
+ struct report_lun_header *report_lun_header;
+
+ report_lun_header = kmalloc(sizeof(*report_lun_header), GFP_KERNEL);
+ if (!report_lun_header) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = pqi_report_luns(ctrl_info, cmd, report_lun_header,
+ sizeof(*report_lun_header));
+ if (rc)
+ goto out;
+
+ lun_list_length = get_unaligned_be32(&report_lun_header->list_length);
+
+again:
+ lun_data_length = sizeof(struct report_lun_header) + lun_list_length;
+
+ lun_data = kmalloc(lun_data_length, GFP_KERNEL);
+ if (!lun_data) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if (lun_list_length == 0) {
+ memcpy(lun_data, report_lun_header, sizeof(*report_lun_header));
+ goto out;
+ }
+
+ rc = pqi_report_luns(ctrl_info, cmd, lun_data, lun_data_length);
+ if (rc)
+ goto out;
+
+ new_lun_list_length = get_unaligned_be32(
+ &((struct report_lun_header *)lun_data)->list_length);
+
+ if (new_lun_list_length > lun_list_length) {
+ lun_list_length = new_lun_list_length;
+ kfree(lun_data);
+ goto again;
+ }
+
+out:
+ kfree(report_lun_header);
+
+ if (rc) {
+ kfree(lun_data);
+ lun_data = NULL;
+ }
+
+ *buffer = lun_data;
+
+ return rc;
+}
+
+static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info,
+ void **buffer)
+{
+ return pqi_report_phys_logical_luns(ctrl_info, CISS_REPORT_PHYS,
+ buffer);
+}
+
+static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info,
+ void **buffer)
+{
+ return pqi_report_phys_logical_luns(ctrl_info, CISS_REPORT_LOG, buffer);
+}
+
+static int pqi_get_device_lists(struct pqi_ctrl_info *ctrl_info,
+ struct report_phys_lun_extended **physdev_list,
+ struct report_log_lun_extended **logdev_list)
+{
+ int rc;
+ size_t logdev_list_length;
+ size_t logdev_data_length;
+ struct report_log_lun_extended *internal_logdev_list;
+ struct report_log_lun_extended *logdev_data;
+ struct report_lun_header report_lun_header;
+
+ rc = pqi_report_phys_luns(ctrl_info, (void **)physdev_list);
+ if (rc)
+ dev_err(&ctrl_info->pci_dev->dev,
+ "report physical LUNs failed\n");
+
+ rc = pqi_report_logical_luns(ctrl_info, (void **)logdev_list);
+ if (rc)
+ dev_err(&ctrl_info->pci_dev->dev,
+ "report logical LUNs failed\n");
+
+ /*
+ * Tack the controller itself onto the end of the logical device list.
+ */
+
+ logdev_data = *logdev_list;
+
+ if (logdev_data) {
+ logdev_list_length =
+ get_unaligned_be32(&logdev_data->header.list_length);
+ } else {
+ memset(&report_lun_header, 0, sizeof(report_lun_header));
+ logdev_data =
+ (struct report_log_lun_extended *)&report_lun_header;
+ logdev_list_length = 0;
+ }
+
+ logdev_data_length = sizeof(struct report_lun_header) +
+ logdev_list_length;
+
+ internal_logdev_list = kmalloc(logdev_data_length +
+ sizeof(struct report_log_lun_extended), GFP_KERNEL);
+ if (!internal_logdev_list) {
+ kfree(*logdev_list);
+ *logdev_list = NULL;
+ return -ENOMEM;
+ }
+
+ memcpy(internal_logdev_list, logdev_data, logdev_data_length);
+ memset((u8 *)internal_logdev_list + logdev_data_length, 0,
+ sizeof(struct report_log_lun_extended_entry));
+ put_unaligned_be32(logdev_list_length +
+ sizeof(struct report_log_lun_extended_entry),
+ &internal_logdev_list->header.list_length);
+
+ kfree(*logdev_list);
+ *logdev_list = internal_logdev_list;
+
+ return 0;
+}
+
+static inline void pqi_set_bus_target_lun(struct pqi_scsi_dev *device,
+ int bus, int target, int lun)
+{
+ device->bus = bus;
+ device->target = target;
+ device->lun = lun;
+}
+
+static void pqi_assign_bus_target_lun(struct pqi_scsi_dev *device)
+{
+ u8 *scsi3addr;
+ u32 lunid;
+
+ scsi3addr = device->scsi3addr;
+ lunid = get_unaligned_le32(scsi3addr);
+
+ if (pqi_is_hba_lunid(scsi3addr)) {
+ /* The specified device is the controller. */
+ pqi_set_bus_target_lun(device, PQI_HBA_BUS, 0, lunid & 0x3fff);
+ device->target_lun_valid = true;
+ return;
+ }
+
+ if (pqi_is_logical_device(device)) {
+ pqi_set_bus_target_lun(device, PQI_RAID_VOLUME_BUS, 0,
+ lunid & 0x3fff);
+ device->target_lun_valid = true;
+ return;
+ }
+
+ /*
+ * Defer target and LUN assignment for non-controller physical devices
+ * because the SAS transport layer will make these assignments later.
+ */
+ pqi_set_bus_target_lun(device, PQI_PHYSICAL_DEVICE_BUS, 0, 0);
+}
+
+static void pqi_get_raid_level(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ u8 raid_level;
+ u8 *buffer;
+
+ raid_level = SA_RAID_UNKNOWN;
+
+ buffer = kmalloc(64, GFP_KERNEL);
+ if (buffer) {
+ rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr,
+ VPD_PAGE | CISS_VPD_LV_DEVICE_GEOMETRY, buffer, 64);
+ if (rc == 0) {
+ raid_level = buffer[8];
+ if (raid_level > SA_RAID_MAX)
+ raid_level = SA_RAID_UNKNOWN;
+ }
+ kfree(buffer);
+ }
+
+ device->raid_level = raid_level;
+}
+
+static int pqi_validate_raid_map(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device, struct raid_map *raid_map)
+{
+ char *err_msg;
+ u32 raid_map_size;
+ u32 r5or6_blocks_per_row;
+ unsigned int num_phys_disks;
+ unsigned int num_raid_map_entries;
+
+ raid_map_size = get_unaligned_le32(&raid_map->structure_size);
+
+ if (raid_map_size < offsetof(struct raid_map, disk_data)) {
+ err_msg = "RAID map too small";
+ goto bad_raid_map;
+ }
+
+ if (raid_map_size > sizeof(*raid_map)) {
+ err_msg = "RAID map too large";
+ goto bad_raid_map;
+ }
+
+ num_phys_disks = get_unaligned_le16(&raid_map->layout_map_count) *
+ (get_unaligned_le16(&raid_map->data_disks_per_row) +
+ get_unaligned_le16(&raid_map->metadata_disks_per_row));
+ num_raid_map_entries = num_phys_disks *
+ get_unaligned_le16(&raid_map->row_cnt);
+
+ if (num_raid_map_entries > RAID_MAP_MAX_ENTRIES) {
+ err_msg = "invalid number of map entries in RAID map";
+ goto bad_raid_map;
+ }
+
+ if (device->raid_level == SA_RAID_1) {
+ if (get_unaligned_le16(&raid_map->layout_map_count) != 2) {
+ err_msg = "invalid RAID-1 map";
+ goto bad_raid_map;
+ }
+ } else if (device->raid_level == SA_RAID_ADM) {
+ if (get_unaligned_le16(&raid_map->layout_map_count) != 3) {
+ err_msg = "invalid RAID-1(ADM) map";
+ goto bad_raid_map;
+ }
+ } else if ((device->raid_level == SA_RAID_5 ||
+ device->raid_level == SA_RAID_6) &&
+ get_unaligned_le16(&raid_map->layout_map_count) > 1) {
+ /* RAID 50/60 */
+ r5or6_blocks_per_row =
+ get_unaligned_le16(&raid_map->strip_size) *
+ get_unaligned_le16(&raid_map->data_disks_per_row);
+ if (r5or6_blocks_per_row == 0) {
+ err_msg = "invalid RAID-5 or RAID-6 map";
+ goto bad_raid_map;
+ }
+ }
+
+ return 0;
+
+bad_raid_map:
+ dev_warn(&ctrl_info->pci_dev->dev, "%s\n", err_msg);
+
+ return -EINVAL;
+}
+
+static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ int pci_direction;
+ struct pqi_raid_path_request request;
+ struct raid_map *raid_map;
+
+ raid_map = kmalloc(sizeof(*raid_map), GFP_KERNEL);
+ if (!raid_map)
+ return -ENOMEM;
+
+ rc = pqi_build_raid_path_request(ctrl_info, &request,
+ CISS_GET_RAID_MAP, device->scsi3addr, raid_map,
+ sizeof(*raid_map), 0, &pci_direction);
+ if (rc)
+ goto error;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
+ NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ pci_direction);
+
+ if (rc)
+ goto error;
+
+ rc = pqi_validate_raid_map(ctrl_info, device, raid_map);
+ if (rc)
+ goto error;
+
+ device->raid_map = raid_map;
+
+ return 0;
+
+error:
+ kfree(raid_map);
+
+ return rc;
+}
+
+static void pqi_get_offload_status(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ u8 *buffer;
+ u8 offload_status;
+
+ buffer = kmalloc(64, GFP_KERNEL);
+ if (!buffer)
+ return;
+
+ rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr,
+ VPD_PAGE | CISS_VPD_LV_OFFLOAD_STATUS, buffer, 64);
+ if (rc)
+ goto out;
+
+#define OFFLOAD_STATUS_BYTE 4
+#define OFFLOAD_CONFIGURED_BIT 0x1
+#define OFFLOAD_ENABLED_BIT 0x2
+
+ offload_status = buffer[OFFLOAD_STATUS_BYTE];
+ device->offload_configured =
+ !!(offload_status & OFFLOAD_CONFIGURED_BIT);
+ if (device->offload_configured) {
+ device->offload_enabled_pending =
+ !!(offload_status & OFFLOAD_ENABLED_BIT);
+ if (pqi_get_raid_map(ctrl_info, device))
+ device->offload_enabled_pending = false;
+ }
+
+out:
+ kfree(buffer);
+}
+
+/*
+ * Use vendor-specific VPD to determine online/offline status of a volume.
+ */
+
+static void pqi_get_volume_status(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ size_t page_length;
+ u8 volume_status = CISS_LV_STATUS_UNAVAILABLE;
+ bool volume_offline = true;
+ u32 volume_flags;
+ struct ciss_vpd_logical_volume_status *vpd;
+
+ vpd = kmalloc(sizeof(*vpd), GFP_KERNEL);
+ if (!vpd)
+ goto no_buffer;
+
+ rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr,
+ VPD_PAGE | CISS_VPD_LV_STATUS, vpd, sizeof(*vpd));
+ if (rc)
+ goto out;
+
+ page_length = offsetof(struct ciss_vpd_logical_volume_status,
+ volume_status) + vpd->page_length;
+ if (page_length < sizeof(*vpd))
+ goto out;
+
+ volume_status = vpd->volume_status;
+ volume_flags = get_unaligned_be32(&vpd->flags);
+ volume_offline = (volume_flags & CISS_LV_FLAGS_NO_HOST_IO) != 0;
+
+out:
+ kfree(vpd);
+no_buffer:
+ device->volume_status = volume_status;
+ device->volume_offline = volume_offline;
+}
+
+static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ u8 *buffer;
+
+ buffer = kmalloc(64, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ /* Send an inquiry to the device to see what it is. */
+ rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr, 0, buffer, 64);
+ if (rc)
+ goto out;
+
+ scsi_sanitize_inquiry_string(&buffer[8], 8);
+ scsi_sanitize_inquiry_string(&buffer[16], 16);
+
+ device->devtype = buffer[0] & 0x1f;
+ memcpy(device->vendor, &buffer[8],
+ sizeof(device->vendor));
+ memcpy(device->model, &buffer[16],
+ sizeof(device->model));
+
+ if (pqi_is_logical_device(device) && device->devtype == TYPE_DISK) {
+ pqi_get_raid_level(ctrl_info, device);
+ pqi_get_offload_status(ctrl_info, device);
+ pqi_get_volume_status(ctrl_info, device);
+ }
+
+out:
+ kfree(buffer);
+
+ return rc;
+}
+
+static void pqi_get_physical_disk_info(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device,
+ struct bmic_identify_physical_device *id_phys)
+{
+ int rc;
+
+ memset(id_phys, 0, sizeof(*id_phys));
+
+ rc = pqi_identify_physical_device(ctrl_info, device,
+ id_phys, sizeof(*id_phys));
+ if (rc) {
+ device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH;
+ return;
+ }
+
+ device->queue_depth =
+ get_unaligned_le16(&id_phys->current_queue_depth_limit);
+ device->device_type = id_phys->device_type;
+ device->active_path_index = id_phys->active_path_number;
+ device->path_map = id_phys->redundant_path_present_map;
+ memcpy(&device->box,
+ &id_phys->alternate_paths_phys_box_on_port,
+ sizeof(device->box));
+ memcpy(&device->phys_connector,
+ &id_phys->alternate_paths_phys_connector,
+ sizeof(device->phys_connector));
+ device->bay = id_phys->phys_bay_in_box;
+}
+
+static void pqi_show_volume_status(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ char *status;
+ static const char unknown_state_str[] =
+ "Volume is in an unknown state (%u)";
+ char unknown_state_buffer[sizeof(unknown_state_str) + 10];
+
+ switch (device->volume_status) {
+ case CISS_LV_OK:
+ status = "Volume online";
+ break;
+ case CISS_LV_FAILED:
+ status = "Volume failed";
+ break;
+ case CISS_LV_NOT_CONFIGURED:
+ status = "Volume not configured";
+ break;
+ case CISS_LV_DEGRADED:
+ status = "Volume degraded";
+ break;
+ case CISS_LV_READY_FOR_RECOVERY:
+ status = "Volume ready for recovery operation";
+ break;
+ case CISS_LV_UNDERGOING_RECOVERY:
+ status = "Volume undergoing recovery";
+ break;
+ case CISS_LV_WRONG_PHYSICAL_DRIVE_REPLACED:
+ status = "Wrong physical drive was replaced";
+ break;
+ case CISS_LV_PHYSICAL_DRIVE_CONNECTION_PROBLEM:
+ status = "A physical drive not properly connected";
+ break;
+ case CISS_LV_HARDWARE_OVERHEATING:
+ status = "Hardware is overheating";
+ break;
+ case CISS_LV_HARDWARE_HAS_OVERHEATED:
+ status = "Hardware has overheated";
+ break;
+ case CISS_LV_UNDERGOING_EXPANSION:
+ status = "Volume undergoing expansion";
+ break;
+ case CISS_LV_NOT_AVAILABLE:
+ status = "Volume waiting for transforming volume";
+ break;
+ case CISS_LV_QUEUED_FOR_EXPANSION:
+ status = "Volume queued for expansion";
+ break;
+ case CISS_LV_DISABLED_SCSI_ID_CONFLICT:
+ status = "Volume disabled due to SCSI ID conflict";
+ break;
+ case CISS_LV_EJECTED:
+ status = "Volume has been ejected";
+ break;
+ case CISS_LV_UNDERGOING_ERASE:
+ status = "Volume undergoing background erase";
+ break;
+ case CISS_LV_READY_FOR_PREDICTIVE_SPARE_REBUILD:
+ status = "Volume ready for predictive spare rebuild";
+ break;
+ case CISS_LV_UNDERGOING_RPI:
+ status = "Volume undergoing rapid parity initialization";
+ break;
+ case CISS_LV_PENDING_RPI:
+ status = "Volume queued for rapid parity initialization";
+ break;
+ case CISS_LV_ENCRYPTED_NO_KEY:
+ status = "Encrypted volume inaccessible - key not present";
+ break;
+ case CISS_LV_UNDERGOING_ENCRYPTION:
+ status = "Volume undergoing encryption process";
+ break;
+ case CISS_LV_UNDERGOING_ENCRYPTION_REKEYING:
+ status = "Volume undergoing encryption re-keying process";
+ break;
+ case CISS_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
+ status =
+ "Encrypted volume inaccessible - disabled on ctrl";
+ break;
+ case CISS_LV_PENDING_ENCRYPTION:
+ status = "Volume pending migration to encrypted state";
+ break;
+ case CISS_LV_PENDING_ENCRYPTION_REKEYING:
+ status = "Volume pending encryption rekeying";
+ break;
+ case CISS_LV_NOT_SUPPORTED:
+ status = "Volume not supported on this controller";
+ break;
+ case CISS_LV_STATUS_UNAVAILABLE:
+ status = "Volume status not available";
+ break;
+ default:
+ snprintf(unknown_state_buffer, sizeof(unknown_state_buffer),
+ unknown_state_str, device->volume_status);
+ status = unknown_state_buffer;
+ break;
+ }
+
+ dev_info(&ctrl_info->pci_dev->dev,
+ "scsi %d:%d:%d:%d %s\n",
+ ctrl_info->scsi_host->host_no,
+ device->bus, device->target, device->lun, status);
+}
+
+static struct pqi_scsi_dev *pqi_find_disk_by_aio_handle(
+ struct pqi_ctrl_info *ctrl_info, u32 aio_handle)
+{
+ struct pqi_scsi_dev *device;
+
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (device->devtype != TYPE_DISK && device->devtype != TYPE_ZBC)
+ continue;
+ if (pqi_is_logical_device(device))
+ continue;
+ if (device->aio_handle == aio_handle)
+ return device;
+ }
+
+ return NULL;
+}
+
+static void pqi_update_logical_drive_queue_depth(
+ struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *logical_drive)
+{
+ unsigned int i;
+ struct raid_map *raid_map;
+ struct raid_map_disk_data *disk_data;
+ struct pqi_scsi_dev *phys_disk;
+ unsigned int num_phys_disks;
+ unsigned int num_raid_map_entries;
+ unsigned int queue_depth;
+
+ logical_drive->queue_depth = PQI_LOGICAL_DRIVE_DEFAULT_MAX_QUEUE_DEPTH;
+
+ raid_map = logical_drive->raid_map;
+ if (!raid_map)
+ return;
+
+ disk_data = raid_map->disk_data;
+ num_phys_disks = get_unaligned_le16(&raid_map->layout_map_count) *
+ (get_unaligned_le16(&raid_map->data_disks_per_row) +
+ get_unaligned_le16(&raid_map->metadata_disks_per_row));
+ num_raid_map_entries = num_phys_disks *
+ get_unaligned_le16(&raid_map->row_cnt);
+
+ queue_depth = 0;
+ for (i = 0; i < num_raid_map_entries; i++) {
+ phys_disk = pqi_find_disk_by_aio_handle(ctrl_info,
+ disk_data[i].aio_handle);
+
+ if (!phys_disk) {
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "failed to find physical disk for logical drive %016llx\n",
+ get_unaligned_be64(logical_drive->scsi3addr));
+ logical_drive->offload_enabled = false;
+ logical_drive->offload_enabled_pending = false;
+ kfree(raid_map);
+ logical_drive->raid_map = NULL;
+ return;
+ }
+
+ queue_depth += phys_disk->queue_depth;
+ }
+
+ logical_drive->queue_depth = queue_depth;
+}
+
+static void pqi_update_all_logical_drive_queue_depths(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ struct pqi_scsi_dev *device;
+
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (device->devtype != TYPE_DISK && device->devtype != TYPE_ZBC)
+ continue;
+ if (!pqi_is_logical_device(device))
+ continue;
+ pqi_update_logical_drive_queue_depth(ctrl_info, device);
+ }
+}
+
+static void pqi_rescan_worker(struct work_struct *work)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = container_of(to_delayed_work(work), struct pqi_ctrl_info,
+ rescan_work);
+
+ pqi_scan_scsi_devices(ctrl_info);
+}
+
+static int pqi_add_device(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+
+ if (pqi_is_logical_device(device))
+ rc = scsi_add_device(ctrl_info->scsi_host, device->bus,
+ device->target, device->lun);
+ else
+ rc = pqi_add_sas_device(ctrl_info->sas_host, device);
+
+ return rc;
+}
+
+static inline void pqi_remove_device(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ if (pqi_is_logical_device(device))
+ scsi_remove_device(device->sdev);
+ else
+ pqi_remove_sas_device(device);
+}
+
+/* Assumes the SCSI device list lock is held. */
+
+static struct pqi_scsi_dev *pqi_find_scsi_dev(struct pqi_ctrl_info *ctrl_info,
+ int bus, int target, int lun)
+{
+ struct pqi_scsi_dev *device;
+
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry)
+ if (device->bus == bus && device->target == target &&
+ device->lun == lun)
+ return device;
+
+ return NULL;
+}
+
+static inline bool pqi_device_equal(struct pqi_scsi_dev *dev1,
+ struct pqi_scsi_dev *dev2)
+{
+ if (dev1->is_physical_device != dev2->is_physical_device)
+ return false;
+
+ if (dev1->is_physical_device)
+ return dev1->wwid == dev2->wwid;
+
+ return memcmp(dev1->volume_id, dev2->volume_id,
+ sizeof(dev1->volume_id)) == 0;
+}
+
+enum pqi_find_result {
+ DEVICE_NOT_FOUND,
+ DEVICE_CHANGED,
+ DEVICE_SAME,
+};
+
+static enum pqi_find_result pqi_scsi_find_entry(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device_to_find,
+ struct pqi_scsi_dev **matching_device)
+{
+ struct pqi_scsi_dev *device;
+
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (pqi_scsi3addr_equal(device_to_find->scsi3addr,
+ device->scsi3addr)) {
+ *matching_device = device;
+ if (pqi_device_equal(device_to_find, device)) {
+ if (device_to_find->volume_offline)
+ return DEVICE_CHANGED;
+ return DEVICE_SAME;
+ }
+ return DEVICE_CHANGED;
+ }
+ }
+
+ return DEVICE_NOT_FOUND;
+}
+
+static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info,
+ char *action, struct pqi_scsi_dev *device)
+{
+ dev_info(&ctrl_info->pci_dev->dev,
+ "%s scsi %d:%d:%d:%d: %s %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
+ action,
+ ctrl_info->scsi_host->host_no,
+ device->bus,
+ device->target,
+ device->lun,
+ scsi_device_type(device->devtype),
+ device->vendor,
+ device->model,
+ pqi_raid_level_to_string(device->raid_level),
+ device->offload_configured ? '+' : '-',
+ device->offload_enabled_pending ? '+' : '-',
+ device->expose_device ? '+' : '-',
+ device->queue_depth);
+}
+
+/* Assumes the SCSI device list lock is held. */
+
+static void pqi_scsi_update_device(struct pqi_scsi_dev *existing_device,
+ struct pqi_scsi_dev *new_device)
+{
+ existing_device->devtype = new_device->devtype;
+ existing_device->device_type = new_device->device_type;
+ existing_device->bus = new_device->bus;
+ if (new_device->target_lun_valid) {
+ existing_device->target = new_device->target;
+ existing_device->lun = new_device->lun;
+ existing_device->target_lun_valid = true;
+ }
+
+ /* By definition, the scsi3addr and wwid fields are already the same. */
+
+ existing_device->is_physical_device = new_device->is_physical_device;
+ existing_device->expose_device = new_device->expose_device;
+ existing_device->no_uld_attach = new_device->no_uld_attach;
+ existing_device->aio_enabled = new_device->aio_enabled;
+ memcpy(existing_device->vendor, new_device->vendor,
+ sizeof(existing_device->vendor));
+ memcpy(existing_device->model, new_device->model,
+ sizeof(existing_device->model));
+ existing_device->sas_address = new_device->sas_address;
+ existing_device->raid_level = new_device->raid_level;
+ existing_device->queue_depth = new_device->queue_depth;
+ existing_device->aio_handle = new_device->aio_handle;
+ existing_device->volume_status = new_device->volume_status;
+ existing_device->active_path_index = new_device->active_path_index;
+ existing_device->path_map = new_device->path_map;
+ existing_device->bay = new_device->bay;
+ memcpy(existing_device->box, new_device->box,
+ sizeof(existing_device->box));
+ memcpy(existing_device->phys_connector, new_device->phys_connector,
+ sizeof(existing_device->phys_connector));
+ existing_device->offload_configured = new_device->offload_configured;
+ existing_device->offload_enabled = false;
+ existing_device->offload_enabled_pending =
+ new_device->offload_enabled_pending;
+ existing_device->offload_to_mirror = 0;
+ kfree(existing_device->raid_map);
+ existing_device->raid_map = new_device->raid_map;
+
+ /* To prevent this from being freed later. */
+ new_device->raid_map = NULL;
+}
+
+static inline void pqi_free_device(struct pqi_scsi_dev *device)
+{
+ if (device) {
+ kfree(device->raid_map);
+ kfree(device);
+ }
+}
+
+/*
+ * Called when exposing a new device to the OS fails in order to re-adjust
+ * our internal SCSI device list to match the SCSI ML's view.
+ */
+
+static inline void pqi_fixup_botched_add(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+ list_del(&device->scsi_device_list_entry);
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
+ /* Allow the device structure to be freed later. */
+ device->keep_device = false;
+}
+
+static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *new_device_list[], unsigned int num_new_devices)
+{
+ int rc;
+ unsigned int i;
+ unsigned long flags;
+ enum pqi_find_result find_result;
+ struct pqi_scsi_dev *device;
+ struct pqi_scsi_dev *next;
+ struct pqi_scsi_dev *matching_device;
+ struct list_head add_list;
+ struct list_head delete_list;
+
+ INIT_LIST_HEAD(&add_list);
+ INIT_LIST_HEAD(&delete_list);
+
+ /*
+ * The idea here is to do as little work as possible while holding the
+ * spinlock. That's why we go to great pains to defer anything other
+ * than updating the internal device list until after we release the
+ * spinlock.
+ */
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ /* Assume that all devices in the existing list have gone away. */
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry)
+ device->device_gone = true;
+
+ for (i = 0; i < num_new_devices; i++) {
+ device = new_device_list[i];
+
+ find_result = pqi_scsi_find_entry(ctrl_info, device,
+ &matching_device);
+
+ switch (find_result) {
+ case DEVICE_SAME:
+ /*
+ * The newly found device is already in the existing
+ * device list.
+ */
+ device->new_device = false;
+ matching_device->device_gone = false;
+ pqi_scsi_update_device(matching_device, device);
+ break;
+ case DEVICE_NOT_FOUND:
+ /*
+ * The newly found device is NOT in the existing device
+ * list.
+ */
+ device->new_device = true;
+ break;
+ case DEVICE_CHANGED:
+ /*
+ * The original device has gone away and we need to add
+ * the new device.
+ */
+ device->new_device = true;
+ break;
+ default:
+ WARN_ON(find_result);
+ break;
+ }
+ }
+
+ /* Process all devices that have gone away. */
+ list_for_each_entry_safe(device, next, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (device->device_gone) {
+ list_del(&device->scsi_device_list_entry);
+ list_add_tail(&device->delete_list_entry, &delete_list);
+ }
+ }
+
+ /* Process all new devices. */
+ for (i = 0; i < num_new_devices; i++) {
+ device = new_device_list[i];
+ if (!device->new_device)
+ continue;
+ if (device->volume_offline)
+ continue;
+ list_add_tail(&device->scsi_device_list_entry,
+ &ctrl_info->scsi_device_list);
+ list_add_tail(&device->add_list_entry, &add_list);
+ /* To prevent this device structure from being freed later. */
+ device->keep_device = true;
+ }
+
+ pqi_update_all_logical_drive_queue_depths(ctrl_info);
+
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry)
+ device->offload_enabled =
+ device->offload_enabled_pending;
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
+ /* Remove all devices that have gone away. */
+ list_for_each_entry_safe(device, next, &delete_list,
+ delete_list_entry) {
+ if (device->sdev)
+ pqi_remove_device(ctrl_info, device);
+ if (device->volume_offline) {
+ pqi_dev_info(ctrl_info, "offline", device);
+ pqi_show_volume_status(ctrl_info, device);
+ } else {
+ pqi_dev_info(ctrl_info, "removed", device);
+ }
+ list_del(&device->delete_list_entry);
+ pqi_free_device(device);
+ }
+
+ /*
+ * Notify the SCSI ML if the queue depth of any existing device has
+ * changed.
+ */
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (device->sdev && device->queue_depth !=
+ device->advertised_queue_depth) {
+ device->advertised_queue_depth = device->queue_depth;
+ scsi_change_queue_depth(device->sdev,
+ device->advertised_queue_depth);
+ }
+ }
+
+ /* Expose any new devices. */
+ list_for_each_entry_safe(device, next, &add_list, add_list_entry) {
+ if (device->expose_device && !device->sdev) {
+ rc = pqi_add_device(ctrl_info, device);
+ if (rc) {
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "scsi %d:%d:%d:%d addition failed, device not added\n",
+ ctrl_info->scsi_host->host_no,
+ device->bus, device->target,
+ device->lun);
+ pqi_fixup_botched_add(ctrl_info, device);
+ continue;
+ }
+ }
+ pqi_dev_info(ctrl_info, "added", device);
+ }
+}
+
+static bool pqi_is_supported_device(struct pqi_scsi_dev *device)
+{
+ bool is_supported = false;
+
+ switch (device->devtype) {
+ case TYPE_DISK:
+ case TYPE_ZBC:
+ case TYPE_TAPE:
+ case TYPE_MEDIUM_CHANGER:
+ case TYPE_ENCLOSURE:
+ is_supported = true;
+ break;
+ case TYPE_RAID:
+ /*
+ * Only support the HBA controller itself as a RAID
+ * controller. If it's a RAID controller other than
+ * the HBA itself (an external RAID controller, MSA500
+ * or similar), we don't support it.
+ */
+ if (pqi_is_hba_lunid(device->scsi3addr))
+ is_supported = true;
+ break;
+ }
+
+ return is_supported;
+}
+
+static inline bool pqi_skip_device(u8 *scsi3addr,
+ struct report_phys_lun_extended_entry *phys_lun_ext_entry)
+{
+ u8 device_flags;
+
+ if (!MASKED_DEVICE(scsi3addr))
+ return false;
+
+ /* The device is masked. */
+
+ device_flags = phys_lun_ext_entry->device_flags;
+
+ if (device_flags & REPORT_PHYS_LUN_DEV_FLAG_NON_DISK) {
+ /*
+ * It's a non-disk device. We ignore all devices of this type
+ * when they're masked.
+ */
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool pqi_expose_device(struct pqi_scsi_dev *device)
+{
+ /* Expose all devices except for physical devices that are masked. */
+ if (device->is_physical_device && MASKED_DEVICE(device->scsi3addr))
+ return false;
+
+ return true;
+}
+
+static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
+{
+ int i;
+ int rc;
+ struct list_head new_device_list_head;
+ struct report_phys_lun_extended *physdev_list = NULL;
+ struct report_log_lun_extended *logdev_list = NULL;
+ struct report_phys_lun_extended_entry *phys_lun_ext_entry;
+ struct report_log_lun_extended_entry *log_lun_ext_entry;
+ struct bmic_identify_physical_device *id_phys = NULL;
+ u32 num_physicals;
+ u32 num_logicals;
+ struct pqi_scsi_dev **new_device_list = NULL;
+ struct pqi_scsi_dev *device;
+ struct pqi_scsi_dev *next;
+ unsigned int num_new_devices;
+ unsigned int num_valid_devices;
+ bool is_physical_device;
+ u8 *scsi3addr;
+ static char *out_of_memory_msg =
+ "out of memory, device discovery stopped";
+
+ INIT_LIST_HEAD(&new_device_list_head);
+
+ rc = pqi_get_device_lists(ctrl_info, &physdev_list, &logdev_list);
+ if (rc)
+ goto out;
+
+ if (physdev_list)
+ num_physicals =
+ get_unaligned_be32(&physdev_list->header.list_length)
+ / sizeof(physdev_list->lun_entries[0]);
+ else
+ num_physicals = 0;
+
+ if (logdev_list)
+ num_logicals =
+ get_unaligned_be32(&logdev_list->header.list_length)
+ / sizeof(logdev_list->lun_entries[0]);
+ else
+ num_logicals = 0;
+
+ if (num_physicals) {
+ /*
+ * We need this buffer for calls to pqi_get_physical_disk_info()
+ * below. We allocate it here instead of inside
+ * pqi_get_physical_disk_info() because it's a fairly large
+ * buffer.
+ */
+ id_phys = kmalloc(sizeof(*id_phys), GFP_KERNEL);
+ if (!id_phys) {
+ dev_warn(&ctrl_info->pci_dev->dev, "%s\n",
+ out_of_memory_msg);
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
+
+ num_new_devices = num_physicals + num_logicals;
+
+ new_device_list = kmalloc(sizeof(*new_device_list) *
+ num_new_devices, GFP_KERNEL);
+ if (!new_device_list) {
+ dev_warn(&ctrl_info->pci_dev->dev, "%s\n", out_of_memory_msg);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < num_new_devices; i++) {
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ dev_warn(&ctrl_info->pci_dev->dev, "%s\n",
+ out_of_memory_msg);
+ rc = -ENOMEM;
+ goto out;
+ }
+ list_add_tail(&device->new_device_list_entry,
+ &new_device_list_head);
+ }
+
+ device = NULL;
+ num_valid_devices = 0;
+
+ for (i = 0; i < num_new_devices; i++) {
+
+ if (i < num_physicals) {
+ is_physical_device = true;
+ phys_lun_ext_entry = &physdev_list->lun_entries[i];
+ log_lun_ext_entry = NULL;
+ scsi3addr = phys_lun_ext_entry->lunid;
+ } else {
+ is_physical_device = false;
+ phys_lun_ext_entry = NULL;
+ log_lun_ext_entry =
+ &logdev_list->lun_entries[i - num_physicals];
+ scsi3addr = log_lun_ext_entry->lunid;
+ }
+
+ if (is_physical_device &&
+ pqi_skip_device(scsi3addr, phys_lun_ext_entry))
+ continue;
+
+ if (device)
+ device = list_next_entry(device, new_device_list_entry);
+ else
+ device = list_first_entry(&new_device_list_head,
+ struct pqi_scsi_dev, new_device_list_entry);
+
+ memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
+ device->is_physical_device = is_physical_device;
+ device->raid_level = SA_RAID_UNKNOWN;
+
+ /* Gather information about the device. */
+ rc = pqi_get_device_info(ctrl_info, device);
+ if (rc == -ENOMEM) {
+ dev_warn(&ctrl_info->pci_dev->dev, "%s\n",
+ out_of_memory_msg);
+ goto out;
+ }
+ if (rc) {
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "obtaining device info failed, skipping device %016llx\n",
+ get_unaligned_be64(device->scsi3addr));
+ rc = 0;
+ continue;
+ }
+
+ if (!pqi_is_supported_device(device))
+ continue;
+
+ pqi_assign_bus_target_lun(device);
+
+ device->expose_device = pqi_expose_device(device);
+
+ if (device->is_physical_device) {
+ device->wwid = phys_lun_ext_entry->wwid;
+ if ((phys_lun_ext_entry->device_flags &
+ REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED) &&
+ phys_lun_ext_entry->aio_handle)
+ device->aio_enabled = true;
+ } else {
+ memcpy(device->volume_id, log_lun_ext_entry->volume_id,
+ sizeof(device->volume_id));
+ }
+
+ switch (device->devtype) {
+ case TYPE_DISK:
+ case TYPE_ZBC:
+ case TYPE_ENCLOSURE:
+ if (device->is_physical_device) {
+ device->sas_address =
+ get_unaligned_be64(&device->wwid);
+ if (device->devtype == TYPE_DISK ||
+ device->devtype == TYPE_ZBC) {
+ device->aio_handle =
+ phys_lun_ext_entry->aio_handle;
+ pqi_get_physical_disk_info(ctrl_info,
+ device, id_phys);
+ }
+ }
+ break;
+ }
+
+ new_device_list[num_valid_devices++] = device;
+ }
+
+ pqi_update_device_list(ctrl_info, new_device_list, num_valid_devices);
+
+out:
+ list_for_each_entry_safe(device, next, &new_device_list_head,
+ new_device_list_entry) {
+ if (device->keep_device)
+ continue;
+ list_del(&device->new_device_list_entry);
+ pqi_free_device(device);
+ }
+
+ kfree(new_device_list);
+ kfree(physdev_list);
+ kfree(logdev_list);
+ kfree(id_phys);
+
+ return rc;
+}
+
+static void pqi_remove_all_scsi_devices(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned long flags;
+ struct pqi_scsi_dev *device;
+ struct pqi_scsi_dev *next;
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ list_for_each_entry_safe(device, next, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (device->sdev)
+ pqi_remove_device(ctrl_info, device);
+ list_del(&device->scsi_device_list_entry);
+ pqi_free_device(device);
+ }
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+}
+
+static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+
+ mutex_lock(&ctrl_info->scan_mutex);
+
+ rc = pqi_update_scsi_devices(ctrl_info);
+ if (rc)
+ pqi_schedule_rescan_worker(ctrl_info);
+
+ mutex_unlock(&ctrl_info->scan_mutex);
+
+ return rc;
+}
+
+static void pqi_scan_start(struct Scsi_Host *shost)
+{
+ pqi_scan_scsi_devices(shost_to_hba(shost));
+}
+
+/* Returns TRUE if scan is finished. */
+
+static int pqi_scan_finished(struct Scsi_Host *shost,
+ unsigned long elapsed_time)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = shost_priv(shost);
+
+ return !mutex_is_locked(&ctrl_info->scan_mutex);
+}
+
+static inline void pqi_set_encryption_info(
+ struct pqi_encryption_info *encryption_info, struct raid_map *raid_map,
+ u64 first_block)
+{
+ u32 volume_blk_size;
+
+ /*
+ * Set the encryption tweak values based on logical block address.
+ * If the block size is 512, the tweak value is equal to the LBA.
+ * For other block sizes, tweak value is (LBA * block size) / 512.
+ */
+ volume_blk_size = get_unaligned_le32(&raid_map->volume_blk_size);
+ if (volume_blk_size != 512)
+ first_block = (first_block * volume_blk_size) / 512;
+
+ encryption_info->data_encryption_key_index =
+ get_unaligned_le16(&raid_map->data_encryption_key_index);
+ encryption_info->encrypt_tweak_lower = lower_32_bits(first_block);
+ encryption_info->encrypt_tweak_upper = upper_32_bits(first_block);
+}
+
+/*
+ * Attempt to perform offload RAID mapping for a logical volume I/O.
+ */
+
+#define PQI_RAID_BYPASS_INELIGIBLE 1
+
+static int pqi_raid_bypass_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device, struct scsi_cmnd *scmd,
+ struct pqi_queue_group *queue_group)
+{
+ struct raid_map *raid_map;
+ bool is_write = false;
+ u32 map_index;
+ u64 first_block;
+ u64 last_block;
+ u32 block_cnt;
+ u32 blocks_per_row;
+ u64 first_row;
+ u64 last_row;
+ u32 first_row_offset;
+ u32 last_row_offset;
+ u32 first_column;
+ u32 last_column;
+ u64 r0_first_row;
+ u64 r0_last_row;
+ u32 r5or6_blocks_per_row;
+ u64 r5or6_first_row;
+ u64 r5or6_last_row;
+ u32 r5or6_first_row_offset;
+ u32 r5or6_last_row_offset;
+ u32 r5or6_first_column;
+ u32 r5or6_last_column;
+ u16 data_disks_per_row;
+ u32 total_disks_per_row;
+ u16 layout_map_count;
+ u32 stripesize;
+ u16 strip_size;
+ u32 first_group;
+ u32 last_group;
+ u32 current_group;
+ u32 map_row;
+ u32 aio_handle;
+ u64 disk_block;
+ u32 disk_block_cnt;
+ u8 cdb[16];
+ u8 cdb_length;
+ int offload_to_mirror;
+ struct pqi_encryption_info *encryption_info_ptr;
+ struct pqi_encryption_info encryption_info;
+#if BITS_PER_LONG == 32
+ u64 tmpdiv;
+#endif
+
+ /* Check for valid opcode, get LBA and block count. */
+ switch (scmd->cmnd[0]) {
+ case WRITE_6:
+ is_write = true;
+ /* fall through */
+ case READ_6:
+ first_block = (u64)(((scmd->cmnd[1] & 0x1f) << 16) |
+ (scmd->cmnd[2] << 8) | scmd->cmnd[3]);
+ block_cnt = (u32)scmd->cmnd[4];
+ if (block_cnt == 0)
+ block_cnt = 256;
+ break;
+ case WRITE_10:
+ is_write = true;
+ /* fall through */
+ case READ_10:
+ first_block = (u64)get_unaligned_be32(&scmd->cmnd[2]);
+ block_cnt = (u32)get_unaligned_be16(&scmd->cmnd[7]);
+ break;
+ case WRITE_12:
+ is_write = true;
+ /* fall through */
+ case READ_12:
+ first_block = (u64)get_unaligned_be32(&scmd->cmnd[2]);
+ block_cnt = get_unaligned_be32(&scmd->cmnd[6]);
+ break;
+ case WRITE_16:
+ is_write = true;
+ /* fall through */
+ case READ_16:
+ first_block = get_unaligned_be64(&scmd->cmnd[2]);
+ block_cnt = get_unaligned_be32(&scmd->cmnd[10]);
+ break;
+ default:
+ /* Process via normal I/O path. */
+ return PQI_RAID_BYPASS_INELIGIBLE;
+ }
+
+ /* Check for write to non-RAID-0. */
+ if (is_write && device->raid_level != SA_RAID_0)
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ if (unlikely(block_cnt == 0))
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ last_block = first_block + block_cnt - 1;
+ raid_map = device->raid_map;
+
+ /* Check for invalid block or wraparound. */
+ if (last_block >= get_unaligned_le64(&raid_map->volume_blk_cnt) ||
+ last_block < first_block)
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ data_disks_per_row = get_unaligned_le16(&raid_map->data_disks_per_row);
+ strip_size = get_unaligned_le16(&raid_map->strip_size);
+ layout_map_count = get_unaligned_le16(&raid_map->layout_map_count);
+
+ /* Calculate stripe information for the request. */
+ blocks_per_row = data_disks_per_row * strip_size;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ do_div(tmpdiv, blocks_per_row);
+ first_row = tmpdiv;
+ tmpdiv = last_block;
+ do_div(tmpdiv, blocks_per_row);
+ last_row = tmpdiv;
+ first_row_offset = (u32)(first_block - (first_row * blocks_per_row));
+ last_row_offset = (u32)(last_block - (last_row * blocks_per_row));
+ tmpdiv = first_row_offset;
+ do_div(tmpdiv, strip_size);
+ first_column = tmpdiv;
+ tmpdiv = last_row_offset;
+ do_div(tmpdiv, strip_size);
+ last_column = tmpdiv;
+#else
+ first_row = first_block / blocks_per_row;
+ last_row = last_block / blocks_per_row;
+ first_row_offset = (u32)(first_block - (first_row * blocks_per_row));
+ last_row_offset = (u32)(last_block - (last_row * blocks_per_row));
+ first_column = first_row_offset / strip_size;
+ last_column = last_row_offset / strip_size;
+#endif
+
+ /* If this isn't a single row/column then give to the controller. */
+ if (first_row != last_row || first_column != last_column)
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ /* Proceeding with driver mapping. */
+ total_disks_per_row = data_disks_per_row +
+ get_unaligned_le16(&raid_map->metadata_disks_per_row);
+ map_row = ((u32)(first_row >> raid_map->parity_rotation_shift)) %
+ get_unaligned_le16(&raid_map->row_cnt);
+ map_index = (map_row * total_disks_per_row) + first_column;
+
+ /* RAID 1 */
+ if (device->raid_level == SA_RAID_1) {
+ if (device->offload_to_mirror)
+ map_index += data_disks_per_row;
+ device->offload_to_mirror = !device->offload_to_mirror;
+ } else if (device->raid_level == SA_RAID_ADM) {
+ /* RAID ADM */
+ /*
+ * Handles N-way mirrors (R1-ADM) and R10 with # of drives
+ * divisible by 3.
+ */
+ offload_to_mirror = device->offload_to_mirror;
+ if (offload_to_mirror == 0) {
+ /* use physical disk in the first mirrored group. */
+ map_index %= data_disks_per_row;
+ } else {
+ do {
+ /*
+ * Determine mirror group that map_index
+ * indicates.
+ */
+ current_group = map_index / data_disks_per_row;
+
+ if (offload_to_mirror != current_group) {
+ if (current_group <
+ layout_map_count - 1) {
+ /*
+ * Select raid index from
+ * next group.
+ */
+ map_index += data_disks_per_row;
+ current_group++;
+ } else {
+ /*
+ * Select raid index from first
+ * group.
+ */
+ map_index %= data_disks_per_row;
+ current_group = 0;
+ }
+ }
+ } while (offload_to_mirror != current_group);
+ }
+
+ /* Set mirror group to use next time. */
+ offload_to_mirror =
+ (offload_to_mirror >= layout_map_count - 1) ?
+ 0 : offload_to_mirror + 1;
+ WARN_ON(offload_to_mirror >= layout_map_count);
+ device->offload_to_mirror = offload_to_mirror;
+ /*
+ * Avoid direct use of device->offload_to_mirror within this
+ * function since multiple threads might simultaneously
+ * increment it beyond the range of device->layout_map_count -1.
+ */
+ } else if ((device->raid_level == SA_RAID_5 ||
+ device->raid_level == SA_RAID_6) && layout_map_count > 1) {
+ /* RAID 50/60 */
+ /* Verify first and last block are in same RAID group */
+ r5or6_blocks_per_row = strip_size * data_disks_per_row;
+ stripesize = r5or6_blocks_per_row * layout_map_count;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_group = do_div(tmpdiv, stripesize);
+ tmpdiv = first_group;
+ do_div(tmpdiv, r5or6_blocks_per_row);
+ first_group = tmpdiv;
+ tmpdiv = last_block;
+ last_group = do_div(tmpdiv, stripesize);
+ tmpdiv = last_group;
+ do_div(tmpdiv, r5or6_blocks_per_row);
+ last_group = tmpdiv;
+#else
+ first_group = (first_block % stripesize) / r5or6_blocks_per_row;
+ last_group = (last_block % stripesize) / r5or6_blocks_per_row;
+#endif
+ if (first_group != last_group)
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ /* Verify request is in a single row of RAID 5/6 */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ do_div(tmpdiv, stripesize);
+ first_row = r5or6_first_row = r0_first_row = tmpdiv;
+ tmpdiv = last_block;
+ do_div(tmpdiv, stripesize);
+ r5or6_last_row = r0_last_row = tmpdiv;
+#else
+ first_row = r5or6_first_row = r0_first_row =
+ first_block / stripesize;
+ r5or6_last_row = r0_last_row = last_block / stripesize;
+#endif
+ if (r5or6_first_row != r5or6_last_row)
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ /* Verify request is in a single column */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_row_offset = do_div(tmpdiv, stripesize);
+ tmpdiv = first_row_offset;
+ first_row_offset = (u32)do_div(tmpdiv, r5or6_blocks_per_row);
+ r5or6_first_row_offset = first_row_offset;
+ tmpdiv = last_block;
+ r5or6_last_row_offset = do_div(tmpdiv, stripesize);
+ tmpdiv = r5or6_last_row_offset;
+ r5or6_last_row_offset = do_div(tmpdiv, r5or6_blocks_per_row);
+ tmpdiv = r5or6_first_row_offset;
+ do_div(tmpdiv, strip_size);
+ first_column = r5or6_first_column = tmpdiv;
+ tmpdiv = r5or6_last_row_offset;
+ do_div(tmpdiv, strip_size);
+ r5or6_last_column = tmpdiv;
+#else
+ first_row_offset = r5or6_first_row_offset =
+ (u32)((first_block % stripesize) %
+ r5or6_blocks_per_row);
+
+ r5or6_last_row_offset =
+ (u32)((last_block % stripesize) %
+ r5or6_blocks_per_row);
+
+ first_column = r5or6_first_row_offset / strip_size;
+ r5or6_first_column = first_column;
+ r5or6_last_column = r5or6_last_row_offset / strip_size;
+#endif
+ if (r5or6_first_column != r5or6_last_column)
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ /* Request is eligible */
+ map_row =
+ ((u32)(first_row >> raid_map->parity_rotation_shift)) %
+ get_unaligned_le16(&raid_map->row_cnt);
+
+ map_index = (first_group *
+ (get_unaligned_le16(&raid_map->row_cnt) *
+ total_disks_per_row)) +
+ (map_row * total_disks_per_row) + first_column;
+ }
+
+ if (unlikely(map_index >= RAID_MAP_MAX_ENTRIES))
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ aio_handle = raid_map->disk_data[map_index].aio_handle;
+ disk_block = get_unaligned_le64(&raid_map->disk_starting_blk) +
+ first_row * strip_size +
+ (first_row_offset - first_column * strip_size);
+ disk_block_cnt = block_cnt;
+
+ /* Handle differing logical/physical block sizes. */
+ if (raid_map->phys_blk_shift) {
+ disk_block <<= raid_map->phys_blk_shift;
+ disk_block_cnt <<= raid_map->phys_blk_shift;
+ }
+
+ if (unlikely(disk_block_cnt > 0xffff))
+ return PQI_RAID_BYPASS_INELIGIBLE;
+
+ /* Build the new CDB for the physical disk I/O. */
+ if (disk_block > 0xffffffff) {
+ cdb[0] = is_write ? WRITE_16 : READ_16;
+ cdb[1] = 0;
+ put_unaligned_be64(disk_block, &cdb[2]);
+ put_unaligned_be32(disk_block_cnt, &cdb[10]);
+ cdb[14] = 0;
+ cdb[15] = 0;
+ cdb_length = 16;
+ } else {
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ put_unaligned_be32((u32)disk_block, &cdb[2]);
+ cdb[6] = 0;
+ put_unaligned_be16((u16)disk_block_cnt, &cdb[7]);
+ cdb[9] = 0;
+ cdb_length = 10;
+ }
+
+ if (get_unaligned_le16(&raid_map->flags) &
+ RAID_MAP_ENCRYPTION_ENABLED) {
+ pqi_set_encryption_info(&encryption_info, raid_map,
+ first_block);
+ encryption_info_ptr = &encryption_info;
+ } else {
+ encryption_info_ptr = NULL;
+ }
+
+ return pqi_aio_submit_io(ctrl_info, scmd, aio_handle,
+ cdb, cdb_length, queue_group, encryption_info_ptr);
+}
+
+#define PQI_STATUS_IDLE 0x0
+
+#define PQI_CREATE_ADMIN_QUEUE_PAIR 1
+#define PQI_DELETE_ADMIN_QUEUE_PAIR 2
+
+#define PQI_DEVICE_STATE_POWER_ON_AND_RESET 0x0
+#define PQI_DEVICE_STATE_STATUS_AVAILABLE 0x1
+#define PQI_DEVICE_STATE_ALL_REGISTERS_READY 0x2
+#define PQI_DEVICE_STATE_ADMIN_QUEUE_PAIR_READY 0x3
+#define PQI_DEVICE_STATE_ERROR 0x4
+
+#define PQI_MODE_READY_TIMEOUT_SECS 30
+#define PQI_MODE_READY_POLL_INTERVAL_MSECS 1
+
+static int pqi_wait_for_pqi_mode_ready(struct pqi_ctrl_info *ctrl_info)
+{
+ struct pqi_device_registers __iomem *pqi_registers;
+ unsigned long timeout;
+ u64 signature;
+ u8 status;
+
+ pqi_registers = ctrl_info->pqi_registers;
+ timeout = (PQI_MODE_READY_TIMEOUT_SECS * HZ) + jiffies;
+
+ while (1) {
+ signature = readq(&pqi_registers->signature);
+ if (memcmp(&signature, PQI_DEVICE_SIGNATURE,
+ sizeof(signature)) == 0)
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "timed out waiting for PQI signature\n");
+ return -ETIMEDOUT;
+ }
+ msleep(PQI_MODE_READY_POLL_INTERVAL_MSECS);
+ }
+
+ while (1) {
+ status = readb(&pqi_registers->function_and_status_code);
+ if (status == PQI_STATUS_IDLE)
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "timed out waiting for PQI IDLE\n");
+ return -ETIMEDOUT;
+ }
+ msleep(PQI_MODE_READY_POLL_INTERVAL_MSECS);
+ }
+
+ while (1) {
+ if (readl(&pqi_registers->device_status) ==
+ PQI_DEVICE_STATE_ALL_REGISTERS_READY)
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "timed out waiting for PQI all registers ready\n");
+ return -ETIMEDOUT;
+ }
+ msleep(PQI_MODE_READY_POLL_INTERVAL_MSECS);
+ }
+
+ return 0;
+}
+
+static inline void pqi_aio_path_disabled(struct pqi_io_request *io_request)
+{
+ struct pqi_scsi_dev *device;
+
+ device = io_request->scmd->device->hostdata;
+ device->offload_enabled = false;
+}
+
+static inline void pqi_take_device_offline(struct scsi_device *sdev)
+{
+ struct pqi_ctrl_info *ctrl_info;
+ struct pqi_scsi_dev *device;
+
+ if (scsi_device_online(sdev)) {
+ scsi_device_set_state(sdev, SDEV_OFFLINE);
+ ctrl_info = shost_to_hba(sdev->host);
+ schedule_delayed_work(&ctrl_info->rescan_work, 0);
+ device = sdev->hostdata;
+ dev_err(&ctrl_info->pci_dev->dev, "offlined scsi %d:%d:%d:%d\n",
+ ctrl_info->scsi_host->host_no, device->bus,
+ device->target, device->lun);
+ }
+}
+
+static void pqi_process_raid_io_error(struct pqi_io_request *io_request)
+{
+ u8 scsi_status;
+ u8 host_byte;
+ struct scsi_cmnd *scmd;
+ struct pqi_raid_error_info *error_info;
+ size_t sense_data_length;
+ int residual_count;
+ int xfer_count;
+ struct scsi_sense_hdr sshdr;
+
+ scmd = io_request->scmd;
+ if (!scmd)
+ return;
+
+ error_info = io_request->error_info;
+ scsi_status = error_info->status;
+ host_byte = DID_OK;
+
+ if (error_info->data_out_result == PQI_DATA_IN_OUT_UNDERFLOW) {
+ xfer_count =
+ get_unaligned_le32(&error_info->data_out_transferred);
+ residual_count = scsi_bufflen(scmd) - xfer_count;
+ scsi_set_resid(scmd, residual_count);
+ if (xfer_count < scmd->underflow)
+ host_byte = DID_SOFT_ERROR;
+ }
+
+ sense_data_length = get_unaligned_le16(&error_info->sense_data_length);
+ if (sense_data_length == 0)
+ sense_data_length =
+ get_unaligned_le16(&error_info->response_data_length);
+ if (sense_data_length) {
+ if (sense_data_length > sizeof(error_info->data))
+ sense_data_length = sizeof(error_info->data);
+
+ if (scsi_status == SAM_STAT_CHECK_CONDITION &&
+ scsi_normalize_sense(error_info->data,
+ sense_data_length, &sshdr) &&
+ sshdr.sense_key == HARDWARE_ERROR &&
+ sshdr.asc == 0x3e &&
+ sshdr.ascq == 0x1) {
+ pqi_take_device_offline(scmd->device);
+ host_byte = DID_NO_CONNECT;
+ }
+
+ if (sense_data_length > SCSI_SENSE_BUFFERSIZE)
+ sense_data_length = SCSI_SENSE_BUFFERSIZE;
+ memcpy(scmd->sense_buffer, error_info->data,
+ sense_data_length);
+ }
+
+ scmd->result = scsi_status;
+ set_host_byte(scmd, host_byte);
+}
+
+static void pqi_process_aio_io_error(struct pqi_io_request *io_request)
+{
+ u8 scsi_status;
+ u8 host_byte;
+ struct scsi_cmnd *scmd;
+ struct pqi_aio_error_info *error_info;
+ size_t sense_data_length;
+ int residual_count;
+ int xfer_count;
+ bool device_offline;
+
+ scmd = io_request->scmd;
+ error_info = io_request->error_info;
+ host_byte = DID_OK;
+ sense_data_length = 0;
+ device_offline = false;
+
+ switch (error_info->service_response) {
+ case PQI_AIO_SERV_RESPONSE_COMPLETE:
+ scsi_status = error_info->status;
+ break;
+ case PQI_AIO_SERV_RESPONSE_FAILURE:
+ switch (error_info->status) {
+ case PQI_AIO_STATUS_IO_ABORTED:
+ scsi_status = SAM_STAT_TASK_ABORTED;
+ break;
+ case PQI_AIO_STATUS_UNDERRUN:
+ scsi_status = SAM_STAT_GOOD;
+ residual_count = get_unaligned_le32(
+ &error_info->residual_count);
+ scsi_set_resid(scmd, residual_count);
+ xfer_count = scsi_bufflen(scmd) - residual_count;
+ if (xfer_count < scmd->underflow)
+ host_byte = DID_SOFT_ERROR;
+ break;
+ case PQI_AIO_STATUS_OVERRUN:
+ scsi_status = SAM_STAT_GOOD;
+ break;
+ case PQI_AIO_STATUS_AIO_PATH_DISABLED:
+ pqi_aio_path_disabled(io_request);
+ scsi_status = SAM_STAT_GOOD;
+ io_request->status = -EAGAIN;
+ break;
+ case PQI_AIO_STATUS_NO_PATH_TO_DEVICE:
+ case PQI_AIO_STATUS_INVALID_DEVICE:
+ device_offline = true;
+ pqi_take_device_offline(scmd->device);
+ host_byte = DID_NO_CONNECT;
+ scsi_status = SAM_STAT_CHECK_CONDITION;
+ break;
+ case PQI_AIO_STATUS_IO_ERROR:
+ default:
+ scsi_status = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+ break;
+ case PQI_AIO_SERV_RESPONSE_TMF_COMPLETE:
+ case PQI_AIO_SERV_RESPONSE_TMF_SUCCEEDED:
+ scsi_status = SAM_STAT_GOOD;
+ break;
+ case PQI_AIO_SERV_RESPONSE_TMF_REJECTED:
+ case PQI_AIO_SERV_RESPONSE_TMF_INCORRECT_LUN:
+ default:
+ scsi_status = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+
+ if (error_info->data_present) {
+ sense_data_length =
+ get_unaligned_le16(&error_info->data_length);
+ if (sense_data_length) {
+ if (sense_data_length > sizeof(error_info->data))
+ sense_data_length = sizeof(error_info->data);
+ if (sense_data_length > SCSI_SENSE_BUFFERSIZE)
+ sense_data_length = SCSI_SENSE_BUFFERSIZE;
+ memcpy(scmd->sense_buffer, error_info->data,
+ sense_data_length);
+ }
+ }
+
+ if (device_offline && sense_data_length == 0)
+ scsi_build_sense_buffer(0, scmd->sense_buffer, HARDWARE_ERROR,
+ 0x3e, 0x1);
+
+ scmd->result = scsi_status;
+ set_host_byte(scmd, host_byte);
+}
+
+static void pqi_process_io_error(unsigned int iu_type,
+ struct pqi_io_request *io_request)
+{
+ switch (iu_type) {
+ case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR:
+ pqi_process_raid_io_error(io_request);
+ break;
+ case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR:
+ pqi_process_aio_io_error(io_request);
+ break;
+ }
+}
+
+static int pqi_interpret_task_management_response(
+ struct pqi_task_management_response *response)
+{
+ int rc;
+
+ switch (response->response_code) {
+ case SOP_TMF_COMPLETE:
+ case SOP_TMF_FUNCTION_SUCCEEDED:
+ rc = 0;
+ break;
+ default:
+ rc = -EIO;
+ break;
+ }
+
+ return rc;
+}
+
+static unsigned int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_queue_group *queue_group)
+{
+ unsigned int num_responses;
+ pqi_index_t oq_pi;
+ pqi_index_t oq_ci;
+ struct pqi_io_request *io_request;
+ struct pqi_io_response *response;
+ u16 request_id;
+
+ num_responses = 0;
+ oq_ci = queue_group->oq_ci_copy;
+
+ while (1) {
+ oq_pi = *queue_group->oq_pi;
+ if (oq_pi == oq_ci)
+ break;
+
+ num_responses++;
+ response = queue_group->oq_element_array +
+ (oq_ci * PQI_OPERATIONAL_OQ_ELEMENT_LENGTH);
+
+ request_id = get_unaligned_le16(&response->request_id);
+ WARN_ON(request_id >= ctrl_info->max_io_slots);
+
+ io_request = &ctrl_info->io_request_pool[request_id];
+ WARN_ON(atomic_read(&io_request->refcount) == 0);
+
+ switch (response->header.iu_type) {
+ case PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS:
+ case PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS:
+ case PQI_RESPONSE_IU_GENERAL_MANAGEMENT:
+ break;
+ case PQI_RESPONSE_IU_TASK_MANAGEMENT:
+ io_request->status =
+ pqi_interpret_task_management_response(
+ (void *)response);
+ break;
+ case PQI_RESPONSE_IU_AIO_PATH_DISABLED:
+ pqi_aio_path_disabled(io_request);
+ io_request->status = -EAGAIN;
+ break;
+ case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR:
+ case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR:
+ io_request->error_info = ctrl_info->error_buffer +
+ (get_unaligned_le16(&response->error_index) *
+ PQI_ERROR_BUFFER_ELEMENT_LENGTH);
+ pqi_process_io_error(response->header.iu_type,
+ io_request);
+ break;
+ default:
+ dev_err(&ctrl_info->pci_dev->dev,
+ "unexpected IU type: 0x%x\n",
+ response->header.iu_type);
+ WARN_ON(response->header.iu_type);
+ break;
+ }
+
+ io_request->io_complete_callback(io_request,
+ io_request->context);
+
+ /*
+ * Note that the I/O request structure CANNOT BE TOUCHED after
+ * returning from the I/O completion callback!
+ */
+
+ oq_ci = (oq_ci + 1) % ctrl_info->num_elements_per_oq;
+ }
+
+ if (num_responses) {
+ queue_group->oq_ci_copy = oq_ci;
+ writel(oq_ci, queue_group->oq_ci);
+ }
+
+ return num_responses;
+}
+
+static inline unsigned int pqi_num_elements_free(unsigned int pi,
+ unsigned int ci, unsigned int elements_in_queue)
+{
+ unsigned int num_elements_used;
+
+ if (pi >= ci)
+ num_elements_used = pi - ci;
+ else
+ num_elements_used = elements_in_queue - ci + pi;
+
+ return elements_in_queue - num_elements_used - 1;
+}
+
+#define PQI_EVENT_ACK_TIMEOUT 30
+
+static void pqi_start_event_ack(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_event_acknowledge_request *iu, size_t iu_length)
+{
+ pqi_index_t iq_pi;
+ pqi_index_t iq_ci;
+ unsigned long flags;
+ void *next_element;
+ unsigned long timeout;
+ struct pqi_queue_group *queue_group;
+
+ queue_group = &ctrl_info->queue_groups[PQI_DEFAULT_QUEUE_GROUP];
+ put_unaligned_le16(queue_group->oq_id, &iu->header.response_queue_id);
+
+ timeout = (PQI_EVENT_ACK_TIMEOUT * HZ) + jiffies;
+
+ while (1) {
+ spin_lock_irqsave(&queue_group->submit_lock[RAID_PATH], flags);
+
+ iq_pi = queue_group->iq_pi_copy[RAID_PATH];
+ iq_ci = *queue_group->iq_ci[RAID_PATH];
+
+ if (pqi_num_elements_free(iq_pi, iq_ci,
+ ctrl_info->num_elements_per_iq))
+ break;
+
+ spin_unlock_irqrestore(
+ &queue_group->submit_lock[RAID_PATH], flags);
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "sending event acknowledge timed out\n");
+ return;
+ }
+ }
+
+ next_element = queue_group->iq_element_array[RAID_PATH] +
+ (iq_pi * PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+
+ memcpy(next_element, iu, iu_length);
+
+ iq_pi = (iq_pi + 1) % ctrl_info->num_elements_per_iq;
+
+ queue_group->iq_pi_copy[RAID_PATH] = iq_pi;
+
+ /*
+ * This write notifies the controller that an IU is available to be
+ * processed.
+ */
+ writel(iq_pi, queue_group->iq_pi[RAID_PATH]);
+
+ spin_unlock_irqrestore(&queue_group->submit_lock[RAID_PATH], flags);
+}
+
+static void pqi_acknowledge_event(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_event *event)
+{
+ struct pqi_event_acknowledge_request request;
+
+ memset(&request, 0, sizeof(request));
+
+ request.header.iu_type = PQI_REQUEST_IU_ACKNOWLEDGE_VENDOR_EVENT;
+ put_unaligned_le16(sizeof(request) - PQI_REQUEST_HEADER_LENGTH,
+ &request.header.iu_length);
+ request.event_type = event->event_type;
+ request.event_id = event->event_id;
+ request.additional_event_id = event->additional_event_id;
+
+ pqi_start_event_ack(ctrl_info, &request, sizeof(request));
+}
+
+static void pqi_event_worker(struct work_struct *work)
+{
+ unsigned int i;
+ struct pqi_ctrl_info *ctrl_info;
+ struct pqi_event *pending_event;
+ bool got_non_heartbeat_event = false;
+
+ ctrl_info = container_of(work, struct pqi_ctrl_info, event_work);
+
+ pending_event = ctrl_info->pending_events;
+ for (i = 0; i < PQI_NUM_SUPPORTED_EVENTS; i++) {
+ if (pending_event->pending) {
+ pending_event->pending = false;
+ pqi_acknowledge_event(ctrl_info, pending_event);
+ if (i != PQI_EVENT_HEARTBEAT)
+ got_non_heartbeat_event = true;
+ }
+ pending_event++;
+ }
+
+ if (got_non_heartbeat_event)
+ pqi_schedule_rescan_worker(ctrl_info);
+}
+
+static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ unsigned int path;
+ struct pqi_queue_group *queue_group;
+ unsigned long flags;
+ struct pqi_io_request *io_request;
+ struct pqi_io_request *next;
+ struct scsi_cmnd *scmd;
+
+ ctrl_info->controller_online = false;
+ dev_err(&ctrl_info->pci_dev->dev, "controller offline\n");
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ queue_group = &ctrl_info->queue_groups[i];
+
+ for (path = 0; path < 2; path++) {
+ spin_lock_irqsave(
+ &queue_group->submit_lock[path], flags);
+
+ list_for_each_entry_safe(io_request, next,
+ &queue_group->request_list[path],
+ request_list_entry) {
+
+ scmd = io_request->scmd;
+ if (scmd) {
+ set_host_byte(scmd, DID_NO_CONNECT);
+ pqi_scsi_done(scmd);
+ }
+
+ list_del(&io_request->request_list_entry);
+ }
+
+ spin_unlock_irqrestore(
+ &queue_group->submit_lock[path], flags);
+ }
+ }
+}
+
+#define PQI_HEARTBEAT_TIMER_INTERVAL (5 * HZ)
+#define PQI_MAX_HEARTBEAT_REQUESTS 5
+
+static void pqi_heartbeat_timer_handler(unsigned long data)
+{
+ int num_interrupts;
+ struct pqi_ctrl_info *ctrl_info = (struct pqi_ctrl_info *)data;
+
+ num_interrupts = atomic_read(&ctrl_info->num_interrupts);
+
+ if (num_interrupts == ctrl_info->previous_num_interrupts) {
+ ctrl_info->num_heartbeats_requested++;
+ if (ctrl_info->num_heartbeats_requested >
+ PQI_MAX_HEARTBEAT_REQUESTS) {
+ pqi_take_ctrl_offline(ctrl_info);
+ return;
+ }
+ ctrl_info->pending_events[PQI_EVENT_HEARTBEAT].pending = true;
+ schedule_work(&ctrl_info->event_work);
+ } else {
+ ctrl_info->num_heartbeats_requested = 0;
+ }
+
+ ctrl_info->previous_num_interrupts = num_interrupts;
+ mod_timer(&ctrl_info->heartbeat_timer,
+ jiffies + PQI_HEARTBEAT_TIMER_INTERVAL);
+}
+
+static void pqi_start_heartbeat_timer(struct pqi_ctrl_info *ctrl_info)
+{
+ ctrl_info->previous_num_interrupts =
+ atomic_read(&ctrl_info->num_interrupts);
+
+ init_timer(&ctrl_info->heartbeat_timer);
+ ctrl_info->heartbeat_timer.expires =
+ jiffies + PQI_HEARTBEAT_TIMER_INTERVAL;
+ ctrl_info->heartbeat_timer.data = (unsigned long)ctrl_info;
+ ctrl_info->heartbeat_timer.function = pqi_heartbeat_timer_handler;
+ add_timer(&ctrl_info->heartbeat_timer);
+ ctrl_info->heartbeat_timer_started = true;
+}
+
+static inline void pqi_stop_heartbeat_timer(struct pqi_ctrl_info *ctrl_info)
+{
+ if (ctrl_info->heartbeat_timer_started)
+ del_timer_sync(&ctrl_info->heartbeat_timer);
+}
+
+static int pqi_event_type_to_event_index(unsigned int event_type)
+{
+ int index;
+
+ switch (event_type) {
+ case PQI_EVENT_TYPE_HEARTBEAT:
+ index = PQI_EVENT_HEARTBEAT;
+ break;
+ case PQI_EVENT_TYPE_HOTPLUG:
+ index = PQI_EVENT_HOTPLUG;
+ break;
+ case PQI_EVENT_TYPE_HARDWARE:
+ index = PQI_EVENT_HARDWARE;
+ break;
+ case PQI_EVENT_TYPE_PHYSICAL_DEVICE:
+ index = PQI_EVENT_PHYSICAL_DEVICE;
+ break;
+ case PQI_EVENT_TYPE_LOGICAL_DEVICE:
+ index = PQI_EVENT_LOGICAL_DEVICE;
+ break;
+ case PQI_EVENT_TYPE_AIO_STATE_CHANGE:
+ index = PQI_EVENT_AIO_STATE_CHANGE;
+ break;
+ case PQI_EVENT_TYPE_AIO_CONFIG_CHANGE:
+ index = PQI_EVENT_AIO_CONFIG_CHANGE;
+ break;
+ default:
+ index = -1;
+ break;
+ }
+
+ return index;
+}
+
+static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int num_events;
+ pqi_index_t oq_pi;
+ pqi_index_t oq_ci;
+ struct pqi_event_queue *event_queue;
+ struct pqi_event_response *response;
+ struct pqi_event *pending_event;
+ bool need_delayed_work;
+ int event_index;
+
+ event_queue = &ctrl_info->event_queue;
+ num_events = 0;
+ need_delayed_work = false;
+ oq_ci = event_queue->oq_ci_copy;
+
+ while (1) {
+ oq_pi = *event_queue->oq_pi;
+ if (oq_pi == oq_ci)
+ break;
+
+ num_events++;
+ response = event_queue->oq_element_array +
+ (oq_ci * PQI_EVENT_OQ_ELEMENT_LENGTH);
+
+ event_index =
+ pqi_event_type_to_event_index(response->event_type);
+
+ if (event_index >= 0) {
+ if (response->request_acknowlege) {
+ pending_event =
+ &ctrl_info->pending_events[event_index];
+ pending_event->event_type =
+ response->event_type;
+ pending_event->event_id = response->event_id;
+ pending_event->additional_event_id =
+ response->additional_event_id;
+ if (event_index != PQI_EVENT_HEARTBEAT) {
+ pending_event->pending = true;
+ need_delayed_work = true;
+ }
+ }
+ }
+
+ oq_ci = (oq_ci + 1) % PQI_NUM_EVENT_QUEUE_ELEMENTS;
+ }
+
+ if (num_events) {
+ event_queue->oq_ci_copy = oq_ci;
+ writel(oq_ci, event_queue->oq_ci);
+
+ if (need_delayed_work)
+ schedule_work(&ctrl_info->event_work);
+ }
+
+ return num_events;
+}
+
+static irqreturn_t pqi_irq_handler(int irq, void *data)
+{
+ struct pqi_ctrl_info *ctrl_info;
+ struct pqi_queue_group *queue_group;
+ unsigned int num_responses_handled;
+
+ queue_group = data;
+ ctrl_info = queue_group->ctrl_info;
+
+ if (!ctrl_info || !queue_group->oq_ci)
+ return IRQ_NONE;
+
+ num_responses_handled = pqi_process_io_intr(ctrl_info, queue_group);
+
+ if (irq == ctrl_info->event_irq)
+ num_responses_handled += pqi_process_event_intr(ctrl_info);
+
+ if (num_responses_handled)
+ atomic_inc(&ctrl_info->num_interrupts);
+
+ pqi_start_io(ctrl_info, queue_group, RAID_PATH, NULL);
+ pqi_start_io(ctrl_info, queue_group, AIO_PATH, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static int pqi_request_irqs(struct pqi_ctrl_info *ctrl_info)
+{
+ int i;
+ int rc;
+
+ ctrl_info->event_irq = ctrl_info->msix_vectors[0];
+
+ for (i = 0; i < ctrl_info->num_msix_vectors_enabled; i++) {
+ rc = request_irq(ctrl_info->msix_vectors[i],
+ pqi_irq_handler, 0,
+ DRIVER_NAME_SHORT, ctrl_info->intr_data[i]);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "irq %u init failed with error %d\n",
+ ctrl_info->msix_vectors[i], rc);
+ return rc;
+ }
+ ctrl_info->num_msix_vectors_initialized++;
+ }
+
+ return 0;
+}
+
+static void pqi_free_irqs(struct pqi_ctrl_info *ctrl_info)
+{
+ int i;
+
+ for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++)
+ free_irq(ctrl_info->msix_vectors[i],
+ ctrl_info->intr_data[i]);
+}
+
+static int pqi_enable_msix_interrupts(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ int max_vectors;
+ int num_vectors_enabled;
+ struct msix_entry msix_entries[PQI_MAX_MSIX_VECTORS];
+
+ max_vectors = ctrl_info->num_queue_groups;
+
+ for (i = 0; i < max_vectors; i++)
+ msix_entries[i].entry = i;
+
+ num_vectors_enabled = pci_enable_msix_range(ctrl_info->pci_dev,
+ msix_entries, PQI_MIN_MSIX_VECTORS, max_vectors);
+
+ if (num_vectors_enabled < 0) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "MSI-X init failed with error %d\n",
+ num_vectors_enabled);
+ return num_vectors_enabled;
+ }
+
+ ctrl_info->num_msix_vectors_enabled = num_vectors_enabled;
+ for (i = 0; i < num_vectors_enabled; i++) {
+ ctrl_info->msix_vectors[i] = msix_entries[i].vector;
+ ctrl_info->intr_data[i] = &ctrl_info->queue_groups[i];
+ }
+
+ return 0;
+}
+
+static void pqi_irq_set_affinity_hint(struct pqi_ctrl_info *ctrl_info)
+{
+ int i;
+ int rc;
+ int cpu;
+
+ cpu = cpumask_first(cpu_online_mask);
+ for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++) {
+ rc = irq_set_affinity_hint(ctrl_info->msix_vectors[i],
+ get_cpu_mask(cpu));
+ if (rc)
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error %d setting affinity hint for irq vector %u\n",
+ rc, ctrl_info->msix_vectors[i]);
+ cpu = cpumask_next(cpu, cpu_online_mask);
+ }
+}
+
+static void pqi_irq_unset_affinity_hint(struct pqi_ctrl_info *ctrl_info)
+{
+ int i;
+
+ for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++)
+ irq_set_affinity_hint(ctrl_info->msix_vectors[i], NULL);
+}
+
+static int pqi_alloc_operational_queues(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ size_t alloc_length;
+ size_t element_array_length_per_iq;
+ size_t element_array_length_per_oq;
+ void *element_array;
+ void *next_queue_index;
+ void *aligned_pointer;
+ unsigned int num_inbound_queues;
+ unsigned int num_outbound_queues;
+ unsigned int num_queue_indexes;
+ struct pqi_queue_group *queue_group;
+
+ element_array_length_per_iq =
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH *
+ ctrl_info->num_elements_per_iq;
+ element_array_length_per_oq =
+ PQI_OPERATIONAL_OQ_ELEMENT_LENGTH *
+ ctrl_info->num_elements_per_oq;
+ num_inbound_queues = ctrl_info->num_queue_groups * 2;
+ num_outbound_queues = ctrl_info->num_queue_groups;
+ num_queue_indexes = (ctrl_info->num_queue_groups * 3) + 1;
+
+ aligned_pointer = NULL;
+
+ for (i = 0; i < num_inbound_queues; i++) {
+ aligned_pointer = PTR_ALIGN(aligned_pointer,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ aligned_pointer += element_array_length_per_iq;
+ }
+
+ for (i = 0; i < num_outbound_queues; i++) {
+ aligned_pointer = PTR_ALIGN(aligned_pointer,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ aligned_pointer += element_array_length_per_oq;
+ }
+
+ aligned_pointer = PTR_ALIGN(aligned_pointer,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ aligned_pointer += PQI_NUM_EVENT_QUEUE_ELEMENTS *
+ PQI_EVENT_OQ_ELEMENT_LENGTH;
+
+ for (i = 0; i < num_queue_indexes; i++) {
+ aligned_pointer = PTR_ALIGN(aligned_pointer,
+ PQI_OPERATIONAL_INDEX_ALIGNMENT);
+ aligned_pointer += sizeof(pqi_index_t);
+ }
+
+ alloc_length = (size_t)aligned_pointer +
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT;
+
+ ctrl_info->queue_memory_base =
+ dma_zalloc_coherent(&ctrl_info->pci_dev->dev,
+ alloc_length,
+ &ctrl_info->queue_memory_base_dma_handle, GFP_KERNEL);
+
+ if (!ctrl_info->queue_memory_base) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate memory for PQI admin queues\n");
+ return -ENOMEM;
+ }
+
+ ctrl_info->queue_memory_length = alloc_length;
+
+ element_array = PTR_ALIGN(ctrl_info->queue_memory_base,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ queue_group = &ctrl_info->queue_groups[i];
+ queue_group->iq_element_array[RAID_PATH] = element_array;
+ queue_group->iq_element_array_bus_addr[RAID_PATH] =
+ ctrl_info->queue_memory_base_dma_handle +
+ (element_array - ctrl_info->queue_memory_base);
+ element_array += element_array_length_per_iq;
+ element_array = PTR_ALIGN(element_array,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ queue_group->iq_element_array[AIO_PATH] = element_array;
+ queue_group->iq_element_array_bus_addr[AIO_PATH] =
+ ctrl_info->queue_memory_base_dma_handle +
+ (element_array - ctrl_info->queue_memory_base);
+ element_array += element_array_length_per_iq;
+ element_array = PTR_ALIGN(element_array,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ }
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ queue_group = &ctrl_info->queue_groups[i];
+ queue_group->oq_element_array = element_array;
+ queue_group->oq_element_array_bus_addr =
+ ctrl_info->queue_memory_base_dma_handle +
+ (element_array - ctrl_info->queue_memory_base);
+ element_array += element_array_length_per_oq;
+ element_array = PTR_ALIGN(element_array,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ }
+
+ ctrl_info->event_queue.oq_element_array = element_array;
+ ctrl_info->event_queue.oq_element_array_bus_addr =
+ ctrl_info->queue_memory_base_dma_handle +
+ (element_array - ctrl_info->queue_memory_base);
+ element_array += PQI_NUM_EVENT_QUEUE_ELEMENTS *
+ PQI_EVENT_OQ_ELEMENT_LENGTH;
+
+ next_queue_index = PTR_ALIGN(element_array,
+ PQI_OPERATIONAL_INDEX_ALIGNMENT);
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ queue_group = &ctrl_info->queue_groups[i];
+ queue_group->iq_ci[RAID_PATH] = next_queue_index;
+ queue_group->iq_ci_bus_addr[RAID_PATH] =
+ ctrl_info->queue_memory_base_dma_handle +
+ (next_queue_index - ctrl_info->queue_memory_base);
+ next_queue_index += sizeof(pqi_index_t);
+ next_queue_index = PTR_ALIGN(next_queue_index,
+ PQI_OPERATIONAL_INDEX_ALIGNMENT);
+ queue_group->iq_ci[AIO_PATH] = next_queue_index;
+ queue_group->iq_ci_bus_addr[AIO_PATH] =
+ ctrl_info->queue_memory_base_dma_handle +
+ (next_queue_index - ctrl_info->queue_memory_base);
+ next_queue_index += sizeof(pqi_index_t);
+ next_queue_index = PTR_ALIGN(next_queue_index,
+ PQI_OPERATIONAL_INDEX_ALIGNMENT);
+ queue_group->oq_pi = next_queue_index;
+ queue_group->oq_pi_bus_addr =
+ ctrl_info->queue_memory_base_dma_handle +
+ (next_queue_index - ctrl_info->queue_memory_base);
+ next_queue_index += sizeof(pqi_index_t);
+ next_queue_index = PTR_ALIGN(next_queue_index,
+ PQI_OPERATIONAL_INDEX_ALIGNMENT);
+ }
+
+ ctrl_info->event_queue.oq_pi = next_queue_index;
+ ctrl_info->event_queue.oq_pi_bus_addr =
+ ctrl_info->queue_memory_base_dma_handle +
+ (next_queue_index - ctrl_info->queue_memory_base);
+
+ return 0;
+}
+
+static void pqi_init_operational_queues(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ u16 next_iq_id = PQI_MIN_OPERATIONAL_QUEUE_ID;
+ u16 next_oq_id = PQI_MIN_OPERATIONAL_QUEUE_ID;
+
+ /*
+ * Initialize the backpointers to the controller structure in
+ * each operational queue group structure.
+ */
+ for (i = 0; i < ctrl_info->num_queue_groups; i++)
+ ctrl_info->queue_groups[i].ctrl_info = ctrl_info;
+
+ /*
+ * Assign IDs to all operational queues. Note that the IDs
+ * assigned to operational IQs are independent of the IDs
+ * assigned to operational OQs.
+ */
+ ctrl_info->event_queue.oq_id = next_oq_id++;
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ ctrl_info->queue_groups[i].iq_id[RAID_PATH] = next_iq_id++;
+ ctrl_info->queue_groups[i].iq_id[AIO_PATH] = next_iq_id++;
+ ctrl_info->queue_groups[i].oq_id = next_oq_id++;
+ }
+
+ /*
+ * Assign MSI-X table entry indexes to all queues. Note that the
+ * interrupt for the event queue is shared with the first queue group.
+ */
+ ctrl_info->event_queue.int_msg_num = 0;
+ for (i = 0; i < ctrl_info->num_queue_groups; i++)
+ ctrl_info->queue_groups[i].int_msg_num = i;
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ spin_lock_init(&ctrl_info->queue_groups[i].submit_lock[0]);
+ spin_lock_init(&ctrl_info->queue_groups[i].submit_lock[1]);
+ INIT_LIST_HEAD(&ctrl_info->queue_groups[i].request_list[0]);
+ INIT_LIST_HEAD(&ctrl_info->queue_groups[i].request_list[1]);
+ }
+}
+
+static int pqi_alloc_admin_queues(struct pqi_ctrl_info *ctrl_info)
+{
+ size_t alloc_length;
+ struct pqi_admin_queues_aligned *admin_queues_aligned;
+ struct pqi_admin_queues *admin_queues;
+
+ alloc_length = sizeof(struct pqi_admin_queues_aligned) +
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT;
+
+ ctrl_info->admin_queue_memory_base =
+ dma_zalloc_coherent(&ctrl_info->pci_dev->dev,
+ alloc_length,
+ &ctrl_info->admin_queue_memory_base_dma_handle,
+ GFP_KERNEL);
+
+ if (!ctrl_info->admin_queue_memory_base)
+ return -ENOMEM;
+
+ ctrl_info->admin_queue_memory_length = alloc_length;
+
+ admin_queues = &ctrl_info->admin_queues;
+ admin_queues_aligned = PTR_ALIGN(ctrl_info->admin_queue_memory_base,
+ PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT);
+ admin_queues->iq_element_array =
+ &admin_queues_aligned->iq_element_array;
+ admin_queues->oq_element_array =
+ &admin_queues_aligned->oq_element_array;
+ admin_queues->iq_ci = &admin_queues_aligned->iq_ci;
+ admin_queues->oq_pi = &admin_queues_aligned->oq_pi;
+
+ admin_queues->iq_element_array_bus_addr =
+ ctrl_info->admin_queue_memory_base_dma_handle +
+ (admin_queues->iq_element_array -
+ ctrl_info->admin_queue_memory_base);
+ admin_queues->oq_element_array_bus_addr =
+ ctrl_info->admin_queue_memory_base_dma_handle +
+ (admin_queues->oq_element_array -
+ ctrl_info->admin_queue_memory_base);
+ admin_queues->iq_ci_bus_addr =
+ ctrl_info->admin_queue_memory_base_dma_handle +
+ ((void *)admin_queues->iq_ci -
+ ctrl_info->admin_queue_memory_base);
+ admin_queues->oq_pi_bus_addr =
+ ctrl_info->admin_queue_memory_base_dma_handle +
+ ((void *)admin_queues->oq_pi -
+ ctrl_info->admin_queue_memory_base);
+
+ return 0;
+}
+
+#define PQI_ADMIN_QUEUE_CREATE_TIMEOUT_JIFFIES HZ
+#define PQI_ADMIN_QUEUE_CREATE_POLL_INTERVAL_MSECS 1
+
+static int pqi_create_admin_queues(struct pqi_ctrl_info *ctrl_info)
+{
+ struct pqi_device_registers __iomem *pqi_registers;
+ struct pqi_admin_queues *admin_queues;
+ unsigned long timeout;
+ u8 status;
+ u32 reg;
+
+ pqi_registers = ctrl_info->pqi_registers;
+ admin_queues = &ctrl_info->admin_queues;
+
+ writeq((u64)admin_queues->iq_element_array_bus_addr,
+ &pqi_registers->admin_iq_element_array_addr);
+ writeq((u64)admin_queues->oq_element_array_bus_addr,
+ &pqi_registers->admin_oq_element_array_addr);
+ writeq((u64)admin_queues->iq_ci_bus_addr,
+ &pqi_registers->admin_iq_ci_addr);
+ writeq((u64)admin_queues->oq_pi_bus_addr,
+ &pqi_registers->admin_oq_pi_addr);
+
+ reg = PQI_ADMIN_IQ_NUM_ELEMENTS |
+ (PQI_ADMIN_OQ_NUM_ELEMENTS) << 8 |
+ (admin_queues->int_msg_num << 16);
+ writel(reg, &pqi_registers->admin_iq_num_elements);
+ writel(PQI_CREATE_ADMIN_QUEUE_PAIR,
+ &pqi_registers->function_and_status_code);
+
+ timeout = PQI_ADMIN_QUEUE_CREATE_TIMEOUT_JIFFIES + jiffies;
+ while (1) {
+ status = readb(&pqi_registers->function_and_status_code);
+ if (status == PQI_STATUS_IDLE)
+ break;
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ msleep(PQI_ADMIN_QUEUE_CREATE_POLL_INTERVAL_MSECS);
+ }
+
+ /*
+ * The offset registers are not initialized to the correct
+ * offsets until *after* the create admin queue pair command
+ * completes successfully.
+ */
+ admin_queues->iq_pi = ctrl_info->iomem_base +
+ PQI_DEVICE_REGISTERS_OFFSET +
+ readq(&pqi_registers->admin_iq_pi_offset);
+ admin_queues->oq_ci = ctrl_info->iomem_base +
+ PQI_DEVICE_REGISTERS_OFFSET +
+ readq(&pqi_registers->admin_oq_ci_offset);
+
+ return 0;
+}
+
+static void pqi_submit_admin_request(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_general_admin_request *request)
+{
+ struct pqi_admin_queues *admin_queues;
+ void *next_element;
+ pqi_index_t iq_pi;
+
+ admin_queues = &ctrl_info->admin_queues;
+ iq_pi = admin_queues->iq_pi_copy;
+
+ next_element = admin_queues->iq_element_array +
+ (iq_pi * PQI_ADMIN_IQ_ELEMENT_LENGTH);
+
+ memcpy(next_element, request, sizeof(*request));
+
+ iq_pi = (iq_pi + 1) % PQI_ADMIN_IQ_NUM_ELEMENTS;
+ admin_queues->iq_pi_copy = iq_pi;
+
+ /*
+ * This write notifies the controller that an IU is available to be
+ * processed.
+ */
+ writel(iq_pi, admin_queues->iq_pi);
+}
+
+static int pqi_poll_for_admin_response(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_general_admin_response *response)
+{
+ struct pqi_admin_queues *admin_queues;
+ pqi_index_t oq_pi;
+ pqi_index_t oq_ci;
+ unsigned long timeout;
+
+ admin_queues = &ctrl_info->admin_queues;
+ oq_ci = admin_queues->oq_ci_copy;
+
+ timeout = (3 * HZ) + jiffies;
+
+ while (1) {
+ oq_pi = *admin_queues->oq_pi;
+ if (oq_pi != oq_ci)
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "timed out waiting for admin response\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(1000, 2000);
+ }
+
+ memcpy(response, admin_queues->oq_element_array +
+ (oq_ci * PQI_ADMIN_OQ_ELEMENT_LENGTH), sizeof(*response));
+
+ oq_ci = (oq_ci + 1) % PQI_ADMIN_OQ_NUM_ELEMENTS;
+ admin_queues->oq_ci_copy = oq_ci;
+ writel(oq_ci, admin_queues->oq_ci);
+
+ return 0;
+}
+
+static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_queue_group *queue_group, enum pqi_io_path path,
+ struct pqi_io_request *io_request)
+{
+ struct pqi_io_request *next;
+ void *next_element;
+ pqi_index_t iq_pi;
+ pqi_index_t iq_ci;
+ size_t iu_length;
+ unsigned long flags;
+ unsigned int num_elements_needed;
+ unsigned int num_elements_to_end_of_queue;
+ size_t copy_count;
+ struct pqi_iu_header *request;
+
+ spin_lock_irqsave(&queue_group->submit_lock[path], flags);
+
+ if (io_request)
+ list_add_tail(&io_request->request_list_entry,
+ &queue_group->request_list[path]);
+
+ iq_pi = queue_group->iq_pi_copy[path];
+
+ list_for_each_entry_safe(io_request, next,
+ &queue_group->request_list[path], request_list_entry) {
+
+ request = io_request->iu;
+
+ iu_length = get_unaligned_le16(&request->iu_length) +
+ PQI_REQUEST_HEADER_LENGTH;
+ num_elements_needed =
+ DIV_ROUND_UP(iu_length,
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+
+ iq_ci = *queue_group->iq_ci[path];
+
+ if (num_elements_needed > pqi_num_elements_free(iq_pi, iq_ci,
+ ctrl_info->num_elements_per_iq))
+ break;
+
+ put_unaligned_le16(queue_group->oq_id,
+ &request->response_queue_id);
+
+ next_element = queue_group->iq_element_array[path] +
+ (iq_pi * PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+
+ num_elements_to_end_of_queue =
+ ctrl_info->num_elements_per_iq - iq_pi;
+
+ if (num_elements_needed <= num_elements_to_end_of_queue) {
+ memcpy(next_element, request, iu_length);
+ } else {
+ copy_count = num_elements_to_end_of_queue *
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH;
+ memcpy(next_element, request, copy_count);
+ memcpy(queue_group->iq_element_array[path],
+ (u8 *)request + copy_count,
+ iu_length - copy_count);
+ }
+
+ iq_pi = (iq_pi + num_elements_needed) %
+ ctrl_info->num_elements_per_iq;
+
+ list_del(&io_request->request_list_entry);
+ }
+
+ if (iq_pi != queue_group->iq_pi_copy[path]) {
+ queue_group->iq_pi_copy[path] = iq_pi;
+ /*
+ * This write notifies the controller that one or more IUs are
+ * available to be processed.
+ */
+ writel(iq_pi, queue_group->iq_pi[path]);
+ }
+
+ spin_unlock_irqrestore(&queue_group->submit_lock[path], flags);
+}
+
+static void pqi_raid_synchronous_complete(struct pqi_io_request *io_request,
+ void *context)
+{
+ struct completion *waiting = context;
+
+ complete(waiting);
+}
+
+static int pqi_submit_raid_request_synchronous_with_io_request(
+ struct pqi_ctrl_info *ctrl_info, struct pqi_io_request *io_request,
+ unsigned long timeout_msecs)
+{
+ int rc = 0;
+ DECLARE_COMPLETION_ONSTACK(wait);
+
+ io_request->io_complete_callback = pqi_raid_synchronous_complete;
+ io_request->context = &wait;
+
+ pqi_start_io(ctrl_info,
+ &ctrl_info->queue_groups[PQI_DEFAULT_QUEUE_GROUP], RAID_PATH,
+ io_request);
+
+ if (timeout_msecs == NO_TIMEOUT) {
+ wait_for_completion_io(&wait);
+ } else {
+ if (!wait_for_completion_io_timeout(&wait,
+ msecs_to_jiffies(timeout_msecs))) {
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "command timed out\n");
+ rc = -ETIMEDOUT;
+ }
+ }
+
+ return rc;
+}
+
+static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_iu_header *request, unsigned int flags,
+ struct pqi_raid_error_info *error_info, unsigned long timeout_msecs)
+{
+ int rc;
+ struct pqi_io_request *io_request;
+ unsigned long start_jiffies;
+ unsigned long msecs_blocked;
+ size_t iu_length;
+
+ /*
+ * Note that specifying PQI_SYNC_FLAGS_INTERRUPTABLE and a timeout value
+ * are mutually exclusive.
+ */
+
+ if (flags & PQI_SYNC_FLAGS_INTERRUPTABLE) {
+ if (down_interruptible(&ctrl_info->sync_request_sem))
+ return -ERESTARTSYS;
+ } else {
+ if (timeout_msecs == NO_TIMEOUT) {
+ down(&ctrl_info->sync_request_sem);
+ } else {
+ start_jiffies = jiffies;
+ if (down_timeout(&ctrl_info->sync_request_sem,
+ msecs_to_jiffies(timeout_msecs)))
+ return -ETIMEDOUT;
+ msecs_blocked =
+ jiffies_to_msecs(jiffies - start_jiffies);
+ if (msecs_blocked >= timeout_msecs)
+ return -ETIMEDOUT;
+ timeout_msecs -= msecs_blocked;
+ }
+ }
+
+ io_request = pqi_alloc_io_request(ctrl_info);
+
+ put_unaligned_le16(io_request->index,
+ &(((struct pqi_raid_path_request *)request)->request_id));
+
+ if (request->iu_type == PQI_REQUEST_IU_RAID_PATH_IO)
+ ((struct pqi_raid_path_request *)request)->error_index =
+ ((struct pqi_raid_path_request *)request)->request_id;
+
+ iu_length = get_unaligned_le16(&request->iu_length) +
+ PQI_REQUEST_HEADER_LENGTH;
+ memcpy(io_request->iu, request, iu_length);
+
+ rc = pqi_submit_raid_request_synchronous_with_io_request(ctrl_info,
+ io_request, timeout_msecs);
+
+ if (error_info) {
+ if (io_request->error_info)
+ memcpy(error_info, io_request->error_info,
+ sizeof(*error_info));
+ else
+ memset(error_info, 0, sizeof(*error_info));
+ } else if (rc == 0 && io_request->error_info) {
+ u8 scsi_status;
+ struct pqi_raid_error_info *raid_error_info;
+
+ raid_error_info = io_request->error_info;
+ scsi_status = raid_error_info->status;
+
+ if (scsi_status == SAM_STAT_CHECK_CONDITION &&
+ raid_error_info->data_out_result ==
+ PQI_DATA_IN_OUT_UNDERFLOW)
+ scsi_status = SAM_STAT_GOOD;
+
+ if (scsi_status != SAM_STAT_GOOD)
+ rc = -EIO;
+ }
+
+ pqi_free_io_request(io_request);
+
+ up(&ctrl_info->sync_request_sem);
+
+ return rc;
+}
+
+static int pqi_validate_admin_response(
+ struct pqi_general_admin_response *response, u8 expected_function_code)
+{
+ if (response->header.iu_type != PQI_RESPONSE_IU_GENERAL_ADMIN)
+ return -EINVAL;
+
+ if (get_unaligned_le16(&response->header.iu_length) !=
+ PQI_GENERAL_ADMIN_IU_LENGTH)
+ return -EINVAL;
+
+ if (response->function_code != expected_function_code)
+ return -EINVAL;
+
+ if (response->status != PQI_GENERAL_ADMIN_STATUS_SUCCESS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int pqi_submit_admin_request_synchronous(
+ struct pqi_ctrl_info *ctrl_info,
+ struct pqi_general_admin_request *request,
+ struct pqi_general_admin_response *response)
+{
+ int rc;
+
+ pqi_submit_admin_request(ctrl_info, request);
+
+ rc = pqi_poll_for_admin_response(ctrl_info, response);
+
+ if (rc == 0)
+ rc = pqi_validate_admin_response(response,
+ request->function_code);
+
+ return rc;
+}
+
+static int pqi_report_device_capability(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct pqi_general_admin_request request;
+ struct pqi_general_admin_response response;
+ struct pqi_device_capability *capability;
+ struct pqi_iu_layer_descriptor *sop_iu_layer_descriptor;
+
+ capability = kmalloc(sizeof(*capability), GFP_KERNEL);
+ if (!capability)
+ return -ENOMEM;
+
+ memset(&request, 0, sizeof(request));
+
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ request.function_code =
+ PQI_GENERAL_ADMIN_FUNCTION_REPORT_DEVICE_CAPABILITY;
+ put_unaligned_le32(sizeof(*capability),
+ &request.data.report_device_capability.buffer_length);
+
+ rc = pqi_map_single(ctrl_info->pci_dev,
+ &request.data.report_device_capability.sg_descriptor,
+ capability, sizeof(*capability),
+ PCI_DMA_FROMDEVICE);
+ if (rc)
+ goto out;
+
+ rc = pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+
+ pqi_pci_unmap(ctrl_info->pci_dev,
+ &request.data.report_device_capability.sg_descriptor, 1,
+ PCI_DMA_FROMDEVICE);
+
+ if (rc)
+ goto out;
+
+ if (response.status != PQI_GENERAL_ADMIN_STATUS_SUCCESS) {
+ rc = -EIO;
+ goto out;
+ }
+
+ ctrl_info->max_inbound_queues =
+ get_unaligned_le16(&capability->max_inbound_queues);
+ ctrl_info->max_elements_per_iq =
+ get_unaligned_le16(&capability->max_elements_per_iq);
+ ctrl_info->max_iq_element_length =
+ get_unaligned_le16(&capability->max_iq_element_length)
+ * 16;
+ ctrl_info->max_outbound_queues =
+ get_unaligned_le16(&capability->max_outbound_queues);
+ ctrl_info->max_elements_per_oq =
+ get_unaligned_le16(&capability->max_elements_per_oq);
+ ctrl_info->max_oq_element_length =
+ get_unaligned_le16(&capability->max_oq_element_length)
+ * 16;
+
+ sop_iu_layer_descriptor =
+ &capability->iu_layer_descriptors[PQI_PROTOCOL_SOP];
+
+ ctrl_info->max_inbound_iu_length_per_firmware =
+ get_unaligned_le16(
+ &sop_iu_layer_descriptor->max_inbound_iu_length);
+ ctrl_info->inbound_spanning_supported =
+ sop_iu_layer_descriptor->inbound_spanning_supported;
+ ctrl_info->outbound_spanning_supported =
+ sop_iu_layer_descriptor->outbound_spanning_supported;
+
+out:
+ kfree(capability);
+
+ return rc;
+}
+
+static int pqi_validate_device_capability(struct pqi_ctrl_info *ctrl_info)
+{
+ if (ctrl_info->max_iq_element_length <
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "max. inbound queue element length of %d is less than the required length of %d\n",
+ ctrl_info->max_iq_element_length,
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+ return -EINVAL;
+ }
+
+ if (ctrl_info->max_oq_element_length <
+ PQI_OPERATIONAL_OQ_ELEMENT_LENGTH) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "max. outbound queue element length of %d is less than the required length of %d\n",
+ ctrl_info->max_oq_element_length,
+ PQI_OPERATIONAL_OQ_ELEMENT_LENGTH);
+ return -EINVAL;
+ }
+
+ if (ctrl_info->max_inbound_iu_length_per_firmware <
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "max. inbound IU length of %u is less than the min. required length of %d\n",
+ ctrl_info->max_inbound_iu_length_per_firmware,
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+ return -EINVAL;
+ }
+
+ if (!ctrl_info->inbound_spanning_supported) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "the controller does not support inbound spanning\n");
+ return -EINVAL;
+ }
+
+ if (ctrl_info->outbound_spanning_supported) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "the controller supports outbound spanning but this driver does not\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pqi_delete_operational_queue(struct pqi_ctrl_info *ctrl_info,
+ bool inbound_queue, u16 queue_id)
+{
+ struct pqi_general_admin_request request;
+ struct pqi_general_admin_response response;
+
+ memset(&request, 0, sizeof(request));
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ if (inbound_queue)
+ request.function_code =
+ PQI_GENERAL_ADMIN_FUNCTION_DELETE_IQ;
+ else
+ request.function_code =
+ PQI_GENERAL_ADMIN_FUNCTION_DELETE_OQ;
+ put_unaligned_le16(queue_id,
+ &request.data.delete_operational_queue.queue_id);
+
+ return pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+}
+
+static int pqi_create_event_queue(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct pqi_event_queue *event_queue;
+ struct pqi_general_admin_request request;
+ struct pqi_general_admin_response response;
+
+ event_queue = &ctrl_info->event_queue;
+
+ /*
+ * Create OQ (Outbound Queue - device to host queue) to dedicate
+ * to events.
+ */
+ memset(&request, 0, sizeof(request));
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ request.function_code = PQI_GENERAL_ADMIN_FUNCTION_CREATE_OQ;
+ put_unaligned_le16(event_queue->oq_id,
+ &request.data.create_operational_oq.queue_id);
+ put_unaligned_le64((u64)event_queue->oq_element_array_bus_addr,
+ &request.data.create_operational_oq.element_array_addr);
+ put_unaligned_le64((u64)event_queue->oq_pi_bus_addr,
+ &request.data.create_operational_oq.pi_addr);
+ put_unaligned_le16(PQI_NUM_EVENT_QUEUE_ELEMENTS,
+ &request.data.create_operational_oq.num_elements);
+ put_unaligned_le16(PQI_EVENT_OQ_ELEMENT_LENGTH / 16,
+ &request.data.create_operational_oq.element_length);
+ request.data.create_operational_oq.queue_protocol = PQI_PROTOCOL_SOP;
+ put_unaligned_le16(event_queue->int_msg_num,
+ &request.data.create_operational_oq.int_msg_num);
+
+ rc = pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+ if (rc)
+ return rc;
+
+ event_queue->oq_ci = ctrl_info->iomem_base +
+ PQI_DEVICE_REGISTERS_OFFSET +
+ get_unaligned_le64(
+ &response.data.create_operational_oq.oq_ci_offset);
+
+ return 0;
+}
+
+static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ int rc;
+ struct pqi_queue_group *queue_group;
+ struct pqi_general_admin_request request;
+ struct pqi_general_admin_response response;
+
+ i = ctrl_info->num_active_queue_groups;
+ queue_group = &ctrl_info->queue_groups[i];
+
+ /*
+ * Create IQ (Inbound Queue - host to device queue) for
+ * RAID path.
+ */
+ memset(&request, 0, sizeof(request));
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ request.function_code = PQI_GENERAL_ADMIN_FUNCTION_CREATE_IQ;
+ put_unaligned_le16(queue_group->iq_id[RAID_PATH],
+ &request.data.create_operational_iq.queue_id);
+ put_unaligned_le64(
+ (u64)queue_group->iq_element_array_bus_addr[RAID_PATH],
+ &request.data.create_operational_iq.element_array_addr);
+ put_unaligned_le64((u64)queue_group->iq_ci_bus_addr[RAID_PATH],
+ &request.data.create_operational_iq.ci_addr);
+ put_unaligned_le16(ctrl_info->num_elements_per_iq,
+ &request.data.create_operational_iq.num_elements);
+ put_unaligned_le16(PQI_OPERATIONAL_IQ_ELEMENT_LENGTH / 16,
+ &request.data.create_operational_iq.element_length);
+ request.data.create_operational_iq.queue_protocol = PQI_PROTOCOL_SOP;
+
+ rc = pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating inbound RAID queue\n");
+ return rc;
+ }
+
+ queue_group->iq_pi[RAID_PATH] = ctrl_info->iomem_base +
+ PQI_DEVICE_REGISTERS_OFFSET +
+ get_unaligned_le64(
+ &response.data.create_operational_iq.iq_pi_offset);
+
+ /*
+ * Create IQ (Inbound Queue - host to device queue) for
+ * Advanced I/O (AIO) path.
+ */
+ memset(&request, 0, sizeof(request));
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ request.function_code = PQI_GENERAL_ADMIN_FUNCTION_CREATE_IQ;
+ put_unaligned_le16(queue_group->iq_id[AIO_PATH],
+ &request.data.create_operational_iq.queue_id);
+ put_unaligned_le64((u64)queue_group->
+ iq_element_array_bus_addr[AIO_PATH],
+ &request.data.create_operational_iq.element_array_addr);
+ put_unaligned_le64((u64)queue_group->iq_ci_bus_addr[AIO_PATH],
+ &request.data.create_operational_iq.ci_addr);
+ put_unaligned_le16(ctrl_info->num_elements_per_iq,
+ &request.data.create_operational_iq.num_elements);
+ put_unaligned_le16(PQI_OPERATIONAL_IQ_ELEMENT_LENGTH / 16,
+ &request.data.create_operational_iq.element_length);
+ request.data.create_operational_iq.queue_protocol = PQI_PROTOCOL_SOP;
+
+ rc = pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating inbound AIO queue\n");
+ goto delete_inbound_queue_raid;
+ }
+
+ queue_group->iq_pi[AIO_PATH] = ctrl_info->iomem_base +
+ PQI_DEVICE_REGISTERS_OFFSET +
+ get_unaligned_le64(
+ &response.data.create_operational_iq.iq_pi_offset);
+
+ /*
+ * Designate the 2nd IQ as the AIO path. By default, all IQs are
+ * assumed to be for RAID path I/O unless we change the queue's
+ * property.
+ */
+ memset(&request, 0, sizeof(request));
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ request.function_code = PQI_GENERAL_ADMIN_FUNCTION_CHANGE_IQ_PROPERTY;
+ put_unaligned_le16(queue_group->iq_id[AIO_PATH],
+ &request.data.change_operational_iq_properties.queue_id);
+ put_unaligned_le32(PQI_IQ_PROPERTY_IS_AIO_QUEUE,
+ &request.data.change_operational_iq_properties.vendor_specific);
+
+ rc = pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error changing queue property\n");
+ goto delete_inbound_queue_aio;
+ }
+
+ /*
+ * Create OQ (Outbound Queue - device to host queue).
+ */
+ memset(&request, 0, sizeof(request));
+ request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN;
+ put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH,
+ &request.header.iu_length);
+ request.function_code = PQI_GENERAL_ADMIN_FUNCTION_CREATE_OQ;
+ put_unaligned_le16(queue_group->oq_id,
+ &request.data.create_operational_oq.queue_id);
+ put_unaligned_le64((u64)queue_group->oq_element_array_bus_addr,
+ &request.data.create_operational_oq.element_array_addr);
+ put_unaligned_le64((u64)queue_group->oq_pi_bus_addr,
+ &request.data.create_operational_oq.pi_addr);
+ put_unaligned_le16(ctrl_info->num_elements_per_oq,
+ &request.data.create_operational_oq.num_elements);
+ put_unaligned_le16(PQI_OPERATIONAL_OQ_ELEMENT_LENGTH / 16,
+ &request.data.create_operational_oq.element_length);
+ request.data.create_operational_oq.queue_protocol = PQI_PROTOCOL_SOP;
+ put_unaligned_le16(queue_group->int_msg_num,
+ &request.data.create_operational_oq.int_msg_num);
+
+ rc = pqi_submit_admin_request_synchronous(ctrl_info, &request,
+ &response);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating outbound queue\n");
+ goto delete_inbound_queue_aio;
+ }
+
+ queue_group->oq_ci = ctrl_info->iomem_base +
+ PQI_DEVICE_REGISTERS_OFFSET +
+ get_unaligned_le64(
+ &response.data.create_operational_oq.oq_ci_offset);
+
+ ctrl_info->num_active_queue_groups++;
+
+ return 0;
+
+delete_inbound_queue_aio:
+ pqi_delete_operational_queue(ctrl_info, true,
+ queue_group->iq_id[AIO_PATH]);
+
+delete_inbound_queue_raid:
+ pqi_delete_operational_queue(ctrl_info, true,
+ queue_group->iq_id[RAID_PATH]);
+
+ return rc;
+}
+
+static int pqi_create_queues(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ unsigned int i;
+
+ rc = pqi_create_event_queue(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating event queue\n");
+ return rc;
+ }
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ rc = pqi_create_queue_group(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating queue group number %u/%u\n",
+ i, ctrl_info->num_queue_groups);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+#define PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH \
+ (offsetof(struct pqi_event_config, descriptors) + \
+ (PQI_MAX_EVENT_DESCRIPTORS * sizeof(struct pqi_event_descriptor)))
+
+static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ unsigned int i;
+ struct pqi_event_config *event_config;
+ struct pqi_general_management_request request;
+
+ event_config = kmalloc(PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
+ GFP_KERNEL);
+ if (!event_config)
+ return -ENOMEM;
+
+ memset(&request, 0, sizeof(request));
+
+ request.header.iu_type = PQI_REQUEST_IU_REPORT_VENDOR_EVENT_CONFIG;
+ put_unaligned_le16(offsetof(struct pqi_general_management_request,
+ data.report_event_configuration.sg_descriptors[1]) -
+ PQI_REQUEST_HEADER_LENGTH, &request.header.iu_length);
+ put_unaligned_le32(PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
+ &request.data.report_event_configuration.buffer_length);
+
+ rc = pqi_map_single(ctrl_info->pci_dev,
+ request.data.report_event_configuration.sg_descriptors,
+ event_config, PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
+ PCI_DMA_FROMDEVICE);
+ if (rc)
+ goto out;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
+ 0, NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev,
+ request.data.report_event_configuration.sg_descriptors, 1,
+ PCI_DMA_FROMDEVICE);
+
+ if (rc)
+ goto out;
+
+ for (i = 0; i < event_config->num_event_descriptors; i++)
+ put_unaligned_le16(ctrl_info->event_queue.oq_id,
+ &event_config->descriptors[i].oq_id);
+
+ memset(&request, 0, sizeof(request));
+
+ request.header.iu_type = PQI_REQUEST_IU_SET_VENDOR_EVENT_CONFIG;
+ put_unaligned_le16(offsetof(struct pqi_general_management_request,
+ data.report_event_configuration.sg_descriptors[1]) -
+ PQI_REQUEST_HEADER_LENGTH, &request.header.iu_length);
+ put_unaligned_le32(PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
+ &request.data.report_event_configuration.buffer_length);
+
+ rc = pqi_map_single(ctrl_info->pci_dev,
+ request.data.report_event_configuration.sg_descriptors,
+ event_config, PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
+ PCI_DMA_TODEVICE);
+ if (rc)
+ goto out;
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
+ NULL, NO_TIMEOUT);
+
+ pqi_pci_unmap(ctrl_info->pci_dev,
+ request.data.report_event_configuration.sg_descriptors, 1,
+ PCI_DMA_TODEVICE);
+
+out:
+ kfree(event_config);
+
+ return rc;
+}
+
+static void pqi_free_all_io_requests(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ struct device *dev;
+ size_t sg_chain_buffer_length;
+ struct pqi_io_request *io_request;
+
+ if (!ctrl_info->io_request_pool)
+ return;
+
+ dev = &ctrl_info->pci_dev->dev;
+ sg_chain_buffer_length = ctrl_info->sg_chain_buffer_length;
+ io_request = ctrl_info->io_request_pool;
+
+ for (i = 0; i < ctrl_info->max_io_slots; i++) {
+ kfree(io_request->iu);
+ if (!io_request->sg_chain_buffer)
+ break;
+ dma_free_coherent(dev, sg_chain_buffer_length,
+ io_request->sg_chain_buffer,
+ io_request->sg_chain_buffer_dma_handle);
+ io_request++;
+ }
+
+ kfree(ctrl_info->io_request_pool);
+ ctrl_info->io_request_pool = NULL;
+}
+
+static inline int pqi_alloc_error_buffer(struct pqi_ctrl_info *ctrl_info)
+{
+ ctrl_info->error_buffer = dma_zalloc_coherent(&ctrl_info->pci_dev->dev,
+ ctrl_info->error_buffer_length,
+ &ctrl_info->error_buffer_dma_handle, GFP_KERNEL);
+
+ if (!ctrl_info->error_buffer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int pqi_alloc_io_resources(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ void *sg_chain_buffer;
+ size_t sg_chain_buffer_length;
+ dma_addr_t sg_chain_buffer_dma_handle;
+ struct device *dev;
+ struct pqi_io_request *io_request;
+
+ ctrl_info->io_request_pool = kzalloc(ctrl_info->max_io_slots *
+ sizeof(ctrl_info->io_request_pool[0]), GFP_KERNEL);
+
+ if (!ctrl_info->io_request_pool) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate I/O request pool\n");
+ goto error;
+ }
+
+ dev = &ctrl_info->pci_dev->dev;
+ sg_chain_buffer_length = ctrl_info->sg_chain_buffer_length;
+ io_request = ctrl_info->io_request_pool;
+
+ for (i = 0; i < ctrl_info->max_io_slots; i++) {
+ io_request->iu =
+ kmalloc(ctrl_info->max_inbound_iu_length, GFP_KERNEL);
+
+ if (!io_request->iu) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate IU buffers\n");
+ goto error;
+ }
+
+ sg_chain_buffer = dma_alloc_coherent(dev,
+ sg_chain_buffer_length, &sg_chain_buffer_dma_handle,
+ GFP_KERNEL);
+
+ if (!sg_chain_buffer) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate PQI scatter-gather chain buffers\n");
+ goto error;
+ }
+
+ io_request->index = i;
+ io_request->sg_chain_buffer = sg_chain_buffer;
+ io_request->sg_chain_buffer_dma_handle =
+ sg_chain_buffer_dma_handle;
+ io_request++;
+ }
+
+ return 0;
+
+error:
+ pqi_free_all_io_requests(ctrl_info);
+
+ return -ENOMEM;
+}
+
+/*
+ * Calculate required resources that are sized based on max. outstanding
+ * requests and max. transfer size.
+ */
+
+static void pqi_calculate_io_resources(struct pqi_ctrl_info *ctrl_info)
+{
+ u32 max_transfer_size;
+ u32 max_sg_entries;
+
+ ctrl_info->scsi_ml_can_queue =
+ ctrl_info->max_outstanding_requests - PQI_RESERVED_IO_SLOTS;
+ ctrl_info->max_io_slots = ctrl_info->max_outstanding_requests;
+
+ ctrl_info->error_buffer_length =
+ ctrl_info->max_io_slots * PQI_ERROR_BUFFER_ELEMENT_LENGTH;
+
+ max_transfer_size =
+ min(ctrl_info->max_transfer_size, PQI_MAX_TRANSFER_SIZE);
+
+ max_sg_entries = max_transfer_size / PAGE_SIZE;
+
+ /* +1 to cover when the buffer is not page-aligned. */
+ max_sg_entries++;
+
+ max_sg_entries = min(ctrl_info->max_sg_entries, max_sg_entries);
+
+ max_transfer_size = (max_sg_entries - 1) * PAGE_SIZE;
+
+ ctrl_info->sg_chain_buffer_length =
+ max_sg_entries * sizeof(struct pqi_sg_descriptor);
+ ctrl_info->sg_tablesize = max_sg_entries;
+ ctrl_info->max_sectors = max_transfer_size / 512;
+}
+
+static void pqi_calculate_queue_resources(struct pqi_ctrl_info *ctrl_info)
+{
+ int num_cpus;
+ int max_queue_groups;
+ int num_queue_groups;
+ u16 num_elements_per_iq;
+ u16 num_elements_per_oq;
+
+ max_queue_groups = min(ctrl_info->max_inbound_queues / 2,
+ ctrl_info->max_outbound_queues - 1);
+ max_queue_groups = min(max_queue_groups, PQI_MAX_QUEUE_GROUPS);
+
+ num_cpus = num_online_cpus();
+ num_queue_groups = min(num_cpus, ctrl_info->max_msix_vectors);
+ num_queue_groups = min(num_queue_groups, max_queue_groups);
+
+ ctrl_info->num_queue_groups = num_queue_groups;
+
+ /*
+ * Make sure that the max. inbound IU length is an even multiple
+ * of our inbound element length.
+ */
+ ctrl_info->max_inbound_iu_length =
+ (ctrl_info->max_inbound_iu_length_per_firmware /
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH) *
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH;
+
+ num_elements_per_iq =
+ (ctrl_info->max_inbound_iu_length /
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+
+ /* Add one because one element in each queue is unusable. */
+ num_elements_per_iq++;
+
+ num_elements_per_iq = min(num_elements_per_iq,
+ ctrl_info->max_elements_per_iq);
+
+ num_elements_per_oq = ((num_elements_per_iq - 1) * 2) + 1;
+ num_elements_per_oq = min(num_elements_per_oq,
+ ctrl_info->max_elements_per_oq);
+
+ ctrl_info->num_elements_per_iq = num_elements_per_iq;
+ ctrl_info->num_elements_per_oq = num_elements_per_oq;
+
+ ctrl_info->max_sg_per_iu =
+ ((ctrl_info->max_inbound_iu_length -
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH) /
+ sizeof(struct pqi_sg_descriptor)) +
+ PQI_MAX_EMBEDDED_SG_DESCRIPTORS;
+}
+
+static inline void pqi_set_sg_descriptor(
+ struct pqi_sg_descriptor *sg_descriptor, struct scatterlist *sg)
+{
+ u64 address = (u64)sg_dma_address(sg);
+ unsigned int length = sg_dma_len(sg);
+
+ put_unaligned_le64(address, &sg_descriptor->address);
+ put_unaligned_le32(length, &sg_descriptor->length);
+ put_unaligned_le32(0, &sg_descriptor->flags);
+}
+
+static int pqi_build_raid_sg_list(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_raid_path_request *request, struct scsi_cmnd *scmd,
+ struct pqi_io_request *io_request)
+{
+ int i;
+ u16 iu_length;
+ int sg_count;
+ bool chained;
+ unsigned int num_sg_in_iu;
+ unsigned int max_sg_per_iu;
+ struct scatterlist *sg;
+ struct pqi_sg_descriptor *sg_descriptor;
+
+ sg_count = scsi_dma_map(scmd);
+ if (sg_count < 0)
+ return sg_count;
+
+ iu_length = offsetof(struct pqi_raid_path_request, sg_descriptors) -
+ PQI_REQUEST_HEADER_LENGTH;
+
+ if (sg_count == 0)
+ goto out;
+
+ sg = scsi_sglist(scmd);
+ sg_descriptor = request->sg_descriptors;
+ max_sg_per_iu = ctrl_info->max_sg_per_iu - 1;
+ chained = false;
+ num_sg_in_iu = 0;
+ i = 0;
+
+ while (1) {
+ pqi_set_sg_descriptor(sg_descriptor, sg);
+ if (!chained)
+ num_sg_in_iu++;
+ i++;
+ if (i == sg_count)
+ break;
+ sg_descriptor++;
+ if (i == max_sg_per_iu) {
+ put_unaligned_le64(
+ (u64)io_request->sg_chain_buffer_dma_handle,
+ &sg_descriptor->address);
+ put_unaligned_le32((sg_count - num_sg_in_iu)
+ * sizeof(*sg_descriptor),
+ &sg_descriptor->length);
+ put_unaligned_le32(CISS_SG_CHAIN,
+ &sg_descriptor->flags);
+ chained = true;
+ num_sg_in_iu++;
+ sg_descriptor = io_request->sg_chain_buffer;
+ }
+ sg = sg_next(sg);
+ }
+
+ put_unaligned_le32(CISS_SG_LAST, &sg_descriptor->flags);
+ request->partial = chained;
+ iu_length += num_sg_in_iu * sizeof(*sg_descriptor);
+
+out:
+ put_unaligned_le16(iu_length, &request->header.iu_length);
+
+ return 0;
+}
+
+static int pqi_build_aio_sg_list(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_aio_path_request *request, struct scsi_cmnd *scmd,
+ struct pqi_io_request *io_request)
+{
+ int i;
+ u16 iu_length;
+ int sg_count;
+ bool chained;
+ unsigned int num_sg_in_iu;
+ unsigned int max_sg_per_iu;
+ struct scatterlist *sg;
+ struct pqi_sg_descriptor *sg_descriptor;
+
+ sg_count = scsi_dma_map(scmd);
+ if (sg_count < 0)
+ return sg_count;
+
+ iu_length = offsetof(struct pqi_aio_path_request, sg_descriptors) -
+ PQI_REQUEST_HEADER_LENGTH;
+ num_sg_in_iu = 0;
+
+ if (sg_count == 0)
+ goto out;
+
+ sg = scsi_sglist(scmd);
+ sg_descriptor = request->sg_descriptors;
+ max_sg_per_iu = ctrl_info->max_sg_per_iu - 1;
+ chained = false;
+ i = 0;
+
+ while (1) {
+ pqi_set_sg_descriptor(sg_descriptor, sg);
+ if (!chained)
+ num_sg_in_iu++;
+ i++;
+ if (i == sg_count)
+ break;
+ sg_descriptor++;
+ if (i == max_sg_per_iu) {
+ put_unaligned_le64(
+ (u64)io_request->sg_chain_buffer_dma_handle,
+ &sg_descriptor->address);
+ put_unaligned_le32((sg_count - num_sg_in_iu)
+ * sizeof(*sg_descriptor),
+ &sg_descriptor->length);
+ put_unaligned_le32(CISS_SG_CHAIN,
+ &sg_descriptor->flags);
+ chained = true;
+ num_sg_in_iu++;
+ sg_descriptor = io_request->sg_chain_buffer;
+ }
+ sg = sg_next(sg);
+ }
+
+ put_unaligned_le32(CISS_SG_LAST, &sg_descriptor->flags);
+ request->partial = chained;
+ iu_length += num_sg_in_iu * sizeof(*sg_descriptor);
+
+out:
+ put_unaligned_le16(iu_length, &request->header.iu_length);
+ request->num_sg_descriptors = num_sg_in_iu;
+
+ return 0;
+}
+
+static void pqi_raid_io_complete(struct pqi_io_request *io_request,
+ void *context)
+{
+ struct scsi_cmnd *scmd;
+
+ scmd = io_request->scmd;
+ pqi_free_io_request(io_request);
+ scsi_dma_unmap(scmd);
+ pqi_scsi_done(scmd);
+}
+
+static int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device, struct scsi_cmnd *scmd,
+ struct pqi_queue_group *queue_group)
+{
+ int rc;
+ size_t cdb_length;
+ struct pqi_io_request *io_request;
+ struct pqi_raid_path_request *request;
+
+ io_request = pqi_alloc_io_request(ctrl_info);
+ io_request->io_complete_callback = pqi_raid_io_complete;
+ io_request->scmd = scmd;
+
+ scmd->host_scribble = (unsigned char *)io_request;
+
+ request = io_request->iu;
+ memset(request, 0,
+ offsetof(struct pqi_raid_path_request, sg_descriptors));
+
+ request->header.iu_type = PQI_REQUEST_IU_RAID_PATH_IO;
+ put_unaligned_le32(scsi_bufflen(scmd), &request->buffer_length);
+ request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
+ put_unaligned_le16(io_request->index, &request->request_id);
+ request->error_index = request->request_id;
+ memcpy(request->lun_number, device->scsi3addr,
+ sizeof(request->lun_number));
+
+ cdb_length = min_t(size_t, scmd->cmd_len, sizeof(request->cdb));
+ memcpy(request->cdb, scmd->cmnd, cdb_length);
+
+ switch (cdb_length) {
+ case 6:
+ case 10:
+ case 12:
+ case 16:
+ /* No bytes in the Additional CDB bytes field */
+ request->additional_cdb_bytes_usage =
+ SOP_ADDITIONAL_CDB_BYTES_0;
+ break;
+ case 20:
+ /* 4 bytes in the Additional cdb field */
+ request->additional_cdb_bytes_usage =
+ SOP_ADDITIONAL_CDB_BYTES_4;
+ break;
+ case 24:
+ /* 8 bytes in the Additional cdb field */
+ request->additional_cdb_bytes_usage =
+ SOP_ADDITIONAL_CDB_BYTES_8;
+ break;
+ case 28:
+ /* 12 bytes in the Additional cdb field */
+ request->additional_cdb_bytes_usage =
+ SOP_ADDITIONAL_CDB_BYTES_12;
+ break;
+ case 32:
+ default:
+ /* 16 bytes in the Additional cdb field */
+ request->additional_cdb_bytes_usage =
+ SOP_ADDITIONAL_CDB_BYTES_16;
+ break;
+ }
+
+ switch (scmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ request->data_direction = SOP_READ_FLAG;
+ break;
+ case DMA_FROM_DEVICE:
+ request->data_direction = SOP_WRITE_FLAG;
+ break;
+ case DMA_NONE:
+ request->data_direction = SOP_NO_DIRECTION_FLAG;
+ break;
+ case DMA_BIDIRECTIONAL:
+ request->data_direction = SOP_BIDIRECTIONAL;
+ break;
+ default:
+ dev_err(&ctrl_info->pci_dev->dev,
+ "unknown data direction: %d\n",
+ scmd->sc_data_direction);
+ WARN_ON(scmd->sc_data_direction);
+ break;
+ }
+
+ rc = pqi_build_raid_sg_list(ctrl_info, request, scmd, io_request);
+ if (rc) {
+ pqi_free_io_request(io_request);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ pqi_start_io(ctrl_info, queue_group, RAID_PATH, io_request);
+
+ return 0;
+}
+
+static void pqi_aio_io_complete(struct pqi_io_request *io_request,
+ void *context)
+{
+ struct scsi_cmnd *scmd;
+
+ scmd = io_request->scmd;
+ scsi_dma_unmap(scmd);
+ if (io_request->status == -EAGAIN)
+ set_host_byte(scmd, DID_IMM_RETRY);
+ pqi_free_io_request(io_request);
+ pqi_scsi_done(scmd);
+}
+
+static inline int pqi_aio_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device, struct scsi_cmnd *scmd,
+ struct pqi_queue_group *queue_group)
+{
+ return pqi_aio_submit_io(ctrl_info, scmd, device->aio_handle,
+ scmd->cmnd, scmd->cmd_len, queue_group, NULL);
+}
+
+static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
+ struct scsi_cmnd *scmd, u32 aio_handle, u8 *cdb,
+ unsigned int cdb_length, struct pqi_queue_group *queue_group,
+ struct pqi_encryption_info *encryption_info)
+{
+ int rc;
+ struct pqi_io_request *io_request;
+ struct pqi_aio_path_request *request;
+
+ io_request = pqi_alloc_io_request(ctrl_info);
+ io_request->io_complete_callback = pqi_aio_io_complete;
+ io_request->scmd = scmd;
+
+ scmd->host_scribble = (unsigned char *)io_request;
+
+ request = io_request->iu;
+ memset(request, 0,
+ offsetof(struct pqi_raid_path_request, sg_descriptors));
+
+ request->header.iu_type = PQI_REQUEST_IU_AIO_PATH_IO;
+ put_unaligned_le32(aio_handle, &request->nexus_id);
+ put_unaligned_le32(scsi_bufflen(scmd), &request->buffer_length);
+ request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
+ put_unaligned_le16(io_request->index, &request->request_id);
+ request->error_index = request->request_id;
+ if (cdb_length > sizeof(request->cdb))
+ cdb_length = sizeof(request->cdb);
+ request->cdb_length = cdb_length;
+ memcpy(request->cdb, cdb, cdb_length);
+
+ switch (scmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ request->data_direction = SOP_READ_FLAG;
+ break;
+ case DMA_FROM_DEVICE:
+ request->data_direction = SOP_WRITE_FLAG;
+ break;
+ case DMA_NONE:
+ request->data_direction = SOP_NO_DIRECTION_FLAG;
+ break;
+ case DMA_BIDIRECTIONAL:
+ request->data_direction = SOP_BIDIRECTIONAL;
+ break;
+ default:
+ dev_err(&ctrl_info->pci_dev->dev,
+ "unknown data direction: %d\n",
+ scmd->sc_data_direction);
+ WARN_ON(scmd->sc_data_direction);
+ break;
+ }
+
+ if (encryption_info) {
+ request->encryption_enable = true;
+ put_unaligned_le16(encryption_info->data_encryption_key_index,
+ &request->data_encryption_key_index);
+ put_unaligned_le32(encryption_info->encrypt_tweak_lower,
+ &request->encrypt_tweak_lower);
+ put_unaligned_le32(encryption_info->encrypt_tweak_upper,
+ &request->encrypt_tweak_upper);
+ }
+
+ rc = pqi_build_aio_sg_list(ctrl_info, request, scmd, io_request);
+ if (rc) {
+ pqi_free_io_request(io_request);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ pqi_start_io(ctrl_info, queue_group, AIO_PATH, io_request);
+
+ return 0;
+}
+
+static int pqi_scsi_queue_command(struct Scsi_Host *shost,
+ struct scsi_cmnd *scmd)
+{
+ int rc;
+ struct pqi_ctrl_info *ctrl_info;
+ struct pqi_scsi_dev *device;
+ u16 hwq;
+ struct pqi_queue_group *queue_group;
+ bool raid_bypassed;
+
+ device = scmd->device->hostdata;
+ ctrl_info = shost_to_hba(shost);
+
+ if (pqi_ctrl_offline(ctrl_info)) {
+ set_host_byte(scmd, DID_NO_CONNECT);
+ pqi_scsi_done(scmd);
+ return 0;
+ }
+
+ /*
+ * This is necessary because the SML doesn't zero out this field during
+ * error recovery.
+ */
+ scmd->result = 0;
+
+ hwq = blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(scmd->request));
+ if (hwq >= ctrl_info->num_queue_groups)
+ hwq = 0;
+
+ queue_group = &ctrl_info->queue_groups[hwq];
+
+ if (pqi_is_logical_device(device)) {
+ raid_bypassed = false;
+ if (device->offload_enabled &&
+ scmd->request->cmd_type == REQ_TYPE_FS) {
+ rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
+ scmd, queue_group);
+ if (rc == 0 ||
+ rc == SCSI_MLQUEUE_HOST_BUSY ||
+ rc == SAM_STAT_CHECK_CONDITION ||
+ rc == SAM_STAT_RESERVATION_CONFLICT)
+ raid_bypassed = true;
+ }
+ if (!raid_bypassed)
+ rc = pqi_raid_submit_scsi_cmd(ctrl_info, device, scmd,
+ queue_group);
+ } else {
+ if (device->aio_enabled)
+ rc = pqi_aio_submit_scsi_cmd(ctrl_info, device, scmd,
+ queue_group);
+ else
+ rc = pqi_raid_submit_scsi_cmd(ctrl_info, device, scmd,
+ queue_group);
+ }
+
+ return rc;
+}
+
+static void pqi_lun_reset_complete(struct pqi_io_request *io_request,
+ void *context)
+{
+ struct completion *waiting = context;
+
+ complete(waiting);
+}
+
+#define PQI_LUN_RESET_TIMEOUT_SECS 10
+
+static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device, struct completion *wait)
+{
+ int rc;
+ unsigned int wait_secs = 0;
+
+ while (1) {
+ if (wait_for_completion_io_timeout(wait,
+ PQI_LUN_RESET_TIMEOUT_SECS * HZ)) {
+ rc = 0;
+ break;
+ }
+
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info)) {
+ rc = -ETIMEDOUT;
+ break;
+ }
+
+ wait_secs += PQI_LUN_RESET_TIMEOUT_SECS;
+
+ dev_err(&ctrl_info->pci_dev->dev,
+ "resetting scsi %d:%d:%d:%d - waiting %u seconds\n",
+ ctrl_info->scsi_host->host_no, device->bus,
+ device->target, device->lun, wait_secs);
+ }
+
+ return rc;
+}
+
+static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ struct pqi_io_request *io_request;
+ DECLARE_COMPLETION_ONSTACK(wait);
+ struct pqi_task_management_request *request;
+
+ down(&ctrl_info->lun_reset_sem);
+
+ io_request = pqi_alloc_io_request(ctrl_info);
+ io_request->io_complete_callback = pqi_lun_reset_complete;
+ io_request->context = &wait;
+
+ request = io_request->iu;
+ memset(request, 0, sizeof(*request));
+
+ request->header.iu_type = PQI_REQUEST_IU_TASK_MANAGEMENT;
+ put_unaligned_le16(sizeof(*request) - PQI_REQUEST_HEADER_LENGTH,
+ &request->header.iu_length);
+ put_unaligned_le16(io_request->index, &request->request_id);
+ memcpy(request->lun_number, device->scsi3addr,
+ sizeof(request->lun_number));
+ request->task_management_function = SOP_TASK_MANAGEMENT_LUN_RESET;
+
+ pqi_start_io(ctrl_info,
+ &ctrl_info->queue_groups[PQI_DEFAULT_QUEUE_GROUP], RAID_PATH,
+ io_request);
+
+ rc = pqi_wait_for_lun_reset_completion(ctrl_info, device, &wait);
+ if (rc == 0)
+ rc = io_request->status;
+
+ pqi_free_io_request(io_request);
+ up(&ctrl_info->lun_reset_sem);
+
+ return rc;
+}
+
+/* Performs a reset at the LUN level. */
+
+static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info))
+ return FAILED;
+
+ rc = pqi_lun_reset(ctrl_info, device);
+
+ return rc == 0 ? SUCCESS : FAILED;
+}
+
+static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd)
+{
+ int rc;
+ struct pqi_ctrl_info *ctrl_info;
+ struct pqi_scsi_dev *device;
+
+ ctrl_info = shost_to_hba(scmd->device->host);
+ device = scmd->device->hostdata;
+
+ dev_err(&ctrl_info->pci_dev->dev,
+ "resetting scsi %d:%d:%d:%d\n",
+ ctrl_info->scsi_host->host_no,
+ device->bus, device->target, device->lun);
+
+ rc = pqi_device_reset(ctrl_info, device);
+
+ dev_err(&ctrl_info->pci_dev->dev,
+ "reset of scsi %d:%d:%d:%d: %s\n",
+ ctrl_info->scsi_host->host_no,
+ device->bus, device->target, device->lun,
+ rc == SUCCESS ? "SUCCESS" : "FAILED");
+
+ return rc;
+}
+
+static int pqi_slave_alloc(struct scsi_device *sdev)
+{
+ struct pqi_scsi_dev *device;
+ unsigned long flags;
+ struct pqi_ctrl_info *ctrl_info;
+ struct scsi_target *starget;
+ struct sas_rphy *rphy;
+
+ ctrl_info = shost_to_hba(sdev->host);
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ if (sdev_channel(sdev) == PQI_PHYSICAL_DEVICE_BUS) {
+ starget = scsi_target(sdev);
+ rphy = target_to_rphy(starget);
+ device = pqi_find_device_by_sas_rphy(ctrl_info, rphy);
+ if (device) {
+ device->target = sdev_id(sdev);
+ device->lun = sdev->lun;
+ device->target_lun_valid = true;
+ }
+ } else {
+ device = pqi_find_scsi_dev(ctrl_info, sdev_channel(sdev),
+ sdev_id(sdev), sdev->lun);
+ }
+
+ if (device && device->expose_device) {
+ sdev->hostdata = device;
+ device->sdev = sdev;
+ if (device->queue_depth) {
+ device->advertised_queue_depth = device->queue_depth;
+ scsi_change_queue_depth(sdev,
+ device->advertised_queue_depth);
+ }
+ }
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
+ return 0;
+}
+
+static int pqi_slave_configure(struct scsi_device *sdev)
+{
+ struct pqi_scsi_dev *device;
+
+ device = sdev->hostdata;
+ if (!device->expose_device)
+ sdev->no_uld_attach = true;
+
+ return 0;
+}
+
+static int pqi_getpciinfo_ioctl(struct pqi_ctrl_info *ctrl_info,
+ void __user *arg)
+{
+ struct pci_dev *pci_dev;
+ u32 subsystem_vendor;
+ u32 subsystem_device;
+ cciss_pci_info_struct pciinfo;
+
+ if (!arg)
+ return -EINVAL;
+
+ pci_dev = ctrl_info->pci_dev;
+
+ pciinfo.domain = pci_domain_nr(pci_dev->bus);
+ pciinfo.bus = pci_dev->bus->number;
+ pciinfo.dev_fn = pci_dev->devfn;
+ subsystem_vendor = pci_dev->subsystem_vendor;
+ subsystem_device = pci_dev->subsystem_device;
+ pciinfo.board_id = ((subsystem_device << 16) & 0xffff0000) |
+ subsystem_vendor;
+
+ if (copy_to_user(arg, &pciinfo, sizeof(pciinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int pqi_getdrivver_ioctl(void __user *arg)
+{
+ u32 version;
+
+ if (!arg)
+ return -EINVAL;
+
+ version = (DRIVER_MAJOR << 28) | (DRIVER_MINOR << 24) |
+ (DRIVER_RELEASE << 16) | DRIVER_REVISION;
+
+ if (copy_to_user(arg, &version, sizeof(version)))
+ return -EFAULT;
+
+ return 0;
+}
+
+struct ciss_error_info {
+ u8 scsi_status;
+ int command_status;
+ size_t sense_data_length;
+};
+
+static void pqi_error_info_to_ciss(struct pqi_raid_error_info *pqi_error_info,
+ struct ciss_error_info *ciss_error_info)
+{
+ int ciss_cmd_status;
+ size_t sense_data_length;
+
+ switch (pqi_error_info->data_out_result) {
+ case PQI_DATA_IN_OUT_GOOD:
+ ciss_cmd_status = CISS_CMD_STATUS_SUCCESS;
+ break;
+ case PQI_DATA_IN_OUT_UNDERFLOW:
+ ciss_cmd_status = CISS_CMD_STATUS_DATA_UNDERRUN;
+ break;
+ case PQI_DATA_IN_OUT_BUFFER_OVERFLOW:
+ ciss_cmd_status = CISS_CMD_STATUS_DATA_OVERRUN;
+ break;
+ case PQI_DATA_IN_OUT_PROTOCOL_ERROR:
+ case PQI_DATA_IN_OUT_BUFFER_ERROR:
+ case PQI_DATA_IN_OUT_BUFFER_OVERFLOW_DESCRIPTOR_AREA:
+ case PQI_DATA_IN_OUT_BUFFER_OVERFLOW_BRIDGE:
+ case PQI_DATA_IN_OUT_ERROR:
+ ciss_cmd_status = CISS_CMD_STATUS_PROTOCOL_ERROR;
+ break;
+ case PQI_DATA_IN_OUT_HARDWARE_ERROR:
+ case PQI_DATA_IN_OUT_PCIE_FABRIC_ERROR:
+ case PQI_DATA_IN_OUT_PCIE_COMPLETION_TIMEOUT:
+ case PQI_DATA_IN_OUT_PCIE_COMPLETER_ABORT_RECEIVED:
+ case PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST_RECEIVED:
+ case PQI_DATA_IN_OUT_PCIE_ECRC_CHECK_FAILED:
+ case PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST:
+ case PQI_DATA_IN_OUT_PCIE_ACS_VIOLATION:
+ case PQI_DATA_IN_OUT_PCIE_TLP_PREFIX_BLOCKED:
+ case PQI_DATA_IN_OUT_PCIE_POISONED_MEMORY_READ:
+ ciss_cmd_status = CISS_CMD_STATUS_HARDWARE_ERROR;
+ break;
+ case PQI_DATA_IN_OUT_UNSOLICITED_ABORT:
+ ciss_cmd_status = CISS_CMD_STATUS_UNSOLICITED_ABORT;
+ break;
+ case PQI_DATA_IN_OUT_ABORTED:
+ ciss_cmd_status = CISS_CMD_STATUS_ABORTED;
+ break;
+ case PQI_DATA_IN_OUT_TIMEOUT:
+ ciss_cmd_status = CISS_CMD_STATUS_TIMEOUT;
+ break;
+ default:
+ ciss_cmd_status = CISS_CMD_STATUS_TARGET_STATUS;
+ break;
+ }
+
+ sense_data_length =
+ get_unaligned_le16(&pqi_error_info->sense_data_length);
+ if (sense_data_length == 0)
+ sense_data_length =
+ get_unaligned_le16(&pqi_error_info->response_data_length);
+ if (sense_data_length)
+ if (sense_data_length > sizeof(pqi_error_info->data))
+ sense_data_length = sizeof(pqi_error_info->data);
+
+ ciss_error_info->scsi_status = pqi_error_info->status;
+ ciss_error_info->command_status = ciss_cmd_status;
+ ciss_error_info->sense_data_length = sense_data_length;
+}
+
+static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg)
+{
+ int rc;
+ char *kernel_buffer = NULL;
+ u16 iu_length;
+ size_t sense_data_length;
+ IOCTL_Command_struct iocommand;
+ struct pqi_raid_path_request request;
+ struct pqi_raid_error_info pqi_error_info;
+ struct ciss_error_info ciss_error_info;
+
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ if (copy_from_user(&iocommand, arg, sizeof(iocommand)))
+ return -EFAULT;
+ if (iocommand.buf_size < 1 &&
+ iocommand.Request.Type.Direction != XFER_NONE)
+ return -EINVAL;
+ if (iocommand.Request.CDBLen > sizeof(request.cdb))
+ return -EINVAL;
+ if (iocommand.Request.Type.Type != TYPE_CMD)
+ return -EINVAL;
+
+ switch (iocommand.Request.Type.Direction) {
+ case XFER_NONE:
+ case XFER_WRITE:
+ case XFER_READ:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (iocommand.buf_size > 0) {
+ kernel_buffer = kmalloc(iocommand.buf_size, GFP_KERNEL);
+ if (!kernel_buffer)
+ return -ENOMEM;
+ if (iocommand.Request.Type.Direction & XFER_WRITE) {
+ if (copy_from_user(kernel_buffer, iocommand.buf,
+ iocommand.buf_size)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ } else {
+ memset(kernel_buffer, 0, iocommand.buf_size);
+ }
+ }
+
+ memset(&request, 0, sizeof(request));
+
+ request.header.iu_type = PQI_REQUEST_IU_RAID_PATH_IO;
+ iu_length = offsetof(struct pqi_raid_path_request, sg_descriptors) -
+ PQI_REQUEST_HEADER_LENGTH;
+ memcpy(request.lun_number, iocommand.LUN_info.LunAddrBytes,
+ sizeof(request.lun_number));
+ memcpy(request.cdb, iocommand.Request.CDB, iocommand.Request.CDBLen);
+ request.additional_cdb_bytes_usage = SOP_ADDITIONAL_CDB_BYTES_0;
+
+ switch (iocommand.Request.Type.Direction) {
+ case XFER_NONE:
+ request.data_direction = SOP_NO_DIRECTION_FLAG;
+ break;
+ case XFER_WRITE:
+ request.data_direction = SOP_WRITE_FLAG;
+ break;
+ case XFER_READ:
+ request.data_direction = SOP_READ_FLAG;
+ break;
+ }
+
+ request.task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
+
+ if (iocommand.buf_size > 0) {
+ put_unaligned_le32(iocommand.buf_size, &request.buffer_length);
+
+ rc = pqi_map_single(ctrl_info->pci_dev,
+ &request.sg_descriptors[0], kernel_buffer,
+ iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+ if (rc)
+ goto out;
+
+ iu_length += sizeof(request.sg_descriptors[0]);
+ }
+
+ put_unaligned_le16(iu_length, &request.header.iu_length);
+
+ rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
+ PQI_SYNC_FLAGS_INTERRUPTABLE, &pqi_error_info, NO_TIMEOUT);
+
+ if (iocommand.buf_size > 0)
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
+ PCI_DMA_BIDIRECTIONAL);
+
+ memset(&iocommand.error_info, 0, sizeof(iocommand.error_info));
+
+ if (rc == 0) {
+ pqi_error_info_to_ciss(&pqi_error_info, &ciss_error_info);
+ iocommand.error_info.ScsiStatus = ciss_error_info.scsi_status;
+ iocommand.error_info.CommandStatus =
+ ciss_error_info.command_status;
+ sense_data_length = ciss_error_info.sense_data_length;
+ if (sense_data_length) {
+ if (sense_data_length >
+ sizeof(iocommand.error_info.SenseInfo))
+ sense_data_length =
+ sizeof(iocommand.error_info.SenseInfo);
+ memcpy(iocommand.error_info.SenseInfo,
+ pqi_error_info.data, sense_data_length);
+ iocommand.error_info.SenseLen = sense_data_length;
+ }
+ }
+
+ if (copy_to_user(arg, &iocommand, sizeof(iocommand))) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ if (rc == 0 && iocommand.buf_size > 0 &&
+ (iocommand.Request.Type.Direction & XFER_READ)) {
+ if (copy_to_user(iocommand.buf, kernel_buffer,
+ iocommand.buf_size)) {
+ rc = -EFAULT;
+ }
+ }
+
+out:
+ kfree(kernel_buffer);
+
+ return rc;
+}
+
+static int pqi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+ int rc;
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = shost_to_hba(sdev->host);
+
+ switch (cmd) {
+ case CCISS_DEREGDISK:
+ case CCISS_REGNEWDISK:
+ case CCISS_REGNEWD:
+ rc = pqi_scan_scsi_devices(ctrl_info);
+ break;
+ case CCISS_GETPCIINFO:
+ rc = pqi_getpciinfo_ioctl(ctrl_info, arg);
+ break;
+ case CCISS_GETDRIVVER:
+ rc = pqi_getdrivver_ioctl(arg);
+ break;
+ case CCISS_PASSTHRU:
+ rc = pqi_passthru_ioctl(ctrl_info, arg);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static ssize_t pqi_version_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t count = 0;
+ struct Scsi_Host *shost;
+ struct pqi_ctrl_info *ctrl_info;
+
+ shost = class_to_shost(dev);
+ ctrl_info = shost_to_hba(shost);
+
+ count += snprintf(buffer + count, PAGE_SIZE - count,
+ " driver: %s\n", DRIVER_VERSION BUILD_TIMESTAMP);
+
+ count += snprintf(buffer + count, PAGE_SIZE - count,
+ "firmware: %s\n", ctrl_info->firmware_version);
+
+ return count;
+}
+
+static ssize_t pqi_host_rescan_store(struct device *dev,
+ struct device_attribute *attr, const char *buffer, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+
+ pqi_scan_start(shost);
+
+ return count;
+}
+
+static DEVICE_ATTR(version, S_IRUGO, pqi_version_show, NULL);
+static DEVICE_ATTR(rescan, S_IWUSR, NULL, pqi_host_rescan_store);
+
+static struct device_attribute *pqi_shost_attrs[] = {
+ &dev_attr_version,
+ &dev_attr_rescan,
+ NULL
+};
+
+static ssize_t pqi_sas_address_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ struct pqi_ctrl_info *ctrl_info;
+ struct scsi_device *sdev;
+ struct pqi_scsi_dev *device;
+ unsigned long flags;
+ u64 sas_address;
+
+ sdev = to_scsi_device(dev);
+ ctrl_info = shost_to_hba(sdev->host);
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ device = sdev->hostdata;
+ if (pqi_is_logical_device(device)) {
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock,
+ flags);
+ return -ENODEV;
+ }
+ sas_address = device->sas_address;
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
+ return snprintf(buffer, PAGE_SIZE, "0x%016llx\n", sas_address);
+}
+
+static ssize_t pqi_ssd_smart_path_enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ struct pqi_ctrl_info *ctrl_info;
+ struct scsi_device *sdev;
+ struct pqi_scsi_dev *device;
+ unsigned long flags;
+
+ sdev = to_scsi_device(dev);
+ ctrl_info = shost_to_hba(sdev->host);
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ device = sdev->hostdata;
+ buffer[0] = device->offload_enabled ? '1' : '0';
+ buffer[1] = '\n';
+ buffer[2] = '\0';
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
+ return 2;
+}
+
+static DEVICE_ATTR(sas_address, S_IRUGO, pqi_sas_address_show, NULL);
+static DEVICE_ATTR(ssd_smart_path_enabled, S_IRUGO,
+ pqi_ssd_smart_path_enabled_show, NULL);
+
+static struct device_attribute *pqi_sdev_attrs[] = {
+ &dev_attr_sas_address,
+ &dev_attr_ssd_smart_path_enabled,
+ NULL
+};
+
+static struct scsi_host_template pqi_driver_template = {
+ .module = THIS_MODULE,
+ .name = DRIVER_NAME_SHORT,
+ .proc_name = DRIVER_NAME_SHORT,
+ .queuecommand = pqi_scsi_queue_command,
+ .scan_start = pqi_scan_start,
+ .scan_finished = pqi_scan_finished,
+ .this_id = -1,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = pqi_eh_device_reset_handler,
+ .ioctl = pqi_ioctl,
+ .slave_alloc = pqi_slave_alloc,
+ .slave_configure = pqi_slave_configure,
+ .sdev_attrs = pqi_sdev_attrs,
+ .shost_attrs = pqi_shost_attrs,
+};
+
+static int pqi_register_scsi(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct Scsi_Host *shost;
+
+ shost = scsi_host_alloc(&pqi_driver_template, sizeof(ctrl_info));
+ if (!shost) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "scsi_host_alloc failed for controller %u\n",
+ ctrl_info->ctrl_id);
+ return -ENOMEM;
+ }
+
+ shost->io_port = 0;
+ shost->n_io_port = 0;
+ shost->this_id = -1;
+ shost->max_channel = PQI_MAX_BUS;
+ shost->max_cmd_len = MAX_COMMAND_SIZE;
+ shost->max_lun = ~0;
+ shost->max_id = ~0;
+ shost->max_sectors = ctrl_info->max_sectors;
+ shost->can_queue = ctrl_info->scsi_ml_can_queue;
+ shost->cmd_per_lun = shost->can_queue;
+ shost->sg_tablesize = ctrl_info->sg_tablesize;
+ shost->transportt = pqi_sas_transport_template;
+ shost->irq = ctrl_info->msix_vectors[0];
+ shost->unique_id = shost->irq;
+ shost->nr_hw_queues = ctrl_info->num_queue_groups;
+ shost->hostdata[0] = (unsigned long)ctrl_info;
+
+ rc = scsi_add_host(shost, &ctrl_info->pci_dev->dev);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "scsi_add_host failed for controller %u\n",
+ ctrl_info->ctrl_id);
+ goto free_host;
+ }
+
+ rc = pqi_add_sas_host(shost, ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "add SAS host failed for controller %u\n",
+ ctrl_info->ctrl_id);
+ goto remove_host;
+ }
+
+ ctrl_info->scsi_host = shost;
+
+ return 0;
+
+remove_host:
+ scsi_remove_host(shost);
+free_host:
+ scsi_host_put(shost);
+
+ return rc;
+}
+
+static void pqi_unregister_scsi(struct pqi_ctrl_info *ctrl_info)
+{
+ struct Scsi_Host *shost;
+
+ pqi_delete_sas_host(ctrl_info);
+
+ shost = ctrl_info->scsi_host;
+ if (!shost)
+ return;
+
+ scsi_remove_host(shost);
+ scsi_host_put(shost);
+}
+
+#define PQI_RESET_ACTION_RESET 0x1
+
+#define PQI_RESET_TYPE_NO_RESET 0x0
+#define PQI_RESET_TYPE_SOFT_RESET 0x1
+#define PQI_RESET_TYPE_FIRM_RESET 0x2
+#define PQI_RESET_TYPE_HARD_RESET 0x3
+
+static int pqi_reset(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ u32 reset_params;
+
+ reset_params = (PQI_RESET_ACTION_RESET << 5) |
+ PQI_RESET_TYPE_HARD_RESET;
+
+ writel(reset_params,
+ &ctrl_info->pqi_registers->device_reset);
+
+ rc = pqi_wait_for_pqi_mode_ready(ctrl_info);
+ if (rc)
+ dev_err(&ctrl_info->pci_dev->dev,
+ "PQI reset failed\n");
+
+ return rc;
+}
+
+static int pqi_get_ctrl_firmware_version(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct bmic_identify_controller *identify;
+
+ identify = kmalloc(sizeof(*identify), GFP_KERNEL);
+ if (!identify)
+ return -ENOMEM;
+
+ rc = pqi_identify_controller(ctrl_info, identify);
+ if (rc)
+ goto out;
+
+ memcpy(ctrl_info->firmware_version, identify->firmware_version,
+ sizeof(identify->firmware_version));
+ ctrl_info->firmware_version[sizeof(identify->firmware_version)] = '\0';
+ snprintf(ctrl_info->firmware_version +
+ strlen(ctrl_info->firmware_version),
+ sizeof(ctrl_info->firmware_version),
+ "-%u", get_unaligned_le16(&identify->firmware_build_number));
+
+out:
+ kfree(identify);
+
+ return rc;
+}
+
+static int pqi_kdump_init(struct pqi_ctrl_info *ctrl_info)
+{
+ if (!sis_is_firmware_running(ctrl_info))
+ return -ENXIO;
+
+ if (pqi_get_ctrl_mode(ctrl_info) == PQI_MODE) {
+ sis_disable_msix(ctrl_info);
+ if (pqi_reset(ctrl_info) == 0)
+ sis_reenable_sis_mode(ctrl_info);
+ }
+
+ return 0;
+}
+
+static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+
+ if (reset_devices) {
+ rc = pqi_kdump_init(ctrl_info);
+ if (rc)
+ return rc;
+ }
+
+ /*
+ * When the controller comes out of reset, it is always running
+ * in legacy SIS mode. This is so that it can be compatible
+ * with legacy drivers shipped with OSes. So we have to talk
+ * to it using SIS commands at first. Once we are satisified
+ * that the controller supports PQI, we transition it into PQI
+ * mode.
+ */
+
+ /*
+ * Wait until the controller is ready to start accepting SIS
+ * commands.
+ */
+ rc = sis_wait_for_ctrl_ready(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error initializing SIS interface\n");
+ return rc;
+ }
+
+ /*
+ * Get the controller properties. This allows us to determine
+ * whether or not it supports PQI mode.
+ */
+ rc = sis_get_ctrl_properties(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error obtaining controller properties\n");
+ return rc;
+ }
+
+ rc = sis_get_pqi_capabilities(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error obtaining controller capabilities\n");
+ return rc;
+ }
+
+ if (ctrl_info->max_outstanding_requests > PQI_MAX_OUTSTANDING_REQUESTS)
+ ctrl_info->max_outstanding_requests =
+ PQI_MAX_OUTSTANDING_REQUESTS;
+
+ pqi_calculate_io_resources(ctrl_info);
+
+ rc = pqi_alloc_error_buffer(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate PQI error buffer\n");
+ return rc;
+ }
+
+ /*
+ * If the function we are about to call succeeds, the
+ * controller will transition from legacy SIS mode
+ * into PQI mode.
+ */
+ rc = sis_init_base_struct_addr(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error initializing PQI mode\n");
+ return rc;
+ }
+
+ /* Wait for the controller to complete the SIS -> PQI transition. */
+ rc = pqi_wait_for_pqi_mode_ready(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "transition to PQI mode failed\n");
+ return rc;
+ }
+
+ /* From here on, we are running in PQI mode. */
+ ctrl_info->pqi_mode_enabled = true;
+ pqi_save_ctrl_mode(ctrl_info, PQI_MODE);
+
+ rc = pqi_alloc_admin_queues(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error allocating admin queues\n");
+ return rc;
+ }
+
+ rc = pqi_create_admin_queues(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating admin queues\n");
+ return rc;
+ }
+
+ rc = pqi_report_device_capability(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "obtaining device capability failed\n");
+ return rc;
+ }
+
+ rc = pqi_validate_device_capability(ctrl_info);
+ if (rc)
+ return rc;
+
+ pqi_calculate_queue_resources(ctrl_info);
+
+ rc = pqi_enable_msix_interrupts(ctrl_info);
+ if (rc)
+ return rc;
+
+ if (ctrl_info->num_msix_vectors_enabled < ctrl_info->num_queue_groups) {
+ ctrl_info->max_msix_vectors =
+ ctrl_info->num_msix_vectors_enabled;
+ pqi_calculate_queue_resources(ctrl_info);
+ }
+
+ rc = pqi_alloc_io_resources(ctrl_info);
+ if (rc)
+ return rc;
+
+ rc = pqi_alloc_operational_queues(ctrl_info);
+ if (rc)
+ return rc;
+
+ pqi_init_operational_queues(ctrl_info);
+
+ rc = pqi_request_irqs(ctrl_info);
+ if (rc)
+ return rc;
+
+ pqi_irq_set_affinity_hint(ctrl_info);
+
+ rc = pqi_create_queues(ctrl_info);
+ if (rc)
+ return rc;
+
+ sis_enable_msix(ctrl_info);
+
+ rc = pqi_configure_events(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error configuring events\n");
+ return rc;
+ }
+
+ pqi_start_heartbeat_timer(ctrl_info);
+
+ ctrl_info->controller_online = true;
+
+ /* Register with the SCSI subsystem. */
+ rc = pqi_register_scsi(ctrl_info);
+ if (rc)
+ return rc;
+
+ rc = pqi_get_ctrl_firmware_version(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error obtaining firmware version\n");
+ return rc;
+ }
+
+ rc = pqi_write_driver_version_to_host_wellness(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error updating host wellness\n");
+ return rc;
+ }
+
+ pqi_schedule_update_time_worker(ctrl_info);
+
+ pqi_scan_scsi_devices(ctrl_info);
+
+ return 0;
+}
+
+static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ u64 mask;
+
+ rc = pci_enable_device(ctrl_info->pci_dev);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to enable PCI device\n");
+ return rc;
+ }
+
+ if (sizeof(dma_addr_t) > 4)
+ mask = DMA_BIT_MASK(64);
+ else
+ mask = DMA_BIT_MASK(32);
+
+ rc = dma_set_mask(&ctrl_info->pci_dev->dev, mask);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev, "failed to set DMA mask\n");
+ goto disable_device;
+ }
+
+ rc = pci_request_regions(ctrl_info->pci_dev, DRIVER_NAME_SHORT);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to obtain PCI resources\n");
+ goto disable_device;
+ }
+
+ ctrl_info->iomem_base = ioremap_nocache(pci_resource_start(
+ ctrl_info->pci_dev, 0),
+ sizeof(struct pqi_ctrl_registers));
+ if (!ctrl_info->iomem_base) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to map memory for controller registers\n");
+ rc = -ENOMEM;
+ goto release_regions;
+ }
+
+ ctrl_info->registers = ctrl_info->iomem_base;
+ ctrl_info->pqi_registers = &ctrl_info->registers->pqi_registers;
+
+ /* Enable bus mastering. */
+ pci_set_master(ctrl_info->pci_dev);
+
+ pci_set_drvdata(ctrl_info->pci_dev, ctrl_info);
+
+ return 0;
+
+release_regions:
+ pci_release_regions(ctrl_info->pci_dev);
+disable_device:
+ pci_disable_device(ctrl_info->pci_dev);
+
+ return rc;
+}
+
+static void pqi_cleanup_pci_init(struct pqi_ctrl_info *ctrl_info)
+{
+ iounmap(ctrl_info->iomem_base);
+ pci_release_regions(ctrl_info->pci_dev);
+ pci_disable_device(ctrl_info->pci_dev);
+ pci_set_drvdata(ctrl_info->pci_dev, NULL);
+}
+
+static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = kzalloc_node(sizeof(struct pqi_ctrl_info),
+ GFP_KERNEL, numa_node);
+ if (!ctrl_info)
+ return NULL;
+
+ mutex_init(&ctrl_info->scan_mutex);
+
+ INIT_LIST_HEAD(&ctrl_info->scsi_device_list);
+ spin_lock_init(&ctrl_info->scsi_device_list_lock);
+
+ INIT_WORK(&ctrl_info->event_work, pqi_event_worker);
+ atomic_set(&ctrl_info->num_interrupts, 0);
+
+ INIT_DELAYED_WORK(&ctrl_info->rescan_work, pqi_rescan_worker);
+ INIT_DELAYED_WORK(&ctrl_info->update_time_work, pqi_update_time_worker);
+
+ sema_init(&ctrl_info->sync_request_sem,
+ PQI_RESERVED_IO_SLOTS_SYNCHRONOUS_REQUESTS);
+ sema_init(&ctrl_info->lun_reset_sem, PQI_RESERVED_IO_SLOTS_LUN_RESET);
+
+ ctrl_info->ctrl_id = atomic_inc_return(&pqi_controller_count) - 1;
+ ctrl_info->max_msix_vectors = PQI_MAX_MSIX_VECTORS;
+
+ return ctrl_info;
+}
+
+static inline void pqi_free_ctrl_info(struct pqi_ctrl_info *ctrl_info)
+{
+ kfree(ctrl_info);
+}
+
+static void pqi_free_interrupts(struct pqi_ctrl_info *ctrl_info)
+{
+ pqi_irq_unset_affinity_hint(ctrl_info);
+ pqi_free_irqs(ctrl_info);
+ if (ctrl_info->num_msix_vectors_enabled)
+ pci_disable_msix(ctrl_info->pci_dev);
+}
+
+static void pqi_free_ctrl_resources(struct pqi_ctrl_info *ctrl_info)
+{
+ pqi_stop_heartbeat_timer(ctrl_info);
+ pqi_free_interrupts(ctrl_info);
+ if (ctrl_info->queue_memory_base)
+ dma_free_coherent(&ctrl_info->pci_dev->dev,
+ ctrl_info->queue_memory_length,
+ ctrl_info->queue_memory_base,
+ ctrl_info->queue_memory_base_dma_handle);
+ if (ctrl_info->admin_queue_memory_base)
+ dma_free_coherent(&ctrl_info->pci_dev->dev,
+ ctrl_info->admin_queue_memory_length,
+ ctrl_info->admin_queue_memory_base,
+ ctrl_info->admin_queue_memory_base_dma_handle);
+ pqi_free_all_io_requests(ctrl_info);
+ if (ctrl_info->error_buffer)
+ dma_free_coherent(&ctrl_info->pci_dev->dev,
+ ctrl_info->error_buffer_length,
+ ctrl_info->error_buffer,
+ ctrl_info->error_buffer_dma_handle);
+ if (ctrl_info->iomem_base)
+ pqi_cleanup_pci_init(ctrl_info);
+ pqi_free_ctrl_info(ctrl_info);
+}
+
+static void pqi_remove_ctrl(struct pqi_ctrl_info *ctrl_info)
+{
+ cancel_delayed_work_sync(&ctrl_info->rescan_work);
+ cancel_delayed_work_sync(&ctrl_info->update_time_work);
+ pqi_remove_all_scsi_devices(ctrl_info);
+ pqi_unregister_scsi(ctrl_info);
+
+ if (ctrl_info->pqi_mode_enabled) {
+ sis_disable_msix(ctrl_info);
+ if (pqi_reset(ctrl_info) == 0)
+ sis_reenable_sis_mode(ctrl_info);
+ }
+ pqi_free_ctrl_resources(ctrl_info);
+}
+
+static void pqi_print_ctrl_info(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ char *ctrl_description;
+
+ if (id->driver_data) {
+ ctrl_description = (char *)id->driver_data;
+ } else {
+ switch (id->subvendor) {
+ case PCI_VENDOR_ID_HP:
+ ctrl_description = hpe_branded_controller;
+ break;
+ case PCI_VENDOR_ID_ADAPTEC2:
+ default:
+ ctrl_description = microsemi_branded_controller;
+ break;
+ }
+ }
+
+ dev_info(&pdev->dev, "%s found\n", ctrl_description);
+}
+
+static int pqi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int rc;
+ int node;
+ struct pqi_ctrl_info *ctrl_info;
+
+ pqi_print_ctrl_info(pdev, id);
+
+ if (pqi_disable_device_id_wildcards &&
+ id->subvendor == PCI_ANY_ID &&
+ id->subdevice == PCI_ANY_ID) {
+ dev_warn(&pdev->dev,
+ "controller not probed because device ID wildcards are disabled\n");
+ return -ENODEV;
+ }
+
+ if (id->subvendor == PCI_ANY_ID || id->subdevice == PCI_ANY_ID)
+ dev_warn(&pdev->dev,
+ "controller device ID matched using wildcards\n");
+
+ node = dev_to_node(&pdev->dev);
+ if (node == NUMA_NO_NODE)
+ set_dev_node(&pdev->dev, 0);
+
+ ctrl_info = pqi_alloc_ctrl_info(node);
+ if (!ctrl_info) {
+ dev_err(&pdev->dev,
+ "failed to allocate controller info block\n");
+ return -ENOMEM;
+ }
+
+ ctrl_info->pci_dev = pdev;
+
+ rc = pqi_pci_init(ctrl_info);
+ if (rc)
+ goto error;
+
+ rc = pqi_ctrl_init(ctrl_info);
+ if (rc)
+ goto error;
+
+ return 0;
+
+error:
+ pqi_remove_ctrl(ctrl_info);
+
+ return rc;
+}
+
+static void pqi_pci_remove(struct pci_dev *pdev)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = pci_get_drvdata(pdev);
+ if (!ctrl_info)
+ return;
+
+ pqi_remove_ctrl(ctrl_info);
+}
+
+static void pqi_shutdown(struct pci_dev *pdev)
+{
+ int rc;
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = pci_get_drvdata(pdev);
+ if (!ctrl_info)
+ goto error;
+
+ /*
+ * Write all data in the controller's battery-backed cache to
+ * storage.
+ */
+ rc = pqi_flush_cache(ctrl_info);
+ if (rc == 0)
+ return;
+
+error:
+ dev_warn(&pdev->dev,
+ "unable to flush controller cache\n");
+}
+
+/* Define the PCI IDs for the controllers that we support. */
+static const struct pci_device_id pqi_pci_id_table[] = {
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0110)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0600)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0601)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0602)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0603)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0650)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0651)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0652)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0653)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0654)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0655)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0700)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0701)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0800)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0801)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0802)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0803)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0804)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0805)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0900)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0901)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0902)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0903)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0904)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0905)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_ADAPTEC2, 0x0906)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x1001)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x1100)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x1101)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x1102)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x1150)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_ANY_ID, PCI_ANY_ID)
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, pqi_pci_id_table);
+
+static struct pci_driver pqi_pci_driver = {
+ .name = DRIVER_NAME_SHORT,
+ .id_table = pqi_pci_id_table,
+ .probe = pqi_pci_probe,
+ .remove = pqi_pci_remove,
+ .shutdown = pqi_shutdown,
+};
+
+static int __init pqi_init(void)
+{
+ int rc;
+
+ pr_info(DRIVER_NAME "\n");
+
+ pqi_sas_transport_template =
+ sas_attach_transport(&pqi_sas_transport_functions);
+ if (!pqi_sas_transport_template)
+ return -ENODEV;
+
+ rc = pci_register_driver(&pqi_pci_driver);
+ if (rc)
+ sas_release_transport(pqi_sas_transport_template);
+
+ return rc;
+}
+
+static void __exit pqi_cleanup(void)
+{
+ pci_unregister_driver(&pqi_pci_driver);
+ sas_release_transport(pqi_sas_transport_template);
+}
+
+module_init(pqi_init);
+module_exit(pqi_cleanup);
+
+static void __attribute__((unused)) verify_structures(void)
+{
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_host_to_ctrl_doorbell) != 0x20);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_interrupt_mask) != 0x34);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_ctrl_to_host_doorbell) != 0x9c);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_ctrl_to_host_doorbell_clear) != 0xa0);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_driver_scratch) != 0xb0);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_firmware_status) != 0xbc);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ sis_mailbox) != 0x1000);
+ BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers,
+ pqi_registers) != 0x4000);
+
+ BUILD_BUG_ON(offsetof(struct pqi_iu_header,
+ iu_type) != 0x0);
+ BUILD_BUG_ON(offsetof(struct pqi_iu_header,
+ iu_length) != 0x2);
+ BUILD_BUG_ON(offsetof(struct pqi_iu_header,
+ response_queue_id) != 0x4);
+ BUILD_BUG_ON(offsetof(struct pqi_iu_header,
+ work_area) != 0x6);
+ BUILD_BUG_ON(sizeof(struct pqi_iu_header) != 0x8);
+
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ status) != 0x0);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ service_response) != 0x1);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ data_present) != 0x2);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ reserved) != 0x3);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ residual_count) != 0x4);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ data_length) != 0x8);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ reserved1) != 0xa);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_error_info,
+ data) != 0xc);
+ BUILD_BUG_ON(sizeof(struct pqi_aio_error_info) != 0x10c);
+
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ data_in_result) != 0x0);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ data_out_result) != 0x1);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ reserved) != 0x2);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ status) != 0x5);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ status_qualifier) != 0x6);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ sense_data_length) != 0x8);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ response_data_length) != 0xa);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ data_in_transferred) != 0xc);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ data_out_transferred) != 0x10);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_error_info,
+ data) != 0x14);
+ BUILD_BUG_ON(sizeof(struct pqi_raid_error_info) != 0x114);
+
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ signature) != 0x0);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ function_and_status_code) != 0x8);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ max_admin_iq_elements) != 0x10);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ max_admin_oq_elements) != 0x11);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_iq_element_length) != 0x12);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_oq_element_length) != 0x13);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ max_reset_timeout) != 0x14);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ legacy_intx_status) != 0x18);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ legacy_intx_mask_set) != 0x1c);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ legacy_intx_mask_clear) != 0x20);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ device_status) != 0x40);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_iq_pi_offset) != 0x48);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_oq_ci_offset) != 0x50);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_iq_element_array_addr) != 0x58);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_oq_element_array_addr) != 0x60);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_iq_ci_addr) != 0x68);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_oq_pi_addr) != 0x70);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_iq_num_elements) != 0x78);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_oq_num_elements) != 0x79);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ admin_queue_int_msg_num) != 0x7a);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ device_error) != 0x80);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ error_details) != 0x88);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ device_reset) != 0x90);
+ BUILD_BUG_ON(offsetof(struct pqi_device_registers,
+ power_action) != 0x94);
+ BUILD_BUG_ON(sizeof(struct pqi_device_registers) != 0x100);
+
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ header.work_area) != 6);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ function_code) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.report_device_capability.buffer_length) != 44);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.report_device_capability.sg_descriptor) != 48);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_iq.queue_id) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_iq.element_array_addr) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_iq.ci_addr) != 24);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_iq.num_elements) != 32);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_iq.element_length) != 34);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_iq.queue_protocol) != 36);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.queue_id) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.element_array_addr) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.pi_addr) != 24);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.num_elements) != 32);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.element_length) != 34);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.queue_protocol) != 36);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.int_msg_num) != 40);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.coalescing_count) != 42);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.min_coalescing_time) != 44);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.create_operational_oq.max_coalescing_time) != 48);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_request,
+ data.delete_operational_queue.queue_id) != 12);
+ BUILD_BUG_ON(sizeof(struct pqi_general_admin_request) != 64);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct pqi_general_admin_request,
+ data.create_operational_iq) != 64 - 11);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct pqi_general_admin_request,
+ data.create_operational_oq) != 64 - 11);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct pqi_general_admin_request,
+ data.delete_operational_queue) != 64 - 11);
+
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ header.work_area) != 6);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ function_code) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ status) != 11);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ data.create_operational_iq.status_descriptor) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ data.create_operational_iq.iq_pi_offset) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ data.create_operational_oq.status_descriptor) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_general_admin_response,
+ data.create_operational_oq.oq_ci_offset) != 16);
+ BUILD_BUG_ON(sizeof(struct pqi_general_admin_response) != 64);
+
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ header.response_queue_id) != 4);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ header.work_area) != 6);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ nexus_id) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ buffer_length) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ lun_number) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ protocol_specific) != 24);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ error_index) != 27);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ cdb) != 32);
+ BUILD_BUG_ON(offsetof(struct pqi_raid_path_request,
+ sg_descriptors) != 64);
+ BUILD_BUG_ON(sizeof(struct pqi_raid_path_request) !=
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ header.response_queue_id) != 4);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ header.work_area) != 6);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ nexus_id) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ buffer_length) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ data_encryption_key_index) != 22);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ encrypt_tweak_lower) != 24);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ encrypt_tweak_upper) != 28);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ cdb) != 32);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ error_index) != 48);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ num_sg_descriptors) != 50);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ cdb_length) != 51);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ lun_number) != 52);
+ BUILD_BUG_ON(offsetof(struct pqi_aio_path_request,
+ sg_descriptors) != 64);
+ BUILD_BUG_ON(sizeof(struct pqi_aio_path_request) !=
+ PQI_OPERATIONAL_IQ_ELEMENT_LENGTH);
+
+ BUILD_BUG_ON(offsetof(struct pqi_io_response,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_io_response,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_io_response,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_io_response,
+ error_index) != 10);
+
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ header.response_queue_id) != 4);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ data.report_event_configuration.buffer_length) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ data.report_event_configuration.sg_descriptors) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ data.set_event_configuration.global_event_oq_id) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ data.set_event_configuration.buffer_length) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_general_management_request,
+ data.set_event_configuration.sg_descriptors) != 16);
+
+ BUILD_BUG_ON(offsetof(struct pqi_iu_layer_descriptor,
+ max_inbound_iu_length) != 6);
+ BUILD_BUG_ON(offsetof(struct pqi_iu_layer_descriptor,
+ max_outbound_iu_length) != 14);
+ BUILD_BUG_ON(sizeof(struct pqi_iu_layer_descriptor) != 16);
+
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ data_length) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ iq_arbitration_priority_support_bitmask) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ maximum_aw_a) != 9);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ maximum_aw_b) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ maximum_aw_c) != 11);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ max_inbound_queues) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ max_elements_per_iq) != 18);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ max_iq_element_length) != 24);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ min_iq_element_length) != 26);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ max_outbound_queues) != 30);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ max_elements_per_oq) != 32);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ intr_coalescing_time_granularity) != 34);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ max_oq_element_length) != 36);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ min_oq_element_length) != 38);
+ BUILD_BUG_ON(offsetof(struct pqi_device_capability,
+ iu_layer_descriptors) != 64);
+ BUILD_BUG_ON(sizeof(struct pqi_device_capability) != 576);
+
+ BUILD_BUG_ON(offsetof(struct pqi_event_descriptor,
+ event_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_event_descriptor,
+ oq_id) != 2);
+ BUILD_BUG_ON(sizeof(struct pqi_event_descriptor) != 4);
+
+ BUILD_BUG_ON(offsetof(struct pqi_event_config,
+ num_event_descriptors) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_event_config,
+ descriptors) != 4);
+
+ BUILD_BUG_ON(offsetof(struct pqi_event_response,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_event_response,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_event_response,
+ event_type) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_event_response,
+ event_id) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_event_response,
+ additional_event_id) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_event_response,
+ data) != 16);
+ BUILD_BUG_ON(sizeof(struct pqi_event_response) != 32);
+
+ BUILD_BUG_ON(offsetof(struct pqi_event_acknowledge_request,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_event_acknowledge_request,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_event_acknowledge_request,
+ event_type) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_event_acknowledge_request,
+ event_id) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_event_acknowledge_request,
+ additional_event_id) != 12);
+ BUILD_BUG_ON(sizeof(struct pqi_event_acknowledge_request) != 16);
+
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ nexus_id) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ lun_number) != 16);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ protocol_specific) != 24);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ outbound_queue_id_to_manage) != 26);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ request_id_to_manage) != 28);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_request,
+ task_management_function) != 30);
+ BUILD_BUG_ON(sizeof(struct pqi_task_management_request) != 32);
+
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_response,
+ header.iu_type) != 0);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_response,
+ header.iu_length) != 2);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_response,
+ request_id) != 8);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_response,
+ nexus_id) != 10);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_response,
+ additional_response_info) != 12);
+ BUILD_BUG_ON(offsetof(struct pqi_task_management_response,
+ response_code) != 15);
+ BUILD_BUG_ON(sizeof(struct pqi_task_management_response) != 16);
+
+ BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
+ configured_logical_drive_count) != 0);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
+ configuration_signature) != 1);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
+ firmware_version) != 5);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
+ extended_logical_unit_count) != 154);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
+ firmware_build_number) != 190);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
+ controller_mode) != 292);
+
+ BUILD_BUG_ON(PQI_ADMIN_IQ_NUM_ELEMENTS > 255);
+ BUILD_BUG_ON(PQI_ADMIN_OQ_NUM_ELEMENTS > 255);
+ BUILD_BUG_ON(PQI_ADMIN_IQ_ELEMENT_LENGTH %
+ PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT != 0);
+ BUILD_BUG_ON(PQI_ADMIN_OQ_ELEMENT_LENGTH %
+ PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT != 0);
+ BUILD_BUG_ON(PQI_OPERATIONAL_IQ_ELEMENT_LENGTH > 1048560);
+ BUILD_BUG_ON(PQI_OPERATIONAL_IQ_ELEMENT_LENGTH %
+ PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT != 0);
+ BUILD_BUG_ON(PQI_OPERATIONAL_OQ_ELEMENT_LENGTH > 1048560);
+ BUILD_BUG_ON(PQI_OPERATIONAL_OQ_ELEMENT_LENGTH %
+ PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT != 0);
+
+ BUILD_BUG_ON(PQI_RESERVED_IO_SLOTS >= PQI_MAX_OUTSTANDING_REQUESTS);
+}
diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
new file mode 100644
index 000000000000..52ca4f93f1b2
--- /dev/null
+++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
@@ -0,0 +1,350 @@
+/*
+ * driver for Microsemi PQI-based storage controllers
+ * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016 PMC-Sierra, 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; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ *
+ */
+
+#include <linux/kernel.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_transport_sas.h>
+#include "smartpqi.h"
+
+static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port)
+{
+ struct pqi_sas_phy *pqi_sas_phy;
+ struct sas_phy *phy;
+
+ pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL);
+ if (!pqi_sas_phy)
+ return NULL;
+
+ phy = sas_phy_alloc(pqi_sas_port->parent_node->parent_dev,
+ pqi_sas_port->next_phy_index);
+ if (!phy) {
+ kfree(pqi_sas_phy);
+ return NULL;
+ }
+
+ pqi_sas_port->next_phy_index++;
+ pqi_sas_phy->phy = phy;
+ pqi_sas_phy->parent_port = pqi_sas_port;
+
+ return pqi_sas_phy;
+}
+
+static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy)
+{
+ struct sas_phy *phy = pqi_sas_phy->phy;
+
+ sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy);
+ sas_phy_free(phy);
+ if (pqi_sas_phy->added_to_port)
+ list_del(&pqi_sas_phy->phy_list_entry);
+ kfree(pqi_sas_phy);
+}
+
+static int pqi_sas_port_add_phy(struct pqi_sas_phy *pqi_sas_phy)
+{
+ int rc;
+ struct pqi_sas_port *pqi_sas_port;
+ struct sas_phy *phy;
+ struct sas_identify *identify;
+
+ pqi_sas_port = pqi_sas_phy->parent_port;
+ phy = pqi_sas_phy->phy;
+
+ identify = &phy->identify;
+ memset(identify, 0, sizeof(*identify));
+ identify->sas_address = pqi_sas_port->sas_address;
+ identify->device_type = SAS_END_DEVICE;
+ identify->initiator_port_protocols = SAS_PROTOCOL_STP;
+ identify->target_port_protocols = SAS_PROTOCOL_STP;
+ phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ rc = sas_phy_add(pqi_sas_phy->phy);
+ if (rc)
+ return rc;
+
+ sas_port_add_phy(pqi_sas_port->port, pqi_sas_phy->phy);
+ list_add_tail(&pqi_sas_phy->phy_list_entry,
+ &pqi_sas_port->phy_list_head);
+ pqi_sas_phy->added_to_port = true;
+
+ return 0;
+}
+
+static int pqi_sas_port_add_rphy(struct pqi_sas_port *pqi_sas_port,
+ struct sas_rphy *rphy)
+{
+ struct sas_identify *identify;
+
+ identify = &rphy->identify;
+ identify->sas_address = pqi_sas_port->sas_address;
+ identify->initiator_port_protocols = SAS_PROTOCOL_STP;
+ identify->target_port_protocols = SAS_PROTOCOL_STP;
+
+ return sas_rphy_add(rphy);
+}
+
+static struct pqi_sas_port *pqi_alloc_sas_port(
+ struct pqi_sas_node *pqi_sas_node, u64 sas_address)
+{
+ int rc;
+ struct pqi_sas_port *pqi_sas_port;
+ struct sas_port *port;
+
+ pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL);
+ if (!pqi_sas_port)
+ return NULL;
+
+ INIT_LIST_HEAD(&pqi_sas_port->phy_list_head);
+ pqi_sas_port->parent_node = pqi_sas_node;
+
+ port = sas_port_alloc_num(pqi_sas_node->parent_dev);
+ if (!port)
+ goto free_pqi_port;
+
+ rc = sas_port_add(port);
+ if (rc)
+ goto free_sas_port;
+
+ pqi_sas_port->port = port;
+ pqi_sas_port->sas_address = sas_address;
+ list_add_tail(&pqi_sas_port->port_list_entry,
+ &pqi_sas_node->port_list_head);
+
+ return pqi_sas_port;
+
+free_sas_port:
+ sas_port_free(port);
+free_pqi_port:
+ kfree(pqi_sas_port);
+
+ return NULL;
+}
+
+static void pqi_free_sas_port(struct pqi_sas_port *pqi_sas_port)
+{
+ struct pqi_sas_phy *pqi_sas_phy;
+ struct pqi_sas_phy *next;
+
+ list_for_each_entry_safe(pqi_sas_phy, next,
+ &pqi_sas_port->phy_list_head, phy_list_entry)
+ pqi_free_sas_phy(pqi_sas_phy);
+
+ sas_port_delete(pqi_sas_port->port);
+ list_del(&pqi_sas_port->port_list_entry);
+ kfree(pqi_sas_port);
+}
+
+static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev)
+{
+ struct pqi_sas_node *pqi_sas_node;
+
+ pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL);
+ if (pqi_sas_node) {
+ pqi_sas_node->parent_dev = parent_dev;
+ INIT_LIST_HEAD(&pqi_sas_node->port_list_head);
+ }
+
+ return pqi_sas_node;
+}
+
+static void pqi_free_sas_node(struct pqi_sas_node *pqi_sas_node)
+{
+ struct pqi_sas_port *pqi_sas_port;
+ struct pqi_sas_port *next;
+
+ if (!pqi_sas_node)
+ return;
+
+ list_for_each_entry_safe(pqi_sas_port, next,
+ &pqi_sas_node->port_list_head, port_list_entry)
+ pqi_free_sas_port(pqi_sas_port);
+
+ kfree(pqi_sas_node);
+}
+
+struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
+ struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy)
+{
+ struct pqi_scsi_dev *device;
+
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (!device->sas_port)
+ continue;
+ if (device->sas_port->rphy == rphy)
+ return device;
+ }
+
+ return NULL;
+}
+
+int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct device *parent_dev;
+ struct pqi_sas_node *pqi_sas_node;
+ struct pqi_sas_port *pqi_sas_port;
+ struct pqi_sas_phy *pqi_sas_phy;
+
+ parent_dev = &shost->shost_gendev;
+
+ pqi_sas_node = pqi_alloc_sas_node(parent_dev);
+ if (!pqi_sas_node)
+ return -ENOMEM;
+
+ pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, ctrl_info->sas_address);
+ if (!pqi_sas_port) {
+ rc = -ENODEV;
+ goto free_sas_node;
+ }
+
+ pqi_sas_phy = pqi_alloc_sas_phy(pqi_sas_port);
+ if (!pqi_sas_phy) {
+ rc = -ENODEV;
+ goto free_sas_port;
+ }
+
+ rc = pqi_sas_port_add_phy(pqi_sas_phy);
+ if (rc)
+ goto free_sas_phy;
+
+ ctrl_info->sas_host = pqi_sas_node;
+
+ return 0;
+
+free_sas_phy:
+ pqi_free_sas_phy(pqi_sas_phy);
+free_sas_port:
+ pqi_free_sas_port(pqi_sas_port);
+free_sas_node:
+ pqi_free_sas_node(pqi_sas_node);
+
+ return rc;
+}
+
+void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info)
+{
+ pqi_free_sas_node(ctrl_info->sas_host);
+}
+
+int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
+ struct pqi_scsi_dev *device)
+{
+ int rc;
+ struct pqi_sas_port *pqi_sas_port;
+ struct sas_rphy *rphy;
+
+ pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, device->sas_address);
+ if (!pqi_sas_port)
+ return -ENOMEM;
+
+ rphy = sas_end_device_alloc(pqi_sas_port->port);
+ if (!rphy) {
+ rc = -ENODEV;
+ goto free_sas_port;
+ }
+
+ pqi_sas_port->rphy = rphy;
+ device->sas_port = pqi_sas_port;
+
+ rc = pqi_sas_port_add_rphy(pqi_sas_port, rphy);
+ if (rc)
+ goto free_sas_port;
+
+ return 0;
+
+free_sas_port:
+ pqi_free_sas_port(pqi_sas_port);
+ device->sas_port = NULL;
+
+ return rc;
+}
+
+void pqi_remove_sas_device(struct pqi_scsi_dev *device)
+{
+ if (device->sas_port) {
+ pqi_free_sas_port(device->sas_port);
+ device->sas_port = NULL;
+ }
+}
+
+static int pqi_sas_get_linkerrors(struct sas_phy *phy)
+{
+ return 0;
+}
+
+static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
+ u64 *identifier)
+{
+ return 0;
+}
+
+static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy)
+{
+ return -ENXIO;
+}
+
+static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+ return 0;
+}
+
+static int pqi_sas_phy_enable(struct sas_phy *phy, int enable)
+{
+ return 0;
+}
+
+static int pqi_sas_phy_setup(struct sas_phy *phy)
+{
+ return 0;
+}
+
+static void pqi_sas_phy_release(struct sas_phy *phy)
+{
+}
+
+static int pqi_sas_phy_speed(struct sas_phy *phy,
+ struct sas_phy_linkrates *rates)
+{
+ return -EINVAL;
+}
+
+/* SMP = Serial Management Protocol */
+
+static int pqi_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ struct request *req)
+{
+ return -EINVAL;
+}
+
+struct sas_function_template pqi_sas_transport_functions = {
+ .get_linkerrors = pqi_sas_get_linkerrors,
+ .get_enclosure_identifier = pqi_sas_get_enclosure_identifier,
+ .get_bay_identifier = pqi_sas_get_bay_identifier,
+ .phy_reset = pqi_sas_phy_reset,
+ .phy_enable = pqi_sas_phy_enable,
+ .phy_setup = pqi_sas_phy_setup,
+ .phy_release = pqi_sas_phy_release,
+ .set_phy_speed = pqi_sas_phy_speed,
+ .smp_handler = pqi_sas_smp_handler,
+};
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c
new file mode 100644
index 000000000000..71408f9e8f75
--- /dev/null
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -0,0 +1,404 @@
+/*
+ * driver for Microsemi PQI-based storage controllers
+ * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016 PMC-Sierra, 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; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <scsi/scsi_device.h>
+#include <asm/unaligned.h>
+#include "smartpqi.h"
+#include "smartpqi_sis.h"
+
+/* legacy SIS interface commands */
+#define SIS_CMD_GET_ADAPTER_PROPERTIES 0x19
+#define SIS_CMD_INIT_BASE_STRUCT_ADDRESS 0x1b
+#define SIS_CMD_GET_PQI_CAPABILITIES 0x3000
+
+/* for submission of legacy SIS commands */
+#define SIS_REENABLE_SIS_MODE 0x1
+#define SIS_ENABLE_MSIX 0x40
+#define SIS_SOFT_RESET 0x100
+#define SIS_CMD_READY 0x200
+#define SIS_CMD_COMPLETE 0x1000
+#define SIS_CLEAR_CTRL_TO_HOST_DOORBELL 0x1000
+#define SIS_CMD_STATUS_SUCCESS 0x1
+#define SIS_CMD_COMPLETE_TIMEOUT_SECS 30
+#define SIS_CMD_COMPLETE_POLL_INTERVAL_MSECS 10
+
+/* used with SIS_CMD_GET_ADAPTER_PROPERTIES command */
+#define SIS_EXTENDED_PROPERTIES_SUPPORTED 0x800000
+#define SIS_SMARTARRAY_FEATURES_SUPPORTED 0x2
+#define SIS_PQI_MODE_SUPPORTED 0x4
+#define SIS_REQUIRED_EXTENDED_PROPERTIES \
+ (SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED)
+
+/* used with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */
+#define SIS_BASE_STRUCT_REVISION 9
+#define SIS_BASE_STRUCT_ALIGNMENT 16
+
+#define SIS_CTRL_KERNEL_UP 0x80
+#define SIS_CTRL_KERNEL_PANIC 0x100
+#define SIS_CTRL_READY_TIMEOUT_SECS 30
+#define SIS_CTRL_READY_POLL_INTERVAL_MSECS 10
+
+#pragma pack(1)
+
+/* for use with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */
+struct sis_base_struct {
+ __le32 revision; /* revision of this structure */
+ __le32 flags; /* reserved */
+ __le32 error_buffer_paddr_low; /* lower 32 bits of physical memory */
+ /* buffer for PQI error response */
+ /* data */
+ __le32 error_buffer_paddr_high; /* upper 32 bits of physical */
+ /* memory buffer for PQI */
+ /* error response data */
+ __le32 error_buffer_element_length; /* length of each PQI error */
+ /* response buffer element */
+ /* in bytes */
+ __le32 error_buffer_num_elements; /* total number of PQI error */
+ /* response buffers available */
+};
+
+#pragma pack()
+
+int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned long timeout;
+ u32 status;
+
+ timeout = (SIS_CTRL_READY_TIMEOUT_SECS * HZ) + jiffies;
+
+ while (1) {
+ status = readl(&ctrl_info->registers->sis_firmware_status);
+ if (status != ~0) {
+ if (status & SIS_CTRL_KERNEL_PANIC) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "controller is offline: status code 0x%x\n",
+ readl(
+ &ctrl_info->registers->sis_mailbox[7]));
+ return -ENODEV;
+ }
+ if (status & SIS_CTRL_KERNEL_UP)
+ break;
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ msleep(SIS_CTRL_READY_POLL_INTERVAL_MSECS);
+ }
+
+ return 0;
+}
+
+bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info)
+{
+ bool running;
+ u32 status;
+
+ status = readl(&ctrl_info->registers->sis_firmware_status);
+
+ if (status & SIS_CTRL_KERNEL_PANIC)
+ running = false;
+ else
+ running = true;
+
+ if (!running)
+ dev_err(&ctrl_info->pci_dev->dev,
+ "controller is offline: status code 0x%x\n",
+ readl(&ctrl_info->registers->sis_mailbox[7]));
+
+ return running;
+}
+
+/* used for passing command parameters/results when issuing SIS commands */
+struct sis_sync_cmd_params {
+ u32 mailbox[6]; /* mailboxes 0-5 */
+};
+
+static int sis_send_sync_cmd(struct pqi_ctrl_info *ctrl_info,
+ u32 cmd, struct sis_sync_cmd_params *params)
+{
+ struct pqi_ctrl_registers __iomem *registers;
+ unsigned int i;
+ unsigned long timeout;
+ u32 doorbell;
+ u32 cmd_status;
+
+ registers = ctrl_info->registers;
+
+ /* Write the command to mailbox 0. */
+ writel(cmd, &registers->sis_mailbox[0]);
+
+ /*
+ * Write the command parameters to mailboxes 1-4 (mailbox 5 is not used
+ * when sending a command to the controller).
+ */
+ for (i = 1; i <= 4; i++)
+ writel(params->mailbox[i], &registers->sis_mailbox[i]);
+
+ /* Clear the command doorbell. */
+ writel(SIS_CLEAR_CTRL_TO_HOST_DOORBELL,
+ &registers->sis_ctrl_to_host_doorbell_clear);
+
+ /* Disable doorbell interrupts by masking all interrupts. */
+ writel(~0, &registers->sis_interrupt_mask);
+
+ /*
+ * Force the completion of the interrupt mask register write before
+ * submitting the command.
+ */
+ readl(&registers->sis_interrupt_mask);
+
+ /* Submit the command to the controller. */
+ writel(SIS_CMD_READY, &registers->sis_host_to_ctrl_doorbell);
+
+ /*
+ * Poll for command completion. Note that the call to msleep() is at
+ * the top of the loop in order to give the controller time to start
+ * processing the command before we start polling.
+ */
+ timeout = (SIS_CMD_COMPLETE_TIMEOUT_SECS * HZ) + jiffies;
+ while (1) {
+ msleep(SIS_CMD_COMPLETE_POLL_INTERVAL_MSECS);
+ doorbell = readl(&registers->sis_ctrl_to_host_doorbell);
+ if (doorbell & SIS_CMD_COMPLETE)
+ break;
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ }
+
+ /* Read the command status from mailbox 0. */
+ cmd_status = readl(&registers->sis_mailbox[0]);
+ if (cmd_status != SIS_CMD_STATUS_SUCCESS) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "SIS command failed for command 0x%x: status = 0x%x\n",
+ cmd, cmd_status);
+ return -EINVAL;
+ }
+
+ /*
+ * The command completed successfully, so save the command status and
+ * read the values returned in mailboxes 1-5.
+ */
+ params->mailbox[0] = cmd_status;
+ for (i = 1; i < ARRAY_SIZE(params->mailbox); i++)
+ params->mailbox[i] = readl(&registers->sis_mailbox[i]);
+
+ return 0;
+}
+
+/*
+ * This function verifies that we are talking to a controller that speaks PQI.
+ */
+
+int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ u32 properties;
+ u32 extended_properties;
+ struct sis_sync_cmd_params params;
+
+ memset(&params, 0, sizeof(params));
+
+ rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_GET_ADAPTER_PROPERTIES,
+ &params);
+ if (rc)
+ return rc;
+
+ properties = params.mailbox[1];
+
+ if (!(properties & SIS_EXTENDED_PROPERTIES_SUPPORTED))
+ return -ENODEV;
+
+ extended_properties = params.mailbox[4];
+
+ if ((extended_properties & SIS_REQUIRED_EXTENDED_PROPERTIES) !=
+ SIS_REQUIRED_EXTENDED_PROPERTIES)
+ return -ENODEV;
+
+ return 0;
+}
+
+int sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct sis_sync_cmd_params params;
+
+ memset(&params, 0, sizeof(params));
+
+ rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_GET_PQI_CAPABILITIES,
+ &params);
+ if (rc)
+ return rc;
+
+ ctrl_info->max_sg_entries = params.mailbox[1];
+ ctrl_info->max_transfer_size = params.mailbox[2];
+ ctrl_info->max_outstanding_requests = params.mailbox[3];
+ ctrl_info->config_table_offset = params.mailbox[4];
+ ctrl_info->config_table_length = params.mailbox[5];
+
+ return 0;
+}
+
+int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ void *base_struct_unaligned;
+ struct sis_base_struct *base_struct;
+ struct sis_sync_cmd_params params;
+ unsigned long error_buffer_paddr;
+ dma_addr_t bus_address;
+
+ base_struct_unaligned = kzalloc(sizeof(*base_struct)
+ + SIS_BASE_STRUCT_ALIGNMENT - 1, GFP_KERNEL);
+ if (!base_struct_unaligned)
+ return -ENOMEM;
+
+ base_struct = PTR_ALIGN(base_struct_unaligned,
+ SIS_BASE_STRUCT_ALIGNMENT);
+ error_buffer_paddr = (unsigned long)ctrl_info->error_buffer_dma_handle;
+
+ put_unaligned_le32(SIS_BASE_STRUCT_REVISION, &base_struct->revision);
+ put_unaligned_le32(lower_32_bits(error_buffer_paddr),
+ &base_struct->error_buffer_paddr_low);
+ put_unaligned_le32(upper_32_bits(error_buffer_paddr),
+ &base_struct->error_buffer_paddr_high);
+ put_unaligned_le32(PQI_ERROR_BUFFER_ELEMENT_LENGTH,
+ &base_struct->error_buffer_element_length);
+ put_unaligned_le32(ctrl_info->max_io_slots,
+ &base_struct->error_buffer_num_elements);
+
+ bus_address = pci_map_single(ctrl_info->pci_dev, base_struct,
+ sizeof(*base_struct), PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(ctrl_info->pci_dev, bus_address)) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ memset(&params, 0, sizeof(params));
+ params.mailbox[1] = lower_32_bits((u64)bus_address);
+ params.mailbox[2] = upper_32_bits((u64)bus_address);
+ params.mailbox[3] = sizeof(*base_struct);
+
+ rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_INIT_BASE_STRUCT_ADDRESS,
+ &params);
+
+ pci_unmap_single(ctrl_info->pci_dev, bus_address, sizeof(*base_struct),
+ PCI_DMA_TODEVICE);
+
+out:
+ kfree(base_struct_unaligned);
+
+ return rc;
+}
+
+/* Enable MSI-X interrupts on the controller. */
+
+void sis_enable_msix(struct pqi_ctrl_info *ctrl_info)
+{
+ u32 doorbell_register;
+
+ doorbell_register =
+ readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+ doorbell_register |= SIS_ENABLE_MSIX;
+
+ writel(doorbell_register,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+}
+
+/* Disable MSI-X interrupts on the controller. */
+
+void sis_disable_msix(struct pqi_ctrl_info *ctrl_info)
+{
+ u32 doorbell_register;
+
+ doorbell_register =
+ readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+ doorbell_register &= ~SIS_ENABLE_MSIX;
+
+ writel(doorbell_register,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+}
+
+void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
+{
+ writel(SIS_SOFT_RESET,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+}
+
+#define SIS_MODE_READY_TIMEOUT_SECS 30
+
+int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ unsigned long timeout;
+ struct pqi_ctrl_registers __iomem *registers;
+ u32 doorbell;
+
+ registers = ctrl_info->registers;
+
+ writel(SIS_REENABLE_SIS_MODE,
+ &registers->sis_host_to_ctrl_doorbell);
+
+ rc = 0;
+ timeout = (SIS_MODE_READY_TIMEOUT_SECS * HZ) + jiffies;
+
+ while (1) {
+ doorbell = readl(&registers->sis_ctrl_to_host_doorbell);
+ if ((doorbell & SIS_REENABLE_SIS_MODE) == 0)
+ break;
+ if (time_after(jiffies, timeout)) {
+ rc = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ if (rc)
+ dev_err(&ctrl_info->pci_dev->dev,
+ "re-enabling SIS mode failed\n");
+
+ return rc;
+}
+
+void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value)
+{
+ writel(value, &ctrl_info->registers->sis_driver_scratch);
+}
+
+u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info)
+{
+ return readl(&ctrl_info->registers->sis_driver_scratch);
+}
+
+static void __attribute__((unused)) verify_structures(void)
+{
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+ revision) != 0x0);
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+ flags) != 0x4);
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+ error_buffer_paddr_low) != 0x8);
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+ error_buffer_paddr_high) != 0xc);
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+ error_buffer_element_length) != 0x10);
+ BUILD_BUG_ON(offsetof(struct sis_base_struct,
+ error_buffer_num_elements) != 0x14);
+ BUILD_BUG_ON(sizeof(struct sis_base_struct) != 0x18);
+}
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h
new file mode 100644
index 000000000000..bd6e7b08338e
--- /dev/null
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -0,0 +1,34 @@
+/*
+ * driver for Microsemi PQI-based storage controllers
+ * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016 PMC-Sierra, 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; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ *
+ */
+
+#if !defined(_SMARTPQI_SIS_H)
+#define _SMARTPQI_SIS_H
+
+int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info);
+bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info);
+int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info);
+int sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info);
+int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info);
+void sis_enable_msix(struct pqi_ctrl_info *ctrl_info);
+void sis_disable_msix(struct pqi_ctrl_info *ctrl_info);
+void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
+int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
+void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
+u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);
+
+#endif /* _SMARTPQI_SIS_H */
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index ed179348de80..bed2bbd6b923 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -83,7 +83,7 @@ static int sr_init_command(struct scsi_cmnd *SCpnt);
static int sr_done(struct scsi_cmnd *);
static int sr_runtime_suspend(struct device *dev);
-static struct dev_pm_ops sr_pm_ops = {
+static const struct dev_pm_ops sr_pm_ops = {
.runtime_suspend = sr_runtime_suspend,
};
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 5d00e514ff28..d32e3ba8863e 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1874,7 +1874,7 @@ static void sym2_io_resume(struct pci_dev *pdev)
spin_lock_irq(shost->host_lock);
if (sym_data->io_reset)
- complete_all(sym_data->io_reset);
+ complete(sym_data->io_reset);
spin_unlock_irq(shost->host_lock);
}
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
deleted file mode 100644
index 8a8608ac62e6..000000000000
--- a/drivers/scsi/t128.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Trantor T128/T128F/T228 driver
- * Note : architecturally, the T100 and T130 are different and won't
- * work
- *
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 440-4894
- *
- * For more information, please consult
- *
- * Trantor Systems, Ltd.
- * T128/T128F/T228 SCSI Host Adapter
- * Hardware Specifications
- *
- * Trantor Systems, Ltd.
- * 5415 Randall Place
- * Fremont, CA 94538
- * 1+ (415) 770-1400, FAX 1+ (415) 770-9910
- */
-
-/*
- * The card is detected and initialized in one of several ways :
- * 1. Autoprobe (default) - since the board is memory mapped,
- * a BIOS signature is scanned for to locate the registers.
- * An interrupt is triggered to autoprobe for the interrupt
- * line.
- *
- * 2. With command line overrides - t128=address,irq may be
- * used on the LILO command line to override the defaults.
- *
- * 3. With the T128_OVERRIDE compile time define. This is
- * specified as an array of address, irq tuples. Ie, for
- * one board at the default 0xcc000 address, IRQ5, I could say
- * -DT128_OVERRIDE={{0xcc000, 5}}
- *
- * Note that if the override methods are used, place holders must
- * be specified for other boards in the system.
- *
- * T128/T128F jumper/dipswitch settings (note : on my sample, the switches
- * were epoxy'd shut, meaning I couldn't change the 0xcc000 base address) :
- *
- * T128 Sw7 Sw8 Sw6 = 0ws Sw5 = boot
- * T128F Sw6 Sw7 Sw5 = 0ws Sw4 = boot Sw8 = floppy disable
- * cc000 off off
- * c8000 off on
- * dc000 on off
- * d8000 on on
- *
- *
- * Interrupts
- * There is a 12 pin jumper block, jp1, numbered as follows :
- * T128 (JP1) T128F (J5)
- * 2 4 6 8 10 12 11 9 7 5 3 1
- * 1 3 5 7 9 11 12 10 8 6 4 2
- *
- * 3 2-4
- * 5 1-3
- * 7 3-5
- * T128F only
- * 10 8-10
- * 12 7-9
- * 14 10-12
- * 15 9-11
- */
-
-#include <linux/io.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <scsi/scsi_host.h>
-#include "t128.h"
-#include "NCR5380.h"
-
-static struct override {
- unsigned long address;
- int irq;
-} overrides
-#ifdef T128_OVERRIDE
- [] __initdata = T128_OVERRIDE;
-#else
- [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO},
- {0 ,IRQ_AUTO}, {0, IRQ_AUTO}};
-#endif
-
-#define NO_OVERRIDES ARRAY_SIZE(overrides)
-
-static struct base {
- unsigned int address;
- int noauto;
-} bases[] __initdata = {
- { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0}
-};
-
-#define NO_BASES ARRAY_SIZE(bases)
-
-static struct signature {
- const char *string;
- int offset;
-} signatures[] __initdata = {
-{"TSROM: SCSI BIOS, Version 1.12", 0x36},
-};
-
-#define NO_SIGNATURES ARRAY_SIZE(signatures)
-
-#ifndef MODULE
-/*
- * Function : t128_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- */
-
-static int __init t128_setup(char *str)
-{
- static int commandline_current;
- int i;
- int ints[10];
-
- get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] != 2)
- printk("t128_setup : usage t128=address,irq\n");
- else
- if (commandline_current < NO_OVERRIDES) {
- overrides[commandline_current].address = ints[1];
- overrides[commandline_current].irq = ints[2];
- for (i = 0; i < NO_BASES; ++i)
- if (bases[i].address == ints[1]) {
- bases[i].noauto = 1;
- break;
- }
- ++commandline_current;
- }
- return 1;
-}
-
-__setup("t128=", t128_setup);
-#endif
-
-/*
- * Function : int t128_detect(struct scsi_host_template * tpnt)
- *
- * Purpose : detects and initializes T128,T128F, or T228 controllers
- * that were autoprobed, overridden on the LILO command line,
- * or specified at compile time.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
- */
-
-static int __init t128_detect(struct scsi_host_template *tpnt)
-{
- static int current_override, current_base;
- struct Scsi_Host *instance;
- unsigned long base;
- void __iomem *p;
- int sig, count;
-
- for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
- base = 0;
- p = NULL;
-
- if (overrides[current_override].address) {
- base = overrides[current_override].address;
- p = ioremap(bases[current_base].address, 0x2000);
- if (!p)
- base = 0;
- } else
- for (; !base && (current_base < NO_BASES); ++current_base) {
- dprintk(NDEBUG_INIT, "t128: probing address 0x%08x\n",
- bases[current_base].address);
- if (bases[current_base].noauto)
- continue;
- p = ioremap(bases[current_base].address, 0x2000);
- if (!p)
- continue;
- for (sig = 0; sig < NO_SIGNATURES; ++sig)
- if (check_signature(p + signatures[sig].offset,
- signatures[sig].string,
- strlen(signatures[sig].string))) {
- base = bases[current_base].address;
- dprintk(NDEBUG_INIT, "t128: detected board\n");
- goto found;
- }
- iounmap(p);
- }
-
- dprintk(NDEBUG_INIT, "t128: base = 0x%08x\n", (unsigned int)base);
-
- if (!base)
- break;
-
-found:
- instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
- if(instance == NULL)
- goto out_unmap;
-
- instance->base = base;
- ((struct NCR5380_hostdata *)instance->hostdata)->base = p;
-
- if (NCR5380_init(instance, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP))
- goto out_unregister;
-
- NCR5380_maybe_reset_bus(instance);
-
- if (overrides[current_override].irq != IRQ_AUTO)
- instance->irq = overrides[current_override].irq;
- else
- instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
-
- /* Compatibility with documented NCR5380 kernel parameters */
- if (instance->irq == 255)
- instance->irq = NO_IRQ;
-
- if (instance->irq != NO_IRQ)
- if (request_irq(instance->irq, t128_intr, 0, "t128",
- instance)) {
- printk("scsi%d : IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = NO_IRQ;
- }
-
- if (instance->irq == NO_IRQ) {
- printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
- printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
- }
-
- dprintk(NDEBUG_INIT, "scsi%d: irq = %d\n",
- instance->host_no, instance->irq);
-
- ++current_override;
- ++count;
- }
- return count;
-
-out_unregister:
- scsi_unregister(instance);
-out_unmap:
- iounmap(p);
- return count;
-}
-
-static int t128_release(struct Scsi_Host *shost)
-{
- struct NCR5380_hostdata *hostdata = shost_priv(shost);
-
- if (shost->irq != NO_IRQ)
- free_irq(shost->irq, shost);
- NCR5380_exit(shost);
- scsi_unregister(shost);
- iounmap(hostdata->base);
- return 0;
-}
-
-/*
- * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip)
- *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
- * the specified device / size.
- *
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- * major / minor, ip[] = {heads, sectors, cylinders}
- *
- * Returns : always 0 (success), initializes ip
- *
- */
-
-/*
- * XXX Most SCSI boards use this mapping, I could be incorrect. Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
- */
-
-static int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int *ip)
-{
- ip[0] = 64;
- ip[1] = 32;
- ip[2] = capacity >> 11;
- return 0;
-}
-
-/*
- * Function : int t128_pread (struct Scsi_Host *instance,
- * unsigned char *dst, int len)
- *
- * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to
- * dst
- *
- * Inputs : dst = destination, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog
- * timeout.
- */
-
-static inline int t128_pread(struct Scsi_Host *instance,
- unsigned char *dst, int len)
-{
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- void __iomem *reg, *base = hostdata->base;
- unsigned char *d = dst;
- register int i = len;
-
- reg = base + T_DATA_REG_OFFSET;
-
-#if 0
- for (; i; --i) {
- while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
-#else
- while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
- for (; i; --i) {
-#endif
- *d++ = readb(reg);
- }
-
- if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
- unsigned char tmp;
- void __iomem *foo = base + T_CONTROL_REG_OFFSET;
- tmp = readb(foo);
- writeb(tmp | T_CR_CT, foo);
- writeb(tmp, foo);
- printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
- instance->host_no);
- return -1;
- } else
- return 0;
-}
-
-/*
- * Function : int t128_pwrite (struct Scsi_Host *instance,
- * unsigned char *src, int len)
- *
- * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
- * src
- *
- * Inputs : src = source, len = length in bytes
- *
- * Returns : 0 on success, non zero on a failure such as a watchdog
- * timeout.
- */
-
-static inline int t128_pwrite(struct Scsi_Host *instance,
- unsigned char *src, int len)
-{
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- void __iomem *reg, *base = hostdata->base;
- unsigned char *s = src;
- register int i = len;
-
- reg = base + T_DATA_REG_OFFSET;
-
-#if 0
- for (; i; --i) {
- while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
-#else
- while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
- for (; i; --i) {
-#endif
- writeb(*s++, reg);
- }
-
- if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
- unsigned char tmp;
- void __iomem *foo = base + T_CONTROL_REG_OFFSET;
- tmp = readb(foo);
- writeb(tmp | T_CR_CT, foo);
- writeb(tmp, foo);
- printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
- instance->host_no);
- return -1;
- } else
- return 0;
-}
-
-MODULE_LICENSE("GPL");
-
-#include "NCR5380.c"
-
-static struct scsi_host_template driver_template = {
- .name = "Trantor T128/T128F/T228",
- .detect = t128_detect,
- .release = t128_release,
- .proc_name = "t128",
- .info = t128_info,
- .queuecommand = t128_queue_command,
- .eh_abort_handler = t128_abort,
- .eh_bus_reset_handler = t128_bus_reset,
- .bios_param = t128_biosparam,
- .can_queue = 32,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING,
- .cmd_size = NCR5380_CMD_SIZE,
- .max_sectors = 128,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
deleted file mode 100644
index c95bcd839109..000000000000
--- a/drivers/scsi/t128.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Trantor T128/T128F/T228 defines
- * Note : architecturally, the T100 and T128 are different and won't work
- *
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 440-4894
- *
- * For more information, please consult
- *
- * Trantor Systems, Ltd.
- * T128/T128F/T228 SCSI Host Adapter
- * Hardware Specifications
- *
- * Trantor Systems, Ltd.
- * 5415 Randall Place
- * Fremont, CA 94538
- * 1+ (415) 770-1400, FAX 1+ (415) 770-9910
- */
-
-#ifndef T128_H
-#define T128_H
-
-/*
- * The trantor boards are memory mapped. They use an NCR5380 or
- * equivalent (my sample board had part second sourced from ZILOG).
- * NCR's recommended "Pseudo-DMA" architecture is used, where
- * a PAL drives the DMA signals on the 5380 allowing fast, blind
- * transfers with proper handshaking.
- */
-
-/*
- * Note : a boot switch is provided for the purpose of informing the
- * firmware to boot or not boot from attached SCSI devices. So, I imagine
- * there are fewer people who've yanked the ROM like they do on the Seagate
- * to make bootup faster, and I'll probably use this for autodetection.
- */
-#define T_ROM_OFFSET 0
-
-/*
- * Note : my sample board *WAS NOT* populated with the SRAM, so this
- * can't be used for autodetection without a ROM present.
- */
-#define T_RAM_OFFSET 0x1800
-
-/*
- * All of the registers are allocated 32 bytes of address space, except
- * for the data register (read/write to/from the 5380 in pseudo-DMA mode)
- */
-#define T_CONTROL_REG_OFFSET 0x1c00 /* rw */
-#define T_CR_INT 0x10 /* Enable interrupts */
-#define T_CR_CT 0x02 /* Reset watchdog timer */
-
-#define T_STATUS_REG_OFFSET 0x1c20 /* ro */
-#define T_ST_BOOT 0x80 /* Boot switch */
-#define T_ST_S3 0x40 /* User settable switches, */
-#define T_ST_S2 0x20 /* read 0 when switch is on, 1 off */
-#define T_ST_S1 0x10
-#define T_ST_PS2 0x08 /* Set for Microchannel 228 */
-#define T_ST_RDY 0x04 /* 5380 DRQ */
-#define T_ST_TIM 0x02 /* indicates 40us watchdog timer fired */
-#define T_ST_ZERO 0x01 /* Always zero */
-
-#define T_5380_OFFSET 0x1d00 /* 8 registers here, see NCR5380.h */
-
-#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
-
-#define NCR5380_implementation_fields \
- void __iomem *base
-
-#define T128_address(reg) \
- (((struct NCR5380_hostdata *)shost_priv(instance))->base + T_5380_OFFSET + ((reg) * 0x20))
-
-#define NCR5380_read(reg) readb(T128_address(reg))
-#define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
-
-#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
-#define NCR5380_dma_recv_setup t128_pread
-#define NCR5380_dma_send_setup t128_pwrite
-#define NCR5380_dma_residual(instance) (0)
-
-#define NCR5380_intr t128_intr
-#define NCR5380_queue_command t128_queue_command
-#define NCR5380_abort t128_abort
-#define NCR5380_bus_reset t128_bus_reset
-#define NCR5380_info t128_info
-
-#define NCR5380_io_delay(x) udelay(x)
-
-/* 15 14 12 10 7 5 3
- 1101 0100 1010 1000 */
-
-#define T128_IRQS 0xc4a8
-
-#endif /* T128_H */
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
deleted file mode 100644
index 14eb50b95a1e..000000000000
--- a/drivers/scsi/u14-34f.c
+++ /dev/null
@@ -1,1971 +0,0 @@
-/*
- * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
- *
- * 03 Jun 2003 Rev. 8.10 for linux-2.5.70
- * + Update for new IRQ API.
- * + Use "goto" when appropriate.
- * + Drop u14-34f.h.
- * + Update for new module_param API.
- * + Module parameters can now be specified only in the
- * same format as the kernel boot options.
- *
- * boot option old module param
- * ----------- ------------------
- * addr,... io_port=addr,...
- * lc:[y|n] linked_comm=[1|0]
- * mq:xx max_queue_depth=xx
- * tm:[0|1|2] tag_mode=[0|1|2]
- * et:[y|n] ext_tran=[1|0]
- * of:[y|n] have_old_firmware=[1|0]
- *
- * A valid example using the new parameter format is:
- * modprobe u14-34f "u14-34f=0x340,0x330,lc:y,tm:0,mq:4"
- *
- * which is equivalent to the old format:
- * modprobe u14-34f io_port=0x340,0x330 linked_comm=1 tag_mode=0 \
- * max_queue_depth=4
- *
- * With actual module code, u14-34f and u14_34f are equivalent
- * as module parameter names.
- *
- * 12 Feb 2003 Rev. 8.04 for linux 2.5.60
- * + Release irq before calling scsi_register.
- *
- * 12 Nov 2002 Rev. 8.02 for linux 2.5.47
- * + Release driver_lock before calling scsi_register.
- *
- * 11 Nov 2002 Rev. 8.01 for linux 2.5.47
- * + Fixed bios_param and scsicam_bios_param calling parameters.
- *
- * 28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4
- * + Use new tcq and adjust_queue_depth api.
- * + New command line option (tm:[0-2]) to choose the type of tags:
- * 0 -> disable tagging ; 1 -> simple tags ; 2 -> ordered tags.
- * Default is tm:0 (tagged commands disabled).
- * For compatibility the "tc:" option is an alias of the "tm:"
- * option; tc:n is equivalent to tm:0 and tc:y is equivalent to
- * tm:1.
- *
- * 10 Oct 2002 Rev. 7.70 for linux 2.5.42
- * + Foreport from revision 6.70.
- *
- * 25 Jun 2002 Rev. 6.70 for linux 2.4.19
- * + Fixed endian-ness problem due to bitfields.
- *
- * 21 Feb 2002 Rev. 6.52 for linux 2.4.18
- * + Backport from rev. 7.22 (use io_request_lock).
- *
- * 20 Feb 2002 Rev. 7.22 for linux 2.5.5
- * + Remove any reference to virt_to_bus().
- * + Fix pio hang while detecting multiple HBAs.
- *
- * 01 Jan 2002 Rev. 7.20 for linux 2.5.1
- * + Use the dynamic DMA mapping API.
- *
- * 19 Dec 2001 Rev. 7.02 for linux 2.5.1
- * + Use SCpnt->sc_data_direction if set.
- * + Use sglist.page instead of sglist.address.
- *
- * 11 Dec 2001 Rev. 7.00 for linux 2.5.1
- * + Use host->host_lock instead of io_request_lock.
- *
- * 1 May 2001 Rev. 6.05 for linux 2.4.4
- * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
- *
- * 25 Jan 2001 Rev. 6.03 for linux 2.4.0
- * + "check_region" call replaced by "request_region".
- *
- * 22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11
- * + Removed old scsi error handling support.
- * + The obsolete boot option flag eh:n is silently ignored.
- * + Removed error messages while a disk drive is powered up at
- * boot time.
- * + Improved boot messages: all tagged capable device are
- * indicated as "tagged".
- *
- * 16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
- * + Updated to the new __setup interface for boot command line options.
- * + When loaded as a module, accepts the new parameter boot_options
- * which value is a string with the same format of the kernel boot
- * command line options. A valid example is:
- * modprobe u14-34f 'boot_options="0x230,0x340,lc:y,mq:4"'
- *
- * 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
- * + Removed pre-2.2 source code compatibility.
- *
- * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
- * Added command line option (et:[y|n]) to use the existing
- * translation (returned by scsicam_bios_param) as disk geometry.
- * The default is et:n, which uses the disk geometry jumpered
- * on the board.
- * The default value et:n is compatible with all previous revisions
- * of this driver.
- *
- * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
- * Increased busy timeout from 10 msec. to 200 msec. while
- * processing interrupts.
- *
- * 18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
- * Improved abort handling during the eh recovery process.
- *
- * 13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
- * The driver is now fully SMP safe, including the
- * abort and reset routines.
- * Added command line options (eh:[y|n]) to choose between
- * new_eh_code and the old scsi code.
- * If linux version >= 2.1.101 the default is eh:y, while the eh
- * option is ignored for previous releases and the old scsi code
- * is used.
- *
- * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
- * Reworked interrupt handler.
- *
- * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
- * Major reliability improvement: when a batch with overlapping
- * requests is detected, requests are queued one at a time
- * eliminating any possible board or drive reordering.
- *
- * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
- * Improved SMP support (if linux version >= 2.1.95).
- *
- * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
- * Performance improvement: when sequential i/o is detected,
- * always use direct sort instead of reverse sort.
- *
- * 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
- * io_port is now unsigned long.
- *
- * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
- * Use new scsi error handling code (if linux version >= 2.1.88).
- * Use new interrupt code.
- *
- * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
- * Use of udelay inside the wait loops to avoid timeout
- * problems with fast cpus.
- * Removed check about useless calls to the interrupt service
- * routine (reported on SMP systems only).
- * At initialization time "sorted/unsorted" is displayed instead
- * of "linked/unlinked" to reinforce the fact that "linking" is
- * nothing but "elevator sorting" in the actual implementation.
- *
- * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
- * Use of serial_number_at_timeout in abort and reset processing.
- * Use of the __initfunc and __initdata macro in setup code.
- * Minor cleanups in the list_statistics code.
- *
- * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
- * When loading as a module, parameter passing is now supported
- * both in 2.0 and in 2.1 style.
- * Fixed data transfer direction for some SCSI opcodes.
- * Immediate acknowledge to request sense commands.
- * Linked commands to each disk device are now reordered by elevator
- * sorting. Rare cases in which reordering of write requests could
- * cause wrong results are managed.
- *
- * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
- * Added command line options to enable/disable linked commands
- * (lc:[y|n]), old firmware support (of:[y|n]) and to set the max
- * queue depth (mq:xx). Default is "u14-34f=lc:n,of:n,mq:8".
- * Improved command linking.
- *
- * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27
- * Added linked command support.
- *
- * 3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27
- * Added queue depth adjustment.
- *
- * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
- * The list of i/o ports to be probed can be overwritten by the
- * "u14-34f=port0,port1,...." boot command line option.
- * Scatter/gather lists are now allocated by a number of kmalloc
- * calls, in order to avoid the previous size limit of 64Kb.
- *
- * 16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
- * Added multichannel support.
- *
- * 27 Sep 1996 rev. 2.12 for linux 2.1.0
- * Portability cleanups (virtual/bus addressing, little/big endian
- * support).
- *
- * 09 Jul 1996 rev. 2.11 for linux 2.0.4
- * "Data over/under-run" no longer implies a redo on all targets.
- * Number of internal retries is now limited.
- *
- * 16 Apr 1996 rev. 2.10 for linux 1.3.90
- * New argument "reset_flags" to the reset routine.
- *
- * 21 Jul 1995 rev. 2.02 for linux 1.3.11
- * Fixed Data Transfer Direction for some SCSI commands.
- *
- * 13 Jun 1995 rev. 2.01 for linux 1.2.10
- * HAVE_OLD_UX4F_FIRMWARE should be defined for U34F boards when
- * the firmware prom is not the latest one (28008-006).
- *
- * 11 Mar 1995 rev. 2.00 for linux 1.2.0
- * Fixed a bug which prevented media change detection for removable
- * disk drives.
- *
- * 23 Feb 1995 rev. 1.18 for linux 1.1.94
- * Added a check for scsi_register returning NULL.
- *
- * 11 Feb 1995 rev. 1.17 for linux 1.1.91
- * U14F qualified to run with 32 sglists.
- * Now DEBUG_RESET is disabled by default.
- *
- * 9 Feb 1995 rev. 1.16 for linux 1.1.90
- * Use host->wish_block instead of host->block.
- *
- * 8 Feb 1995 rev. 1.15 for linux 1.1.89
- * Cleared target_time_out counter while performing a reset.
- *
- * 28 Jan 1995 rev. 1.14 for linux 1.1.86
- * Added module support.
- * Log and do a retry when a disk drive returns a target status
- * different from zero on a recovered error.
- * Auto detects if U14F boards have an old firmware revision.
- * Max number of scatter/gather lists set to 16 for all boards
- * (most installation run fine using 33 sglists, while other
- * has problems when using more than 16).
- *
- * 16 Jan 1995 rev. 1.13 for linux 1.1.81
- * Display a message if check_region detects a port address
- * already in use.
- *
- * 15 Dec 1994 rev. 1.12 for linux 1.1.74
- * The host->block flag is set for all the detected ISA boards.
- *
- * 30 Nov 1994 rev. 1.11 for linux 1.1.68
- * Redo i/o on target status CHECK_CONDITION for TYPE_DISK only.
- * Added optional support for using a single board at a time.
- *
- * 14 Nov 1994 rev. 1.10 for linux 1.1.63
- *
- * 28 Oct 1994 rev. 1.09 for linux 1.1.58 Final BETA release.
- * 16 Jul 1994 rev. 1.00 for linux 1.1.29 Initial ALPHA release.
- *
- * This driver is a total replacement of the original UltraStor
- * scsi driver, but it supports ONLY the 14F and 34F boards.
- * It can be configured in the same kernel in which the original
- * ultrastor driver is configured to allow the original U24F
- * support.
- *
- * Multiple U14F and/or U34F host adapters are supported.
- *
- * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com)
- *
- * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * WARNING: if your 14/34F board has an old firmware revision (see below)
- * you must change "#undef" into "#define" in the following
- * statement.
- */
-#undef HAVE_OLD_UX4F_FIRMWARE
-/*
- * The UltraStor 14F, 24F, and 34F are a family of intelligent, high
- * performance SCSI-2 host adapters.
- * Here is the scoop on the various models:
- *
- * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
- * 24F - EISA Bus Master HA with floppy support and WD1003 emulation.
- * 34F - VESA Local-Bus Bus Master HA (no WD1003 emulation).
- *
- * This code has been tested with up to two U14F boards, using both
- * firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware
- * 28004-006/38004-005 (BIOS rev. 2.01).
- *
- * The latest firmware is required in order to get reliable operations when
- * clustering is enabled. ENABLE_CLUSTERING provides a performance increase
- * up to 50% on sequential access.
- *
- * Since the struct scsi_host_template structure is shared among all 14F and 34F,
- * the last setting of use_clustering is in effect for all of these boards.
- *
- * Here a sample configuration using two U14F boards:
- *
- U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, of:n, lc:y, mq:8.
- U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, of:n, lc:y, mq:8.
- *
- * The boot controller must have its BIOS enabled, while other boards can
- * have their BIOS disabled, or enabled to an higher address.
- * Boards are named Ux4F0, Ux4F1..., according to the port address order in
- * the io_port[] array.
- *
- * The following facts are based on real testing results (not on
- * documentation) on the above U14F board.
- *
- * - The U14F board should be jumpered for bus on time less or equal to 7
- * microseconds, while the default is 11 microseconds. This is order to
- * get acceptable performance while using floppy drive and hard disk
- * together. The jumpering for 7 microseconds is: JP13 pin 15-16,
- * JP14 pin 7-8 and pin 9-10.
- * The reduction has a little impact on scsi performance.
- *
- * - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced
- * from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8).
- *
- * - If U14F on board firmware is older than 28004-006/38004-005,
- * the U14F board is unable to provide reliable operations if the scsi
- * request length exceeds 16Kbyte. When this length is exceeded the
- * behavior is:
- * - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94;
- * - adapter_status equal 0 and target_status equal 2 on for all targets
- * in the next operation following the reset.
- * This sequence takes a long time (>3 seconds), so in the meantime
- * the SD_TIMEOUT in sd.c could expire giving rise to scsi aborts
- * (SD_TIMEOUT has been increased from 3 to 6 seconds in 1.1.31).
- * Because of this I had to DISABLE_CLUSTERING and to work around the
- * bus reset in the interrupt service routine, returning DID_BUS_BUSY
- * so that the operations are retried without complains from the scsi.c
- * code.
- * Any reset of the scsi bus is going to kill tape operations, since
- * no retry is allowed for tapes. Bus resets are more likely when the
- * scsi bus is under heavy load.
- * Requests using scatter/gather have a maximum length of 16 x 1024 bytes
- * when DISABLE_CLUSTERING is in effect, but unscattered requests could be
- * larger than 16Kbyte.
- *
- * The new firmware has fixed all the above problems.
- *
- * For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01),
- * the latest firmware prom is 28008-006. Older firmware 28008-005 has
- * problems when using more than 16 scatter/gather lists.
- *
- * The list of i/o ports to be probed can be totally replaced by the
- * boot command line option: "u14-34f=port0,port1,port2,...", where the
- * port0, port1... arguments are ISA/VESA addresses to be probed.
- * For example using "u14-34f=0x230,0x340", the driver probes only the two
- * addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables
- * this driver.
- *
- * After the optional list of detection probes, other possible command line
- * options are:
- *
- * et:y use disk geometry returned by scsicam_bios_param;
- * et:n use disk geometry jumpered on the board;
- * lc:y enables linked commands;
- * lc:n disables linked commands;
- * tm:0 disables tagged commands (same as tc:n);
- * tm:1 use simple queue tags (same as tc:y);
- * tm:2 use ordered queue tags (same as tc:2);
- * of:y enables old firmware support;
- * of:n disables old firmware support;
- * mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
- *
- * The default value is: "u14-34f=lc:n,of:n,mq:8,tm:0,et:n".
- * An example using the list of detection probes could be:
- * "u14-34f=0x230,0x340,lc:y,tm:2,of:n,mq:4,et:n".
- *
- * When loading as a module, parameters can be specified as well.
- * The above example would be (use 1 in place of y and 0 in place of n):
- *
- * modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- * max_queue_depth=4 ext_tran=0 tag_mode=2
- *
- * ----------------------------------------------------------------------------
- * In this implementation, linked commands are designed to work with any DISK
- * or CD-ROM, since this linking has only the intent of clustering (time-wise)
- * and reordering by elevator sorting commands directed to each device,
- * without any relation with the actual SCSI protocol between the controller
- * and the device.
- * If Q is the queue depth reported at boot time for each device (also named
- * cmds/lun) and Q > 2, whenever there is already an active command to the
- * device all other commands to the same device (up to Q-1) are kept waiting
- * in the elevator sorting queue. When the active command completes, the
- * commands in this queue are sorted by sector address. The sort is chosen
- * between increasing or decreasing by minimizing the seek distance between
- * the sector of the commands just completed and the sector of the first
- * command in the list to be sorted.
- * Trivial math assures that the unsorted average seek distance when doing
- * random seeks over S sectors is S/3.
- * When (Q-1) requests are uniformly distributed over S sectors, the average
- * distance between two adjacent requests is S/((Q-1) + 1), so the sorted
- * average seek distance for (Q-1) random requests over S sectors is S/Q.
- * The elevator sorting hence divides the seek distance by a factor Q/3.
- * The above pure geometric remarks are valid in all cases and the
- * driver effectively reduces the seek distance by the predicted factor
- * when there are Q concurrent read i/o operations on the device, but this
- * does not necessarily results in a noticeable performance improvement:
- * your mileage may vary....
- *
- * Note: command reordering inside a batch of queued commands could cause
- * wrong results only if there is at least one write request and the
- * intersection (sector-wise) of all requests is not empty.
- * When the driver detects a batch including overlapping requests
- * (a really rare event) strict serial (pid) order is enforced.
- * ----------------------------------------------------------------------------
- *
- * The boards are named Ux4F0, Ux4F1,... according to the detection order.
- *
- * In order to support multiple ISA boards in a reliable way,
- * the driver sets host->wish_block = TRUE for all ISA boards.
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/proc_fs.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/stat.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsicam.h>
-
-static int u14_34f_detect(struct scsi_host_template *);
-static int u14_34f_release(struct Scsi_Host *);
-static int u14_34f_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-static int u14_34f_eh_abort(struct scsi_cmnd *);
-static int u14_34f_eh_host_reset(struct scsi_cmnd *);
-static int u14_34f_bios_param(struct scsi_device *, struct block_device *,
- sector_t, int *);
-static int u14_34f_slave_configure(struct scsi_device *);
-
-static struct scsi_host_template driver_template = {
- .name = "UltraStor 14F/34F rev. 8.10.00 ",
- .detect = u14_34f_detect,
- .release = u14_34f_release,
- .queuecommand = u14_34f_queuecommand,
- .eh_abort_handler = u14_34f_eh_abort,
- .eh_host_reset_handler = u14_34f_eh_host_reset,
- .bios_param = u14_34f_bios_param,
- .slave_configure = u14_34f_slave_configure,
- .this_id = 7,
- .unchecked_isa_dma = 1,
- .use_clustering = ENABLE_CLUSTERING,
- };
-
-#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
-
-/* Values for the PRODUCT_ID ports for the 14/34F */
-#define PRODUCT_ID1 0x56
-#define PRODUCT_ID2 0x40 /* NOTE: Only upper nibble is used */
-
-/* Subversion values */
-#define ISA 0
-#define ESA 1
-
-#define OP_HOST_ADAPTER 0x1
-#define OP_SCSI 0x2
-#define OP_RESET 0x4
-#define DTD_SCSI 0x0
-#define DTD_IN 0x1
-#define DTD_OUT 0x2
-#define DTD_NONE 0x3
-#define HA_CMD_INQUIRY 0x1
-#define HA_CMD_SELF_DIAG 0x2
-#define HA_CMD_READ_BUFF 0x3
-#define HA_CMD_WRITE_BUFF 0x4
-
-#undef DEBUG_LINKED_COMMANDS
-#undef DEBUG_DETECT
-#undef DEBUG_INTERRUPT
-#undef DEBUG_RESET
-#undef DEBUG_GENERATE_ERRORS
-#undef DEBUG_GENERATE_ABORTS
-#undef DEBUG_GEOMETRY
-
-#define MAX_ISA 3
-#define MAX_VESA 1
-#define MAX_EISA 0
-#define MAX_PCI 0
-#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
-#define MAX_CHANNEL 1
-#define MAX_LUN 8
-#define MAX_TARGET 8
-#define MAX_MAILBOXES 16
-#define MAX_SGLIST 32
-#define MAX_SAFE_SGLIST 16
-#define MAX_INTERNAL_RETRIES 64
-#define MAX_CMD_PER_LUN 2
-#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
-
-#define SKIP ULONG_MAX
-#define FALSE 0
-#define TRUE 1
-#define FREE 0
-#define IN_USE 1
-#define LOCKED 2
-#define IN_RESET 3
-#define IGNORE 4
-#define READY 5
-#define ABORTING 6
-#define NO_DMA 0xff
-#define MAXLOOP 10000
-#define TAG_DISABLED 0
-#define TAG_SIMPLE 1
-#define TAG_ORDERED 2
-
-#define REG_LCL_MASK 0
-#define REG_LCL_INTR 1
-#define REG_SYS_MASK 2
-#define REG_SYS_INTR 3
-#define REG_PRODUCT_ID1 4
-#define REG_PRODUCT_ID2 5
-#define REG_CONFIG1 6
-#define REG_CONFIG2 7
-#define REG_OGM 8
-#define REG_ICM 12
-#define REGION_SIZE 13UL
-#define BSY_ASSERTED 0x01
-#define IRQ_ASSERTED 0x01
-#define CMD_RESET 0xc0
-#define CMD_OGM_INTR 0x01
-#define CMD_CLR_INTR 0x01
-#define CMD_ENA_INTR 0x81
-#define ASOK 0x00
-#define ASST 0x91
-
-#define YESNO(a) ((a) ? 'y' : 'n')
-#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
-
-#define PACKED __attribute__((packed))
-
-struct sg_list {
- unsigned int address; /* Segment Address */
- unsigned int num_bytes; /* Segment Length */
- };
-
-/* MailBox SCSI Command Packet */
-struct mscp {
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned char sg:1, ca:1, dcn:1, xdir:2, opcode:3;
- unsigned char lun: 3, channel:2, target:3;
-#else
- unsigned char opcode: 3, /* type of command */
- xdir: 2, /* data transfer direction */
- dcn: 1, /* disable disconnect */
- ca: 1, /* use cache (if available) */
- sg: 1; /* scatter/gather operation */
- unsigned char target: 3, /* SCSI target id */
- channel: 2, /* SCSI channel number */
- lun: 3; /* SCSI logical unit number */
-#endif
-
- unsigned int data_address PACKED; /* transfer data pointer */
- unsigned int data_len PACKED; /* length in bytes */
- unsigned int link_address PACKED; /* for linking command chains */
- unsigned char clink_id; /* identifies command in chain */
- unsigned char use_sg; /* (if sg is set) 8 bytes per list */
- unsigned char sense_len;
- unsigned char cdb_len; /* 6, 10, or 12 */
- unsigned char cdb[12]; /* SCSI Command Descriptor Block */
- unsigned char adapter_status; /* non-zero indicates HA error */
- unsigned char target_status; /* non-zero indicates target error */
- unsigned int sense_addr PACKED;
-
- /* Additional fields begin here. */
- struct scsi_cmnd *SCpnt;
- unsigned int cpp_index; /* cp index */
-
- /* All the cp structure is zero filled by queuecommand except the
- following CP_TAIL_SIZE bytes, initialized by detect */
- dma_addr_t cp_dma_addr; /* dma handle for this cp structure */
- struct sg_list *sglist; /* pointer to the allocated SG list */
- };
-
-#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
-
-struct hostdata {
- struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */
- unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
- unsigned int last_cp_used; /* Index of last mailbox used */
- unsigned int iocount; /* Total i/o done for this board */
- int board_number; /* Number of this board */
- char board_name[16]; /* Name of this board */
- int in_reset; /* True if board is doing a reset */
- int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
- int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
- unsigned int retries; /* Number of internal retries */
- unsigned long last_retried_pid; /* Pid of last retried command */
- unsigned char subversion; /* Bus type, either ISA or ESA */
- struct pci_dev *pdev; /* Always NULL */
- unsigned char heads;
- unsigned char sectors;
- char board_id[256]; /* data from INQUIRY on this board */
- };
-
-static struct Scsi_Host *sh[MAX_BOARDS + 1];
-static const char *driver_name = "Ux4F";
-static char sha[MAX_BOARDS];
-static DEFINE_SPINLOCK(driver_lock);
-
-/* Initialize num_boards so that ihdlr can work while detect is in progress */
-static unsigned int num_boards = MAX_BOARDS;
-
-static unsigned long io_port[] = {
-
- /* Space for MAX_INT_PARAM ports usable while loading as a module */
- SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
- SKIP, SKIP,
-
- /* Possible ISA/VESA ports */
- 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140,
-
- /* End of list */
- 0x0
- };
-
-#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
-#define BN(board) (HD(board)->board_name)
-
-/* Device is Little Endian */
-#define H2DEV(x) cpu_to_le32(x)
-#define DEV2H(x) le32_to_cpu(x)
-
-static irqreturn_t do_interrupt_handler(int, void *);
-static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int);
-static int do_trace = FALSE;
-static int setup_done = FALSE;
-static int link_statistics;
-static int ext_tran = FALSE;
-
-#if defined(HAVE_OLD_UX4F_FIRMWARE)
-static int have_old_firmware = TRUE;
-#else
-static int have_old_firmware = FALSE;
-#endif
-
-#if defined(CONFIG_SCSI_U14_34F_TAGGED_QUEUE)
-static int tag_mode = TAG_SIMPLE;
-#else
-static int tag_mode = TAG_DISABLED;
-#endif
-
-#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
-static int linked_comm = TRUE;
-#else
-static int linked_comm = FALSE;
-#endif
-
-#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS)
-static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;
-#else
-static int max_queue_depth = MAX_CMD_PER_LUN;
-#endif
-
-#define MAX_INT_PARAM 10
-#define MAX_BOOT_OPTIONS_SIZE 256
-static char boot_options[MAX_BOOT_OPTIONS_SIZE];
-
-#if defined(MODULE)
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-module_param_string(u14_34f, boot_options, MAX_BOOT_OPTIONS_SIZE, 0);
-MODULE_PARM_DESC(u14_34f, " equivalent to the \"u14-34f=...\" kernel boot " \
-"option." \
-" Example: modprobe u14-34f \"u14_34f=0x340,0x330,lc:y,tm:0,mq:4\"");
-MODULE_AUTHOR("Dario Ballabio");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("UltraStor 14F/34F SCSI Driver");
-
-#endif
-
-static int u14_34f_slave_configure(struct scsi_device *dev) {
- int j, tqd, utqd;
- char *tag_suffix, *link_suffix;
- struct Scsi_Host *host = dev->host;
-
- j = ((struct hostdata *) host->hostdata)->board_number;
-
- utqd = MAX_CMD_PER_LUN;
- tqd = max_queue_depth;
-
- if (TLDEV(dev->type) && dev->tagged_supported)
-
- if (tag_mode == TAG_SIMPLE) {
- scsi_change_queue_depth(dev, tqd);
- tag_suffix = ", simple tags";
- }
- else if (tag_mode == TAG_ORDERED) {
- scsi_change_queue_depth(dev, tqd);
- tag_suffix = ", ordered tags";
- }
- else {
- scsi_change_queue_depth(dev, tqd);
- tag_suffix = ", no tags";
- }
-
- else if (TLDEV(dev->type) && linked_comm) {
- scsi_change_queue_depth(dev, tqd);
- tag_suffix = ", untagged";
- }
-
- else {
- scsi_change_queue_depth(dev, utqd);
- tag_suffix = "";
- }
-
- if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2)
- link_suffix = ", sorted";
- else if (TLDEV(dev->type))
- link_suffix = ", unsorted";
- else
- link_suffix = "";
-
- sdev_printk(KERN_INFO, dev, "cmds/lun %d%s%s.\n",
- dev->queue_depth, link_suffix, tag_suffix);
-
- return FALSE;
-}
-
-static int wait_on_busy(unsigned long iobase, unsigned int loop) {
-
- while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {
- udelay(1L);
- if (--loop == 0) return TRUE;
- }
-
- return FALSE;
-}
-
-static int board_inquiry(unsigned int j) {
- struct mscp *cpp;
- dma_addr_t id_dma_addr;
- unsigned int limit = 0;
- unsigned long time;
-
- id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
- sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
- cpp = &HD(j)->cp[0];
- cpp->cp_dma_addr = pci_map_single(HD(j)->pdev, cpp, sizeof(struct mscp),
- PCI_DMA_BIDIRECTIONAL);
- memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
- cpp->opcode = OP_HOST_ADAPTER;
- cpp->xdir = DTD_IN;
- cpp->data_address = H2DEV(id_dma_addr);
- cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
- cpp->cdb_len = 6;
- cpp->cdb[0] = HA_CMD_INQUIRY;
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: board_inquiry, adapter busy.\n", BN(j));
- return TRUE;
- }
-
- HD(j)->cp_stat[0] = IGNORE;
-
- /* Clear the interrupt indication */
- outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-
- /* Store pointer in OGM address bytes */
- outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
-
- /* Issue OGM interrupt */
- outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
-
- spin_unlock_irq(&driver_lock);
- time = jiffies;
- while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
- spin_lock_irq(&driver_lock);
-
- if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
- HD(j)->cp_stat[0] = FREE;
- printk("%s: board_inquiry, err 0x%x.\n", BN(j), cpp->adapter_status);
- return TRUE;
- }
-
- pci_unmap_single(HD(j)->pdev, cpp->cp_dma_addr, sizeof(struct mscp),
- PCI_DMA_BIDIRECTIONAL);
- pci_unmap_single(HD(j)->pdev, id_dma_addr, sizeof(HD(j)->board_id),
- PCI_DMA_BIDIRECTIONAL);
- return FALSE;
-}
-
-static int port_detect \
- (unsigned long port_base, unsigned int j, struct scsi_host_template *tpnt) {
- unsigned char irq, dma_channel, subversion, i;
- unsigned char in_byte;
- char *bus_type, dma_name[16];
-
- /* Allowed BIOS base addresses (NULL indicates reserved) */
- unsigned long bios_segment_table[8] = {
- 0,
- 0xc4000, 0xc8000, 0xcc000, 0xd0000,
- 0xd4000, 0xd8000, 0xdc000
- };
-
- /* Allowed IRQs */
- unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
-
- /* Allowed DMA channels for ISA (0 indicates reserved) */
- unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
-
- /* Head/sector mappings */
- struct {
- unsigned char heads;
- unsigned char sectors;
- } mapping_table[4] = {
- { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
- };
-
- struct config_1 {
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned char dma_channel: 2, interrupt:2,
- removable_disks_as_fixed:1, bios_segment: 3;
-#else
- unsigned char bios_segment: 3, removable_disks_as_fixed: 1,
- interrupt: 2, dma_channel: 2;
-#endif
-
- } config_1;
-
- struct config_2 {
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned char tfr_port: 2, bios_drive_number: 1,
- mapping_mode: 2, ha_scsi_id: 3;
-#else
- unsigned char ha_scsi_id: 3, mapping_mode: 2,
- bios_drive_number: 1, tfr_port: 2;
-#endif
-
- } config_2;
-
- char name[16];
-
- sprintf(name, "%s%d", driver_name, j);
-
- if (!request_region(port_base, REGION_SIZE, driver_name)) {
-#if defined(DEBUG_DETECT)
- printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
-#endif
- goto fail;
- }
-
- spin_lock_irq(&driver_lock);
-
- if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) goto freelock;
-
- in_byte = inb(port_base + REG_PRODUCT_ID2);
-
- if ((in_byte & 0xf0) != PRODUCT_ID2) goto freelock;
-
- *(char *)&config_1 = inb(port_base + REG_CONFIG1);
- *(char *)&config_2 = inb(port_base + REG_CONFIG2);
-
- irq = interrupt_table[config_1.interrupt];
- dma_channel = dma_channel_table[config_1.dma_channel];
- subversion = (in_byte & 0x0f);
-
- /* Board detected, allocate its IRQ */
- if (request_irq(irq, do_interrupt_handler,
- (subversion == ESA) ? IRQF_SHARED : 0,
- driver_name, (void *) &sha[j])) {
- printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
- goto freelock;
- }
-
- if (subversion == ISA && request_dma(dma_channel, driver_name)) {
- printk("%s: unable to allocate DMA channel %u, detaching.\n",
- name, dma_channel);
- goto freeirq;
- }
-
- if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
-
- spin_unlock_irq(&driver_lock);
- sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
- spin_lock_irq(&driver_lock);
-
- if (sh[j] == NULL) {
- printk("%s: unable to register host, detaching.\n", name);
- goto freedma;
- }
-
- sh[j]->io_port = port_base;
- sh[j]->unique_id = port_base;
- sh[j]->n_io_port = REGION_SIZE;
- sh[j]->base = bios_segment_table[config_1.bios_segment];
- sh[j]->irq = irq;
- sh[j]->sg_tablesize = MAX_SGLIST;
- sh[j]->this_id = config_2.ha_scsi_id;
- sh[j]->can_queue = MAX_MAILBOXES;
- sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
-
-#if defined(DEBUG_DETECT)
- {
- unsigned char sys_mask, lcl_mask;
-
- sys_mask = inb(sh[j]->io_port + REG_SYS_MASK);
- lcl_mask = inb(sh[j]->io_port + REG_LCL_MASK);
- printk("SYS_MASK 0x%x, LCL_MASK 0x%x.\n", sys_mask, lcl_mask);
- }
-#endif
-
- /* Probably a bogus host scsi id, set it to the dummy value */
- if (sh[j]->this_id == 0) sh[j]->this_id = -1;
-
- /* If BIOS is disabled, force enable interrupts */
- if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
-
- memset(HD(j), 0, sizeof(struct hostdata));
- HD(j)->heads = mapping_table[config_2.mapping_mode].heads;
- HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
- HD(j)->subversion = subversion;
- HD(j)->pdev = NULL;
- HD(j)->board_number = j;
-
- if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
-
- if (HD(j)->subversion == ESA) {
- sh[j]->unchecked_isa_dma = FALSE;
- sh[j]->dma_channel = NO_DMA;
- sprintf(BN(j), "U34F%d", j);
- bus_type = "VESA";
- }
- else {
- unsigned long flags;
- sh[j]->unchecked_isa_dma = TRUE;
-
- flags=claim_dma_lock();
- disable_dma(dma_channel);
- clear_dma_ff(dma_channel);
- set_dma_mode(dma_channel, DMA_MODE_CASCADE);
- enable_dma(dma_channel);
- release_dma_lock(flags);
-
- sh[j]->dma_channel = dma_channel;
- sprintf(BN(j), "U14F%d", j);
- bus_type = "ISA";
- }
-
- sh[j]->max_channel = MAX_CHANNEL - 1;
- sh[j]->max_id = MAX_TARGET;
- sh[j]->max_lun = MAX_LUN;
-
- if (HD(j)->subversion == ISA && !board_inquiry(j)) {
- HD(j)->board_id[40] = 0;
-
- if (strcmp(&HD(j)->board_id[32], "06000600")) {
- printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
- printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
- BN(j), &HD(j)->board_id[32]);
- sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
- sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
- }
- }
-
- if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
- else sprintf(dma_name, "DMA %u", dma_channel);
-
- spin_unlock_irq(&driver_lock);
-
- for (i = 0; i < sh[j]->can_queue; i++)
- HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev,
- &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
-
- for (i = 0; i < sh[j]->can_queue; i++)
- if (! ((&HD(j)->cp[i])->sglist = kmalloc(
- sh[j]->sg_tablesize * sizeof(struct sg_list),
- (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
- printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
- goto release;
- }
-
- if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
- max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
-
- if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
-
- if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE)
- tag_mode = TAG_ORDERED;
-
- if (j == 0) {
- printk("UltraStor 14F/34F: Copyright (C) 1994-2003 Dario Ballabio.\n");
- printk("%s config options -> of:%c, tm:%d, lc:%c, mq:%d, et:%c.\n",
- driver_name, YESNO(have_old_firmware), tag_mode,
- YESNO(linked_comm), max_queue_depth, YESNO(ext_tran));
- }
-
- printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
- BN(j), bus_type, (unsigned long)sh[j]->io_port, (int)sh[j]->base,
- sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
-
- if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
- printk("%s: wide SCSI support enabled, max_id %u, max_lun %llu.\n",
- BN(j), sh[j]->max_id, sh[j]->max_lun);
-
- for (i = 0; i <= sh[j]->max_channel; i++)
- printk("%s: SCSI channel %u enabled, host target ID %d.\n",
- BN(j), i, sh[j]->this_id);
-
- return TRUE;
-
-freedma:
- if (subversion == ISA) free_dma(dma_channel);
-freeirq:
- free_irq(irq, &sha[j]);
-freelock:
- spin_unlock_irq(&driver_lock);
- release_region(port_base, REGION_SIZE);
-fail:
- return FALSE;
-
-release:
- u14_34f_release(sh[j]);
- return FALSE;
-}
-
-static void internal_setup(char *str, int *ints) {
- int i, argc = ints[0];
- char *cur = str, *pc;
-
- if (argc > 0) {
-
- if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
-
- for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
-
- io_port[i] = 0;
- setup_done = TRUE;
- }
-
- while (cur && (pc = strchr(cur, ':'))) {
- int val = 0, c = *++pc;
-
- if (c == 'n' || c == 'N') val = FALSE;
- else if (c == 'y' || c == 'Y') val = TRUE;
- else val = (int) simple_strtoul(pc, NULL, 0);
-
- if (!strncmp(cur, "lc:", 3)) linked_comm = val;
- else if (!strncmp(cur, "of:", 3)) have_old_firmware = val;
- else if (!strncmp(cur, "tm:", 3)) tag_mode = val;
- else if (!strncmp(cur, "tc:", 3)) tag_mode = val;
- else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val;
- else if (!strncmp(cur, "ls:", 3)) link_statistics = val;
- else if (!strncmp(cur, "et:", 3)) ext_tran = val;
-
- if ((cur = strchr(cur, ','))) ++cur;
- }
-
- return;
-}
-
-static int option_setup(char *str) {
- int ints[MAX_INT_PARAM];
- char *cur = str;
- int i = 1;
-
- while (cur && isdigit(*cur) && i < MAX_INT_PARAM) {
- ints[i++] = simple_strtoul(cur, NULL, 0);
-
- if ((cur = strchr(cur, ',')) != NULL) cur++;
- }
-
- ints[0] = i - 1;
- internal_setup(cur, ints);
- return 1;
-}
-
-static int u14_34f_detect(struct scsi_host_template *tpnt) {
- unsigned int j = 0, k;
-
- tpnt->proc_name = "u14-34f";
-
- if(strlen(boot_options)) option_setup(boot_options);
-
-#if defined(MODULE)
- /* io_port could have been modified when loading as a module */
- if(io_port[0] != SKIP) {
- setup_done = TRUE;
- io_port[MAX_INT_PARAM] = 0;
- }
-#endif
-
- for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
-
- for (k = 0; io_port[k]; k++) {
-
- if (io_port[k] == SKIP) continue;
-
- if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
- }
-
- num_boards = j;
- return j;
-}
-
-static void map_dma(unsigned int i, unsigned int j) {
- unsigned int data_len = 0;
- unsigned int k, pci_dir;
- int count;
- struct scatterlist *sg;
- struct mscp *cpp;
- struct scsi_cmnd *SCpnt;
-
- cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
- pci_dir = SCpnt->sc_data_direction;
-
- if (SCpnt->sense_buffer)
- cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
-
- cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
-
- if (scsi_bufflen(SCpnt)) {
- count = scsi_dma_map(SCpnt);
- BUG_ON(count < 0);
-
- scsi_for_each_sg(SCpnt, sg, count, k) {
- cpp->sglist[k].address = H2DEV(sg_dma_address(sg));
- cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg));
- data_len += sg->length;
- }
-
- cpp->sg = TRUE;
- cpp->use_sg = scsi_sg_count(SCpnt);
- cpp->data_address =
- H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
- cpp->use_sg * sizeof(struct sg_list),
- pci_dir));
- cpp->data_len = H2DEV(data_len);
-
- } else {
- pci_dir = PCI_DMA_BIDIRECTIONAL;
- cpp->data_len = H2DEV(scsi_bufflen(SCpnt));
- }
-}
-
-static void unmap_dma(unsigned int i, unsigned int j) {
- unsigned int pci_dir;
- struct mscp *cpp;
- struct scsi_cmnd *SCpnt;
-
- cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
- pci_dir = SCpnt->sc_data_direction;
-
- if (DEV2H(cpp->sense_addr))
- pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
- DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
-
- scsi_dma_unmap(SCpnt);
-
- if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
-
- if (DEV2H(cpp->data_address))
- pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
- DEV2H(cpp->data_len), pci_dir);
-}
-
-static void sync_dma(unsigned int i, unsigned int j) {
- unsigned int pci_dir;
- struct mscp *cpp;
- struct scsi_cmnd *SCpnt;
-
- cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
- pci_dir = SCpnt->sc_data_direction;
-
- if (DEV2H(cpp->sense_addr))
- pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr),
- DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
-
- if (scsi_sg_count(SCpnt))
- pci_dma_sync_sg_for_cpu(HD(j)->pdev, scsi_sglist(SCpnt),
- scsi_sg_count(SCpnt), pci_dir);
-
- if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
-
- if (DEV2H(cpp->data_address))
- pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address),
- DEV2H(cpp->data_len), pci_dir);
-}
-
-static void scsi_to_dev_dir(unsigned int i, unsigned int j) {
- unsigned int k;
-
- static const unsigned char data_out_cmds[] = {
- 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
- 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
- 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d
- };
-
- static const unsigned char data_none_cmds[] = {
- 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
- 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
- 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
- };
-
- struct mscp *cpp;
- struct scsi_cmnd *SCpnt;
-
- cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
-
- if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
- cpp->xdir = DTD_IN;
- return;
- }
- else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
- cpp->xdir = DTD_OUT;
- return;
- }
- else if (SCpnt->sc_data_direction == DMA_NONE) {
- cpp->xdir = DTD_NONE;
- return;
- }
-
- if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL)
- panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
-
- cpp->xdir = DTD_IN;
-
- for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
- if (SCpnt->cmnd[0] == data_out_cmds[k]) {
- cpp->xdir = DTD_OUT;
- break;
- }
-
- if (cpp->xdir == DTD_IN)
- for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
- if (SCpnt->cmnd[0] == data_none_cmds[k]) {
- cpp->xdir = DTD_NONE;
- break;
- }
-
-}
-
-static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
- unsigned int i, j, k;
- struct mscp *cpp;
-
- /* j is the board number */
- j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number;
-
- if (SCpnt->host_scribble)
- panic("%s: qcomm, SCpnt %p already active.\n",
- BN(j), SCpnt);
-
- /* i is the mailbox number, look for the first free mailbox
- starting from last_cp_used */
- i = HD(j)->last_cp_used + 1;
-
- for (k = 0; k < sh[j]->can_queue; k++, i++) {
-
- if (i >= sh[j]->can_queue) i = 0;
-
- if (HD(j)->cp_stat[i] == FREE) {
- HD(j)->last_cp_used = i;
- break;
- }
- }
-
- if (k == sh[j]->can_queue) {
- printk("%s: qcomm, no free mailbox.\n", BN(j));
- return 1;
- }
-
- /* Set pointer to control packet structure */
- cpp = &HD(j)->cp[i];
-
- memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
- SCpnt->scsi_done = done;
- cpp->cpp_index = i;
- SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
-
- if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%u.\n",
- BN(j), i, SCpnt->device->channel, SCpnt->device->id,
- (u8)SCpnt->device->lun);
-
- cpp->opcode = OP_SCSI;
- cpp->channel = SCpnt->device->channel;
- cpp->target = SCpnt->device->id;
- cpp->lun = (u8)SCpnt->device->lun;
- cpp->SCpnt = SCpnt;
- cpp->cdb_len = SCpnt->cmd_len;
- memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
- /* Use data transfer direction SCpnt->sc_data_direction */
- scsi_to_dev_dir(i, j);
-
- /* Map DMA buffers and SG list */
- map_dma(i, j);
-
- if (linked_comm && SCpnt->device->queue_depth > 2
- && TLDEV(SCpnt->device->type)) {
- HD(j)->cp_stat[i] = READY;
- flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, FALSE);
- return 0;
- }
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- unmap_dma(i, j);
- SCpnt->host_scribble = NULL;
- scmd_printk(KERN_INFO, SCpnt,
- "qcomm, adapter busy.\n");
- return 1;
- }
-
- /* Store pointer in OGM address bytes */
- outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
-
- /* Issue OGM interrupt */
- outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
-
- HD(j)->cp_stat[i] = IN_USE;
- return 0;
-}
-
-static DEF_SCSI_QCMD(u14_34f_queuecommand)
-
-static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
- unsigned int i, j;
-
- j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
-
- if (SCarg->host_scribble == NULL) {
- scmd_printk(KERN_INFO, SCarg, "abort, command inactive.\n");
- return SUCCESS;
- }
-
- i = *(unsigned int *)SCarg->host_scribble;
- scmd_printk(KERN_INFO, SCarg, "abort, mbox %d.\n", i);
-
- if (i >= sh[j]->can_queue)
- panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: abort, timeout error.\n", BN(j));
- return FAILED;
- }
-
- if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: abort, mbox %d is free.\n", BN(j), i);
- return SUCCESS;
- }
-
- if (HD(j)->cp_stat[i] == IN_USE) {
- printk("%s: abort, mbox %d is in use.\n", BN(j), i);
-
- if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
-
- if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
- printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
-
- return FAILED;
- }
-
- if (HD(j)->cp_stat[i] == IN_RESET) {
- printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
- return FAILED;
- }
-
- if (HD(j)->cp_stat[i] == LOCKED) {
- printk("%s: abort, mbox %d is locked.\n", BN(j), i);
- return SUCCESS;
- }
-
- if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
- unmap_dma(i, j);
- SCarg->result = DID_ABORT << 16;
- SCarg->host_scribble = NULL;
- HD(j)->cp_stat[i] = FREE;
- printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", BN(j), i);
- SCarg->scsi_done(SCarg);
- return SUCCESS;
- }
-
- panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
-}
-
-static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
- unsigned int i, j, k, c, limit = 0;
- unsigned long time;
- int arg_done = FALSE;
- struct scsi_cmnd *SCpnt;
-
- j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
- scmd_printk(KERN_INFO, SCarg, "reset, enter.\n");
-
- spin_lock_irq(sh[j]->host_lock);
-
- if (SCarg->host_scribble == NULL)
- printk("%s: reset, inactive.\n", BN(j));
-
- if (HD(j)->in_reset) {
- printk("%s: reset, exit, already in reset.\n", BN(j));
- spin_unlock_irq(sh[j]->host_lock);
- return FAILED;
- }
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: reset, exit, timeout error.\n", BN(j));
- spin_unlock_irq(sh[j]->host_lock);
- return FAILED;
- }
-
- HD(j)->retries = 0;
-
- for (c = 0; c <= sh[j]->max_channel; c++)
- for (k = 0; k < sh[j]->max_id; k++) {
- HD(j)->target_redo[k][c] = TRUE;
- HD(j)->target_to[k][c] = 0;
- }
-
- for (i = 0; i < sh[j]->can_queue; i++) {
-
- if (HD(j)->cp_stat[i] == FREE) continue;
-
- if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
-
- if (!(SCpnt = HD(j)->cp[i].SCpnt))
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
- if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
- HD(j)->cp_stat[i] = ABORTING;
- printk("%s: reset, mbox %d aborting.\n", BN(j), i);
- }
-
- else {
- HD(j)->cp_stat[i] = IN_RESET;
- printk("%s: reset, mbox %d in reset.\n", BN(j), i);
- }
-
- if (SCpnt->host_scribble == NULL)
- panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
-
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
-
- if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
-
- if (SCpnt == SCarg) arg_done = TRUE;
- }
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: reset, cannot reset, timeout error.\n", BN(j));
- spin_unlock_irq(sh[j]->host_lock);
- return FAILED;
- }
-
- outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
- printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
-
-#if defined(DEBUG_RESET)
- do_trace = TRUE;
-#endif
-
- HD(j)->in_reset = TRUE;
-
- spin_unlock_irq(sh[j]->host_lock);
- time = jiffies;
- while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
- spin_lock_irq(sh[j]->host_lock);
-
- printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
-
- for (i = 0; i < sh[j]->can_queue; i++) {
-
- if (HD(j)->cp_stat[i] == IN_RESET) {
- SCpnt = HD(j)->cp[i].SCpnt;
- unmap_dma(i, j);
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- /* This mailbox is still waiting for its interrupt */
- HD(j)->cp_stat[i] = LOCKED;
-
- printk("%s, reset, mbox %d locked, DID_RESET, done.\n", BN(j), i);
- }
-
- else if (HD(j)->cp_stat[i] == ABORTING) {
- SCpnt = HD(j)->cp[i].SCpnt;
- unmap_dma(i, j);
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- /* This mailbox was never queued to the adapter */
- HD(j)->cp_stat[i] = FREE;
-
- printk("%s, reset, mbox %d aborting, DID_RESET, done.\n", BN(j), i);
- }
-
- else
-
- /* Any other mailbox has already been set free by interrupt */
- continue;
-
- SCpnt->scsi_done(SCpnt);
- }
-
- HD(j)->in_reset = FALSE;
- do_trace = FALSE;
-
- if (arg_done) printk("%s: reset, exit, done.\n", BN(j));
- else printk("%s: reset, exit.\n", BN(j));
-
- spin_unlock_irq(sh[j]->host_lock);
- return SUCCESS;
-}
-
-static int u14_34f_bios_param(struct scsi_device *disk,
- struct block_device *bdev, sector_t capacity, int *dkinfo) {
- unsigned int j = 0;
- unsigned int size = capacity;
-
- dkinfo[0] = HD(j)->heads;
- dkinfo[1] = HD(j)->sectors;
- dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
-
- if (ext_tran && (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) {
- dkinfo[0] = 255;
- dkinfo[1] = 63;
- dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
- }
-
-#if defined (DEBUG_GEOMETRY)
- printk ("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name,
- dkinfo[0], dkinfo[1], dkinfo[2]);
-#endif
-
- return FALSE;
-}
-
-static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
- unsigned int rev) {
- unsigned int i, j, k, y;
- unsigned long x;
-
- for (i = 0; i < n - 1; i++) {
- k = i;
-
- for (j = k + 1; j < n; j++)
- if (rev) {
- if (sk[j] > sk[k]) k = j;
- }
- else {
- if (sk[j] < sk[k]) k = j;
- }
-
- if (k != i) {
- x = sk[k]; sk[k] = sk[i]; sk[i] = x;
- y = da[k]; da[k] = da[i]; da[i] = y;
- }
- }
-
- return;
- }
-
-static int reorder(unsigned int j, unsigned long cursec,
- unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
- struct scsi_cmnd *SCpnt;
- struct mscp *cpp;
- unsigned int k, n;
- unsigned int rev = FALSE, s = TRUE, r = TRUE;
- unsigned int input_only = TRUE, overlap = FALSE;
- unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
- unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
- unsigned long ioseek = 0;
-
- static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
- static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
- static unsigned int readysorted = 0, revcount = 0;
- static unsigned long seeksorted = 0, seeknosort = 0;
-
- if (link_statistics && !(++flushcount % link_statistics))
- printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
- " av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
- ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount + 1),
- seeksorted / (readycount + 1));
-
- if (n_ready <= 1) return FALSE;
-
- for (n = 0; n < n_ready; n++) {
- k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-
- if (!(cpp->xdir == DTD_IN)) input_only = FALSE;
-
- if (blk_rq_pos(SCpnt->request) < minsec)
- minsec = blk_rq_pos(SCpnt->request);
- if (blk_rq_pos(SCpnt->request) > maxsec)
- maxsec = blk_rq_pos(SCpnt->request);
-
- sl[n] = blk_rq_pos(SCpnt->request);
- ioseek += blk_rq_sectors(SCpnt->request);
-
- if (!n) continue;
-
- if (sl[n] < sl[n - 1]) s = FALSE;
- if (sl[n] > sl[n - 1]) r = FALSE;
-
- if (link_statistics) {
- if (sl[n] > sl[n - 1])
- seek += sl[n] - sl[n - 1];
- else
- seek += sl[n - 1] - sl[n];
- }
-
- }
-
- if (link_statistics) {
- if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
- }
-
- if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
-
- if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
-
- if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
-
- if (!input_only) for (n = 0; n < n_ready; n++) {
- k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
- ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number;
-
- if (!n) continue;
-
- if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
- || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
- }
-
- if (overlap) sort(pl, il, n_ready, FALSE);
-
- if (link_statistics) {
- if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
- batchcount++; readycount += n_ready; seeknosort += seek / 1024;
- if (input_only) inputcount++;
- if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
- else seeksorted += (iseek + maxsec - minsec) / 1024;
- if (rev && !r) { revcount++; readysorted += n_ready; }
- if (!rev && !s) { sortcount++; readysorted += n_ready; }
- }
-
-#if defined(DEBUG_LINKED_COMMANDS)
- if (link_statistics && (overlap || !(flushcount % link_statistics)))
- for (n = 0; n < n_ready; n++) {
- k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
- printk("%s %d.%d:%llu mb %d fc %d nr %d sec %ld ns %u"\
- " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
- (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
- (u8)SCpnt->lun, k, flushcount, n_ready,
- blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request),
- cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
- YESNO(overlap), cpp->xdir);
- }
-#endif
- return overlap;
-}
-
-static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned int j,
- unsigned int ihdlr) {
- struct scsi_cmnd *SCpnt;
- struct mscp *cpp;
- unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES];
-
- for (k = 0; k < sh[j]->can_queue; k++) {
-
- if (HD(j)->cp_stat[k] != READY && HD(j)->cp_stat[k] != IN_USE) continue;
-
- cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-
- if (SCpnt->device != dev) continue;
-
- if (HD(j)->cp_stat[k] == IN_USE) return;
-
- il[n_ready++] = k;
- }
-
- if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
-
- for (n = 0; n < n_ready; n++) {
- k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- scmd_printk(KERN_INFO, SCpnt,
- "%s, mbox %d, adapter"
- " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"),
- k);
- HD(j)->cp_stat[k] = ABORTING;
- continue;
- }
-
- outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
- outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
- HD(j)->cp_stat[k] = IN_USE;
- }
-
-}
-
-static irqreturn_t ihdlr(unsigned int j)
-{
- struct scsi_cmnd *SCpnt;
- unsigned int i, k, c, status, tstatus, reg, ret;
- struct mscp *spp, *cpp;
- int irq = sh[j]->irq;
-
- /* Check if this board need to be serviced */
- if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none;
-
- HD(j)->iocount++;
-
- if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
- HD(j)->iocount);
-
- /* Check if this board is still busy */
- if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) {
- outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
- printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
- BN(j), irq, reg, HD(j)->iocount);
- goto none;
- }
-
- ret = inl(sh[j]->io_port + REG_ICM);
-
- /* Clear interrupt pending flag */
- outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-
- /* Find the mailbox to be serviced on this board */
- for (i = 0; i < sh[j]->can_queue; i++)
- if (H2DEV(HD(j)->cp[i].cp_dma_addr) == ret) break;
-
- if (i >= sh[j]->can_queue)
- panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
- (void *)ret, (void *)H2DEV(HD(j)->cp[0].cp_dma_addr));
-
- cpp = &(HD(j)->cp[i]);
- spp = cpp;
-
-#if defined(DEBUG_GENERATE_ABORTS)
- if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled;
-#endif
-
- if (HD(j)->cp_stat[i] == IGNORE) {
- HD(j)->cp_stat[i] = FREE;
- goto handled;
- }
- else if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
- HD(j)->iocount);
- goto handled;
- }
- else if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
- HD(j)->iocount);
- goto handled;
- }
- else if (HD(j)->cp_stat[i] == IN_RESET)
- printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
- else if (HD(j)->cp_stat[i] != IN_USE)
- panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
- BN(j), i, HD(j)->cp_stat[i]);
-
- HD(j)->cp_stat[i] = FREE;
- SCpnt = cpp->SCpnt;
-
- if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
- if (SCpnt->host_scribble == NULL)
- panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", BN(j), i,
- SCpnt);
-
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: ihdlr, mbox %d, index mismatch %d.\n",
- BN(j), i, *(unsigned int *)SCpnt->host_scribble);
-
- sync_dma(i, j);
-
- if (linked_comm && SCpnt->device->queue_depth > 2
- && TLDEV(SCpnt->device->type))
- flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, TRUE);
-
- tstatus = status_byte(spp->target_status);
-
-#if defined(DEBUG_GENERATE_ERRORS)
- if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2))
- spp->adapter_status = 0x01;
-#endif
-
- switch (spp->adapter_status) {
- case ASOK: /* status OK */
-
- /* Forces a reset if a disk drive keeps returning BUSY */
- if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
- status = DID_ERROR << 16;
-
- /* If there was a bus reset, redo operation on each target */
- else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
- && HD(j)->target_redo[scmd_id(SCpnt)][scmd_channel(SCpnt)])
- status = DID_BUS_BUSY << 16;
-
- /* Works around a flaw in scsi.c */
- else if (tstatus == CHECK_CONDITION
- && SCpnt->device->type == TYPE_DISK
- && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
- status = DID_BUS_BUSY << 16;
-
- else
- status = DID_OK << 16;
-
- if (tstatus == GOOD)
- HD(j)->target_redo[scmd_id(SCpnt)][scmd_channel(SCpnt)] = FALSE;
-
- if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
- (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 &&
- (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
- scmd_printk(KERN_INFO, SCpnt,
- "ihdlr, target_status 0x%x, sense key 0x%x.\n",
- spp->target_status,
- SCpnt->sense_buffer[2]);
-
- HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0;
-
- if (HD(j)->last_retried_pid == SCpnt->serial_number) HD(j)->retries = 0;
-
- break;
- case ASST: /* Selection Time Out */
-
- if (HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] > 1)
- status = DID_ERROR << 16;
- else {
- status = DID_TIME_OUT << 16;
- HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)]++;
- }
-
- break;
-
- /* Perform a limited number of internal retries */
- case 0x93: /* Unexpected bus free */
- case 0x94: /* Target bus phase sequence failure */
- case 0x96: /* Illegal SCSI command */
- case 0xa3: /* SCSI bus reset error */
-
- for (c = 0; c <= sh[j]->max_channel; c++)
- for (k = 0; k < sh[j]->max_id; k++)
- HD(j)->target_redo[k][c] = TRUE;
-
-
- case 0x92: /* Data over/under-run */
-
- if (SCpnt->device->type != TYPE_TAPE
- && HD(j)->retries < MAX_INTERNAL_RETRIES) {
-
-#if defined(DID_SOFT_ERROR)
- status = DID_SOFT_ERROR << 16;
-#else
- status = DID_BUS_BUSY << 16;
-#endif
-
- HD(j)->retries++;
- HD(j)->last_retried_pid = SCpnt->serial_number;
- }
- else
- status = DID_ERROR << 16;
-
- break;
- case 0x01: /* Invalid command */
- case 0x02: /* Invalid parameters */
- case 0x03: /* Invalid data list */
- case 0x84: /* SCSI bus abort error */
- case 0x9b: /* Auto request sense error */
- case 0x9f: /* Unexpected command complete message error */
- case 0xff: /* Invalid parameter in the S/G list */
- default:
- status = DID_ERROR << 16;
- break;
- }
-
- SCpnt->result = status | spp->target_status;
-
-#if defined(DEBUG_INTERRUPT)
- if (SCpnt->result || do_trace)
-#else
- if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
- (spp->adapter_status != ASOK &&
- spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
- do_trace || msg_byte(spp->target_status))
-#endif
- scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\
- " reg 0x%x, count %d.\n",
- i, spp->adapter_status, spp->target_status,
- reg, HD(j)->iocount);
-
- unmap_dma(i, j);
-
- /* Set the command state to inactive */
- SCpnt->host_scribble = NULL;
-
- SCpnt->scsi_done(SCpnt);
-
- if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
- HD(j)->iocount);
-
-handled:
- return IRQ_HANDLED;
-none:
- return IRQ_NONE;
-}
-
-static irqreturn_t do_interrupt_handler(int irq, void *shap) {
- unsigned int j;
- unsigned long spin_flags;
- irqreturn_t ret;
-
- /* Check if the interrupt must be processed by this handler */
- if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE;
-
- spin_lock_irqsave(sh[j]->host_lock, spin_flags);
- ret = ihdlr(j);
- spin_unlock_irqrestore(sh[j]->host_lock, spin_flags);
- return ret;
-}
-
-static int u14_34f_release(struct Scsi_Host *shpnt) {
- unsigned int i, j;
-
- for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
-
- if (sh[j] == NULL)
- panic("%s: release, invalid Scsi_Host pointer.\n", driver_name);
-
- for (i = 0; i < sh[j]->can_queue; i++)
- kfree((&HD(j)->cp[i])->sglist);
-
- for (i = 0; i < sh[j]->can_queue; i++)
- pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr,
- sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
-
- free_irq(sh[j]->irq, &sha[j]);
-
- if (sh[j]->dma_channel != NO_DMA)
- free_dma(sh[j]->dma_channel);
-
- release_region(sh[j]->io_port, sh[j]->n_io_port);
- scsi_unregister(sh[j]);
- return FALSE;
-}
-
-#include "scsi_module.c"
-
-#ifndef MODULE
-__setup("u14-34f=", option_setup);
-#endif /* end MODULE */
diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c
index 70db6d999ca3..dc03e47f7c58 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.c
+++ b/drivers/scsi/ufs/tc-dwc-g210.c
@@ -15,6 +15,7 @@
#include "ufshcd-dwc.h"
#include "ufshci-dwc.h"
+#include "tc-dwc-g210.h"
/**
* tc_dwc_g210_setup_40bit_rmmi()
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index b291fa6ed2ad..845b874e2977 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -327,6 +327,7 @@ enum {
MASK_QUERY_DATA_SEG_LEN = 0xFFFF,
MASK_RSP_UPIU_DATA_SEG_LEN = 0xFFFF,
MASK_RSP_EXCEPTION_EVENT = 0x10000,
+ MASK_TM_SERVICE_RESP = 0xFF,
};
/* Task management service response */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f08d41a2d70b..37f3c51e9d92 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2568,7 +2568,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
status = ufshcd_get_upmcrs(hba);
if (status != PWR_LOCAL) {
dev_err(hba->dev,
- "pwr ctrl cmd 0x%0x failed, host umpcrs:0x%x\n",
+ "pwr ctrl cmd 0x%0x failed, host upmcrs:0x%x\n",
cmd->command, status);
ret = (status != PWR_OK) ? status : -1;
}
@@ -3364,8 +3364,8 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8 *resp)
if (ocs_value == OCS_SUCCESS) {
task_rsp_upiup = (struct utp_upiu_task_rsp *)
task_req_descp[index].task_rsp_upiu;
- task_result = be32_to_cpu(task_rsp_upiup->header.dword_1);
- task_result = ((task_result & MASK_TASK_RESPONSE) >> 8);
+ task_result = be32_to_cpu(task_rsp_upiup->output_param1);
+ task_result = task_result & MASK_TM_SERVICE_RESP;
if (resp)
*resp = (u8)task_result;
} else {
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
deleted file mode 100644
index 14e0c40a68c9..000000000000
--- a/drivers/scsi/ultrastor.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/*
- * ultrastor.c Copyright (C) 1992 David B. Gentzel
- * Low-level SCSI driver for UltraStor 14F, 24F, and 34F
- * by David B. Gentzel, Whitfield Software Services, Carnegie, PA
- * (gentzel@nova.enet.dec.com)
- * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
- * 24F and multiple command support by John F. Carr (jfc@athena.mit.edu)
- * John's work modified by Caleb Epstein (cae@jpmorgan.com) and
- * Eric Youngdale (ericy@cais.com).
- * Thanks to UltraStor for providing the necessary documentation
- *
- * This is an old driver, for the 14F and 34F you should be using the
- * u14-34f driver instead.
- */
-
-/*
- * TODO:
- * 1. Find out why scatter/gather is limited to 16 requests per command.
- * This is fixed, at least on the 24F, as of version 1.12 - CAE.
- * 2. Look at command linking (mscp.command_link and
- * mscp.command_link_id). (Does not work with many disks,
- * and no performance increase. ERY).
- * 3. Allow multiple adapters.
- */
-
-/*
- * NOTES:
- * The UltraStor 14F, 24F, and 34F are a family of intelligent, high
- * performance SCSI-2 host adapters. They all support command queueing
- * and scatter/gather I/O. Some of them can also emulate the standard
- * WD1003 interface for use with OS's which don't support SCSI. Here
- * is the scoop on the various models:
- * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
- * 14N - ISA HA with floppy support. I think that this is a non-DMA
- * HA. Nothing further known.
- * 24F - EISA Bus Master HA with floppy support and WD1003 emulation.
- * 34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation).
- *
- * The 14F, 24F, and 34F are supported by this driver.
- *
- * Places flagged with a triple question-mark are things which are either
- * unfinished, questionable, or wrong.
- */
-
-/* Changes from version 1.11 alpha to 1.12
- *
- * Increased the size of the scatter-gather list to 33 entries for
- * the 24F adapter (it was 16). I don't have the specs for the 14F
- * or the 34F, so they may support larger s-g lists as well.
- *
- * Caleb Epstein <cae@jpmorgan.com>
- */
-
-/* Changes from version 1.9 to 1.11
- *
- * Patches to bring this driver up to speed with the default kernel
- * driver which supports only the 14F and 34F adapters. This version
- * should compile cleanly into 0.99.13, 0.99.12 and probably 0.99.11.
- *
- * Fixes from Eric Youngdale to fix a few possible race conditions and
- * several problems with bit testing operations (insufficient
- * parentheses).
- *
- * Removed the ultrastor_abort() and ultrastor_reset() functions
- * (enclosed them in #if 0 / #endif). These functions, at least on
- * the 24F, cause the SCSI bus to do odd things and generally lead to
- * kernel panics and machine hangs. This is like the Adaptec code.
- *
- * Use check/snarf_region for 14f, 34f to avoid I/O space address conflicts.
- */
-
-/* Changes from version 1.8 to version 1.9
- *
- * 0.99.11 patches (cae@jpmorgan.com) */
-
-/* Changes from version 1.7 to version 1.8
- *
- * Better error reporting.
- */
-
-/* Changes from version 1.6 to version 1.7
- *
- * Removed CSIR command code.
- *
- * Better race condition avoidance (xchgb function added).
- *
- * Set ICM and OGM status to zero at probe (24F)
- *
- * reset sends soft reset to UltraStor adapter
- *
- * reset adapter if adapter interrupts with an invalid MSCP address
- *
- * handle aborted command interrupt (24F)
- *
- */
-
-/* Changes from version 1.5 to version 1.6:
- *
- * Read MSCP address from ICM _before_ clearing the interrupt flag.
- * This fixes a race condition.
- */
-
-/* Changes from version 1.4 to version 1.5:
- *
- * Abort now calls done when multiple commands are enabled.
- *
- * Clear busy when aborted command finishes, not when abort is called.
- *
- * More debugging messages for aborts.
- */
-
-/* Changes from version 1.3 to version 1.4:
- *
- * Enable automatic request of sense data on error (requires newer version
- * of scsi.c to be useful).
- *
- * Fix PORT_OVERRIDE for 14F.
- *
- * Fix abort and reset to work properly (config.aborted wasn't cleared
- * after it was tested, so after a command abort no further commands would
- * work).
- *
- * Boot time test to enable SCSI bus reset (defaults to not allowing reset).
- *
- * Fix test for OGM busy -- the busy bit is in different places on the 24F.
- *
- * Release ICM slot by clearing first byte on 24F.
- */
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "ultrastor.h"
-
-#define FALSE 0
-#define TRUE 1
-
-#ifndef ULTRASTOR_DEBUG
-#define ULTRASTOR_DEBUG (UD_ABORT|UD_CSIR|UD_RESET)
-#endif
-
-#define VERSION "1.12"
-
-#define PACKED __attribute__((packed))
-#define ALIGNED(x) __attribute__((aligned(x)))
-
-
-/* The 14F uses an array of 4-byte ints for its scatter/gather list.
- The data can be unaligned, but need not be. It's easier to give
- the list normal alignment since it doesn't need to fit into a
- packed structure. */
-
-typedef struct {
- u32 address;
- u32 num_bytes;
-} ultrastor_sg_list;
-
-
-/* MailBox SCSI Command Packet. Basic command structure for communicating
- with controller. */
-struct mscp {
- unsigned char opcode: 3; /* type of command */
- unsigned char xdir: 2; /* data transfer direction */
- unsigned char dcn: 1; /* disable disconnect */
- unsigned char ca: 1; /* use cache (if available) */
- unsigned char sg: 1; /* scatter/gather operation */
- unsigned char target_id: 3; /* target SCSI id */
- unsigned char ch_no: 2; /* SCSI channel (always 0 for 14f) */
- unsigned char lun: 3; /* logical unit number */
- unsigned int transfer_data PACKED; /* transfer data pointer */
- unsigned int transfer_data_length PACKED; /* length in bytes */
- unsigned int command_link PACKED; /* for linking command chains */
- unsigned char scsi_command_link_id; /* identifies command in chain */
- unsigned char number_of_sg_list; /* (if sg is set) 8 bytes per list */
- unsigned char length_of_sense_byte;
- unsigned char length_of_scsi_cdbs; /* 6, 10, or 12 */
- unsigned char scsi_cdbs[12]; /* SCSI commands */
- unsigned char adapter_status; /* non-zero indicates HA error */
- unsigned char target_status; /* non-zero indicates target error */
- u32 sense_data PACKED;
- /* The following fields are for software only. They are included in
- the MSCP structure because they are associated with SCSI requests. */
- void (*done) (struct scsi_cmnd *);
- struct scsi_cmnd *SCint;
- ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */
-};
-
-
-/* Port addresses (relative to the base address) */
-#define U14F_PRODUCT_ID(port) ((port) + 0x4)
-#define CONFIG(port) ((port) + 0x6)
-
-/* Port addresses relative to the doorbell base address. */
-#define LCL_DOORBELL_MASK(port) ((port) + 0x0)
-#define LCL_DOORBELL_INTR(port) ((port) + 0x1)
-#define SYS_DOORBELL_MASK(port) ((port) + 0x2)
-#define SYS_DOORBELL_INTR(port) ((port) + 0x3)
-
-
-/* Used to store configuration info read from config i/o registers. Most of
- this is not used yet, but might as well save it.
-
- This structure also holds port addresses that are not at the same offset
- on the 14F and 24F.
-
- This structure holds all data that must be duplicated to support multiple
- adapters. */
-
-static struct ultrastor_config
-{
- unsigned short port_address; /* base address of card */
- unsigned short doorbell_address; /* base address of doorbell CSRs */
- unsigned short ogm_address; /* base address of OGM */
- unsigned short icm_address; /* base address of ICM */
- const void *bios_segment;
- unsigned char interrupt: 4;
- unsigned char dma_channel: 3;
- unsigned char bios_drive_number: 1;
- unsigned char heads;
- unsigned char sectors;
- unsigned char ha_scsi_id: 3;
- unsigned char subversion: 4;
- unsigned char revision;
- /* The slot number is used to distinguish the 24F (slot != 0) from
- the 14F and 34F (slot == 0). */
- unsigned char slot;
-
-#ifdef PRINT_U24F_VERSION
- volatile int csir_done;
-#endif
-
- /* A pool of MSCP structures for this adapter, and a bitmask of
- busy structures. (If ULTRASTOR_14F_MAX_CMDS == 1, a 1 byte
- busy flag is used instead.) */
-
-#if ULTRASTOR_MAX_CMDS == 1
- unsigned char mscp_busy;
-#else
- unsigned long mscp_free;
-#endif
- volatile unsigned char aborted[ULTRASTOR_MAX_CMDS];
- struct mscp mscp[ULTRASTOR_MAX_CMDS];
-} config = {0};
-
-/* Set this to 1 to reset the SCSI bus on error. */
-static int ultrastor_bus_reset;
-
-
-/* Allowed BIOS base addresses (NULL indicates reserved) */
-static const void *const bios_segment_table[8] = {
- NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
- (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
-};
-
-/* Allowed IRQs for 14f */
-static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 };
-
-/* Allowed DMA channels for 14f (0 indicates reserved) */
-static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
-
-/* Head/sector mappings allowed by 14f */
-static const struct {
- unsigned char heads;
- unsigned char sectors;
-} mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } };
-
-#ifndef PORT_OVERRIDE
-/* ??? A probe of address 0x310 screws up NE2000 cards */
-static const unsigned short ultrastor_ports_14f[] = {
- 0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140,
-};
-#endif
-
-static void ultrastor_interrupt(void *);
-static irqreturn_t do_ultrastor_interrupt(int, void *);
-static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt);
-
-
-/* Always called with host lock held */
-
-static inline int find_and_clear_bit_16(unsigned long *field)
-{
- int rv;
-
- if (*field == 0)
- panic("No free mscp");
-
- asm volatile (
- "xorl %0,%0\n\t"
- "0: bsfw %1,%w0\n\t"
- "btr %0,%1\n\t"
- "jnc 0b"
- : "=&r" (rv), "+m" (*field) :);
-
- return rv;
-}
-
-/* This has been re-implemented with the help of Richard Earnshaw,
- <rwe@pegasus.esprit.ec.org> and works with gcc-2.5.8 and gcc-2.6.0.
- The instability noted by jfc below appears to be a bug in
- gcc-2.5.x when compiling w/o optimization. --Caleb
-
- This asm is fragile: it doesn't work without the casts and it may
- not work without optimization. Maybe I should add a swap builtin
- to gcc. --jfc */
-static inline unsigned char xchgb(unsigned char reg,
- volatile unsigned char *mem)
-{
- __asm__ ("xchgb %0,%1" : "=q" (reg), "=m" (*mem) : "0" (reg));
- return reg;
-}
-
-#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
-
-/* Always called with the host lock held */
-static void log_ultrastor_abort(struct ultrastor_config *config,
- int command)
-{
- static char fmt[80] = "abort %d (%x); MSCP free pool: %x;";
- int i;
-
- for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
- {
- fmt[20 + i*2] = ' ';
- if (! (config->mscp_free & (1 << i)))
- fmt[21 + i*2] = '0' + config->mscp[i].target_id;
- else
- fmt[21 + i*2] = '-';
- }
- fmt[20 + ULTRASTOR_MAX_CMDS * 2] = '\n';
- fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0;
- printk(fmt, command, &config->mscp[command], config->mscp_free);
-
-}
-#endif
-
-static int ultrastor_14f_detect(struct scsi_host_template * tpnt)
-{
- size_t i;
- unsigned char in_byte, version_byte = 0;
- struct config_1 {
- unsigned char bios_segment: 3;
- unsigned char removable_disks_as_fixed: 1;
- unsigned char interrupt: 2;
- unsigned char dma_channel: 2;
- } config_1;
- struct config_2 {
- unsigned char ha_scsi_id: 3;
- unsigned char mapping_mode: 2;
- unsigned char bios_drive_number: 1;
- unsigned char tfr_port: 2;
- } config_2;
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: called\n");
-#endif
-
- /* If a 24F has already been configured, don't look for a 14F. */
- if (config.bios_segment)
- return FALSE;
-
-#ifdef PORT_OVERRIDE
- if(!request_region(PORT_OVERRIDE, 0xc, "ultrastor")) {
- printk("Ultrastor I/O space already in use\n");
- return FALSE;
- };
- config.port_address = PORT_OVERRIDE;
-#else
- for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
- if(!request_region(ultrastor_ports_14f[i], 0x0c, "ultrastor")) continue;
- config.port_address = ultrastor_ports_14f[i];
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: testing port address %03X\n", config.port_address);
-#endif
-
- in_byte = inb(U14F_PRODUCT_ID(config.port_address));
- if (in_byte != US14F_PRODUCT_ID_0) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
-# ifdef PORT_OVERRIDE
- printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
-# else
- printk("US14F: detect: no adapter at port %03X\n", config.port_address);
-# endif
-#endif
-#ifdef PORT_OVERRIDE
- goto out_release_port;
-#else
- release_region(config.port_address, 0x0c);
- continue;
-#endif
- }
- in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1);
- /* Only upper nibble is significant for Product ID 1 */
- if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
-# ifdef PORT_OVERRIDE
- printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
-# else
- printk("US14F: detect: no adapter at port %03X\n", config.port_address);
-# endif
-#endif
-#ifdef PORT_OVERRIDE
- goto out_release_port;
-#else
- release_region(config.port_address, 0x0c);
- continue;
-#endif
- }
- version_byte = in_byte;
-#ifndef PORT_OVERRIDE
- break;
- }
- if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
-# if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: no port address found!\n");
-# endif
- /* all ports probed already released - we can just go straight out */
- return FALSE;
- }
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: adapter found at port address %03X\n",
- config.port_address);
-#endif
-
- /* Set local doorbell mask to disallow bus reset unless
- ultrastor_bus_reset is true. */
- outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address));
-
- /* All above tests passed, must be the right thing. Get some useful
- info. */
-
- /* Register the I/O space that we use */
-
- *(char *)&config_1 = inb(CONFIG(config.port_address + 0));
- *(char *)&config_2 = inb(CONFIG(config.port_address + 1));
- config.bios_segment = bios_segment_table[config_1.bios_segment];
- config.doorbell_address = config.port_address;
- config.ogm_address = config.port_address + 0x8;
- config.icm_address = config.port_address + 0xC;
- config.interrupt = interrupt_table_14f[config_1.interrupt];
- config.ha_scsi_id = config_2.ha_scsi_id;
- config.heads = mapping_table[config_2.mapping_mode].heads;
- config.sectors = mapping_table[config_2.mapping_mode].sectors;
- config.bios_drive_number = config_2.bios_drive_number;
- config.subversion = (version_byte & 0x0F);
- if (config.subversion == U34F)
- config.dma_channel = 0;
- else
- config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
-
- if (!config.bios_segment) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: not detected.\n");
-#endif
- goto out_release_port;
- }
-
- /* Final consistency check, verify previous info. */
- if (config.subversion != U34F)
- if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: consistency check failed\n");
-#endif
- goto out_release_port;
- }
-
- /* If we were TRULY paranoid, we could issue a host adapter inquiry
- command here and verify the data returned. But frankly, I'm
- exhausted! */
-
- /* Finally! Now I'm satisfied... */
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: detect succeeded\n"
- " Port address: %03X\n"
- " BIOS segment: %05X\n"
- " Interrupt: %u\n"
- " DMA channel: %u\n"
- " H/A SCSI ID: %u\n"
- " Subversion: %u\n",
- config.port_address, config.bios_segment, config.interrupt,
- config.dma_channel, config.ha_scsi_id, config.subversion);
-#endif
- tpnt->this_id = config.ha_scsi_id;
- tpnt->unchecked_isa_dma = (config.subversion != U34F);
-
-#if ULTRASTOR_MAX_CMDS > 1
- config.mscp_free = ~0;
-#endif
-
- /*
- * Brrr, &config.mscp[0].SCint->host) it is something magical....
- * XXX and FIXME
- */
- if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->device->host)) {
- printk("Unable to allocate IRQ%u for UltraStor controller.\n",
- config.interrupt);
- goto out_release_port;
- }
- if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) {
- printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
- config.dma_channel);
- free_irq(config.interrupt, NULL);
- goto out_release_port;
- }
- tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG;
- printk("UltraStor driver version" VERSION ". Using %d SG lists.\n",
- ULTRASTOR_14F_MAX_SG);
-
- return TRUE;
-out_release_port:
- release_region(config.port_address, 0x0c);
- return FALSE;
-}
-
-static int ultrastor_24f_detect(struct scsi_host_template * tpnt)
-{
- int i;
- struct Scsi_Host * shpnt = NULL;
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US24F: detect");
-#endif
-
- /* probe each EISA slot at slot address C80 */
- for (i = 1; i < 15; i++)
- {
- unsigned char config_1, config_2;
- unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT;
-
- if (inb(addr) != US24F_PRODUCT_ID_0 &&
- inb(addr+1) != US24F_PRODUCT_ID_1 &&
- inb(addr+2) != US24F_PRODUCT_ID_2)
- continue;
-
- config.revision = inb(addr+3);
- config.slot = i;
- if (! (inb(addr+4) & 1))
- {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("U24F: found disabled card in slot %u\n", i);
-#endif
- continue;
- }
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("U24F: found card in slot %u\n", i);
-#endif
- config_1 = inb(addr + 5);
- config.bios_segment = bios_segment_table[config_1 & 7];
- switch(config_1 >> 4)
- {
- case 1:
- config.interrupt = 15;
- break;
- case 2:
- config.interrupt = 14;
- break;
- case 4:
- config.interrupt = 11;
- break;
- case 8:
- config.interrupt = 10;
- break;
- default:
- printk("U24F: invalid IRQ\n");
- return FALSE;
- }
-
- /* BIOS addr set */
- /* base port set */
- config.port_address = addr;
- config.doorbell_address = addr + 12;
- config.ogm_address = addr + 0x17;
- config.icm_address = addr + 0x1C;
- config_2 = inb(addr + 7);
- config.ha_scsi_id = config_2 & 7;
- config.heads = mapping_table[(config_2 >> 3) & 3].heads;
- config.sectors = mapping_table[(config_2 >> 3) & 3].sectors;
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US24F: detect: detect succeeded\n"
- " Port address: %03X\n"
- " BIOS segment: %05X\n"
- " Interrupt: %u\n"
- " H/A SCSI ID: %u\n",
- config.port_address, config.bios_segment,
- config.interrupt, config.ha_scsi_id);
-#endif
- tpnt->this_id = config.ha_scsi_id;
- tpnt->unchecked_isa_dma = 0;
- tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;
-
- shpnt = scsi_register(tpnt, 0);
- if (!shpnt) {
- printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n");
- free_irq(config.interrupt, do_ultrastor_interrupt);
- return FALSE;
- }
-
- if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", shpnt))
- {
- printk("Unable to allocate IRQ%u for UltraStor controller.\n",
- config.interrupt);
- return FALSE;
- }
-
- shpnt->irq = config.interrupt;
- shpnt->dma_channel = config.dma_channel;
- shpnt->io_port = config.port_address;
-
-#if ULTRASTOR_MAX_CMDS > 1
- config.mscp_free = ~0;
-#endif
- /* Mark ICM and OGM free */
- outb(0, addr + 0x16);
- outb(0, addr + 0x1B);
-
- /* Set local doorbell mask to disallow bus reset unless
- ultrastor_bus_reset is true. */
- outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12));
- outb(0x02, SYS_DOORBELL_MASK(addr+12));
- printk("UltraStor driver version " VERSION ". Using %d SG lists.\n",
- tpnt->sg_tablesize);
- return TRUE;
- }
- return FALSE;
-}
-
-static int ultrastor_detect(struct scsi_host_template * tpnt)
-{
- tpnt->proc_name = "ultrastor";
- return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);
-}
-
-static int ultrastor_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static const char *ultrastor_info(struct Scsi_Host * shpnt)
-{
- static char buf[64];
-
- if (config.slot)
- sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u",
- config.slot, config.interrupt);
- else if (config.subversion)
- sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u",
- config.port_address, (int)config.bios_segment,
- config.interrupt);
- else
- sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u",
- config.port_address, (int)config.bios_segment,
- config.interrupt, config.dma_channel);
- return buf;
-}
-
-static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
-{
- struct scatterlist *sg;
- long transfer_length = 0;
- int i, max;
-
- max = scsi_sg_count(SCpnt);
- scsi_for_each_sg(SCpnt, sg, max, i) {
- mscp->sglist[i].address = isa_page_to_bus(sg_page(sg)) + sg->offset;
- mscp->sglist[i].num_bytes = sg->length;
- transfer_length += sg->length;
- }
- mscp->number_of_sg_list = max;
- mscp->transfer_data = isa_virt_to_bus(mscp->sglist);
- /* ??? May not be necessary. Docs are unclear as to whether transfer
- length field is ignored or whether it should be set to the total
- number of bytes of the transfer. */
- mscp->transfer_data_length = transfer_length;
-}
-
-static int ultrastor_queuecommand_lck(struct scsi_cmnd *SCpnt,
- void (*done) (struct scsi_cmnd *))
-{
- struct mscp *my_mscp;
-#if ULTRASTOR_MAX_CMDS > 1
- int mscp_index;
-#endif
- unsigned int status;
-
- /* Next test is for debugging; "can't happen" */
- if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0)
- panic("ultrastor_queuecommand: no free MSCP\n");
- mscp_index = find_and_clear_bit_16(&config.mscp_free);
-
- /* Has the command been aborted? */
- if (xchgb(0xff, &config.aborted[mscp_index]) != 0)
- {
- status = DID_ABORT << 16;
- goto aborted;
- }
-
- my_mscp = &config.mscp[mscp_index];
-
- *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);
-
- /* Tape drives don't work properly if the cache is used. The SCSI
- READ command for a tape doesn't have a block offset, and the adapter
- incorrectly assumes that all reads from the tape read the same
- blocks. Results will depend on read buffer size and other disk
- activity.
-
- ??? Which other device types should never use the cache? */
- my_mscp->ca = SCpnt->device->type != TYPE_TAPE;
- my_mscp->target_id = SCpnt->device->id;
- my_mscp->ch_no = 0;
- my_mscp->lun = SCpnt->device->lun;
- if (scsi_sg_count(SCpnt)) {
- /* Set scatter/gather flag in SCSI command packet */
- my_mscp->sg = TRUE;
- build_sg_list(my_mscp, SCpnt);
- } else {
- /* Unset scatter/gather flag in SCSI command packet */
- my_mscp->sg = FALSE;
- my_mscp->transfer_data = isa_virt_to_bus(scsi_sglist(SCpnt));
- my_mscp->transfer_data_length = scsi_bufflen(SCpnt);
- }
- my_mscp->command_link = 0; /*???*/
- my_mscp->scsi_command_link_id = 0; /*???*/
- my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE;
- my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
- memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
- my_mscp->adapter_status = 0;
- my_mscp->target_status = 0;
- my_mscp->sense_data = isa_virt_to_bus(&SCpnt->sense_buffer);
- my_mscp->done = done;
- my_mscp->SCint = SCpnt;
- SCpnt->host_scribble = (unsigned char *)my_mscp;
-
- /* Find free OGM slot. On 24F, look for OGM status byte == 0.
- On 14F and 34F, wait for local interrupt pending flag to clear.
-
- FIXME: now we are using new_eh we should punt here and let the
- midlayer sort it out */
-
-retry:
- if (config.slot)
- while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff)
- barrier();
-
- /* else??? */
-
- while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) && config.aborted[mscp_index] == 0xff)
- barrier();
-
- /* To avoid race conditions, keep the code to write to the adapter
- atomic. This simplifies the abort code. Right now the
- scsi mid layer has the host_lock already held
- */
-
- if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))
- goto retry;
-
- status = xchgb(0, &config.aborted[mscp_index]);
- if (status != 0xff) {
-
-#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
- printk("USx4F: queuecommand: aborted\n");
-#if ULTRASTOR_MAX_CMDS > 1
- log_ultrastor_abort(&config, mscp_index);
-#endif
-#endif
- status <<= 16;
-
- aborted:
- set_bit(mscp_index, &config.mscp_free);
- /* If the driver queues commands, call the done proc here. Otherwise
- return an error. */
-#if ULTRASTOR_MAX_CMDS > 1
- SCpnt->result = status;
- done(SCpnt);
- return 0;
-#else
- return status;
-#endif
- }
-
- /* Store pointer in OGM address bytes */
- outl(isa_virt_to_bus(my_mscp), config.ogm_address);
-
- /* Issue OGM interrupt */
- if (config.slot) {
- /* Write OGM command register on 24F */
- outb(1, config.ogm_address - 1);
- outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
- } else {
- outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address));
- }
-
-#if (ULTRASTOR_DEBUG & UD_COMMAND)
- printk("USx4F: queuecommand: returning\n");
-#endif
-
- return 0;
-}
-
-static DEF_SCSI_QCMD(ultrastor_queuecommand)
-
-/* This code must deal with 2 cases:
-
- 1. The command has not been written to the OGM. In this case, set
- the abort flag and return.
-
- 2. The command has been written to the OGM and is stuck somewhere in
- the adapter.
-
- 2a. On a 24F, ask the adapter to abort the command. It will interrupt
- when it does.
-
- 2b. Call the command's done procedure.
-
- */
-
-static int ultrastor_abort(struct scsi_cmnd *SCpnt)
-{
-#if ULTRASTOR_DEBUG & UD_ABORT
- char out[108];
- unsigned char icm_status = 0, ogm_status = 0;
- unsigned int icm_addr = 0, ogm_addr = 0;
-#endif
- unsigned int mscp_index;
- unsigned char old_aborted;
- unsigned long flags;
- void (*done)(struct scsi_cmnd *);
- struct Scsi_Host *host = SCpnt->device->host;
-
- if(config.slot)
- return FAILED; /* Do not attempt an abort for the 24f */
-
- /* Simple consistency checking */
- if(!SCpnt->host_scribble)
- return FAILED;
-
- mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
- if (mscp_index >= ULTRASTOR_MAX_CMDS)
- panic("Ux4F aborting invalid MSCP");
-
-#if ULTRASTOR_DEBUG & UD_ABORT
- if (config.slot)
- {
- int port0 = (config.slot << 12) | 0xc80;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(host->host_lock, flags);
- strcpy(out, "OGM %d:%x ICM %d:%x ports: ");
- for (i = 0; i < 16; i++)
- {
- unsigned char p = inb(port0 + i);
- out[28 + i * 3] = "0123456789abcdef"[p >> 4];
- out[29 + i * 3] = "0123456789abcdef"[p & 15];
- out[30 + i * 3] = ' ';
- }
- out[28 + i * 3] = '\n';
- out[29 + i * 3] = 0;
- ogm_status = inb(port0 + 22);
- ogm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 23));
- icm_status = inb(port0 + 27);
- icm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 28));
- spin_unlock_irqrestore(host->host_lock, flags);
- }
-
- /* First check to see if an interrupt is pending. I suspect the SiS
- chipset loses interrupts. (I also suspect is mangles data, but
- one bug at a time... */
- if (config.slot ? inb(config.icm_address - 1) == 2 :
- (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
- {
- printk("Ux4F: abort while completed command pending\n");
-
- spin_lock_irqsave(host->host_lock, flags);
- /* FIXME: Ewww... need to think about passing host around properly */
- ultrastor_interrupt(NULL);
- spin_unlock_irqrestore(host->host_lock, flags);
- return SUCCESS;
- }
-#endif
-
- old_aborted = xchgb(DID_ABORT, &config.aborted[mscp_index]);
-
- /* aborted == 0xff is the signal that queuecommand has not yet sent
- the command. It will notice the new abort flag and fail. */
- if (old_aborted == 0xff)
- return SUCCESS;
-
- /* On 24F, send an abort MSCP request. The adapter will interrupt
- and the interrupt handler will call done. */
- if (config.slot && inb(config.ogm_address - 1) == 0)
- {
- unsigned long flags;
-
- spin_lock_irqsave(host->host_lock, flags);
- outl(isa_virt_to_bus(&config.mscp[mscp_index]), config.ogm_address);
- udelay(8);
- outb(0x80, config.ogm_address - 1);
- outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
-#if ULTRASTOR_DEBUG & UD_ABORT
- log_ultrastor_abort(&config, mscp_index);
- printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
-#endif
- spin_unlock_irqrestore(host->host_lock, flags);
- /* FIXME: add a wait for the abort to complete */
- return SUCCESS;
- }
-
-#if ULTRASTOR_DEBUG & UD_ABORT
- log_ultrastor_abort(&config, mscp_index);
-#endif
-
- /* Can't request a graceful abort. Either this is not a 24F or
- the OGM is busy. Don't free the command -- the adapter might
- still be using it. Setting SCint = 0 causes the interrupt
- handler to ignore the command. */
-
- /* FIXME - devices that implement soft resets will still be running
- the command after a bus reset. We would probably rather leave
- the command in the queue. The upper level code will automatically
- leave the command in the active state instead of requeueing it. ERY */
-
-#if ULTRASTOR_DEBUG & UD_ABORT
- if (config.mscp[mscp_index].SCint != SCpnt)
- printk("abort: command mismatch, %p != %p\n",
- config.mscp[mscp_index].SCint, SCpnt);
-#endif
- if (config.mscp[mscp_index].SCint == NULL)
- return FAILED;
-
- if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
- config.mscp[mscp_index].SCint = NULL;
- done = config.mscp[mscp_index].done;
- config.mscp[mscp_index].done = NULL;
- SCpnt->result = DID_ABORT << 16;
-
- /* Take the host lock to guard against scsi layer re-entry */
- done(SCpnt);
-
- /* Need to set a timeout here in case command never completes. */
- return SUCCESS;
-}
-
-static int ultrastor_host_reset(struct scsi_cmnd * SCpnt)
-{
- unsigned long flags;
- int i;
- struct Scsi_Host *host = SCpnt->device->host;
-
-#if (ULTRASTOR_DEBUG & UD_RESET)
- printk("US14F: reset: called\n");
-#endif
-
- if(config.slot)
- return FAILED;
-
- spin_lock_irqsave(host->host_lock, flags);
- /* Reset the adapter and SCSI bus. The SCSI bus reset can be
- inhibited by clearing ultrastor_bus_reset before probe. */
- outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address));
- if (config.slot)
- {
- outb(0, config.ogm_address - 1);
- outb(0, config.icm_address - 1);
- }
-
-#if ULTRASTOR_MAX_CMDS == 1
- if (config.mscp_busy && config.mscp->done && config.mscp->SCint)
- {
- config.mscp->SCint->result = DID_RESET << 16;
- config.mscp->done(config.mscp->SCint);
- }
- config.mscp->SCint = 0;
-#else
- for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
- {
- if (! (config.mscp_free & (1 << i)) &&
- config.mscp[i].done && config.mscp[i].SCint)
- {
- config.mscp[i].SCint->result = DID_RESET << 16;
- config.mscp[i].done(config.mscp[i].SCint);
- config.mscp[i].done = NULL;
- }
- config.mscp[i].SCint = NULL;
- }
-#endif
-
- /* FIXME - if the device implements soft resets, then the command
- will still be running. ERY
-
- Even bigger deal with new_eh!
- */
-
- memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
-#if ULTRASTOR_MAX_CMDS == 1
- config.mscp_busy = 0;
-#else
- config.mscp_free = ~0;
-#endif
-
- spin_unlock_irqrestore(host->host_lock, flags);
- return SUCCESS;
-
-}
-
-int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int * dkinfo)
-{
- int size = capacity;
- unsigned int s = config.heads * config.sectors;
-
- dkinfo[0] = config.heads;
- dkinfo[1] = config.sectors;
- dkinfo[2] = size / s; /* Ignore partial cylinders */
-#if 0
- if (dkinfo[2] > 1024)
- dkinfo[2] = 1024;
-#endif
- return 0;
-}
-
-static void ultrastor_interrupt(void *dev_id)
-{
- unsigned int status;
-#if ULTRASTOR_MAX_CMDS > 1
- unsigned int mscp_index;
-#endif
- struct mscp *mscp;
- void (*done) (struct scsi_cmnd *);
- struct scsi_cmnd *SCtmp;
-
-#if ULTRASTOR_MAX_CMDS == 1
- mscp = &config.mscp[0];
-#else
- mscp = (struct mscp *)isa_bus_to_virt(inl(config.icm_address));
- mscp_index = mscp - config.mscp;
- if (mscp_index >= ULTRASTOR_MAX_CMDS) {
- printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
- /* A command has been lost. Reset and report an error
- for all commands. */
- ultrastor_host_reset(dev_id);
- return;
- }
-#endif
-
- /* Clean ICM slot (set ICMINT bit to 0) */
- if (config.slot) {
- unsigned char icm_status = inb(config.icm_address - 1);
-#if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT)
- if (icm_status != 1 && icm_status != 2)
- printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status,
- mscp_index, (unsigned int) mscp);
-#endif
- /* The manual says clear interrupt then write 0 to ICM status.
- This seems backwards, but I'll do it anyway. --jfc */
- outb(2, SYS_DOORBELL_INTR(config.doorbell_address));
- outb(0, config.icm_address - 1);
- if (icm_status == 4) {
- printk("UltraStor abort command failed\n");
- return;
- }
- if (icm_status == 3) {
- void (*done)(struct scsi_cmnd *) = mscp->done;
- if (done) {
- mscp->done = NULL;
- mscp->SCint->result = DID_ABORT << 16;
- done(mscp->SCint);
- }
- return;
- }
- } else {
- outb(1, SYS_DOORBELL_INTR(config.doorbell_address));
- }
-
- SCtmp = mscp->SCint;
- mscp->SCint = NULL;
-
- if (!SCtmp)
- {
-#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
- printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);
-#endif
-#if ULTRASTOR_MAX_CMDS == 1
- config.mscp_busy = FALSE;
-#else
- set_bit(mscp_index, &config.mscp_free);
-#endif
- config.aborted[mscp_index] = 0;
- return;
- }
-
- /* Save done locally and zero before calling. This is needed as
- once we call done, we may get another command queued before this
- interrupt service routine can return. */
- done = mscp->done;
- mscp->done = NULL;
-
- /* Let the higher levels know that we're done */
- switch (mscp->adapter_status)
- {
- case 0:
- status = DID_OK << 16;
- break;
- case 0x01: /* invalid command */
- case 0x02: /* invalid parameters */
- case 0x03: /* invalid data list */
- default:
- status = DID_ERROR << 16;
- break;
- case 0x84: /* SCSI bus abort */
- status = DID_ABORT << 16;
- break;
- case 0x91:
- status = DID_TIME_OUT << 16;
- break;
- }
-
- SCtmp->result = status | mscp->target_status;
-
- SCtmp->host_scribble = NULL;
-
- /* Free up mscp block for next command */
-#if ULTRASTOR_MAX_CMDS == 1
- config.mscp_busy = FALSE;
-#else
- set_bit(mscp_index, &config.mscp_free);
-#endif
-
-#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
- if (config.aborted[mscp_index])
- printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n",
- mscp_index, (unsigned int) mscp, config.aborted[mscp_index]);
-#endif
- config.aborted[mscp_index] = 0;
-
- if (done)
- done(SCtmp);
- else
- printk("US14F: interrupt: unexpected interrupt\n");
-
- if (config.slot ? inb(config.icm_address - 1) :
- (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
-#if (ULTRASTOR_DEBUG & UD_MULTI_CMD)
- printk("Ux4F: multiple commands completed\n");
-#else
- ;
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
- printk("USx4F: interrupt: returning\n");
-#endif
-}
-
-static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id)
-{
- unsigned long flags;
- struct Scsi_Host *dev = dev_id;
-
- spin_lock_irqsave(dev->host_lock, flags);
- ultrastor_interrupt(dev_id);
- spin_unlock_irqrestore(dev->host_lock, flags);
- return IRQ_HANDLED;
-}
-
-MODULE_LICENSE("GPL");
-
-static struct scsi_host_template driver_template = {
- .name = "UltraStor 14F/24F/34F",
- .detect = ultrastor_detect,
- .release = ultrastor_release,
- .info = ultrastor_info,
- .queuecommand = ultrastor_queuecommand,
- .eh_abort_handler = ultrastor_abort,
- .eh_host_reset_handler = ultrastor_host_reset,
- .bios_param = ultrastor_biosparam,
- .can_queue = ULTRASTOR_MAX_CMDS,
- .sg_tablesize = ULTRASTOR_14F_MAX_SG,
- .cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN,
- .unchecked_isa_dma = 1,
- .use_clustering = ENABLE_CLUSTERING,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
deleted file mode 100644
index 165c18b5cf5f..000000000000
--- a/drivers/scsi/ultrastor.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * ultrastor.c (C) 1991 David B. Gentzel
- * Low-level scsi driver for UltraStor 14F
- * by David B. Gentzel, Whitfield Software Services, Carnegie, PA
- * (gentzel@nova.enet.dec.com)
- * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
- * 24F support by John F. Carr (jfc@athena.mit.edu)
- * John's work modified by Caleb Epstein (cae@jpmorgan.com) and
- * Eric Youngdale (eric@tantalus.nrl.navy.mil).
- * Thanks to UltraStor for providing the necessary documentation
- */
-
-#ifndef _ULTRASTOR_H
-#define _ULTRASTOR_H
-
-static int ultrastor_detect(struct scsi_host_template *);
-static const char *ultrastor_info(struct Scsi_Host *shpnt);
-static int ultrastor_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-static int ultrastor_abort(struct scsi_cmnd *);
-static int ultrastor_host_reset(struct scsi_cmnd *);
-static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int *);
-
-
-#define ULTRASTOR_14F_MAX_SG 16
-#define ULTRASTOR_24F_MAX_SG 33
-
-#define ULTRASTOR_MAX_CMDS_PER_LUN 5
-#define ULTRASTOR_MAX_CMDS 16
-
-#define ULTRASTOR_24F_PORT 0xC80
-
-
-#ifdef ULTRASTOR_PRIVATE
-
-#define UD_ABORT 0x0001
-#define UD_COMMAND 0x0002
-#define UD_DETECT 0x0004
-#define UD_INTERRUPT 0x0008
-#define UD_RESET 0x0010
-#define UD_MULTI_CMD 0x0020
-#define UD_CSIR 0x0040
-#define UD_ERROR 0x0080
-
-/* #define PORT_OVERRIDE 0x330 */
-
-/* Values for the PRODUCT_ID ports for the 14F */
-#define US14F_PRODUCT_ID_0 0x56
-#define US14F_PRODUCT_ID_1 0x40 /* NOTE: Only upper nibble is used */
-
-#define US24F_PRODUCT_ID_0 0x56
-#define US24F_PRODUCT_ID_1 0x63
-#define US24F_PRODUCT_ID_2 0x02
-
-/* Subversion values */
-#define U14F 0
-#define U34F 1
-
-/* MSCP field values */
-
-/* Opcode */
-#define OP_HOST_ADAPTER 0x1
-#define OP_SCSI 0x2
-#define OP_RESET 0x4
-
-/* Date Transfer Direction */
-#define DTD_SCSI 0x0
-#define DTD_IN 0x1
-#define DTD_OUT 0x2
-#define DTD_NONE 0x3
-
-/* Host Adapter command subcodes */
-#define HA_CMD_INQUIRY 0x1
-#define HA_CMD_SELF_DIAG 0x2
-#define HA_CMD_READ_BUFF 0x3
-#define HA_CMD_WRITE_BUFF 0x4
-
-#endif
-
-#endif
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index deefab3a94d0..ec91bd07f00a 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -259,7 +259,7 @@ static void virtscsi_complete_free(struct virtio_scsi *vscsi, void *buf)
struct virtio_scsi_cmd *cmd = buf;
if (cmd->comp)
- complete_all(cmd->comp);
+ complete(cmd->comp);
}
static void virtscsi_ctrl_done(struct virtqueue *vq)
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
deleted file mode 100644
index 409f959845c4..000000000000
--- a/drivers/scsi/wd7000.c
+++ /dev/null
@@ -1,1657 +0,0 @@
-/* $Id: $
- * linux/drivers/scsi/wd7000.c
- *
- * Copyright (C) 1992 Thomas Wuensche
- * closely related to the aha1542 driver from Tommy Thorn
- * ( as close as different hardware allows on a lowlevel-driver :-) )
- *
- * Revised (and renamed) by John Boyd <boyd@cis.ohio-state.edu> to
- * accommodate Eric Youngdale's modifications to scsi.c. Nov 1992.
- *
- * Additional changes to support scatter/gather. Dec. 1992. tw/jb
- *
- * No longer tries to reset SCSI bus at boot (it wasn't working anyway).
- * Rewritten to support multiple host adapters.
- * Miscellaneous cleanup.
- * So far, still doesn't do reset or abort correctly, since I have no idea
- * how to do them with this board (8^(. Jan 1994 jb
- *
- * This driver now supports both of the two standard configurations (per
- * the 3.36 Owner's Manual, my latest reference) by the same method as
- * before; namely, by looking for a BIOS signature. Thus, the location of
- * the BIOS signature determines the board configuration. Until I have
- * time to do something more flexible, users should stick to one of the
- * following:
- *
- * Standard configuration for single-adapter systems:
- * - BIOS at CE00h
- * - I/O base address 350h
- * - IRQ level 15
- * - DMA channel 6
- * Standard configuration for a second adapter in a system:
- * - BIOS at C800h
- * - I/O base address 330h
- * - IRQ level 11
- * - DMA channel 5
- *
- * Anyone who can recompile the kernel is welcome to add others as need
- * arises, but unpredictable results may occur if there are conflicts.
- * In any event, if there are multiple adapters in a system, they MUST
- * use different I/O bases, IRQ levels, and DMA channels, since they will be
- * indistinguishable (and in direct conflict) otherwise.
- *
- * As a point of information, the NO_OP command toggles the CMD_RDY bit
- * of the status port, and this fact could be used as a test for the I/O
- * base address (or more generally, board detection). There is an interrupt
- * status port, so IRQ probing could also be done. I suppose the full
- * DMA diagnostic could be used to detect the DMA channel being used. I
- * haven't done any of this, though, because I think there's too much of
- * a chance that such explorations could be destructive, if some other
- * board's resources are used inadvertently. So, call me a wimp, but I
- * don't want to try it. The only kind of exploration I trust is memory
- * exploration, since it's more certain that reading memory won't be
- * destructive.
- *
- * More to my liking would be a LILO boot command line specification, such
- * as is used by the aha152x driver (and possibly others). I'll look into
- * it, as I have time...
- *
- * I get mail occasionally from people who either are using or are
- * considering using a WD7000 with Linux. There is a variety of
- * nomenclature describing WD7000's. To the best of my knowledge, the
- * following is a brief summary (from an old WD doc - I don't work for
- * them or anything like that):
- *
- * WD7000-FASST2: This is a WD7000 board with the real-mode SST ROM BIOS
- * installed. Last I heard, the BIOS was actually done by Columbia
- * Data Products. The BIOS is only used by this driver (and thus
- * by Linux) to identify the board; none of it can be executed under
- * Linux.
- *
- * WD7000-ASC: This is the original adapter board, with or without BIOS.
- * The board uses a WD33C93 or WD33C93A SBIC, which in turn is
- * controlled by an onboard Z80 processor. The board interface
- * visible to the host CPU is defined effectively by the Z80's
- * firmware, and it is this firmware's revision level that is
- * determined and reported by this driver. (The version of the
- * on-board BIOS is of no interest whatsoever.) The host CPU has
- * no access to the SBIC; hence the fact that it is a WD33C93 is
- * also of no interest to this driver.
- *
- * WD7000-AX:
- * WD7000-MX:
- * WD7000-EX: These are newer versions of the WD7000-ASC. The -ASC is
- * largely built from discrete components; these boards use more
- * integration. The -AX is an ISA bus board (like the -ASC),
- * the -MX is an MCA (i.e., PS/2) bus board), and the -EX is an
- * EISA bus board.
- *
- * At the time of my documentation, the -?X boards were "future" products,
- * and were not yet available. However, I vaguely recall that Thomas
- * Wuensche had an -AX, so I believe at least it is supported by this
- * driver. I have no personal knowledge of either -MX or -EX boards.
- *
- * P.S. Just recently, I've discovered (directly from WD and Future
- * Domain) that all but the WD7000-EX have been out of production for
- * two years now. FD has production rights to the 7000-EX, and are
- * producing it under a new name, and with a new BIOS. If anyone has
- * one of the FD boards, it would be nice to come up with a signature
- * for it.
- * J.B. Jan 1994.
- *
- *
- * Revisions by Miroslav Zagorac <zaga@fly.cc.fer.hr>
- *
- * 08/24/1996.
- *
- * Enhancement for wd7000_detect function has been made, so you don't have
- * to enter BIOS ROM address in initialisation data (see struct Config).
- * We cannot detect IRQ, DMA and I/O base address for now, so we have to
- * enter them as arguments while wd_7000 is detected. If someone has IRQ,
- * DMA or I/O base address set to some other value, he can enter them in
- * configuration without any problem. Also I wrote a function wd7000_setup,
- * so now you can enter WD-7000 definition as kernel arguments,
- * as in lilo.conf:
- *
- * append="wd7000=IRQ,DMA,IO"
- *
- * PS: If card BIOS ROM is disabled, function wd7000_detect now will recognize
- * adapter, unlike the old one. Anyway, BIOS ROM from WD7000 adapter is
- * useless for Linux. B^)
- *
- *
- * 09/06/1996.
- *
- * Autodetecting of I/O base address from wd7000_detect function is removed,
- * some little bugs removed, etc...
- *
- * Thanks to Roger Scott for driver debugging.
- *
- * 06/07/1997
- *
- * Added support for /proc file system (/proc/scsi/wd7000/[0...] files).
- * Now, driver can handle hard disks with capacity >1GB.
- *
- * 01/15/1998
- *
- * Added support for BUS_ON and BUS_OFF parameters in config line.
- * Miscellaneous cleanup.
- *
- * 03/01/1998
- *
- * WD7000 driver now work on kernels >= 2.1.x
- *
- *
- * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * use host->host_lock, not io_request_lock, cleanups
- *
- * 2002/10/04 - Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * Use dev_id for interrupts, kill __func__ pasting
- * Add a lock for the scb pool, clean up all other cli/sti usage stuff
- * Use the adapter lock for the other places we had the cli's
- *
- * 2002/10/06 - Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * Switch to new style error handling
- * Clean up delay to udelay, and yielding sleeps
- * Make host reset actually reset the card
- * Make everything static
- *
- * 2003/02/12 - Christoph Hellwig <hch@infradead.org>
- *
- * Cleaned up host template definition
- * Removed now obsolete wd7000.h
- */
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/proc_fs.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/stat.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsicam.h>
-
-
-#undef WD7000_DEBUG /* general debug */
-#ifdef WD7000_DEBUG
-#define dprintk printk
-#else
-#define dprintk no_printk
-#endif
-
-/*
- * Mailbox structure sizes.
- * I prefer to keep the number of ICMBs much larger than the number of
- * OGMBs. OGMBs are used very quickly by the driver to start one or
- * more commands, while ICMBs are used by the host adapter per command.
- */
-#define OGMB_CNT 16
-#define ICMB_CNT 32
-
-/*
- * Scb's are shared by all active adapters. So, if they all become busy,
- * callers may be made to wait in alloc_scbs for them to free. That can
- * be avoided by setting MAX_SCBS to NUM_CONFIG * WD7000_Q. If you'd
- * rather conserve memory, use a smaller number (> 0, of course) - things
- * will should still work OK.
- */
-#define MAX_SCBS 32
-
-/*
- * In this version, sg_tablesize now defaults to WD7000_SG, and will
- * be set to SG_NONE for older boards. This is the reverse of the
- * previous default, and was changed so that the driver-level
- * scsi_host_template would reflect the driver's support for scatter/
- * gather.
- *
- * Also, it has been reported that boards at Revision 6 support scatter/
- * gather, so the new definition of an "older" board has been changed
- * accordingly.
- */
-#define WD7000_Q 16
-#define WD7000_SG 16
-
-
-/*
- * WD7000-specific mailbox structure
- *
- */
-typedef volatile struct mailbox {
- unchar status;
- unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */
-} Mailbox;
-
-/*
- * This structure should contain all per-adapter global data. I.e., any
- * new global per-adapter data should put in here.
- */
-typedef struct adapter {
- struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */
- int iobase; /* This adapter's I/O base address */
- int irq; /* This adapter's IRQ level */
- int dma; /* This adapter's DMA channel */
- int int_counter; /* This adapter's interrupt counter */
- int bus_on; /* This adapter's BUS_ON time */
- int bus_off; /* This adapter's BUS_OFF time */
- struct { /* This adapter's mailboxes */
- Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */
- Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */
- } mb;
- int next_ogmb; /* to reduce contention at mailboxes */
- unchar control; /* shadows CONTROL port value */
- unchar rev1, rev2; /* filled in by wd7000_revision */
-} Adapter;
-
-/*
- * (linear) base address for ROM BIOS
- */
-static const long wd7000_biosaddr[] = {
- 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
- 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
-};
-#define NUM_ADDRS ARRAY_SIZE(wd7000_biosaddr)
-
-static const unsigned short wd7000_iobase[] = {
- 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
- 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
- 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
- 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
-};
-#define NUM_IOPORTS ARRAY_SIZE(wd7000_iobase)
-
-static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
-#define NUM_IRQS ARRAY_SIZE(wd7000_irq)
-
-static const short wd7000_dma[] = { 5, 6, 7 };
-#define NUM_DMAS ARRAY_SIZE(wd7000_dma)
-
-/*
- * The following is set up by wd7000_detect, and used thereafter for
- * proc and other global ookups
- */
-
-#define UNITS 8
-static struct Scsi_Host *wd7000_host[UNITS];
-
-#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */
-#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */
-
-/*
- * Standard Adapter Configurations - used by wd7000_detect
- */
-typedef struct {
- short irq; /* IRQ level */
- short dma; /* DMA channel */
- unsigned iobase; /* I/O base address */
- short bus_on; /* Time that WD7000 spends on the AT-bus when */
- /* transferring data. BIOS default is 8000ns. */
- short bus_off; /* Time that WD7000 spends OFF THE BUS after */
- /* while it is transferring data. */
- /* BIOS default is 1875ns */
-} Config;
-
-/*
- * Add here your configuration...
- */
-static Config configs[] = {
- {15, 6, 0x350, BUS_ON, BUS_OFF}, /* defaults for single adapter */
- {11, 5, 0x320, BUS_ON, BUS_OFF}, /* defaults for second adapter */
- {7, 6, 0x350, BUS_ON, BUS_OFF}, /* My configuration (Zaga) */
- {-1, -1, 0x0, BUS_ON, BUS_OFF} /* Empty slot */
-};
-#define NUM_CONFIGS ARRAY_SIZE(configs)
-
-/*
- * The following list defines strings to look for in the BIOS that identify
- * it as the WD7000-FASST2 SST BIOS. I suspect that something should be
- * added for the Future Domain version.
- */
-typedef struct signature {
- const char *sig; /* String to look for */
- unsigned long ofs; /* offset from BIOS base address */
- unsigned len; /* length of string */
-} Signature;
-
-static const Signature signatures[] = {
- {"SSTBIOS", 0x0000d, 7} /* "SSTBIOS" @ offset 0x0000d */
-};
-#define NUM_SIGNATURES ARRAY_SIZE(signatures)
-
-
-/*
- * I/O Port Offsets and Bit Definitions
- * 4 addresses are used. Those not defined here are reserved.
- */
-#define ASC_STAT 0 /* Status, Read */
-#define ASC_COMMAND 0 /* Command, Write */
-#define ASC_INTR_STAT 1 /* Interrupt Status, Read */
-#define ASC_INTR_ACK 1 /* Acknowledge, Write */
-#define ASC_CONTROL 2 /* Control, Write */
-
-/*
- * ASC Status Port
- */
-#define INT_IM 0x80 /* Interrupt Image Flag */
-#define CMD_RDY 0x40 /* Command Port Ready */
-#define CMD_REJ 0x20 /* Command Port Byte Rejected */
-#define ASC_INIT 0x10 /* ASC Initialized Flag */
-#define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */
-
-/*
- * COMMAND opcodes
- *
- * Unfortunately, I have no idea how to properly use some of these commands,
- * as the OEM manual does not make it clear. I have not been able to use
- * enable/disable unsolicited interrupts or the reset commands with any
- * discernible effect whatsoever. I think they may be related to certain
- * ICB commands, but again, the OEM manual doesn't make that clear.
- */
-#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */
-#define INITIALIZATION 1 /* initialization (10 bytes) */
-#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */
-#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */
-#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */
-#define SOFT_RESET 5 /* SCSI bus soft reset */
-#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */
-#define START_OGMB 0x80 /* start command in OGMB (n) */
-#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */
- /* where (n) = lower 6 bits */
-/*
- * For INITIALIZATION:
- */
-typedef struct initCmd {
- unchar op; /* command opcode (= 1) */
- unchar ID; /* Adapter's SCSI ID */
- unchar bus_on; /* Bus on time, x 125ns (see below) */
- unchar bus_off; /* Bus off time, "" "" */
- unchar rsvd; /* Reserved */
- unchar mailboxes[3]; /* Address of Mailboxes, MSB first */
- unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */
- unchar icmbs; /* Number of incoming MBs, "" "" */
-} InitCmd;
-
-/*
- * Interrupt Status Port - also returns diagnostic codes at ASC reset
- *
- * if msb is zero, the lower bits are diagnostic status
- * Diagnostics:
- * 01 No diagnostic error occurred
- * 02 RAM failure
- * 03 FIFO R/W failed
- * 04 SBIC register read/write failed
- * 05 Initialization D-FF failed
- * 06 Host IRQ D-FF failed
- * 07 ROM checksum error
- * Interrupt status (bitwise):
- * 10NNNNNN outgoing mailbox NNNNNN is free
- * 11NNNNNN incoming mailbox NNNNNN needs service
- */
-#define MB_INTR 0xC0 /* Mailbox Service possible/required */
-#define IMB_INTR 0x40 /* 1 Incoming / 0 Outgoing */
-#define MB_MASK 0x3f /* mask for mailbox number */
-
-/*
- * CONTROL port bits
- */
-#define INT_EN 0x08 /* Interrupt Enable */
-#define DMA_EN 0x04 /* DMA Enable */
-#define SCSI_RES 0x02 /* SCSI Reset */
-#define ASC_RES 0x01 /* ASC Reset */
-
-/*
- * Driver data structures:
- * - mb and scbs are required for interfacing with the host adapter.
- * An SCB has extra fields not visible to the adapter; mb's
- * _cannot_ do this, since the adapter assumes they are contiguous in
- * memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact
- * to access them.
- * - An icb is for host-only (non-SCSI) commands. ICBs are 16 bytes each;
- * the additional bytes are used only by the driver.
- * - For now, a pool of SCBs are kept in global storage by this driver,
- * and are allocated and freed as needed.
- *
- * The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command,
- * not when it has finished. Since the SCB must be around for completion,
- * problems arise when SCBs correspond to OGMBs, which may be reallocated
- * earlier (or delayed unnecessarily until a command completes).
- * Mailboxes are used as transient data structures, simply for
- * carrying SCB addresses to/from the 7000-FASST2.
- *
- * Note also since SCBs are not "permanently" associated with mailboxes,
- * there is no need to keep a global list of scsi_cmnd pointers indexed
- * by OGMB. Again, SCBs reference their scsi_cmnds directly, so mailbox
- * indices need not be involved.
- */
-
-/*
- * WD7000-specific scatter/gather element structure
- */
-typedef struct sgb {
- unchar len[3];
- unchar ptr[3]; /* Also SCSI-style - MSB first */
-} Sgb;
-
-typedef struct scb { /* Command Control Block 5.4.1 */
- unchar op; /* Command Control Block Operation Code */
- unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */
- /* Outbound data transfer, length is checked */
- /* Inbound data transfer, length is checked */
- /* Logical Unit Number */
- unchar cdb[12]; /* SCSI Command Block */
- volatile unchar status; /* SCSI Return Status */
- volatile unchar vue; /* Vendor Unique Error Code */
- unchar maxlen[3]; /* Maximum Data Transfer Length */
- unchar dataptr[3]; /* SCSI Data Block Pointer */
- unchar linkptr[3]; /* Next Command Link Pointer */
- unchar direc; /* Transfer Direction */
- unchar reserved2[6]; /* SCSI Command Descriptor Block */
- /* end of hardware SCB */
- struct scsi_cmnd *SCpnt;/* scsi_cmnd using this SCB */
- Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */
- Adapter *host; /* host adapter */
- struct scb *next; /* for lists of scbs */
-} Scb;
-
-/*
- * This driver is written to allow host-only commands to be executed.
- * These use a 16-byte block called an ICB. The format is extended by the
- * driver to 18 bytes, to support the status returned in the ICMB and
- * an execution phase code.
- *
- * There are other formats besides these; these are the ones I've tried
- * to use. Formats for some of the defined ICB opcodes are not defined
- * (notably, get/set unsolicited interrupt status) in my copy of the OEM
- * manual, and others are ambiguous/hard to follow.
- */
-#define ICB_OP_MASK 0x80 /* distinguishes scbs from icbs */
-#define ICB_OP_OPEN_RBUF 0x80 /* open receive buffer */
-#define ICB_OP_RECV_CMD 0x81 /* receive command from initiator */
-#define ICB_OP_RECV_DATA 0x82 /* receive data from initiator */
-#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */
-#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */
-#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */
- /* 0x87 is reserved */
-#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */
-#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */
-#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */
-#define ICB_OP_GET_UMASK 0x8B /* read unsolicited interrupt mask */
-#define ICB_OP_GET_REVISION 0x8C /* read firmware revision level */
-#define ICB_OP_DIAGNOSTICS 0x8D /* execute diagnostics */
-#define ICB_OP_SET_EPARMS 0x8E /* set execution parameters */
-#define ICB_OP_GET_EPARMS 0x8F /* read execution parameters */
-
-typedef struct icbRecvCmd {
- unchar op;
- unchar IDlun; /* Initiator SCSI ID/lun */
- unchar len[3]; /* command buffer length */
- unchar ptr[3]; /* command buffer address */
- unchar rsvd[7]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbRecvCmd;
-
-typedef struct icbSendStat {
- unchar op;
- unchar IDlun; /* Target SCSI ID/lun */
- unchar stat; /* (outgoing) completion status byte 1 */
- unchar rsvd[12]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbSendStat;
-
-typedef struct icbRevLvl {
- unchar op;
- volatile unchar primary; /* primary revision level (returned) */
- volatile unchar secondary; /* secondary revision level (returned) */
- unchar rsvd[12]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbRevLvl;
-
-typedef struct icbUnsMask { /* I'm totally guessing here */
- unchar op;
- volatile unchar mask[14]; /* mask bits */
-#if 0
- unchar rsvd[12]; /* reserved */
-#endif
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbUnsMask;
-
-typedef struct icbDiag {
- unchar op;
- unchar type; /* diagnostics type code (0-3) */
- unchar len[3]; /* buffer length */
- unchar ptr[3]; /* buffer address */
- unchar rsvd[7]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbDiag;
-
-#define ICB_DIAG_POWERUP 0 /* Power-up diags only */
-#define ICB_DIAG_WALKING 1 /* walking 1's pattern */
-#define ICB_DIAG_DMA 2 /* DMA - system memory diags */
-#define ICB_DIAG_FULL 3 /* do both 1 & 2 */
-
-typedef struct icbParms {
- unchar op;
- unchar rsvd1; /* reserved */
- unchar len[3]; /* parms buffer length */
- unchar ptr[3]; /* parms buffer address */
- unchar idx[2]; /* index (MSB-LSB) */
- unchar rsvd2[5]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbParms;
-
-typedef struct icbAny {
- unchar op;
- unchar data[14]; /* format-specific data */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
-} IcbAny;
-
-typedef union icb {
- unchar op; /* ICB opcode */
- IcbRecvCmd recv_cmd; /* format for receive command */
- IcbSendStat send_stat; /* format for send status */
- IcbRevLvl rev_lvl; /* format for get revision level */
- IcbDiag diag; /* format for execute diagnostics */
- IcbParms eparms; /* format for get/set exec parms */
- IcbAny icb; /* generic format */
- unchar data[18];
-} Icb;
-
-#ifdef MODULE
-static char *wd7000;
-module_param(wd7000, charp, 0);
-#endif
-
-/*
- * Driver SCB structure pool.
- *
- * The SCBs declared here are shared by all host adapters; hence, this
- * structure is not part of the Adapter structure.
- */
-static Scb scbs[MAX_SCBS];
-static Scb *scbfree; /* free list */
-static int freescbs = MAX_SCBS; /* free list counter */
-static spinlock_t scbpool_lock; /* guards the scb free list and count */
-
-/*
- * END of data/declarations - code follows.
- */
-static void __init setup_error(char *mesg, int *ints)
-{
- if (ints[0] == 3)
- printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", ints[1], ints[2], ints[3], mesg);
- else if (ints[0] == 4)
- printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], mesg);
- else
- printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
-}
-
-
-/*
- * Note: You can now set these options from the kernel's "command line".
- * The syntax is:
- *
- * wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]]
- *
- * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values
- * are 8000ns for BUS_ON and 1875ns for BUS_OFF.
- * eg:
- * wd7000=7,6,0x350
- *
- * will configure the driver for a WD-7000 controller
- * using IRQ 15 with a DMA channel 6, at IO base address 0x350.
- */
-static int __init wd7000_setup(char *str)
-{
- static short wd7000_card_num; /* .bss will zero this */
- short i;
- int ints[6];
-
- (void) get_options(str, ARRAY_SIZE(ints), ints);
-
- if (wd7000_card_num >= NUM_CONFIGS) {
- printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__);
- return 0;
- }
-
- if ((ints[0] < 3) || (ints[0] > 5)) {
- printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __func__);
- } else {
- for (i = 0; i < NUM_IRQS; i++)
- if (ints[1] == wd7000_irq[i])
- break;
-
- if (i == NUM_IRQS) {
- setup_error("invalid IRQ.", ints);
- return 0;
- } else
- configs[wd7000_card_num].irq = ints[1];
-
- for (i = 0; i < NUM_DMAS; i++)
- if (ints[2] == wd7000_dma[i])
- break;
-
- if (i == NUM_DMAS) {
- setup_error("invalid DMA channel.", ints);
- return 0;
- } else
- configs[wd7000_card_num].dma = ints[2];
-
- for (i = 0; i < NUM_IOPORTS; i++)
- if (ints[3] == wd7000_iobase[i])
- break;
-
- if (i == NUM_IOPORTS) {
- setup_error("invalid I/O base address.", ints);
- return 0;
- } else
- configs[wd7000_card_num].iobase = ints[3];
-
- if (ints[0] > 3) {
- if ((ints[4] < 500) || (ints[4] > 31875)) {
- setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints);
- configs[wd7000_card_num].bus_on = BUS_ON;
- } else
- configs[wd7000_card_num].bus_on = ints[4] / 125;
- } else
- configs[wd7000_card_num].bus_on = BUS_ON;
-
- if (ints[0] > 4) {
- if ((ints[5] < 500) || (ints[5] > 31875)) {
- setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints);
- configs[wd7000_card_num].bus_off = BUS_OFF;
- } else
- configs[wd7000_card_num].bus_off = ints[5] / 125;
- } else
- configs[wd7000_card_num].bus_off = BUS_OFF;
-
- if (wd7000_card_num) {
- for (i = 0; i < (wd7000_card_num - 1); i++) {
- int j = i + 1;
-
- for (; j < wd7000_card_num; j++)
- if (configs[i].irq == configs[j].irq) {
- setup_error("duplicated IRQ!", ints);
- return 0;
- }
- if (configs[i].dma == configs[j].dma) {
- setup_error("duplicated DMA " "channel!", ints);
- return 0;
- }
- if (configs[i].iobase == configs[j].iobase) {
- setup_error("duplicated I/O " "base address!", ints);
- return 0;
- }
- }
- }
-
- dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
- "BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125);
-
- wd7000_card_num++;
- }
- return 1;
-}
-
-__setup("wd7000=", wd7000_setup);
-
-static inline void any2scsi(unchar * scsi, int any)
-{
- *scsi++ = (unsigned)any >> 16;
- *scsi++ = (unsigned)any >> 8;
- *scsi++ = any;
-}
-
-static inline int scsi2int(unchar * scsi)
-{
- return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2];
-}
-
-static inline void wd7000_enable_intr(Adapter * host)
-{
- host->control |= INT_EN;
- outb(host->control, host->iobase + ASC_CONTROL);
-}
-
-
-static inline void wd7000_enable_dma(Adapter * host)
-{
- unsigned long flags;
- host->control |= DMA_EN;
- outb(host->control, host->iobase + ASC_CONTROL);
-
- flags = claim_dma_lock();
- set_dma_mode(host->dma, DMA_MODE_CASCADE);
- enable_dma(host->dma);
- release_dma_lock(flags);
-
-}
-
-
-#define WAITnexttimeout 200 /* 2 seconds */
-
-static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof)
-{
- unsigned WAITbits;
- unsigned long WAITtimeout = jiffies + WAITnexttimeout;
-
- while (time_before_eq(jiffies, WAITtimeout)) {
- WAITbits = inb(port) & mask;
-
- if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
- return (0);
- }
-
- return (1);
-}
-
-
-static inline int command_out(Adapter * host, unchar * cmd, int len)
-{
- if (!WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
- while (len--) {
- do {
- outb(*cmd, host->iobase + ASC_COMMAND);
- WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
- } while (inb(host->iobase + ASC_STAT) & CMD_REJ);
-
- cmd++;
- }
-
- return (1);
- }
-
- printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
-
- return (0);
-}
-
-
-/*
- * This version of alloc_scbs is in preparation for supporting multiple
- * commands per lun and command chaining, by queueing pending commands.
- * We will need to allocate Scbs in blocks since they will wait to be
- * executed so there is the possibility of deadlock otherwise.
- * Also, to keep larger requests from being starved by smaller requests,
- * we limit access to this routine with an internal busy flag, so that
- * the satisfiability of a request is not dependent on the size of the
- * request.
- */
-static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
-{
- Scb *scb, *p = NULL;
- unsigned long flags;
- unsigned long timeout = jiffies + WAITnexttimeout;
- unsigned long now;
- int i;
-
- if (needed <= 0)
- return (NULL); /* sanity check */
-
- spin_unlock_irq(host->host_lock);
-
- retry:
- while (freescbs < needed) {
- timeout = jiffies + WAITnexttimeout;
- do {
- /* FIXME: can we actually just yield here ?? */
- for (now = jiffies; now == jiffies;)
- cpu_relax(); /* wait a jiffy */
- } while (freescbs < needed && time_before_eq(jiffies, timeout));
- /*
- * If we get here with enough free Scbs, we can take them.
- * Otherwise, we timed out and didn't get enough.
- */
- if (freescbs < needed) {
- printk(KERN_ERR "wd7000: can't get enough free SCBs.\n");
- return (NULL);
- }
- }
-
- /* Take the lock, then check we didn't get beaten, if so try again */
- spin_lock_irqsave(&scbpool_lock, flags);
- if (freescbs < needed) {
- spin_unlock_irqrestore(&scbpool_lock, flags);
- goto retry;
- }
-
- scb = scbfree;
- freescbs -= needed;
- for (i = 0; i < needed; i++) {
- p = scbfree;
- scbfree = p->next;
- }
- p->next = NULL;
-
- spin_unlock_irqrestore(&scbpool_lock, flags);
-
- spin_lock_irq(host->host_lock);
- return (scb);
-}
-
-
-static inline void free_scb(Scb * scb)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scbpool_lock, flags);
-
- memset(scb, 0, sizeof(Scb));
- scb->next = scbfree;
- scbfree = scb;
- freescbs++;
-
- spin_unlock_irqrestore(&scbpool_lock, flags);
-}
-
-
-static inline void init_scbs(void)
-{
- int i;
-
- spin_lock_init(&scbpool_lock);
-
- /* This is only ever called before the SCB pool is active */
-
- scbfree = &(scbs[0]);
- memset(scbs, 0, sizeof(scbs));
- for (i = 0; i < MAX_SCBS - 1; i++) {
- scbs[i].next = &(scbs[i + 1]);
- scbs[i].SCpnt = NULL;
- }
- scbs[MAX_SCBS - 1].next = NULL;
- scbs[MAX_SCBS - 1].SCpnt = NULL;
-}
-
-
-static int mail_out(Adapter * host, Scb * scbptr)
-/*
- * Note: this can also be used for ICBs; just cast to the parm type.
- */
-{
- int i, ogmb;
- unsigned long flags;
- unchar start_ogmb;
- Mailbox *ogmbs = host->mb.ogmb;
- int *next_ogmb = &(host->next_ogmb);
-
- dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
-
- /* We first look for a free outgoing mailbox */
- spin_lock_irqsave(host->sh->host_lock, flags);
- ogmb = *next_ogmb;
- for (i = 0; i < OGMB_CNT; i++) {
- if (ogmbs[ogmb].status == 0) {
- dprintk(" using OGMB 0x%x", ogmb);
- ogmbs[ogmb].status = 1;
- any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
-
- *next_ogmb = (ogmb + 1) % OGMB_CNT;
- break;
- } else
- ogmb = (ogmb + 1) % OGMB_CNT;
- }
- spin_unlock_irqrestore(host->sh->host_lock, flags);
-
- dprintk(", scb is 0x%06lx", (long) scbptr);
-
- if (i >= OGMB_CNT) {
- /*
- * Alternatively, we might issue the "interrupt on free OGMB",
- * and sleep, but it must be ensured that it isn't the init
- * task running. Instead, this version assumes that the caller
- * will be persistent, and try again. Since it's the adapter
- * that marks OGMB's free, waiting even with interrupts off
- * should work, since they are freed very quickly in most cases.
- */
- dprintk(", no free OGMBs.\n");
- return (0);
- }
-
- wd7000_enable_intr(host);
-
- start_ogmb = START_OGMB | ogmb;
- command_out(host, &start_ogmb, 1);
-
- dprintk(", awaiting interrupt.\n");
-
- return (1);
-}
-
-
-static int make_code(unsigned hosterr, unsigned scsierr)
-{
-#ifdef WD7000_DEBUG
- int in_error = hosterr;
-#endif
-
- switch ((hosterr >> 8) & 0xff) {
- case 0: /* Reserved */
- hosterr = DID_ERROR;
- break;
- case 1: /* Command Complete, no errors */
- hosterr = DID_OK;
- break;
- case 2: /* Command complete, error logged in scb status (scsierr) */
- hosterr = DID_OK;
- break;
- case 4: /* Command failed to complete - timeout */
- hosterr = DID_TIME_OUT;
- break;
- case 5: /* Command terminated; Bus reset by external device */
- hosterr = DID_RESET;
- break;
- case 6: /* Unexpected Command Received w/ host as target */
- hosterr = DID_BAD_TARGET;
- break;
- case 80: /* Unexpected Reselection */
- case 81: /* Unexpected Selection */
- hosterr = DID_BAD_INTR;
- break;
- case 82: /* Abort Command Message */
- hosterr = DID_ABORT;
- break;
- case 83: /* SCSI Bus Software Reset */
- case 84: /* SCSI Bus Hardware Reset */
- hosterr = DID_RESET;
- break;
- default: /* Reserved */
- hosterr = DID_ERROR;
- }
-#ifdef WD7000_DEBUG
- if (scsierr || hosterr)
- dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr);
-#endif
- return (scsierr | (hosterr << 16));
-}
-
-#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
-
-
-static irqreturn_t wd7000_intr(int irq, void *dev_id)
-{
- Adapter *host = (Adapter *) dev_id;
- int flag, icmb, errstatus, icmb_status;
- int host_error, scsi_error;
- Scb *scb; /* for SCSI commands */
- IcbAny *icb; /* for host commands */
- struct scsi_cmnd *SCpnt;
- Mailbox *icmbs = host->mb.icmb;
- unsigned long flags;
-
- spin_lock_irqsave(host->sh->host_lock, flags);
- host->int_counter++;
-
- dprintk("wd7000_intr: irq = %d, host = 0x%06lx\n", irq, (long) host);
-
- flag = inb(host->iobase + ASC_INTR_STAT);
-
- dprintk("wd7000_intr: intr stat = 0x%02x\n", flag);
-
- if (!(inb(host->iobase + ASC_STAT) & INT_IM)) {
- /* NB: these are _very_ possible if IRQ 15 is being used, since
- * it's the "garbage collector" on the 2nd 8259 PIC. Specifically,
- * any interrupt signal into the 8259 which can't be identified
- * comes out as 7 from the 8259, which is 15 to the host. Thus, it
- * is a good thing the WD7000 has an interrupt status port, so we
- * can sort these out. Otherwise, electrical noise and other such
- * problems would be indistinguishable from valid interrupts...
- */
- dprintk("wd7000_intr: phantom interrupt...\n");
- goto ack;
- }
-
- if (!(flag & MB_INTR))
- goto ack;
-
- /* The interrupt is for a mailbox */
- if (!(flag & IMB_INTR)) {
- dprintk("wd7000_intr: free outgoing mailbox\n");
- /*
- * If sleep_on() and the "interrupt on free OGMB" command are
- * used in mail_out(), wake_up() should correspondingly be called
- * here. For now, we don't need to do anything special.
- */
- goto ack;
- }
-
- /* The interrupt is for an incoming mailbox */
- icmb = flag & MB_MASK;
- icmb_status = icmbs[icmb].status;
- if (icmb_status & 0x80) { /* unsolicited - result in ICMB */
- dprintk("wd7000_intr: unsolicited interrupt 0x%02x\n", icmb_status);
- goto ack;
- }
-
- /* Aaaargh! (Zaga) */
- scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
- icmbs[icmb].status = 0;
- if (scb->op & ICB_OP_MASK) { /* an SCB is done */
- icb = (IcbAny *) scb;
- icb->status = icmb_status;
- icb->phase = 0;
- goto ack;
- }
-
- SCpnt = scb->SCpnt;
- if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
- host_error = scb->vue | (icmb_status << 8);
- scsi_error = scb->status;
- errstatus = make_code(host_error, scsi_error);
- SCpnt->result = errstatus;
-
- free_scb(scb);
-
- SCpnt->scsi_done(SCpnt);
- }
-
- ack:
- dprintk("wd7000_intr: return from interrupt handler\n");
- wd7000_intr_ack(host);
-
- spin_unlock_irqrestore(host->sh->host_lock, flags);
- return IRQ_HANDLED;
-}
-
-static int wd7000_queuecommand_lck(struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- Scb *scb;
- Sgb *sgb;
- unchar *cdb = (unchar *) SCpnt->cmnd;
- unchar idlun;
- short cdblen;
- int nseg;
- Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
-
- cdblen = SCpnt->cmd_len;
- idlun = ((SCpnt->device->id << 5) & 0xe0) | (SCpnt->device->lun & 7);
- SCpnt->scsi_done = done;
- SCpnt->SCp.phase = 1;
- scb = alloc_scbs(SCpnt->device->host, 1);
- scb->idlun = idlun;
- memcpy(scb->cdb, cdb, cdblen);
- scb->direc = 0x40; /* Disable direction check */
-
- scb->SCpnt = SCpnt; /* so we can find stuff later */
- SCpnt->host_scribble = (unchar *) scb;
- scb->host = host;
-
- nseg = scsi_sg_count(SCpnt);
- if (nseg > 1) {
- struct scatterlist *sg;
- unsigned i;
-
- dprintk("Using scatter/gather with %d elements.\n", nseg);
-
- sgb = scb->sgb;
- scb->op = 1;
- any2scsi(scb->dataptr, (int) sgb);
- any2scsi(scb->maxlen, nseg * sizeof(Sgb));
-
- scsi_for_each_sg(SCpnt, sg, nseg, i) {
- any2scsi(sgb[i].ptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
- any2scsi(sgb[i].len, sg->length);
- }
- } else {
- scb->op = 0;
- if (nseg) {
- struct scatterlist *sg = scsi_sglist(SCpnt);
- any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
- }
- any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
- }
-
- /* FIXME: drop lock and yield here ? */
-
- while (!mail_out(host, scb))
- cpu_relax(); /* keep trying */
-
- return 0;
-}
-
-static DEF_SCSI_QCMD(wd7000_queuecommand)
-
-static int wd7000_diagnostics(Adapter * host, int code)
-{
- static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
- static unchar buf[256];
- unsigned long timeout;
-
- icb.type = code;
- any2scsi(icb.len, sizeof(buf));
- any2scsi(icb.ptr, (int) &buf);
- icb.phase = 1;
- /*
- * This routine is only called at init, so there should be OGMBs
- * available. I'm assuming so here. If this is going to
- * fail, I can just let the timeout catch the failure.
- */
- mail_out(host, (struct scb *) &icb);
- timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */
- while (icb.phase && time_before(jiffies, timeout)) {
- cpu_relax(); /* wait for completion */
- barrier();
- }
-
- if (icb.phase) {
- printk("wd7000_diagnostics: timed out.\n");
- return (0);
- }
- if (make_code(icb.vue | (icb.status << 8), 0)) {
- printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", icb.vue, icb.status);
- return (0);
- }
-
- return (1);
-}
-
-
-static int wd7000_adapter_reset(Adapter * host)
-{
- InitCmd init_cmd = {
- INITIALIZATION,
- 7,
- host->bus_on,
- host->bus_off,
- 0,
- {0, 0, 0},
- OGMB_CNT,
- ICMB_CNT
- };
- int diag;
- /*
- * Reset the adapter - only. The SCSI bus was initialized at power-up,
- * and we need to do this just so we control the mailboxes, etc.
- */
- outb(ASC_RES, host->iobase + ASC_CONTROL);
- udelay(40); /* reset pulse: this is 40us, only need 25us */
- outb(0, host->iobase + ASC_CONTROL);
- host->control = 0; /* this must always shadow ASC_CONTROL */
-
- if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
- printk(KERN_ERR "wd7000_init: WAIT timed out.\n");
- return -1; /* -1 = not ok */
- }
-
- if ((diag = inb(host->iobase + ASC_INTR_STAT)) != 1) {
- printk("wd7000_init: ");
-
- switch (diag) {
- case 2:
- printk(KERN_ERR "RAM failure.\n");
- break;
- case 3:
- printk(KERN_ERR "FIFO R/W failed\n");
- break;
- case 4:
- printk(KERN_ERR "SBIC register R/W failed\n");
- break;
- case 5:
- printk(KERN_ERR "Initialization D-FF failed.\n");
- break;
- case 6:
- printk(KERN_ERR "Host IRQ D-FF failed.\n");
- break;
- case 7:
- printk(KERN_ERR "ROM checksum error.\n");
- break;
- default:
- printk(KERN_ERR "diagnostic code 0x%02Xh received.\n", diag);
- }
- return -1;
- }
- /* Clear mailboxes */
- memset(&(host->mb), 0, sizeof(host->mb));
-
- /* Execute init command */
- any2scsi((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
- if (!command_out(host, (unchar *) & init_cmd, sizeof(init_cmd))) {
- printk(KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n");
- return -1;
- }
-
- if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
- printk("wd7000_adapter_reset: WAIT timed out.\n");
- return -1;
- }
- return 0;
-}
-
-static int wd7000_init(Adapter * host)
-{
- if (wd7000_adapter_reset(host) == -1)
- return 0;
-
-
- if (request_irq(host->irq, wd7000_intr, 0, "wd7000", host)) {
- printk("wd7000_init: can't get IRQ %d.\n", host->irq);
- return (0);
- }
- if (request_dma(host->dma, "wd7000")) {
- printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
- free_irq(host->irq, host);
- return (0);
- }
- wd7000_enable_dma(host);
- wd7000_enable_intr(host);
-
- if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) {
- free_dma(host->dma);
- free_irq(host->irq, NULL);
- return (0);
- }
-
- return (1);
-}
-
-
-static void wd7000_revision(Adapter * host)
-{
- static IcbRevLvl icb = { ICB_OP_GET_REVISION };
-
- icb.phase = 1;
- /*
- * Like diagnostics, this is only done at init time, in fact, from
- * wd7000_detect, so there should be OGMBs available. If it fails,
- * the only damage will be that the revision will show up as 0.0,
- * which in turn means that scatter/gather will be disabled.
- */
- mail_out(host, (struct scb *) &icb);
- while (icb.phase) {
- cpu_relax(); /* wait for completion */
- barrier();
- }
- host->rev1 = icb.primary;
- host->rev2 = icb.secondary;
-}
-
-
-static int wd7000_set_info(struct Scsi_Host *host, char *buffer, int length)
-{
- dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
-
- /*
- * Currently this is a no-op
- */
- dprintk("Sorry, this function is currently out of order...\n");
- return (length);
-}
-
-
-static int wd7000_show_info(struct seq_file *m, struct Scsi_Host *host)
-{
- Adapter *adapter = (Adapter *)host->hostdata;
- unsigned long flags;
-#ifdef WD7000_DEBUG
- Mailbox *ogmbs, *icmbs;
- short count;
-#endif
-
- spin_lock_irqsave(host->host_lock, flags);
- seq_printf(m, "Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
- seq_printf(m, " IO base: 0x%x\n", adapter->iobase);
- seq_printf(m, " IRQ: %d\n", adapter->irq);
- seq_printf(m, " DMA channel: %d\n", adapter->dma);
- seq_printf(m, " Interrupts: %d\n", adapter->int_counter);
- seq_printf(m, " BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125);
- seq_printf(m, " BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
-
-#ifdef WD7000_DEBUG
- ogmbs = adapter->mb.ogmb;
- icmbs = adapter->mb.icmb;
-
- seq_printf(m, "\nControl port value: 0x%x\n", adapter->control);
- seq_puts(m, "Incoming mailbox:\n");
- seq_printf(m, " size: %d\n", ICMB_CNT);
- seq_puts(m, " queued messages: ");
-
- for (i = count = 0; i < ICMB_CNT; i++)
- if (icmbs[i].status) {
- count++;
- seq_printf(m, "0x%x ", i);
- }
-
- seq_puts(m, count ? "\n" : "none\n");
-
- seq_puts(m, "Outgoing mailbox:\n");
- seq_printf(m, " size: %d\n", OGMB_CNT);
- seq_printf(m, " next message: 0x%x\n", adapter->next_ogmb);
- seq_puts(m, " queued messages: ");
-
- for (i = count = 0; i < OGMB_CNT; i++)
- if (ogmbs[i].status) {
- count++;
- seq_printf(m, "0x%x ", i);
- }
-
- seq_puts(m, count ? "\n" : "none\n");
-#endif
-
- spin_unlock_irqrestore(host->host_lock, flags);
-
- return 0;
-}
-
-
-/*
- * Returns the number of adapters this driver is supporting.
- *
- * The source for hosts.c says to wait to call scsi_register until 100%
- * sure about an adapter. We need to do it a little sooner here; we
- * need the storage set up by scsi_register before wd7000_init, and
- * changing the location of an Adapter structure is more trouble than
- * calling scsi_unregister.
- *
- */
-
-static __init int wd7000_detect(struct scsi_host_template *tpnt)
-{
- short present = 0, biosaddr_ptr, sig_ptr, i, pass;
- short biosptr[NUM_CONFIGS];
- unsigned iobase;
- Adapter *host = NULL;
- struct Scsi_Host *sh;
- int unit = 0;
-
- dprintk("wd7000_detect: started\n");
-
-#ifdef MODULE
- if (wd7000)
- wd7000_setup(wd7000);
-#endif
-
- for (i = 0; i < UNITS; wd7000_host[i++] = NULL);
- for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
-
- tpnt->proc_name = "wd7000";
- tpnt->show_info = &wd7000_show_info;
- tpnt->write_info = wd7000_set_info;
-
- /*
- * Set up SCB free list, which is shared by all adapters
- */
- init_scbs();
-
- for (pass = 0; pass < NUM_CONFIGS; pass++) {
- /*
- * First, search for BIOS SIGNATURE...
- */
- for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
- for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
- for (i = 0; i < pass; i++)
- if (biosptr[i] == biosaddr_ptr)
- break;
-
- if (i == pass) {
- void __iomem *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs,
- signatures[sig_ptr].len);
- short bios_match = 1;
-
- if (biosaddr)
- bios_match = check_signature(biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len);
-
- iounmap(biosaddr);
-
- if (bios_match)
- goto bios_matched;
- }
- }
-
- bios_matched:
- /*
- * BIOS SIGNATURE has been found.
- */
-#ifdef WD7000_DEBUG
- dprintk("wd7000_detect: pass %d\n", pass + 1);
-
- if (biosaddr_ptr == NUM_ADDRS)
- dprintk("WD-7000 SST BIOS not detected...\n");
- else
- dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);
-#endif
-
- if (configs[pass].irq < 0)
- continue;
-
- if (unit == UNITS)
- continue;
-
- iobase = configs[pass].iobase;
-
- dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
-
- if (request_region(iobase, 4, "wd7000")) {
-
- dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
- /*
- * ASC reset...
- */
- outb(ASC_RES, iobase + ASC_CONTROL);
- msleep(10);
- outb(0, iobase + ASC_CONTROL);
-
- if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
- dprintk("failed!\n");
- goto err_release;
- } else
- dprintk("ok!\n");
-
- if (inb(iobase + ASC_INTR_STAT) == 1) {
- /*
- * We register here, to get a pointer to the extra space,
- * which we'll use as the Adapter structure (host) for
- * this adapter. It is located just after the registered
- * Scsi_Host structure (sh), and is located by the empty
- * array hostdata.
- */
- sh = scsi_register(tpnt, sizeof(Adapter));
- if (sh == NULL)
- goto err_release;
-
- host = (Adapter *) sh->hostdata;
-
- dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
- memset(host, 0, sizeof(Adapter));
-
- host->irq = configs[pass].irq;
- host->dma = configs[pass].dma;
- host->iobase = iobase;
- host->int_counter = 0;
- host->bus_on = configs[pass].bus_on;
- host->bus_off = configs[pass].bus_off;
- host->sh = wd7000_host[unit] = sh;
- unit++;
-
- dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);
-
- if (!wd7000_init(host)) /* Initialization failed */
- goto err_unregister;
-
- /*
- * OK from here - we'll use this adapter/configuration.
- */
- wd7000_revision(host); /* important for scatter/gather */
-
- /*
- * For boards before rev 6.0, scatter/gather isn't supported.
- */
- if (host->rev1 < 6)
- sh->sg_tablesize = 1;
-
- present++; /* count it */
-
- if (biosaddr_ptr != NUM_ADDRS)
- biosptr[pass] = biosaddr_ptr;
-
- printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2);
- printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma);
- printk(" BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125);
- }
- } else
- dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
-
- continue;
-
- err_unregister:
- scsi_unregister(sh);
- err_release:
- release_region(iobase, 4);
-
- }
-
- if (!present)
- printk("Failed initialization of WD-7000 SCSI card!\n");
-
- return (present);
-}
-
-static int wd7000_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-#if 0
-/*
- * I have absolutely NO idea how to do an abort with the WD7000...
- */
-static int wd7000_abort(Scsi_Cmnd * SCpnt)
-{
- Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
-
- if (inb(host->iobase + ASC_STAT) & INT_IM) {
- printk("wd7000_abort: lost interrupt\n");
- wd7000_intr_handle(host->irq, NULL, NULL);
- return FAILED;
- }
- return FAILED;
-}
-#endif
-
-/*
- * Last resort. Reinitialize the board.
- */
-
-static int wd7000_host_reset(struct scsi_cmnd *SCpnt)
-{
- Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
-
- spin_lock_irq(SCpnt->device->host->host_lock);
-
- if (wd7000_adapter_reset(host) < 0) {
- spin_unlock_irq(SCpnt->device->host->host_lock);
- return FAILED;
- }
-
- wd7000_enable_intr(host);
-
- spin_unlock_irq(SCpnt->device->host->host_lock);
- return SUCCESS;
-}
-
-/*
- * This was borrowed directly from aha1542.c. (Zaga)
- */
-
-static int wd7000_biosparam(struct scsi_device *sdev,
- struct block_device *bdev, sector_t capacity, int *ip)
-{
- char b[BDEVNAME_SIZE];
-
- dprintk("wd7000_biosparam: dev=%s, size=%llu, ",
- bdevname(bdev, b), (u64)capacity);
- (void)b; /* unused var warning? */
-
- /*
- * try default translation
- */
- ip[0] = 64;
- ip[1] = 32;
- ip[2] = capacity >> 11;
-
- /*
- * for disks >1GB do some guessing
- */
- if (ip[2] >= 1024) {
- int info[3];
-
- /*
- * try to figure out the geometry from the partition table
- */
- if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) {
- printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" " using extended translation.\n");
-
- ip[0] = 255;
- ip[1] = 63;
- ip[2] = (unsigned long) capacity / (255 * 63);
- } else {
- ip[0] = info[0];
- ip[1] = info[1];
- ip[2] = info[2];
-
- if (info[0] == 255)
- printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __func__);
- }
- }
-
- dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
- dprintk("WARNING: check, if the bios geometry is correct.\n");
-
- return (0);
-}
-
-MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
-MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
-MODULE_LICENSE("GPL");
-
-static struct scsi_host_template driver_template = {
- .proc_name = "wd7000",
- .show_info = wd7000_show_info,
- .write_info = wd7000_set_info,
- .name = "Western Digital WD-7000",
- .detect = wd7000_detect,
- .release = wd7000_release,
- .queuecommand = wd7000_queuecommand,
- .eh_host_reset_handler = wd7000_host_reset,
- .bios_param = wd7000_biosparam,
- .can_queue = WD7000_Q,
- .this_id = 7,
- .sg_tablesize = WD7000_SG,
- .unchecked_isa_dma = 1,
- .use_clustering = ENABLE_CLUSTERING,
-};
-
-#include "scsi_module.c"
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index a003ba26ca6e..a5f10936fb9c 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -583,7 +583,7 @@ static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
{
unsigned long timeout;
- timeout = jiffies + usecs_to_jiffies(255);
+ timeout = jiffies + usecs_to_jiffies(10000);
do {
if (time_after(jiffies, timeout))
diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c
index ac1957dfdf24..322034ab9d37 100644
--- a/drivers/soc/qcom/smd.c
+++ b/drivers/soc/qcom/smd.c
@@ -95,7 +95,7 @@ static const struct {
/**
* struct qcom_smd_edge - representing a remote processor
- * @smd: handle to qcom_smd
+ * @dev: device for this edge
* @of_node: of_node handle for information related to this edge
* @edge_id: identifier of this edge
* @remote_pid: identifier of remote processor
@@ -111,7 +111,8 @@ static const struct {
* @state_work: work item for edge state changes
*/
struct qcom_smd_edge {
- struct qcom_smd *smd;
+ struct device dev;
+
struct device_node *of_node;
unsigned edge_id;
unsigned remote_pid;
@@ -135,6 +136,8 @@ struct qcom_smd_edge {
struct work_struct state_work;
};
+#define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev)
+
/*
* SMD channel states.
*/
@@ -197,20 +200,6 @@ struct qcom_smd_channel {
void *drvdata;
struct list_head list;
- struct list_head dev_list;
-};
-
-/**
- * struct qcom_smd - smd struct
- * @dev: device struct
- * @num_edges: number of entries in @edges
- * @edges: array of edges to be handled
- */
-struct qcom_smd {
- struct device *dev;
-
- unsigned num_edges;
- struct qcom_smd_edge edges[0];
};
/*
@@ -374,7 +363,7 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
SET_TX_CHANNEL_INFO(channel, head, 0);
- SET_TX_CHANNEL_INFO(channel, tail, 0);
+ SET_RX_CHANNEL_INFO(channel, tail, 0);
qcom_smd_signal_channel(channel);
@@ -421,7 +410,7 @@ static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel,
if (channel->state == state)
return;
- dev_dbg(edge->smd->dev, "set_state(%s, %d)\n", channel->name, state);
+ dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state);
SET_TX_CHANNEL_FLAG(channel, fDSR, is_open);
SET_TX_CHANNEL_FLAG(channel, fCTS, is_open);
@@ -891,8 +880,6 @@ static int qcom_smd_dev_remove(struct device *dev)
struct qcom_smd_device *qsdev = to_smd_device(dev);
struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
struct qcom_smd_channel *channel = qsdev->channel;
- struct qcom_smd_channel *tmp;
- struct qcom_smd_channel *ch;
qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING);
@@ -911,15 +898,9 @@ static int qcom_smd_dev_remove(struct device *dev)
if (qsdrv->remove)
qsdrv->remove(qsdev);
- /*
- * The client is now gone, close and release all channels associated
- * with this sdev
- */
- list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) {
- qcom_smd_channel_close(ch);
- list_del(&ch->dev_list);
- ch->qsdev = NULL;
- }
+ /* The client is now gone, close the primary channel */
+ qcom_smd_channel_close(channel);
+ channel->qsdev = NULL;
return 0;
}
@@ -973,13 +954,12 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
struct qcom_smd_device *qsdev;
struct qcom_smd_edge *edge = channel->edge;
struct device_node *node;
- struct qcom_smd *smd = edge->smd;
int ret;
if (channel->qsdev)
return -EEXIST;
- dev_dbg(smd->dev, "registering '%s'\n", channel->name);
+ dev_dbg(&edge->dev, "registering '%s'\n", channel->name);
qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL);
if (!qsdev)
@@ -990,7 +970,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
edge->of_node->name,
node ? node->name : channel->name);
- qsdev->dev.parent = smd->dev;
+ qsdev->dev.parent = &edge->dev;
qsdev->dev.bus = &qcom_smd_bus;
qsdev->dev.release = qcom_smd_release_device;
qsdev->dev.of_node = node;
@@ -1001,7 +981,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
ret = device_register(&qsdev->dev);
if (ret) {
- dev_err(smd->dev, "device_register failed: %d\n", ret);
+ dev_err(&edge->dev, "device_register failed: %d\n", ret);
put_device(&qsdev->dev);
}
@@ -1091,6 +1071,8 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
*
* Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
* ready.
+ *
+ * Any channels returned must be closed with a call to qcom_smd_close_channel()
*/
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
const char *name,
@@ -1120,15 +1102,21 @@ struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
return ERR_PTR(ret);
}
- /*
- * Append the list of channel to the channels associated with the sdev
- */
- list_add_tail(&channel->dev_list, &sdev->channel->dev_list);
-
return channel;
}
EXPORT_SYMBOL(qcom_smd_open_channel);
+/**
+ * qcom_smd_close_channel() - close an additionally opened channel
+ * @channel: channel handle, returned by qcom_smd_open_channel()
+ */
+void qcom_smd_close_channel(struct qcom_smd_channel *channel)
+{
+ qcom_smd_channel_close(channel);
+ channel->qsdev = NULL;
+}
+EXPORT_SYMBOL(qcom_smd_close_channel);
+
/*
* Allocate the qcom_smd_channel object for a newly found smd channel,
* retrieving and validating the smem items involved.
@@ -1139,20 +1127,18 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
char *name)
{
struct qcom_smd_channel *channel;
- struct qcom_smd *smd = edge->smd;
size_t fifo_size;
size_t info_size;
void *fifo_base;
void *info;
int ret;
- channel = devm_kzalloc(smd->dev, sizeof(*channel), GFP_KERNEL);
+ channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL);
if (!channel)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&channel->dev_list);
channel->edge = edge;
- channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL);
+ channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL);
if (!channel->name)
return ERR_PTR(-ENOMEM);
@@ -1175,7 +1161,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
} else if (info_size == 2 * sizeof(struct smd_channel_info)) {
channel->info = info;
} else {
- dev_err(smd->dev,
+ dev_err(&edge->dev,
"channel info of size %zu not supported\n", info_size);
ret = -EINVAL;
goto free_name_and_channel;
@@ -1190,7 +1176,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
/* The channel consist of a rx and tx fifo of equal size */
fifo_size /= 2;
- dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
+ dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
name, info_size, fifo_size);
channel->tx_fifo = fifo_base;
@@ -1202,8 +1188,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
return channel;
free_name_and_channel:
- devm_kfree(smd->dev, channel->name);
- devm_kfree(smd->dev, channel);
+ devm_kfree(&edge->dev, channel->name);
+ devm_kfree(&edge->dev, channel);
return ERR_PTR(ret);
}
@@ -1219,7 +1205,6 @@ static void qcom_channel_scan_worker(struct work_struct *work)
struct qcom_smd_alloc_entry *alloc_tbl;
struct qcom_smd_alloc_entry *entry;
struct qcom_smd_channel *channel;
- struct qcom_smd *smd = edge->smd;
unsigned long flags;
unsigned fifo_id;
unsigned info_id;
@@ -1263,7 +1248,7 @@ static void qcom_channel_scan_worker(struct work_struct *work)
list_add(&channel->list, &edge->channels);
spin_unlock_irqrestore(&edge->channels_lock, flags);
- dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name);
+ dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name);
set_bit(i, edge->allocated[tbl]);
wake_up_interruptible(&edge->new_channel_event);
@@ -1350,22 +1335,6 @@ static int qcom_smd_parse_edge(struct device *dev,
edge->of_node = of_node_get(node);
- irq = irq_of_parse_and_map(node, 0);
- if (irq < 0) {
- dev_err(dev, "required smd interrupt missing\n");
- return -EINVAL;
- }
-
- ret = devm_request_irq(dev, irq,
- qcom_smd_edge_intr, IRQF_TRIGGER_RISING,
- node->name, edge);
- if (ret) {
- dev_err(dev, "failed to request smd irq\n");
- return ret;
- }
-
- edge->irq = irq;
-
key = "qcom,smd-edge";
ret = of_property_read_u32(node, key, &edge->edge_id);
if (ret) {
@@ -1400,18 +1369,121 @@ static int qcom_smd_parse_edge(struct device *dev,
return -EINVAL;
}
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq < 0) {
+ dev_err(dev, "required smd interrupt missing\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(dev, irq,
+ qcom_smd_edge_intr, IRQF_TRIGGER_RISING,
+ node->name, edge);
+ if (ret) {
+ dev_err(dev, "failed to request smd irq\n");
+ return ret;
+ }
+
+ edge->irq = irq;
+
return 0;
}
-static int qcom_smd_probe(struct platform_device *pdev)
+/*
+ * Release function for an edge.
+ * Reset the state of each associated channel and free the edge context.
+ */
+static void qcom_smd_edge_release(struct device *dev)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_edge *edge = to_smd_edge(dev);
+
+ list_for_each_entry(channel, &edge->channels, list) {
+ SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
+ SET_RX_CHANNEL_INFO(channel, head, 0);
+ SET_RX_CHANNEL_INFO(channel, tail, 0);
+ }
+
+ kfree(edge);
+}
+
+/**
+ * qcom_smd_register_edge() - register an edge based on an device_node
+ * @parent: parent device for the edge
+ * @node: device_node describing the edge
+ *
+ * Returns an edge reference, or negative ERR_PTR() on failure.
+ */
+struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
+ struct device_node *node)
{
struct qcom_smd_edge *edge;
- struct device_node *node;
- struct qcom_smd *smd;
- size_t array_size;
- int num_edges;
int ret;
- int i = 0;
+
+ edge = kzalloc(sizeof(*edge), GFP_KERNEL);
+ if (!edge)
+ return ERR_PTR(-ENOMEM);
+
+ init_waitqueue_head(&edge->new_channel_event);
+
+ edge->dev.parent = parent;
+ edge->dev.release = qcom_smd_edge_release;
+ dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name);
+ ret = device_register(&edge->dev);
+ if (ret) {
+ pr_err("failed to register smd edge\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = qcom_smd_parse_edge(&edge->dev, node, edge);
+ if (ret) {
+ dev_err(&edge->dev, "failed to parse smd edge\n");
+ goto unregister_dev;
+ }
+
+ schedule_work(&edge->scan_work);
+
+ return edge;
+
+unregister_dev:
+ put_device(&edge->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(qcom_smd_register_edge);
+
+static int qcom_smd_remove_device(struct device *dev, void *data)
+{
+ device_unregister(dev);
+ of_node_put(dev->of_node);
+ put_device(dev);
+
+ return 0;
+}
+
+/**
+ * qcom_smd_unregister_edge() - release an edge and its children
+ * @edge: edge reference acquired from qcom_smd_register_edge
+ */
+int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
+{
+ int ret;
+
+ disable_irq(edge->irq);
+ cancel_work_sync(&edge->scan_work);
+ cancel_work_sync(&edge->state_work);
+
+ ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device);
+ if (ret)
+ dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);
+
+ device_unregister(&edge->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(qcom_smd_unregister_edge);
+
+static int qcom_smd_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
void *p;
/* Wait for smem */
@@ -1419,29 +1491,17 @@ static int qcom_smd_probe(struct platform_device *pdev)
if (PTR_ERR(p) == -EPROBE_DEFER)
return PTR_ERR(p);
- num_edges = of_get_available_child_count(pdev->dev.of_node);
- array_size = sizeof(*smd) + num_edges * sizeof(struct qcom_smd_edge);
- smd = devm_kzalloc(&pdev->dev, array_size, GFP_KERNEL);
- if (!smd)
- return -ENOMEM;
- smd->dev = &pdev->dev;
-
- smd->num_edges = num_edges;
- for_each_available_child_of_node(pdev->dev.of_node, node) {
- edge = &smd->edges[i++];
- edge->smd = smd;
- init_waitqueue_head(&edge->new_channel_event);
-
- ret = qcom_smd_parse_edge(&pdev->dev, node, edge);
- if (ret)
- continue;
+ for_each_available_child_of_node(pdev->dev.of_node, node)
+ qcom_smd_register_edge(&pdev->dev, node);
- schedule_work(&edge->scan_work);
- }
+ return 0;
+}
- platform_set_drvdata(pdev, smd);
+static int qcom_smd_remove_edge(struct device *dev, void *data)
+{
+ struct qcom_smd_edge *edge = to_smd_edge(dev);
- return 0;
+ return qcom_smd_unregister_edge(edge);
}
/*
@@ -1450,28 +1510,13 @@ static int qcom_smd_probe(struct platform_device *pdev)
*/
static int qcom_smd_remove(struct platform_device *pdev)
{
- struct qcom_smd_channel *channel;
- struct qcom_smd_edge *edge;
- struct qcom_smd *smd = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < smd->num_edges; i++) {
- edge = &smd->edges[i];
-
- disable_irq(edge->irq);
- cancel_work_sync(&edge->scan_work);
- cancel_work_sync(&edge->state_work);
-
- /* No need to lock here, because the writer is gone */
- list_for_each_entry(channel, &edge->channels, list) {
- if (!channel->qsdev)
- continue;
+ int ret;
- qcom_smd_destroy_device(channel);
- }
- }
+ ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge);
+ if (ret)
+ dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret);
- return 0;
+ return ret;
}
static const struct of_device_id qcom_smd_of_match[] = {
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 2e1aa9f130f4..18ec52f2078a 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -740,7 +740,8 @@ static int qcom_smem_probe(struct platform_device *pdev)
hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
if (hwlock_id < 0) {
- dev_err(&pdev->dev, "failed to retrieve hwlock\n");
+ if (hwlock_id != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to retrieve hwlock\n");
return hwlock_id;
}
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 44842a205e4b..7acd1517dd37 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -27,6 +27,7 @@ struct rockchip_domain_info {
int req_mask;
int idle_mask;
int ack_mask;
+ bool active_wakeup;
};
struct rockchip_pmu_info {
@@ -75,23 +76,24 @@ struct rockchip_pmu {
#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
-#define DOMAIN(pwr, status, req, idle, ack) \
+#define DOMAIN(pwr, status, req, idle, ack, wakeup) \
{ \
.pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \
.status_mask = (status >= 0) ? BIT(status) : 0, \
.req_mask = (req >= 0) ? BIT(req) : 0, \
.idle_mask = (idle >= 0) ? BIT(idle) : 0, \
.ack_mask = (ack >= 0) ? BIT(ack) : 0, \
+ .active_wakeup = wakeup, \
}
-#define DOMAIN_RK3288(pwr, status, req) \
- DOMAIN(pwr, status, req, req, (req) + 16)
+#define DOMAIN_RK3288(pwr, status, req, wakeup) \
+ DOMAIN(pwr, status, req, req, (req) + 16, wakeup)
-#define DOMAIN_RK3368(pwr, status, req) \
- DOMAIN(pwr, status, req, (req) + 16, req)
+#define DOMAIN_RK3368(pwr, status, req, wakeup) \
+ DOMAIN(pwr, status, req, (req) + 16, req, wakeup)
-#define DOMAIN_RK3399(pwr, status, req) \
- DOMAIN(pwr, status, req, req, req)
+#define DOMAIN_RK3399(pwr, status, req, wakeup) \
+ DOMAIN(pwr, status, req, req, req, wakeup)
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
{
@@ -295,6 +297,17 @@ static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
pm_clk_destroy(dev);
}
+static bool rockchip_active_wakeup(struct device *dev)
+{
+ struct generic_pm_domain *genpd;
+ struct rockchip_pm_domain *pd;
+
+ genpd = pd_to_genpd(dev->pm_domain);
+ pd = container_of(genpd, struct rockchip_pm_domain, genpd);
+
+ return pd->info->active_wakeup;
+}
+
static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
struct device_node *node)
{
@@ -415,6 +428,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
pd->genpd.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev;
pd->genpd.detach_dev = rockchip_pd_detach_dev;
+ pd->genpd.dev_ops.active_wakeup = rockchip_active_wakeup;
pd->genpd.flags = GENPD_FLAG_PM_CLK;
pm_genpd_init(&pd->genpd, NULL, false);
@@ -623,48 +637,48 @@ err_out:
}
static const struct rockchip_domain_info rk3288_pm_domains[] = {
- [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4),
- [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9),
- [RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3),
- [RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2),
+ [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4, false),
+ [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9, false),
+ [RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3, false),
+ [RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2, false),
};
static const struct rockchip_domain_info rk3368_pm_domains[] = {
- [RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6),
- [RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8),
- [RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7),
- [RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2),
- [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2),
+ [RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6, true),
+ [RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8, false),
+ [RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7, false),
+ [RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2, false),
+ [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2, false),
};
static const struct rockchip_domain_info rk3399_pm_domains[] = {
- [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1),
- [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1),
- [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1),
- [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15),
- [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16),
- [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1),
- [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2),
- [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14),
- [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17),
- [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0),
- [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3),
- [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4),
- [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5),
- [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6),
- [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1),
- [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7),
- [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8),
- [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9),
- [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10),
- [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11),
- [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23),
- [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24),
- [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12),
- [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22),
- [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27),
- [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28),
- [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29),
+ [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1, false),
+ [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1, false),
+ [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1, true),
+ [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15, true),
+ [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16, true),
+ [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1, true),
+ [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2, true),
+ [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14, true),
+ [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17, false),
+ [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0, false),
+ [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3, false),
+ [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4, false),
+ [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5, false),
+ [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6, false),
+ [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1, false),
+ [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7, false),
+ [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8, false),
+ [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9, false),
+ [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10, false),
+ [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11, false),
+ [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23, true),
+ [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24, true),
+ [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12, true),
+ [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22, false),
+ [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27, true),
+ [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28, true),
+ [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29, true),
};
static const struct rockchip_pmu_info rk3288_pmu = {
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 71c834f3847e..7792ed88d80b 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -967,8 +967,8 @@ static void tegra_io_rail_unprepare(void)
int tegra_io_rail_power_on(unsigned int id)
{
- unsigned long request, status, value;
- unsigned int bit, mask;
+ unsigned long request, status;
+ unsigned int bit;
int err;
mutex_lock(&pmc->powergates_lock);
@@ -977,15 +977,9 @@ int tegra_io_rail_power_on(unsigned int id)
if (err)
goto error;
- mask = 1 << bit;
+ tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request);
- value = tegra_pmc_readl(request);
- value |= mask;
- value &= ~IO_DPD_REQ_CODE_MASK;
- value |= IO_DPD_REQ_CODE_OFF;
- tegra_pmc_writel(value, request);
-
- err = tegra_io_rail_poll(status, mask, 0, 250);
+ err = tegra_io_rail_poll(status, BIT(bit), 0, 250);
if (err) {
pr_info("tegra_io_rail_poll() failed: %d\n", err);
goto error;
@@ -1002,8 +996,8 @@ EXPORT_SYMBOL(tegra_io_rail_power_on);
int tegra_io_rail_power_off(unsigned int id)
{
- unsigned long request, status, value;
- unsigned int bit, mask;
+ unsigned long request, status;
+ unsigned int bit;
int err;
mutex_lock(&pmc->powergates_lock);
@@ -1014,15 +1008,9 @@ int tegra_io_rail_power_off(unsigned int id)
goto error;
}
- mask = 1 << bit;
-
- value = tegra_pmc_readl(request);
- value |= mask;
- value &= ~IO_DPD_REQ_CODE_MASK;
- value |= IO_DPD_REQ_CODE_ON;
- tegra_pmc_writel(value, request);
+ tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request);
- err = tegra_io_rail_poll(status, mask, mask, 250);
+ err = tegra_io_rail_poll(status, BIT(bit), BIT(bit), 250);
if (err)
goto error;
diff --git a/drivers/staging/lustre/lnet/Kconfig b/drivers/staging/lustre/lnet/Kconfig
index 2b5930150cda..13b43278a38d 100644
--- a/drivers/staging/lustre/lnet/Kconfig
+++ b/drivers/staging/lustre/lnet/Kconfig
@@ -35,6 +35,7 @@ config LNET_SELFTEST
config LNET_XPRT_IB
tristate "LNET infiniband support"
depends on LNET && INFINIBAND && INFINIBAND_ADDR_TRANS
+ depends on BROKEN
default LNET && INFINIBAND
help
This option allows the LNET users to use infiniband as an
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index c7a5d49e487f..9e8802181452 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -2467,7 +2467,7 @@ int kiblnd_dev_failover(struct kib_dev *dev)
hdev->ibh_cmid = cmid;
hdev->ibh_ibdev = cmid->device;
- pd = ib_alloc_pd(cmid->device);
+ pd = ib_alloc_pd(cmid->device, 0);
if (IS_ERR(pd)) {
rc = PTR_ERR(pd);
CERROR("Can't allocate PD: %d\n", rc);
diff --git a/drivers/staging/lustre/lustre/include/lustre_acl.h b/drivers/staging/lustre/lustre/include/lustre_acl.h
index fecabe139b1f..9786f6caaade 100644
--- a/drivers/staging/lustre/lustre/include/lustre_acl.h
+++ b/drivers/staging/lustre/lustre/include/lustre_acl.h
@@ -38,8 +38,8 @@
#include <linux/posix_acl_xattr.h>
#define LUSTRE_POSIX_ACL_MAX_ENTRIES 32
-#define LUSTRE_POSIX_ACL_MAX_SIZE \
- (sizeof(posix_acl_xattr_header) + \
- LUSTRE_POSIX_ACL_MAX_ENTRIES * sizeof(posix_acl_xattr_entry))
+#define LUSTRE_POSIX_ACL_MAX_SIZE \
+ (sizeof(struct posix_acl_xattr_header) + \
+ LUSTRE_POSIX_ACL_MAX_ENTRIES * sizeof(struct posix_acl_xattr_entry))
#endif
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 6e3a188baaae..e1d784bae064 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -1121,8 +1121,8 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
struct cl_io *io;
ssize_t result;
- CDEBUG(D_VFSTRACE, "file: %s, type: %d ppos: %llu, count: %zu\n",
- file->f_path.dentry->d_name.name, iot, *ppos, count);
+ CDEBUG(D_VFSTRACE, "file: %pD, type: %d ppos: %llu, count: %zu\n",
+ file, iot, *ppos, count);
restart:
io = vvp_env_thread_io(env);
@@ -1138,45 +1138,31 @@ restart:
range_lock_init(&range, *ppos, *ppos + count - 1);
vio->vui_fd = LUSTRE_FPRIVATE(file);
- vio->vui_io_subtype = args->via_io_subtype;
+ vio->vui_iter = args->u.normal.via_iter;
+ vio->vui_iocb = args->u.normal.via_iocb;
+ /*
+ * Direct IO reads must also take range lock,
+ * or multiple reads will try to work on the same pages
+ * See LU-6227 for details.
+ */
+ if (((iot == CIT_WRITE) ||
+ (iot == CIT_READ && (file->f_flags & O_DIRECT))) &&
+ !(vio->vui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
+ CDEBUG(D_VFSTRACE, "Range lock [%llu, %llu]\n",
+ range.rl_node.in_extent.start,
+ range.rl_node.in_extent.end);
+ result = range_lock(&lli->lli_write_tree,
+ &range);
+ if (result < 0)
+ goto out;
- switch (vio->vui_io_subtype) {
- case IO_NORMAL:
- vio->vui_iter = args->u.normal.via_iter;
- vio->vui_iocb = args->u.normal.via_iocb;
- /*
- * Direct IO reads must also take range lock,
- * or multiple reads will try to work on the same pages
- * See LU-6227 for details.
- */
- if (((iot == CIT_WRITE) ||
- (iot == CIT_READ && (file->f_flags & O_DIRECT))) &&
- !(vio->vui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
- CDEBUG(D_VFSTRACE, "Range lock [%llu, %llu]\n",
- range.rl_node.in_extent.start,
- range.rl_node.in_extent.end);
- result = range_lock(&lli->lli_write_tree,
- &range);
- if (result < 0)
- goto out;
-
- range_locked = true;
- }
- down_read(&lli->lli_trunc_sem);
- break;
- case IO_SPLICE:
- vio->u.splice.vui_pipe = args->u.splice.via_pipe;
- vio->u.splice.vui_flags = args->u.splice.via_flags;
- break;
- default:
- CERROR("Unknown IO type - %u\n", vio->vui_io_subtype);
- LBUG();
+ range_locked = true;
}
+ down_read(&lli->lli_trunc_sem);
ll_cl_add(file, env, io);
result = cl_io_loop(env, io);
ll_cl_remove(file, env);
- if (args->via_io_subtype == IO_NORMAL)
- up_read(&lli->lli_trunc_sem);
+ up_read(&lli->lli_trunc_sem);
if (range_locked) {
CDEBUG(D_VFSTRACE, "Range unlock [%llu, %llu]\n",
range.rl_node.in_extent.start,
@@ -1235,7 +1221,7 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
if (IS_ERR(env))
return PTR_ERR(env);
- args = ll_env_args(env, IO_NORMAL);
+ args = ll_env_args(env);
args->u.normal.via_iter = to;
args->u.normal.via_iocb = iocb;
@@ -1259,7 +1245,7 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (IS_ERR(env))
return PTR_ERR(env);
- args = ll_env_args(env, IO_NORMAL);
+ args = ll_env_args(env);
args->u.normal.via_iter = from;
args->u.normal.via_iocb = iocb;
@@ -1269,31 +1255,6 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
return result;
}
-/*
- * Send file content (through pagecache) somewhere with helper
- */
-static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t count,
- unsigned int flags)
-{
- struct lu_env *env;
- struct vvp_io_args *args;
- ssize_t result;
- int refcheck;
-
- env = cl_env_get(&refcheck);
- if (IS_ERR(env))
- return PTR_ERR(env);
-
- args = ll_env_args(env, IO_SPLICE);
- args->u.splice.via_pipe = pipe;
- args->u.splice.via_flags = flags;
-
- result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count);
- cl_env_put(env, &refcheck);
- return result;
-}
-
int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry,
__u64 flags, struct lov_user_md *lum,
int lum_size)
@@ -3267,7 +3228,7 @@ struct file_operations ll_file_operations = {
.release = ll_file_release,
.mmap = ll_file_mmap,
.llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
+ .splice_read = generic_file_splice_read,
.fsync = ll_fsync,
.flush = ll_flush
};
@@ -3280,7 +3241,7 @@ struct file_operations ll_file_operations_flock = {
.release = ll_file_release,
.mmap = ll_file_mmap,
.llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
+ .splice_read = generic_file_splice_read,
.fsync = ll_fsync,
.flush = ll_flush,
.flock = ll_file_flock,
@@ -3296,7 +3257,7 @@ struct file_operations ll_file_operations_noflock = {
.release = ll_file_release,
.mmap = ll_file_mmap,
.llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
+ .splice_read = generic_file_splice_read,
.fsync = ll_fsync,
.flush = ll_flush,
.flock = ll_file_noflock,
@@ -3307,10 +3268,7 @@ const struct inode_operations ll_file_inode_operations = {
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ll_listxattr,
- .removexattr = generic_removexattr,
.fiemap = ll_fiemap,
.get_acl = ll_get_acl,
};
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 3e98bd685061..4bc551279aa4 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -908,17 +908,11 @@ void vvp_write_complete(struct vvp_object *club, struct vvp_page *page);
*/
struct vvp_io_args {
/** normal/splice */
- enum vvp_io_subtype via_io_subtype;
-
union {
struct {
struct kiocb *via_iocb;
struct iov_iter *via_iter;
} normal;
- struct {
- struct pipe_inode_info *via_pipe;
- unsigned int via_flags;
- } splice;
} u;
};
@@ -946,14 +940,9 @@ static inline struct ll_thread_info *ll_env_info(const struct lu_env *env)
return lti;
}
-static inline struct vvp_io_args *ll_env_args(const struct lu_env *env,
- enum vvp_io_subtype type)
+static inline struct vvp_io_args *ll_env_args(const struct lu_env *env)
{
- struct vvp_io_args *via = &ll_env_info(env)->lti_args;
-
- via->via_io_subtype = type;
-
- return via;
+ return &ll_env_info(env)->lti_args;
}
void ll_queue_done_writing(struct inode *inode, unsigned long flags);
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 6bb41b09172e..e5c62f4ce3d8 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -1459,7 +1459,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
}
- /* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
+ /* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
if (attr->ia_valid & TIMES_SET_FLAGS) {
if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
!capable(CFS_CAP_FOWNER))
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index dfa36d34c645..180f35e3afd9 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -1097,13 +1097,17 @@ out:
}
static int ll_rename(struct inode *src, struct dentry *src_dchild,
- struct inode *tgt, struct dentry *tgt_dchild)
+ struct inode *tgt, struct dentry *tgt_dchild,
+ unsigned int flags)
{
struct ptlrpc_request *request = NULL;
struct ll_sb_info *sbi = ll_i2sbi(src);
struct md_op_data *op_data;
int err;
+ if (flags)
+ return -EINVAL;
+
CDEBUG(D_VFSTRACE,
"VFS Op:oldname=%pd, src_dir="DFID"(%p), newname=%pd, tgt_dir="DFID"(%p)\n",
src_dchild, PFID(ll_inode2fid(src)), src,
@@ -1148,14 +1152,11 @@ const struct inode_operations ll_dir_inode_operations = {
.rmdir = ll_rmdir,
.symlink = ll_symlink,
.link = ll_link,
- .rename = ll_rename,
+ .rename = ll_rename,
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ll_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ll_get_acl,
};
@@ -1163,9 +1164,6 @@ const struct inode_operations ll_special_inode_operations = {
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ll_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ll_get_acl,
};
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index f8bc7ed59646..82c7c48aa619 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -154,8 +154,5 @@ const struct inode_operations ll_fast_symlink_inode_operations = {
.get_link = ll_get_link,
.getattr = ll_getattr,
.permission = ll_inode_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ll_listxattr,
- .removexattr = generic_removexattr,
};
diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h
index 5802da81cd0e..4464ad258387 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_internal.h
+++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h
@@ -49,14 +49,6 @@ struct obd_device;
struct obd_export;
struct page;
-/* specific architecture can implement only part of this list */
-enum vvp_io_subtype {
- /** normal IO */
- IO_NORMAL,
- /** io started from splice_{read|write} */
- IO_SPLICE
-};
-
/**
* IO state private to IO state private to VVP layer.
*/
@@ -99,10 +91,6 @@ struct vvp_io {
bool ft_flags_valid;
} fault;
struct {
- struct pipe_inode_info *vui_pipe;
- unsigned int vui_flags;
- } splice;
- struct {
struct cl_page_list vui_queue;
unsigned long vui_written;
int vui_from;
@@ -110,8 +98,6 @@ struct vvp_io {
} write;
} u;
- enum vvp_io_subtype vui_io_subtype;
-
/**
* Layout version when this IO is initialized
*/
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index 2ab450359b6d..2b7f182a15e2 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -54,18 +54,6 @@ static struct vvp_io *cl2vvp_io(const struct lu_env *env,
}
/**
- * True, if \a io is a normal io, False for splice_{read,write}
- */
-static int cl_is_normalio(const struct lu_env *env, const struct cl_io *io)
-{
- struct vvp_io *vio = vvp_env_io(env);
-
- LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
-
- return vio->vui_io_subtype == IO_NORMAL;
-}
-
-/**
* For swapping layout. The file's layout may have changed.
* To avoid populating pages to a wrong stripe, we have to verify the
* correctness of layout. It works because swapping layout processes
@@ -390,9 +378,6 @@ static int vvp_mmap_locks(const struct lu_env *env,
LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
- if (!cl_is_normalio(env, io))
- return 0;
-
if (!vio->vui_iter) /* nfs or loop back device write */
return 0;
@@ -461,15 +446,10 @@ static void vvp_io_advance(const struct lu_env *env,
const struct cl_io_slice *ios,
size_t nob)
{
- struct vvp_io *vio = cl2vvp_io(env, ios);
- struct cl_io *io = ios->cis_io;
struct cl_object *obj = ios->cis_io->ci_obj;
-
+ struct vvp_io *vio = cl2vvp_io(env, ios);
CLOBINVRNT(env, obj, vvp_object_invariant(obj));
- if (!cl_is_normalio(env, io))
- return;
-
iov_iter_reexpand(vio->vui_iter, vio->vui_tot_count -= nob);
}
@@ -478,7 +458,7 @@ static void vvp_io_update_iov(const struct lu_env *env,
{
size_t size = io->u.ci_rw.crw_count;
- if (!cl_is_normalio(env, io) || !vio->vui_iter)
+ if (!vio->vui_iter)
return;
iov_iter_truncate(vio->vui_iter, size);
@@ -715,25 +695,8 @@ static int vvp_io_read_start(const struct lu_env *env,
/* BUG: 5972 */
file_accessed(file);
- switch (vio->vui_io_subtype) {
- case IO_NORMAL:
- LASSERT(vio->vui_iocb->ki_pos == pos);
- result = generic_file_read_iter(vio->vui_iocb, vio->vui_iter);
- break;
- case IO_SPLICE:
- result = generic_file_splice_read(file, &pos,
- vio->u.splice.vui_pipe, cnt,
- vio->u.splice.vui_flags);
- /* LU-1109: do splice read stripe by stripe otherwise if it
- * may make nfsd stuck if this read occupied all internal pipe
- * buffers.
- */
- io->ci_continue = 0;
- break;
- default:
- CERROR("Wrong IO type %u\n", vio->vui_io_subtype);
- LBUG();
- }
+ LASSERT(vio->vui_iocb->ki_pos == pos);
+ result = generic_file_read_iter(vio->vui_iocb, vio->vui_iter);
out:
if (result >= 0) {
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c
index 5d3995d5c69a..a7416cd9ac71 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -2220,7 +2220,7 @@ int sptlrpc_pack_user_desc(struct lustre_msg *msg, int offset)
task_lock(current);
if (pud->pud_ngroups > current_ngroups)
pud->pud_ngroups = current_ngroups;
- memcpy(pud->pud_groups, current_cred()->group_info->blocks[0],
+ memcpy(pud->pud_groups, current_cred()->group_info->gid,
pud->pud_ngroups * sizeof(__u32));
task_unlock(current);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
index e5945e2ccc49..b05b1f935e4c 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
@@ -3742,32 +3742,28 @@ void lustre_assert_wire_constants(void)
CLASSERT(FIEMAP_EXTENT_NET == 0x80000000);
/* Checks for type posix_acl_xattr_entry */
- LASSERTF((int)sizeof(posix_acl_xattr_entry) == 8, "found %lld\n",
- (long long)(int)sizeof(posix_acl_xattr_entry));
- LASSERTF((int)offsetof(posix_acl_xattr_entry, e_tag) == 0, "found %lld\n",
- (long long)(int)offsetof(posix_acl_xattr_entry, e_tag));
- LASSERTF((int)sizeof(((posix_acl_xattr_entry *)0)->e_tag) == 2, "found %lld\n",
- (long long)(int)sizeof(((posix_acl_xattr_entry *)0)->e_tag));
- LASSERTF((int)offsetof(posix_acl_xattr_entry, e_perm) == 2, "found %lld\n",
- (long long)(int)offsetof(posix_acl_xattr_entry, e_perm));
- LASSERTF((int)sizeof(((posix_acl_xattr_entry *)0)->e_perm) == 2, "found %lld\n",
- (long long)(int)sizeof(((posix_acl_xattr_entry *)0)->e_perm));
- LASSERTF((int)offsetof(posix_acl_xattr_entry, e_id) == 4, "found %lld\n",
- (long long)(int)offsetof(posix_acl_xattr_entry, e_id));
- LASSERTF((int)sizeof(((posix_acl_xattr_entry *)0)->e_id) == 4, "found %lld\n",
- (long long)(int)sizeof(((posix_acl_xattr_entry *)0)->e_id));
+ LASSERTF((int)sizeof(struct posix_acl_xattr_entry) == 8, "found %lld\n",
+ (long long)(int)sizeof(struct posix_acl_xattr_entry));
+ LASSERTF((int)offsetof(struct posix_acl_xattr_entry, e_tag) == 0, "found %lld\n",
+ (long long)(int)offsetof(struct posix_acl_xattr_entry, e_tag));
+ LASSERTF((int)sizeof(((struct posix_acl_xattr_entry *)0)->e_tag) == 2, "found %lld\n",
+ (long long)(int)sizeof(((struct posix_acl_xattr_entry *)0)->e_tag));
+ LASSERTF((int)offsetof(struct posix_acl_xattr_entry, e_perm) == 2, "found %lld\n",
+ (long long)(int)offsetof(struct posix_acl_xattr_entry, e_perm));
+ LASSERTF((int)sizeof(((struct posix_acl_xattr_entry *)0)->e_perm) == 2, "found %lld\n",
+ (long long)(int)sizeof(((struct posix_acl_xattr_entry *)0)->e_perm));
+ LASSERTF((int)offsetof(struct posix_acl_xattr_entry, e_id) == 4, "found %lld\n",
+ (long long)(int)offsetof(struct posix_acl_xattr_entry, e_id));
+ LASSERTF((int)sizeof(((struct posix_acl_xattr_entry *)0)->e_id) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct posix_acl_xattr_entry *)0)->e_id));
/* Checks for type posix_acl_xattr_header */
- LASSERTF((int)sizeof(posix_acl_xattr_header) == 4, "found %lld\n",
- (long long)(int)sizeof(posix_acl_xattr_header));
- LASSERTF((int)offsetof(posix_acl_xattr_header, a_version) == 0, "found %lld\n",
- (long long)(int)offsetof(posix_acl_xattr_header, a_version));
- LASSERTF((int)sizeof(((posix_acl_xattr_header *)0)->a_version) == 4, "found %lld\n",
- (long long)(int)sizeof(((posix_acl_xattr_header *)0)->a_version));
- LASSERTF((int)offsetof(posix_acl_xattr_header, a_entries) == 4, "found %lld\n",
- (long long)(int)offsetof(posix_acl_xattr_header, a_entries));
- LASSERTF((int)sizeof(((posix_acl_xattr_header *)0)->a_entries) == 0, "found %lld\n",
- (long long)(int)sizeof(((posix_acl_xattr_header *)0)->a_entries));
+ LASSERTF((int)sizeof(struct posix_acl_xattr_header) == 4, "found %lld\n",
+ (long long)(int)sizeof(struct posix_acl_xattr_header));
+ LASSERTF((int)offsetof(struct posix_acl_xattr_header, a_version) == 0, "found %lld\n",
+ (long long)(int)offsetof(struct posix_acl_xattr_header, a_version));
+ LASSERTF((int)sizeof(((struct posix_acl_xattr_header *)0)->a_version) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct posix_acl_xattr_header *)0)->a_version));
/* Checks for struct link_ea_header */
LASSERTF((int)sizeof(struct link_ea_header) == 24, "found %lld\n",
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e841a4e0e726..06fb39c1d6dd 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3187,11 +3187,11 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
pr_info("Console: switching ");
if (!deflt)
- printk("consoles %d-%d ", first+1, last+1);
+ printk(KERN_CONT "consoles %d-%d ", first+1, last+1);
if (j >= 0) {
struct vc_data *vc = vc_cons[j].d;
- printk("to %s %s %dx%d\n",
+ printk(KERN_CONT "to %s %s %dx%d\n",
vc->vc_can_do_color ? "colour" : "mono",
desc, vc->vc_cols, vc->vc_rows);
@@ -3200,7 +3200,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
update_screen(vc);
}
} else
- printk("to %s\n", desc);
+ printk(KERN_CONT "to %s\n", desc);
retval = 0;
err:
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 09c8d9ca61ae..4016dae7433b 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -2409,21 +2409,21 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: CONTROL\n", __func__);
ret = proc_control(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_BULK:
snoop(&dev->dev, "%s: BULK\n", __func__);
ret = proc_bulk(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_RESETEP:
snoop(&dev->dev, "%s: RESETEP\n", __func__);
ret = proc_resetep(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_RESET:
@@ -2435,7 +2435,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
ret = proc_clearhalt(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_GETDRIVER:
@@ -2462,7 +2462,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
ret = proc_submiturb(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
#ifdef CONFIG_COMPAT
@@ -2470,14 +2470,14 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: CONTROL32\n", __func__);
ret = proc_control_compat(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_BULK32:
snoop(&dev->dev, "%s: BULK32\n", __func__);
ret = proc_bulk_compat(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_DISCSIGNAL32:
@@ -2489,7 +2489,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
ret = proc_submiturb_compat(ps, p);
if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
break;
case USBDEVFS_IOCTL32:
@@ -2552,7 +2552,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
done:
usb_unlock_device(dev);
if (ret >= 0)
- inode->i_atime = CURRENT_TIME;
+ inode->i_atime = current_time(inode);
return ret;
}
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 530959a8a6d1..8e1728b39a49 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -182,6 +182,38 @@ static const struct dwc2_core_params params_ltq = {
.hibernation = -1,
};
+static const struct dwc2_core_params params_amlogic = {
+ .otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE,
+ .otg_ver = -1,
+ .dma_enable = 1,
+ .dma_desc_enable = 0,
+ .dma_desc_fs_enable = 0,
+ .speed = DWC2_SPEED_PARAM_HIGH,
+ .enable_dynamic_fifo = 1,
+ .en_multiple_tx_fifo = -1,
+ .host_rx_fifo_size = 512,
+ .host_nperio_tx_fifo_size = 500,
+ .host_perio_tx_fifo_size = 500,
+ .max_transfer_size = -1,
+ .max_packet_count = -1,
+ .host_channels = 16,
+ .phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
+ .phy_utmi_width = -1,
+ .phy_ulpi_ddr = -1,
+ .phy_ulpi_ext_vbus = -1,
+ .i2c_enable = -1,
+ .ulpi_fs_ls = -1,
+ .host_support_fs_ls_low_power = -1,
+ .host_ls_low_power_phy_clk = -1,
+ .ts_dline = -1,
+ .reload_ctl = 1,
+ .ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
+ GAHBCFG_HBSTLEN_SHIFT,
+ .uframe_sched = 0,
+ .external_id_pin_ctl = -1,
+ .hibernation = -1,
+};
+
/*
* Check the dr_mode against the module configuration and hardware
* capabilities.
@@ -486,6 +518,8 @@ static const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "lantiq,xrx200-usb", .data = &params_ltq },
{ .compatible = "snps,dwc2", .data = NULL },
{ .compatible = "samsung,s3c6400-hsotg", .data = NULL},
+ { .compatible = "amlogic,meson8b-usb", .data = &params_amlogic },
+ { .compatible = "amlogic,meson-gxbb-usb", .data = &params_amlogic },
{},
};
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 0aeed85bb5cb..54ad100af35b 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1196,15 +1196,15 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
inode = new_inode(sb);
if (likely(inode)) {
- struct timespec current_time = CURRENT_TIME;
+ struct timespec ts = current_time(inode);
inode->i_ino = get_next_ino();
inode->i_mode = perms->mode;
inode->i_uid = perms->uid;
inode->i_gid = perms->gid;
- inode->i_atime = current_time;
- inode->i_mtime = current_time;
- inode->i_ctime = current_time;
+ inode->i_atime = ts;
+ inode->i_mtime = ts;
+ inode->i_ctime = ts;
inode->i_private = data;
if (fops)
inode->i_fop = fops;
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 16104b5ebdcb..bd82dd12deff 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1913,7 +1913,7 @@ gadgetfs_make_inode (struct super_block *sb,
inode->i_uid = make_kuid(&init_user_ns, default_uid);
inode->i_gid = make_kgid(&init_user_ns, default_gid);
inode->i_atime = inode->i_mtime = inode->i_ctime
- = CURRENT_TIME;
+ = current_time(inode);
inode->i_private = data;
inode->i_fop = fops;
}
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 688691d9058d..65d4a3015542 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -70,7 +70,7 @@ static const u8 pci_cap_length[PCI_CAP_ID_MAX + 1] = {
/*
* Lengths of PCIe/PCI-X Extended Config Capabilities
- * 0: Removed or masked from the user visible capabilty list
+ * 0: Removed or masked from the user visible capability list
* FF: Variable length
*/
static const u16 pci_ext_cap_length[PCI_EXT_CAP_ID_MAX + 1] = {
@@ -355,7 +355,7 @@ static int alloc_perm_bits(struct perm_bits *perm, int size)
* ignore whether a read/write exceeds the defined capability
* structure. We can do this because:
* - Standard config space is already dword aligned
- * - Capabilities are all dword alinged (bits 0:1 of next reserved)
+ * - Capabilities are all dword aligned (bits 0:1 of next reserved)
* - Express capabilities defined as dword aligned
*/
size = round_up(size, 4);
@@ -804,6 +804,40 @@ static int __init init_pci_cap_pcix_perm(struct perm_bits *perm)
return 0;
}
+static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos,
+ int count, struct perm_bits *perm,
+ int offset, __le32 val)
+{
+ __le16 *ctrl = (__le16 *)(vdev->vconfig + pos -
+ offset + PCI_EXP_DEVCTL);
+
+ count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+ if (count < 0)
+ return count;
+
+ /*
+ * The FLR bit is virtualized, if set and the device supports PCIe
+ * FLR, issue a reset_function. Regardless, clear the bit, the spec
+ * requires it to be always read as zero. NB, reset_function might
+ * not use a PCIe FLR, we don't have that level of granularity.
+ */
+ if (*ctrl & cpu_to_le16(PCI_EXP_DEVCTL_BCR_FLR)) {
+ u32 cap;
+ int ret;
+
+ *ctrl &= ~cpu_to_le16(PCI_EXP_DEVCTL_BCR_FLR);
+
+ ret = pci_user_read_config_dword(vdev->pdev,
+ pos - offset + PCI_EXP_DEVCAP,
+ &cap);
+
+ if (!ret && (cap & PCI_EXP_DEVCAP_FLR))
+ pci_try_reset_function(vdev->pdev);
+ }
+
+ return count;
+}
+
/* Permissions for PCI Express capability */
static int __init init_pci_cap_exp_perm(struct perm_bits *perm)
{
@@ -811,26 +845,64 @@ static int __init init_pci_cap_exp_perm(struct perm_bits *perm)
if (alloc_perm_bits(perm, PCI_CAP_EXP_ENDPOINT_SIZEOF_V2))
return -ENOMEM;
+ perm->writefn = vfio_exp_config_write;
+
p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
/*
- * Allow writes to device control fields (includes FLR!)
- * but not to devctl_phantom which could confuse IOMMU
- * or to the ARI bit in devctl2 which is set at probe time
+ * Allow writes to device control fields, except devctl_phantom,
+ * which could confuse IOMMU, and the ARI bit in devctl2, which
+ * is set at probe time. FLR gets virtualized via our writefn.
*/
- p_setw(perm, PCI_EXP_DEVCTL, NO_VIRT, ~PCI_EXP_DEVCTL_PHANTOM);
+ p_setw(perm, PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_BCR_FLR, ~PCI_EXP_DEVCTL_PHANTOM);
p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI);
return 0;
}
+static int vfio_af_config_write(struct vfio_pci_device *vdev, int pos,
+ int count, struct perm_bits *perm,
+ int offset, __le32 val)
+{
+ u8 *ctrl = vdev->vconfig + pos - offset + PCI_AF_CTRL;
+
+ count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+ if (count < 0)
+ return count;
+
+ /*
+ * The FLR bit is virtualized, if set and the device supports AF
+ * FLR, issue a reset_function. Regardless, clear the bit, the spec
+ * requires it to be always read as zero. NB, reset_function might
+ * not use an AF FLR, we don't have that level of granularity.
+ */
+ if (*ctrl & PCI_AF_CTRL_FLR) {
+ u8 cap;
+ int ret;
+
+ *ctrl &= ~PCI_AF_CTRL_FLR;
+
+ ret = pci_user_read_config_byte(vdev->pdev,
+ pos - offset + PCI_AF_CAP,
+ &cap);
+
+ if (!ret && (cap & PCI_AF_CAP_FLR) && (cap & PCI_AF_CAP_TP))
+ pci_try_reset_function(vdev->pdev);
+ }
+
+ return count;
+}
+
/* Permissions for Advanced Function capability */
static int __init init_pci_cap_af_perm(struct perm_bits *perm)
{
if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_AF]))
return -ENOMEM;
+ perm->writefn = vfio_af_config_write;
+
p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
- p_setb(perm, PCI_AF_CTRL, NO_VIRT, PCI_AF_CTRL_FLR);
+ p_setb(perm, PCI_AF_CTRL, PCI_AF_CTRL_FLR, PCI_AF_CTRL_FLR);
return 0;
}
@@ -1516,10 +1588,10 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
* space which tracks reads and writes to bits that we emulate for
* the user. Initial values filled from device.
*
- * Using shared stuct perm_bits between all vfio-pci devices saves
+ * Using shared struct perm_bits between all vfio-pci devices saves
* us from allocating cfg_size buffers for virt and write for every
* device. We could remove vconfig and allocate individual buffers
- * for each area requring emulated bits, but the array of pointers
+ * for each area requiring emulated bits, but the array of pointers
* would be comparable in size (at least for standard config space).
*/
int vfio_config_init(struct vfio_pci_device *vdev)
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 152b43822ef1..c2e60893cd09 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -250,6 +250,7 @@ static irqreturn_t vfio_msihandler(int irq, void *arg)
static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
{
struct pci_dev *pdev = vdev->pdev;
+ unsigned int flag = msix ? PCI_IRQ_MSIX : PCI_IRQ_MSI;
int ret;
if (!is_irq_none(vdev))
@@ -259,35 +260,13 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
if (!vdev->ctx)
return -ENOMEM;
- if (msix) {
- int i;
-
- vdev->msix = kzalloc(nvec * sizeof(struct msix_entry),
- GFP_KERNEL);
- if (!vdev->msix) {
- kfree(vdev->ctx);
- return -ENOMEM;
- }
-
- for (i = 0; i < nvec; i++)
- vdev->msix[i].entry = i;
-
- ret = pci_enable_msix_range(pdev, vdev->msix, 1, nvec);
- if (ret < nvec) {
- if (ret > 0)
- pci_disable_msix(pdev);
- kfree(vdev->msix);
- kfree(vdev->ctx);
- return ret;
- }
- } else {
- ret = pci_enable_msi_range(pdev, 1, nvec);
- if (ret < nvec) {
- if (ret > 0)
- pci_disable_msi(pdev);
- kfree(vdev->ctx);
- return ret;
- }
+ /* return the number of supported vectors if we can't get all: */
+ ret = pci_alloc_irq_vectors(pdev, 1, nvec, flag);
+ if (ret < nvec) {
+ if (ret > 0)
+ pci_free_irq_vectors(pdev);
+ kfree(vdev->ctx);
+ return ret;
}
vdev->num_ctx = nvec;
@@ -315,7 +294,7 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
if (vector < 0 || vector >= vdev->num_ctx)
return -EINVAL;
- irq = msix ? vdev->msix[vector].vector : pdev->irq + vector;
+ irq = pci_irq_vector(pdev, vector);
if (vdev->ctx[vector].trigger) {
free_irq(irq, vdev->ctx[vector].trigger);
@@ -408,11 +387,14 @@ static void vfio_msi_disable(struct vfio_pci_device *vdev, bool msix)
vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
- if (msix) {
- pci_disable_msix(vdev->pdev);
- kfree(vdev->msix);
- } else
- pci_disable_msi(pdev);
+ pci_free_irq_vectors(pdev);
+
+ /*
+ * Both disable paths above use pci_intx_for_msi() to clear DisINTx
+ * via their shutdown paths. Restore for NoINTx devices.
+ */
+ if (vdev->nointx)
+ pci_intx(pdev, 0);
vdev->irq_type = VFIO_PCI_NUM_IRQS;
vdev->num_ctx = 0;
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 2128de86c80d..f561ac1c78a0 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -72,7 +72,6 @@ struct vfio_pci_device {
struct perm_bits *msi_perm;
spinlock_t irqlock;
struct mutex igate;
- struct msix_entry *msix;
struct vfio_pci_irq_ctx *ctx;
int num_ctx;
int irq_type;
diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
index d4030d0c38e9..bcd419cfd79c 100644
--- a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
+++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
@@ -56,7 +56,7 @@ static void xmdio_write(void *ioaddr, unsigned int mmd,
iowrite32(value, ioaddr + ((mmd_address & 0xff) << 2));
}
-int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
+static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
{
struct vfio_platform_region *xgmac_regs = &vdev->regions[0];
struct vfio_platform_region *xpcs_regs = &vdev->regions[1];
diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c
index e3d3d948e661..49e5df6e8f29 100644
--- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c
+++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c
@@ -57,7 +57,7 @@ static inline void xgmac_mac_disable(void __iomem *ioaddr)
writel(value, ioaddr + XGMAC_CONTROL);
}
-int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev)
+static int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev)
{
struct vfio_platform_region *reg = &vdev->regions[0];
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c
index 1cf2d462b53d..d78142830754 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -73,7 +73,7 @@ static int vfio_platform_acpi_probe(struct vfio_platform_device *vdev,
return WARN_ON(!vdev->acpihid) ? -EINVAL : 0;
}
-int vfio_platform_acpi_call_reset(struct vfio_platform_device *vdev,
+static int vfio_platform_acpi_call_reset(struct vfio_platform_device *vdev,
const char **extra_dbg)
{
#ifdef CONFIG_ACPI
@@ -95,7 +95,7 @@ int vfio_platform_acpi_call_reset(struct vfio_platform_device *vdev,
#endif
}
-bool vfio_platform_acpi_has_reset(struct vfio_platform_device *vdev)
+static bool vfio_platform_acpi_has_reset(struct vfio_platform_device *vdev)
{
#ifdef CONFIG_ACPI
struct device *dev = vdev->device;
@@ -637,7 +637,7 @@ static const struct vfio_device_ops vfio_platform_ops = {
.mmap = vfio_platform_mmap,
};
-int vfio_platform_of_probe(struct vfio_platform_device *vdev,
+static int vfio_platform_of_probe(struct vfio_platform_device *vdev,
struct device *dev)
{
int ret;
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index b2b366bb0f97..12614006211e 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -55,7 +55,7 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
dev_err(pb->dev, "failed to enable power supply\n");
if (pb->enable_gpio)
- gpiod_set_value(pb->enable_gpio, 1);
+ gpiod_set_value_cansleep(pb->enable_gpio, 1);
pwm_enable(pb->pwm);
pb->enabled = true;
@@ -70,7 +70,7 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
pwm_disable(pb->pwm);
if (pb->enable_gpio)
- gpiod_set_value(pb->enable_gpio, 0);
+ gpiod_set_value_cansleep(pb->enable_gpio, 0);
regulator_disable(pb->power_supply);
pb->enabled = false;
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 83742d806391..97067597e6bf 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -163,7 +163,6 @@ MODULE_DEVICE_TABLE(i2c, tosa_bl_id);
static struct i2c_driver tosa_bl_driver = {
.driver = {
.name = "tosa-bl",
- .owner = THIS_MODULE,
.pm = &tosa_bl_pm_ops,
},
.probe = tosa_bl_probe,
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 5b6a1743ea17..b3c2cc79c20d 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -276,32 +276,26 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
switch (handler->flags) {
case ACL_TYPE_ACCESS:
if (acl) {
- umode_t mode = inode->i_mode;
- retval = posix_acl_equiv_mode(acl, &mode);
- if (retval < 0)
+ struct iattr iattr;
+
+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+ if (retval)
goto err_out;
- else {
- struct iattr iattr;
- if (retval == 0) {
- /*
- * ACL can be represented
- * by the mode bits. So don't
- * update ACL.
- */
- acl = NULL;
- value = NULL;
- size = 0;
- }
- /* Updte the mode bits */
- iattr.ia_mode = ((mode & S_IALLUGO) |
- (inode->i_mode & ~S_IALLUGO));
- iattr.ia_valid = ATTR_MODE;
- /* FIXME should we update ctime ?
- * What is the following setxattr update the
- * mode ?
+ if (!acl) {
+ /*
+ * ACL can be represented
+ * by the mode bits. So don't
+ * update ACL.
*/
- v9fs_vfs_setattr_dotl(dentry, &iattr);
+ value = NULL;
+ size = 0;
}
+ iattr.ia_valid = ATTR_MODE;
+ /* FIXME should we update ctime ?
+ * What is the following setxattr update the
+ * mode ?
+ */
+ v9fs_vfs_setattr_dotl(dentry, &iattr);
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 6877050384a1..443d12e02043 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -148,7 +148,8 @@ extern struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags);
extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
struct super_block *sb, int new);
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8b1999b528e9..30ca770c5e0b 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -276,7 +276,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
inode_init_owner(inode, NULL, mode);
inode->i_blocks = 0;
inode->i_rdev = rdev;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_mapping->a_ops = &v9fs_addr_operations;
switch (mode & S_IFMT) {
@@ -955,7 +955,8 @@ int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
int
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
int retval;
struct inode *old_inode;
@@ -966,6 +967,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct p9_fid *newdirfid;
struct p9_wstat wstat;
+ if (flags)
+ return -EINVAL;
+
p9_debug(P9_DEBUG_VFS, "\n");
retval = 0;
old_inode = d_inode(old_dentry);
@@ -1094,7 +1098,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct p9_wstat wstat;
p9_debug(P9_DEBUG_VFS, "\n");
- retval = inode_change_ok(d_inode(dentry), iattr);
+ retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index eeabcb0bad12..afaa4b6de801 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -558,7 +558,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
p9_debug(P9_DEBUG_VFS, "\n");
- retval = inode_change_ok(inode, iattr);
+ retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;
@@ -967,9 +967,6 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = {
.rename = v9fs_vfs_rename,
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = v9fs_listxattr,
.get_acl = v9fs_iop_get_acl,
};
@@ -977,9 +974,6 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = {
const struct inode_operations v9fs_file_inode_operations_dotl = {
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = v9fs_listxattr,
.get_acl = v9fs_iop_get_acl,
};
@@ -989,8 +983,5 @@ const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.get_link = v9fs_vfs_get_link_dotl,
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = v9fs_listxattr,
};
diff --git a/fs/Kconfig b/fs/Kconfig
index 3ef62bad8f2b..4bd03a2b0518 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -200,6 +200,9 @@ config HUGETLBFS
config HUGETLB_PAGE
def_bool HUGETLBFS
+config ARCH_HAS_GIGANTIC_PAGE
+ bool
+
source "fs/configfs/Kconfig"
source "fs/efivarfs/Kconfig"
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 335055d828e4..8dbd36f5e581 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -199,7 +199,7 @@ adfs_adfs2unix_time(struct timespec *tv, struct inode *inode)
return;
cur_time:
- *tv = CURRENT_TIME;
+ *tv = current_time(inode);
return;
too_early:
@@ -303,7 +303,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid = attr->ia_valid;
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
/*
* we can't change the UID or GID of any file -
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index cc2b2efc9211..2f088773f1c0 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -173,7 +173,8 @@ extern int affs_link(struct dentry *olddentry, struct inode *dir,
extern int affs_symlink(struct inode *dir, struct dentry *dentry,
const char *symname);
extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags);
/* inode.c */
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index d8f217c711d3..0ec65c133b93 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -58,7 +58,7 @@ affs_insert_hash(struct inode *dir, struct buffer_head *bh)
mark_buffer_dirty_inode(dir_bh, dir);
affs_brelse(dir_bh);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
dir->i_version++;
mark_inode_dirty(dir);
@@ -112,7 +112,7 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
affs_brelse(bh);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
dir->i_version++;
mark_inode_dirty(dir);
@@ -313,7 +313,7 @@ affs_remove_header(struct dentry *dentry)
else
clear_nlink(inode);
affs_unlock_link(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
done:
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 0fdb0f5b2239..fe4e1290dbb5 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -219,7 +219,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);
- error = inode_change_ok(inode,attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out;
@@ -309,7 +309,7 @@ affs_new_inode(struct inode *dir)
inode->i_gid = current_fsgid();
inode->i_ino = block;
set_nlink(inode, 1);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL;
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index a2d68f828d53..29186d29a3b6 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -414,12 +414,16 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
int
affs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct super_block *sb = old_dir->i_sb;
struct buffer_head *bh = NULL;
int retval;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index eba541004d90..51a241e09fbb 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -38,7 +38,8 @@ static int afs_link(struct dentry *from, struct inode *dir,
static int afs_symlink(struct inode *dir, struct dentry *dentry,
const char *content);
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags);
const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
@@ -1083,12 +1084,16 @@ error:
* rename a file in an AFS filesystem and/or move it between directories
*/
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
struct key *key;
int ret;
+ if (flags)
+ return -EINVAL;
+
vnode = AFS_FS_I(d_inode(old_dentry));
orig_dvnode = AFS_FS_I(old_dir);
new_dvnode = AFS_FS_I(new_dir);
diff --git a/fs/aio.c b/fs/aio.c
index 4fe81d1c60f9..1157e13a36d6 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -274,14 +274,17 @@ __initcall(aio_setup);
static void put_aio_ring_file(struct kioctx *ctx)
{
struct file *aio_ring_file = ctx->aio_ring_file;
+ struct address_space *i_mapping;
+
if (aio_ring_file) {
truncate_setsize(aio_ring_file->f_inode, 0);
/* Prevent further access to the kioctx from migratepages */
- spin_lock(&aio_ring_file->f_inode->i_mapping->private_lock);
- aio_ring_file->f_inode->i_mapping->private_data = NULL;
+ i_mapping = aio_ring_file->f_inode->i_mapping;
+ spin_lock(&i_mapping->private_lock);
+ i_mapping->private_data = NULL;
ctx->aio_ring_file = NULL;
- spin_unlock(&aio_ring_file->f_inode->i_mapping->private_lock);
+ spin_unlock(&i_mapping->private_lock);
fput(aio_ring_file);
}
diff --git a/fs/attr.c b/fs/attr.c
index 42bb42bb3c72..c902b3d53508 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -17,19 +17,22 @@
#include <linux/ima.h>
/**
- * inode_change_ok - check if attribute changes to an inode are allowed
- * @inode: inode to check
+ * setattr_prepare - check if attribute changes to a dentry are allowed
+ * @dentry: dentry to check
* @attr: attributes to change
*
* Check if we are allowed to change the attributes contained in @attr
- * in the given inode. This includes the normal unix access permission
- * checks, as well as checks for rlimits and others.
+ * in the given dentry. This includes the normal unix access permission
+ * checks, as well as checks for rlimits and others. The function also clears
+ * SGID bit from mode if user is not allowed to set it. Also file capabilities
+ * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
*
* Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks.
*/
-int inode_change_ok(const struct inode *inode, struct iattr *attr)
+int setattr_prepare(struct dentry *dentry, struct iattr *attr)
{
+ struct inode *inode = d_inode(dentry);
unsigned int ia_valid = attr->ia_valid;
/*
@@ -44,7 +47,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
- return 0;
+ goto kill_priv;
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
@@ -77,9 +80,19 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return -EPERM;
}
+kill_priv:
+ /* User has permission for the change */
+ if (ia_valid & ATTR_KILL_PRIV) {
+ int error;
+
+ error = security_inode_killpriv(dentry);
+ if (error)
+ return error;
+ }
+
return 0;
}
-EXPORT_SYMBOL(inode_change_ok);
+EXPORT_SYMBOL(setattr_prepare);
/**
* inode_newsize_ok - may this inode be truncated to a given size
@@ -202,6 +215,21 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
return -EPERM;
}
+ /*
+ * If utimes(2) and friends are called with times == NULL (or both
+ * times are UTIME_NOW), then we need to check for write permission
+ */
+ if (ia_valid & ATTR_TOUCH) {
+ if (IS_IMMUTABLE(inode))
+ return -EPERM;
+
+ if (!inode_owner_or_capable(inode)) {
+ error = inode_permission(inode, MAY_WRITE);
+ if (error)
+ return error;
+ }
+ }
+
if ((ia_valid & ATTR_MODE)) {
umode_t amode = attr->ia_mode;
/* Flag setting protected by i_mutex */
@@ -209,7 +237,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
inode->i_flags &= ~S_NOSEC;
}
- now = current_fs_time(inode->i_sb);
+ now = current_time(inode);
attr->ia_ctime = now;
if (!(ia_valid & ATTR_ATIME_SET))
@@ -217,13 +245,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
if (!(ia_valid & ATTR_MTIME_SET))
attr->ia_mtime = now;
if (ia_valid & ATTR_KILL_PRIV) {
- attr->ia_valid &= ~ATTR_KILL_PRIV;
- ia_valid &= ~ATTR_KILL_PRIV;
error = security_inode_need_killpriv(dentry);
- if (error > 0)
- error = security_inode_killpriv(dentry);
- if (error)
+ if (error < 0)
return error;
+ if (error == 0)
+ ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
}
/*
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 61b21051bd5a..ca9cbd6362e0 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -359,7 +359,7 @@ struct inode *autofs4_get_inode(struct super_block *sb, umode_t mode)
inode->i_uid = d_inode(sb->s_root)->i_uid;
inode->i_gid = d_inode(sb->s_root)->i_gid;
}
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_ino = get_next_ino();
if (S_ISDIR(mode)) {
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index fa84bb8832e0..623510e84c96 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -591,7 +591,7 @@ static int autofs4_dir_symlink(struct inode *dir,
if (p_ino && !IS_ROOT(dentry))
atomic_inc(&p_ino->count);
- dir->i_mtime = CURRENT_TIME;
+ dir->i_mtime = current_time(dir);
return 0;
}
@@ -631,7 +631,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
d_inode(dentry)->i_size = 0;
clear_nlink(d_inode(dentry));
- dir->i_mtime = CURRENT_TIME;
+ dir->i_mtime = current_time(dir);
spin_lock(&sbi->lookup_lock);
__autofs4_add_expiring(dentry);
@@ -762,7 +762,7 @@ static int autofs4_dir_mkdir(struct inode *dir,
if (p_ino && !IS_ROOT(dentry))
atomic_inc(&p_ino->count);
inc_nlink(dir);
- dir->i_mtime = CURRENT_TIME;
+ dir->i_mtime = current_time(dir);
return 0;
}
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 3ba385eaa26e..8712062275b8 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -100,29 +100,12 @@ static int bad_inode_setattr(struct dentry *direntry, struct iattr *attrs)
return -EIO;
}
-static int bad_inode_setxattr(struct dentry *dentry, struct inode *inode,
- const char *name, const void *value, size_t size, int flags)
-{
- return -EIO;
-}
-
-static ssize_t bad_inode_getxattr(struct dentry *dentry, struct inode *inode,
- const char *name, void *buffer, size_t size)
-{
- return -EIO;
-}
-
static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer,
size_t buffer_size)
{
return -EIO;
}
-static int bad_inode_removexattr(struct dentry *dentry, const char *name)
-{
- return -EIO;
-}
-
static const struct inode_operations bad_inode_ops =
{
.create = bad_inode_create,
@@ -133,7 +116,7 @@ static const struct inode_operations bad_inode_ops =
.mkdir = bad_inode_mkdir,
.rmdir = bad_inode_rmdir,
.mknod = bad_inode_mknod,
- .rename2 = bad_inode_rename2,
+ .rename = bad_inode_rename2,
.readlink = bad_inode_readlink,
/* follow_link must be no-op, otherwise unmounting this inode
won't work */
@@ -142,10 +125,7 @@ static const struct inode_operations bad_inode_ops =
.permission = bad_inode_permission,
.getattr = bad_inode_getattr,
.setattr = bad_inode_setattr,
- .setxattr = bad_inode_setxattr,
- .getxattr = bad_inode_getxattr,
.listxattr = bad_inode_listxattr,
- .removexattr = bad_inode_removexattr,
};
@@ -173,8 +153,9 @@ void make_bad_inode(struct inode *inode)
inode->i_mode = S_IFREG;
inode->i_atime = inode->i_mtime = inode->i_ctime =
- current_fs_time(inode->i_sb);
+ current_time(inode);
inode->i_op = &bad_inode_ops;
+ inode->i_opflags &= ~IOP_XATTR;
inode->i_fop = &bad_file_ops;
}
EXPORT_SYMBOL(make_bad_inode);
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 7da05b159ade..bfe9f9994935 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -789,7 +789,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
* Will be set to real fs blocksize later.
*
* Linux 2.4.10 and later refuse to read blocks smaller than
- * the hardsect size for the device. But we also need to read at
+ * the logical block size for the device. But we also need to read at
* least 1k to get the second 512 bytes of the volume.
* -WD 10-26-01
*/
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 34a5bc2f1290..3e5ac30e8b6f 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -97,7 +97,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
set_bit(ino, info->si_imap);
info->si_freei--;
inode_init_owner(inode, dir, mode);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_blocks = 0;
inode->i_op = &bfs_file_inops;
inode->i_fop = &bfs_file_operations;
@@ -165,7 +165,7 @@ static int bfs_link(struct dentry *old, struct inode *dir,
return err;
}
inc_nlink(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
ihold(inode);
d_instantiate(new, inode);
@@ -194,7 +194,7 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry)
}
de->ino = 0;
mark_buffer_dirty_inode(bh, dir);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
inode->i_ctime = dir->i_ctime;
inode_dec_link_count(inode);
@@ -207,7 +207,8 @@ out_brelse:
}
static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *old_inode, *new_inode;
struct buffer_head *old_bh, *new_bh;
@@ -215,6 +216,9 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct bfs_sb_info *info;
int error = -ENOENT;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
old_bh = new_bh = NULL;
old_inode = d_inode(old_dentry);
if (S_ISDIR(old_inode->i_mode))
@@ -249,10 +253,10 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto end_rename;
}
old_de->ino = 0;
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
mark_inode_dirty(old_dir);
if (new_inode) {
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = current_time(new_inode);
inode_dec_link_count(new_inode);
}
mark_buffer_dirty_inode(old_bh, old_dir);
@@ -300,9 +304,9 @@ static int bfs_add_entry(struct inode *dir, const unsigned char *name,
pos = (block - sblock) * BFS_BSIZE + off;
if (pos >= dir->i_size) {
dir->i_size += BFS_DIRENT_SIZE;
- dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_ctime = current_time(dir);
}
- dir->i_mtime = CURRENT_TIME_SEC;
+ dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
de->ino = cpu_to_le16((u16)ino);
for (i = 0; i < BFS_NAMELEN; i++)
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 6103a6362ccd..9b4688ab1d8e 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -584,7 +584,7 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime =
- current_fs_time(inode->i_sb);
+ current_time(inode);
}
return inode;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 08ae99343d92..376e4e426324 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -180,9 +180,6 @@ blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
struct file *file = iocb->ki_filp;
struct inode *inode = bdev_file_inode(file);
- if (IS_DAX(inode))
- return dax_do_io(iocb, inode, iter, blkdev_get_block,
- NULL, DIO_SKIP_DIO_COUNT);
return __blockdev_direct_IO(iocb, inode, I_BDEV(inode), iter,
blkdev_get_block, NULL, NULL,
DIO_SKIP_DIO_COUNT);
@@ -302,14 +299,11 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb)
error = sb->s_op->thaw_super(sb);
else
error = thaw_super(sb);
- if (error) {
+ if (error)
bdev->bd_fsfreeze_count++;
- mutex_unlock(&bdev->bd_fsfreeze_mutex);
- return error;
- }
out:
mutex_unlock(&bdev->bd_fsfreeze_mutex);
- return 0;
+ return error;
}
EXPORT_SYMBOL(thaw_bdev);
@@ -1275,7 +1269,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
bdev->bd_disk = disk;
bdev->bd_queue = disk->queue;
bdev->bd_contains = bdev;
- bdev->bd_inode->i_flags = 0;
if (!partno) {
ret = -ENXIO;
@@ -1303,11 +1296,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
}
}
- if (!ret) {
+ if (!ret)
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
- if (!bdev_dax_capable(bdev))
- bdev->bd_inode->i_flags &= ~S_DAX;
- }
/*
* If the device is invalidated, rescan partition
@@ -1342,8 +1332,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
goto out_clear;
}
bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
- if (!bdev_dax_capable(bdev))
- bdev->bd_inode->i_flags &= ~S_DAX;
}
} else {
if (bdev->bd_contains == bdev) {
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 53bb7af4e5f0..247b8dfaf6e5 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -79,11 +79,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (ret < 0)
+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (ret)
return ret;
- if (ret == 0)
- acl = NULL;
}
ret = 0;
break;
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 33fe03551105..e62fd50237e4 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3161,7 +3161,6 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
struct btrfs_trans_handle *trans, int mode,
u64 start, u64 num_bytes, u64 min_size,
loff_t actual_len, u64 *alloc_hint);
-int btrfs_inode_check_errors(struct inode *inode);
extern const struct dentry_operations btrfs_dentry_operations;
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
void btrfs_test_inode_set_ops(struct inode *inode);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index fea31a4a6e36..36f4589e349c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1757,7 +1757,7 @@ static void update_time_for_write(struct inode *inode)
if (IS_NOCMTIME(inode))
return;
- now = current_fs_time(inode->i_sb);
+ now = current_time(inode);
if (!timespec_equal(&inode->i_mtime, &now))
inode->i_mtime = now;
@@ -2040,7 +2040,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
* flags for any errors that might have happened while doing
* writeback of file data.
*/
- ret = btrfs_inode_check_errors(inode);
+ ret = filemap_check_errors(inode->i_mapping);
inode_unlock(inode);
goto out;
}
@@ -2578,7 +2578,7 @@ out_trans:
goto out_free;
inode_inc_iversion(inode);
- inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_mtime = inode->i_ctime = current_time(inode);
trans->block_rsv = &root->fs_info->trans_block_rsv;
ret = btrfs_update_inode(trans, root, inode);
@@ -2842,7 +2842,7 @@ static long btrfs_fallocate(struct file *file, int mode,
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
} else {
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
i_size_write(inode, actual_end);
btrfs_ordered_update_i_size(inode, actual_end, NULL);
ret = btrfs_update_inode(trans, root, inode);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index e6811c42e41e..22a7ca43c7cd 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4059,7 +4059,7 @@ err:
inode_inc_iversion(inode);
inode_inc_iversion(dir);
inode->i_ctime = dir->i_mtime =
- dir->i_ctime = current_fs_time(inode->i_sb);
+ dir->i_ctime = current_time(inode);
ret = btrfs_update_inode(trans, root, dir);
out:
return ret;
@@ -4202,7 +4202,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
btrfs_i_size_write(dir, dir->i_size - name_len * 2);
inode_inc_iversion(dir);
- dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+ dir->i_mtime = dir->i_ctime = current_time(dir);
ret = btrfs_update_inode_fallback(trans, root, dir);
if (ret)
btrfs_abort_transaction(trans, ret);
@@ -4965,7 +4965,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
inode_inc_iversion(inode);
if (!(mask & (ATTR_CTIME | ATTR_MTIME)))
inode->i_ctime = inode->i_mtime =
- current_fs_time(inode->i_sb);
+ current_time(inode);
}
if (newsize > oldsize) {
@@ -5072,7 +5072,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
if (btrfs_root_readonly(root))
return -EROFS;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
@@ -5672,7 +5672,7 @@ static struct inode *new_simple_dir(struct super_block *s,
inode->i_op = &btrfs_dir_ro_inode_operations;
inode->i_fop = &simple_dir_operations;
inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
- inode->i_mtime = current_fs_time(inode->i_sb);
+ inode->i_mtime = current_time(inode);
inode->i_atime = inode->i_mtime;
inode->i_ctime = inode->i_mtime;
BTRFS_I(inode)->i_otime = inode->i_mtime;
@@ -6258,7 +6258,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
inode_init_owner(inode, dir, mode);
inode_set_bytes(inode, 0);
- inode->i_mtime = current_fs_time(inode->i_sb);
+ inode->i_mtime = current_time(inode);
inode->i_atime = inode->i_mtime;
inode->i_ctime = inode->i_mtime;
BTRFS_I(inode)->i_otime = inode->i_mtime;
@@ -6372,7 +6372,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
name_len * 2);
inode_inc_iversion(parent_inode);
parent_inode->i_mtime = parent_inode->i_ctime =
- current_fs_time(parent_inode->i_sb);
+ current_time(parent_inode);
ret = btrfs_update_inode(trans, root, parent_inode);
if (ret)
btrfs_abort_transaction(trans, ret);
@@ -6590,7 +6590,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
BTRFS_I(inode)->dir_index = 0ULL;
inc_nlink(inode);
inode_inc_iversion(inode);
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
ihold(inode);
set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
@@ -8412,7 +8412,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
if (!bio)
return -ENOMEM;
- bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_opf);
+ bio_set_op_attrs(bio, bio_op(orig_bio), bio_flags(orig_bio));
bio->bi_private = dip;
bio->bi_end_io = btrfs_end_dio_bio;
btrfs_io_bio(bio)->logical = file_offset;
@@ -8450,7 +8450,8 @@ next_block:
start_sector, GFP_NOFS);
if (!bio)
goto out_err;
- bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_opf);
+ bio_set_op_attrs(bio, bio_op(orig_bio),
+ bio_flags(orig_bio));
bio->bi_private = dip;
bio->bi_end_io = btrfs_end_dio_bio;
btrfs_io_bio(bio)->logical = file_offset;
@@ -8618,7 +8619,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, struct kiocb *iocb,
goto out;
/* If this is a write we don't need to check anymore */
- if (iov_iter_rw(iter) == WRITE)
+ if (iov_iter_rw(iter) != READ || !iter_is_iovec(iter))
return 0;
/*
* Check to make sure we don't have duplicate iov_base's in this
@@ -9492,7 +9493,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
struct btrfs_root *dest = BTRFS_I(new_dir)->root;
struct inode *new_inode = new_dentry->d_inode;
struct inode *old_inode = old_dentry->d_inode;
- struct timespec ctime = CURRENT_TIME;
+ struct timespec ctime = current_time(old_inode);
struct dentry *parent;
u64 old_ino = btrfs_ino(old_inode);
u64 new_ino = btrfs_ino(new_inode);
@@ -9860,7 +9861,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
inode_inc_iversion(old_inode);
old_dir->i_ctime = old_dir->i_mtime =
new_dir->i_ctime = new_dir->i_mtime =
- old_inode->i_ctime = current_fs_time(old_dir->i_sb);
+ old_inode->i_ctime = current_time(old_dir);
if (old_dentry->d_parent != new_dentry->d_parent)
btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
@@ -9885,7 +9886,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_inode) {
inode_inc_iversion(new_inode);
- new_inode->i_ctime = current_fs_time(new_inode->i_sb);
+ new_inode->i_ctime = current_time(new_inode);
if (unlikely(btrfs_ino(new_inode) ==
BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
root_objectid = BTRFS_I(new_inode)->location.objectid;
@@ -10403,7 +10404,7 @@ next:
*alloc_hint = ins.objectid + ins.offset;
inode_inc_iversion(inode);
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC;
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
(actual_len > inode->i_size) &&
@@ -10543,21 +10544,6 @@ out_inode:
}
-/* Inspired by filemap_check_errors() */
-int btrfs_inode_check_errors(struct inode *inode)
-{
- int ret = 0;
-
- if (test_bit(AS_ENOSPC, &inode->i_mapping->flags) &&
- test_and_clear_bit(AS_ENOSPC, &inode->i_mapping->flags))
- ret = -ENOSPC;
- if (test_bit(AS_EIO, &inode->i_mapping->flags) &&
- test_and_clear_bit(AS_EIO, &inode->i_mapping->flags))
- ret = -EIO;
-
- return ret;
-}
-
static const struct inode_operations btrfs_dir_inode_operations = {
.getattr = btrfs_getattr,
.lookup = btrfs_lookup,
@@ -10566,14 +10552,11 @@ static const struct inode_operations btrfs_dir_inode_operations = {
.link = btrfs_link,
.mkdir = btrfs_mkdir,
.rmdir = btrfs_rmdir,
- .rename2 = btrfs_rename2,
+ .rename = btrfs_rename2,
.symlink = btrfs_symlink,
.setattr = btrfs_setattr,
.mknod = btrfs_mknod,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
.permission = btrfs_permission,
.get_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
@@ -10647,10 +10630,7 @@ static const struct address_space_operations btrfs_symlink_aops = {
static const struct inode_operations btrfs_file_inode_operations = {
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
.permission = btrfs_permission,
.fiemap = btrfs_fiemap,
.get_acl = btrfs_get_acl,
@@ -10661,10 +10641,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.permission = btrfs_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
.get_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
@@ -10675,10 +10652,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.permission = btrfs_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
- .removexattr = generic_removexattr,
.update_time = btrfs_update_time,
};
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 7fd939bfbd99..b182197f7091 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -349,7 +349,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
btrfs_update_iflags(inode);
inode_inc_iversion(inode);
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
ret = btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
@@ -445,7 +445,7 @@ static noinline int create_subvol(struct inode *dir,
struct btrfs_root *root = BTRFS_I(dir)->root;
struct btrfs_root *new_root;
struct btrfs_block_rsv block_rsv;
- struct timespec cur_time = current_fs_time(dir->i_sb);
+ struct timespec cur_time = current_time(dir);
struct inode *inode;
int ret;
int err;
@@ -3291,7 +3291,7 @@ static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
inode_inc_iversion(inode);
if (!no_time_update)
- inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_mtime = inode->i_ctime = current_time(inode);
/*
* We round up to the block size at eof when determining which
* extents to clone above, but shouldn't round up the file size.
@@ -5106,7 +5106,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_root_item *root_item = &root->root_item;
struct btrfs_trans_handle *trans;
- struct timespec ct = current_fs_time(inode->i_sb);
+ struct timespec ct = current_time(inode);
int ret = 0;
int received_uuid_changed;
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index a87675ffd02b..1379e59277e2 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -4329,7 +4329,7 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key,
int ret;
struct send_ctx *sctx = ctx;
struct fs_path *p;
- posix_acl_xattr_header dummy_acl;
+ struct posix_acl_xattr_header dummy_acl;
p = fs_path_alloc();
if (!p)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 95d41919d034..c294313ea2c8 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1474,7 +1474,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
parent_root = BTRFS_I(parent_inode)->root;
record_root_in_trans(trans, parent_root, 0);
- cur_time = current_fs_time(parent_inode->i_sb);
+ cur_time = current_time(parent_inode);
/*
* insert the directory item
@@ -1630,7 +1630,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
btrfs_i_size_write(parent_inode, parent_inode->i_size +
dentry->d_name.len * 2);
parent_inode->i_mtime = parent_inode->i_ctime =
- current_fs_time(parent_inode->i_sb);
+ current_time(parent_inode);
ret = btrfs_update_inode_fallback(trans, parent_root, parent_inode);
if (ret) {
btrfs_abort_transaction(trans, ret);
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index ef9c55bc7907..8a84ebd8e7cc 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3961,7 +3961,7 @@ static int wait_ordered_extents(struct btrfs_trans_handle *trans,
* i_mapping flags, so that the next fsync won't get
* an outdated io error too.
*/
- btrfs_inode_check_errors(inode);
+ filemap_check_errors(inode->i_mapping);
*ordered_io_error = true;
break;
}
@@ -4198,7 +4198,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
* without writing to the log tree and the fsync must report the
* file data write error and not commit the current transaction.
*/
- ret = btrfs_inode_check_errors(inode);
+ ret = filemap_check_errors(inode->i_mapping);
if (ret)
ctx->io_err = ret;
process:
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index d1a177a3dbe8..fccbf5567e78 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -252,7 +252,7 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans,
goto out;
inode_inc_iversion(inode);
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
diff --git a/fs/buffer.c b/fs/buffer.c
index 9c8eb9b6db6a..7dad8713fac8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1078,7 +1078,7 @@ grow_buffers(struct block_device *bdev, sector_t block, int size, gfp_t gfp)
return grow_dev_page(bdev, block, index, size, sizebits, gfp);
}
-struct buffer_head *
+static struct buffer_head *
__getblk_slow(struct block_device *bdev, sector_t block,
unsigned size, gfp_t gfp)
{
@@ -1109,7 +1109,6 @@ __getblk_slow(struct block_device *bdev, sector_t block,
free_more_memory();
}
}
-EXPORT_SYMBOL(__getblk_slow);
/*
* The relationship between dirty buffers and dirty pages:
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c
index 6af790fc3df8..3ff867f87d73 100644
--- a/fs/cachefiles/bind.c
+++ b/fs/cachefiles/bind.c
@@ -20,6 +20,7 @@
#include <linux/mount.h>
#include <linux/statfs.h>
#include <linux/ctype.h>
+#include <linux/xattr.h>
#include "internal.h"
static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches);
@@ -126,8 +127,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
if (d_is_negative(root) ||
!d_backing_inode(root)->i_op->lookup ||
!d_backing_inode(root)->i_op->mkdir ||
- !d_backing_inode(root)->i_op->setxattr ||
- !d_backing_inode(root)->i_op->getxattr ||
+ !(d_backing_inode(root)->i_opflags & IOP_XATTR) ||
!root->d_sb->s_op->statfs ||
!root->d_sb->s_op->sync_fs)
goto error_unsupported;
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index ce5f345d70f5..e7f16a77a22a 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -253,6 +253,8 @@ static void cachefiles_drop_object(struct fscache_object *_object)
struct cachefiles_object *object;
struct cachefiles_cache *cache;
const struct cred *saved_cred;
+ struct inode *inode;
+ blkcnt_t i_blocks = 0;
ASSERT(_object);
@@ -279,6 +281,10 @@ static void cachefiles_drop_object(struct fscache_object *_object)
_object != cache->cache.fsdef
) {
_debug("- retire object OBJ%x", object->fscache.debug_id);
+ inode = d_backing_inode(object->dentry);
+ if (inode)
+ i_blocks = inode->i_blocks;
+
cachefiles_begin_secure(cache, &saved_cred);
cachefiles_delete_object(cache, object);
cachefiles_end_secure(cache, saved_cred);
@@ -292,7 +298,7 @@ static void cachefiles_drop_object(struct fscache_object *_object)
/* note that the object is now inactive */
if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags))
- cachefiles_mark_object_inactive(cache, object);
+ cachefiles_mark_object_inactive(cache, object, i_blocks);
dput(object->dentry);
object->dentry = NULL;
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
index 2fcde1a34b7c..cd1effee8a49 100644
--- a/fs/cachefiles/internal.h
+++ b/fs/cachefiles/internal.h
@@ -160,7 +160,8 @@ extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type);
* namei.c
*/
extern void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
- struct cachefiles_object *object);
+ struct cachefiles_object *object,
+ blkcnt_t i_blocks);
extern int cachefiles_delete_object(struct cachefiles_cache *cache,
struct cachefiles_object *object);
extern int cachefiles_walk_to_object(struct cachefiles_object *parent,
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 3f7c2cd41f8f..41df8a27d7eb 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -20,6 +20,7 @@
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/slab.h>
+#include <linux/xattr.h>
#include "internal.h"
#define CACHEFILES_KEYBUF_SIZE 512
@@ -261,10 +262,9 @@ requeue:
* Mark an object as being inactive.
*/
void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
- struct cachefiles_object *object)
+ struct cachefiles_object *object,
+ blkcnt_t i_blocks)
{
- blkcnt_t i_blocks = d_backing_inode(object->dentry)->i_blocks;
-
write_lock(&cache->active_lock);
rb_erase(&object->active_node, &cache->active_nodes);
clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
@@ -707,7 +707,8 @@ mark_active_timed_out:
check_error:
_debug("check error %d", ret);
- cachefiles_mark_object_inactive(cache, object);
+ cachefiles_mark_object_inactive(
+ cache, object, d_backing_inode(object->dentry)->i_blocks);
release_dentry:
dput(object->dentry);
object->dentry = NULL;
@@ -799,13 +800,11 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
}
ret = -EPERM;
- if (!d_backing_inode(subdir)->i_op->setxattr ||
- !d_backing_inode(subdir)->i_op->getxattr ||
+ if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) ||
!d_backing_inode(subdir)->i_op->lookup ||
!d_backing_inode(subdir)->i_op->mkdir ||
!d_backing_inode(subdir)->i_op->create ||
- (!d_backing_inode(subdir)->i_op->rename &&
- !d_backing_inode(subdir)->i_op->rename2) ||
+ !d_backing_inode(subdir)->i_op->rename ||
!d_backing_inode(subdir)->i_op->rmdir ||
!d_backing_inode(subdir)->i_op->unlink)
goto check_error;
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
index 4f67227f69a5..987044bca1c2 100644
--- a/fs/ceph/acl.c
+++ b/fs/ceph/acl.c
@@ -95,11 +95,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- ret = posix_acl_equiv_mode(acl, &new_mode);
- if (ret < 0)
+ ret = posix_acl_update_mode(inode, &new_mode, &acl);
+ if (ret)
goto out;
- if (ret == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
@@ -127,6 +125,11 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
goto out_free;
}
+ if (ceph_snap(inode) != CEPH_NOSNAP) {
+ ret = -EROFS;
+ goto out_free;
+ }
+
if (new_mode != old_mode) {
newattrs.ia_mode = new_mode;
newattrs.ia_valid = ATTR_MODE;
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index d5b6f959a3c3..ef3ebd780aff 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -175,9 +175,8 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset,
static int ceph_releasepage(struct page *page, gfp_t g)
{
- dout("%p releasepage %p idx %lu\n", page->mapping->host,
- page, page->index);
- WARN_ON(PageDirty(page));
+ dout("%p releasepage %p idx %lu (%sdirty)\n", page->mapping->host,
+ page, page->index, PageDirty(page) ? "" : "not ");
/* Can we release the page from the cache? */
if (!ceph_release_fscache_page(page, g))
@@ -298,14 +297,6 @@ unlock:
kfree(osd_data->pages);
}
-static void ceph_unlock_page_vector(struct page **pages, int num_pages)
-{
- int i;
-
- for (i = 0; i < num_pages; i++)
- unlock_page(pages[i]);
-}
-
/*
* start an async read(ahead) operation. return nr_pages we submitted
* a read for on success, or negative error code.
@@ -370,6 +361,10 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max)
dout("start_read %p add_to_page_cache failed %p\n",
inode, page);
nr_pages = i;
+ if (nr_pages > 0) {
+ len = nr_pages << PAGE_SHIFT;
+ break;
+ }
goto out_pages;
}
pages[i] = page;
@@ -386,8 +381,11 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max)
return nr_pages;
out_pages:
- ceph_unlock_page_vector(pages, nr_pages);
- ceph_release_page_vector(pages, nr_pages);
+ for (i = 0; i < nr_pages; ++i) {
+ ceph_fscache_readpage_cancel(inode, pages[i]);
+ unlock_page(pages[i]);
+ }
+ ceph_put_page_vector(pages, nr_pages, false);
out:
ceph_osdc_put_request(req);
return ret;
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index df4b3e6fa563..78180d151730 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1061,7 +1061,8 @@ out:
}
static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb);
struct ceph_mds_client *mdsc = fsc->mdsc;
@@ -1069,6 +1070,9 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
int op = CEPH_MDS_OP_RENAME;
int err;
+ if (flags)
+ return -EINVAL;
+
if (ceph_snap(old_dir) != ceph_snap(new_dir))
return -EXDEV;
if (ceph_snap(old_dir) != CEPH_NOSNAP) {
@@ -1486,10 +1490,7 @@ const struct inode_operations ceph_dir_iops = {
.permission = ceph_permission,
.getattr = ceph_getattr,
.setattr = ceph_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ceph_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ceph_get_acl,
.set_acl = ceph_set_acl,
.mknod = ceph_mknod,
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 0f5375d8e030..7bf08825cc11 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -886,7 +886,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
int num_pages = 0;
int flags;
int ret;
- struct timespec mtime = current_fs_time(inode->i_sb);
+ struct timespec mtime = current_time(inode);
size_t count = iov_iter_count(iter);
loff_t pos = iocb->ki_pos;
bool write = iov_iter_rw(iter) == WRITE;
@@ -902,10 +902,10 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
return ret;
if (write) {
- ret = invalidate_inode_pages2_range(inode->i_mapping,
+ int ret2 = invalidate_inode_pages2_range(inode->i_mapping,
pos >> PAGE_SHIFT,
(pos + count) >> PAGE_SHIFT);
- if (ret < 0)
+ if (ret2 < 0)
dout("invalidate_inode_pages2_range returned %d\n", ret);
flags = CEPH_OSD_FLAG_ORDERSNAP |
@@ -1091,7 +1091,7 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
int flags;
int check_caps = 0;
int ret;
- struct timespec mtime = current_fs_time(inode->i_sb);
+ struct timespec mtime = current_time(inode);
size_t count = iov_iter_count(from);
if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index dd3a6dbf71eb..bca1b49c1c4b 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -94,10 +94,7 @@ const struct inode_operations ceph_file_iops = {
.permission = ceph_permission,
.setattr = ceph_setattr,
.getattr = ceph_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ceph_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ceph_get_acl,
.set_acl = ceph_set_acl,
};
@@ -1885,10 +1882,7 @@ static const struct inode_operations ceph_symlink_iops = {
.get_link = simple_get_link,
.setattr = ceph_setattr,
.getattr = ceph_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ceph_listxattr,
- .removexattr = generic_removexattr,
};
int __ceph_setattr(struct inode *inode, struct iattr *attr)
@@ -1905,13 +1899,6 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
int inode_dirty_flags = 0;
bool lock_snap_rwsem = false;
- if (ceph_snap(inode) != CEPH_NOSNAP)
- return -EROFS;
-
- err = inode_change_ok(inode, attr);
- if (err != 0)
- return err;
-
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return -ENOMEM;
@@ -2080,7 +2067,7 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
if (dirtied) {
inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied,
&prealloc_cf);
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
}
release &= issued;
@@ -2124,7 +2111,17 @@ out_put:
*/
int ceph_setattr(struct dentry *dentry, struct iattr *attr)
{
- return __ceph_setattr(d_inode(dentry), attr);
+ struct inode *inode = d_inode(dentry);
+ int err;
+
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+ err = setattr_prepare(dentry, attr);
+ if (err != 0)
+ return err;
+
+ return __ceph_setattr(inode, attr);
}
/*
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
index a2cb0c254060..6806dbeaee19 100644
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -210,8 +210,8 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_FLOCK))
return -ENOLCK;
/* No mandatory locks */
- if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK)
- return -ENOLCK;
+ if (fl->fl_type & LOCK_MAND)
+ return -EOPNOTSUPP;
dout("ceph_flock, fl_file: %p", fl->fl_file);
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index f72d4ae303b2..815acd1a56d4 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -370,6 +370,7 @@ const char *ceph_session_state_name(int s)
case CEPH_MDS_SESSION_CLOSING: return "closing";
case CEPH_MDS_SESSION_RESTARTING: return "restarting";
case CEPH_MDS_SESSION_RECONNECTING: return "reconnecting";
+ case CEPH_MDS_SESSION_REJECTED: return "rejected";
default: return "???";
}
}
@@ -1150,8 +1151,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
while (!list_empty(&ci->i_cap_flush_list)) {
cf = list_first_entry(&ci->i_cap_flush_list,
struct ceph_cap_flush, i_list);
- list_del(&cf->i_list);
- list_add(&cf->i_list, &to_remove);
+ list_move(&cf->i_list, &to_remove);
}
spin_lock(&mdsc->cap_dirty_lock);
@@ -1378,7 +1378,7 @@ static int request_close_session(struct ceph_mds_client *mdsc,
if (!msg)
return -ENOMEM;
ceph_con_send(&session->s_con, msg);
- return 0;
+ return 1;
}
/*
@@ -2131,6 +2131,10 @@ static int __do_request(struct ceph_mds_client *mdsc,
ceph_session_state_name(session->s_state));
if (session->s_state != CEPH_MDS_SESSION_OPEN &&
session->s_state != CEPH_MDS_SESSION_HUNG) {
+ if (session->s_state == CEPH_MDS_SESSION_REJECTED) {
+ err = -EACCES;
+ goto out_session;
+ }
if (session->s_state == CEPH_MDS_SESSION_NEW ||
session->s_state == CEPH_MDS_SESSION_CLOSING)
__open_session(mdsc, session);
@@ -2652,6 +2656,15 @@ static void handle_session(struct ceph_mds_session *session,
wake_up_session_caps(session, 0);
break;
+ case CEPH_SESSION_REJECT:
+ WARN_ON(session->s_state != CEPH_MDS_SESSION_OPENING);
+ pr_info("mds%d rejected session\n", session->s_mds);
+ session->s_state = CEPH_MDS_SESSION_REJECTED;
+ cleanup_session_requests(mdsc, session);
+ remove_session_caps(session);
+ wake = 2; /* for good measure */
+ break;
+
default:
pr_err("mdsc_handle_session bad op %d mds%d\n", op, mds);
WARN_ON(1);
@@ -3557,11 +3570,11 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
/*
* true if all sessions are closed, or we force unmount
*/
-static bool done_closing_sessions(struct ceph_mds_client *mdsc)
+static bool done_closing_sessions(struct ceph_mds_client *mdsc, int skipped)
{
if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN)
return true;
- return atomic_read(&mdsc->num_sessions) == 0;
+ return atomic_read(&mdsc->num_sessions) <= skipped;
}
/*
@@ -3572,6 +3585,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
struct ceph_options *opts = mdsc->fsc->client->options;
struct ceph_mds_session *session;
int i;
+ int skipped = 0;
dout("close_sessions\n");
@@ -3583,7 +3597,8 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
continue;
mutex_unlock(&mdsc->mutex);
mutex_lock(&session->s_mutex);
- __close_session(mdsc, session);
+ if (__close_session(mdsc, session) <= 0)
+ skipped++;
mutex_unlock(&session->s_mutex);
ceph_put_mds_session(session);
mutex_lock(&mdsc->mutex);
@@ -3591,7 +3606,8 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
mutex_unlock(&mdsc->mutex);
dout("waiting for sessions to close\n");
- wait_event_timeout(mdsc->session_close_wq, done_closing_sessions(mdsc),
+ wait_event_timeout(mdsc->session_close_wq,
+ done_closing_sessions(mdsc, skipped),
ceph_timeout_jiffies(opts->mount_timeout));
/* tear down remaining sessions */
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 6b3679737d4a..3c6f77b7bb02 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -121,6 +121,7 @@ enum {
CEPH_MDS_SESSION_CLOSING = 5,
CEPH_MDS_SESSION_RESTARTING = 6,
CEPH_MDS_SESSION_RECONNECTING = 7,
+ CEPH_MDS_SESSION_REJECTED = 8,
};
struct ceph_mds_session {
diff --git a/fs/ceph/strings.c b/fs/ceph/strings.c
index 89e6bc321df3..913dea163d5c 100644
--- a/fs/ceph/strings.c
+++ b/fs/ceph/strings.c
@@ -43,6 +43,8 @@ const char *ceph_session_op_name(int op)
case CEPH_SESSION_RECALL_STATE: return "recall_state";
case CEPH_SESSION_FLUSHMSG: return "flushmsg";
case CEPH_SESSION_FLUSHMSG_ACK: return "flushmsg_ack";
+ case CEPH_SESSION_FORCE_RO: return "force_ro";
+ case CEPH_SESSION_REJECT: return "reject";
}
return "???";
}
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index e247f6f0feb7..a29ffce98187 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -396,10 +396,12 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
*/
dev_name_end = strchr(dev_name, '/');
if (dev_name_end) {
- fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
- if (!fsopt->server_path) {
- err = -ENOMEM;
- goto out;
+ if (strlen(dev_name_end) > 1) {
+ fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
+ if (!fsopt->server_path) {
+ err = -ENOMEM;
+ goto out;
+ }
}
} else {
dev_name_end = dev_name + strlen(dev_name);
@@ -788,15 +790,10 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
struct inode *inode = req->r_target_inode;
req->r_target_inode = NULL;
dout("open_root_inode success\n");
- if (ceph_ino(inode) == CEPH_INO_ROOT &&
- fsc->sb->s_root == NULL) {
- root = d_make_root(inode);
- if (!root) {
- root = ERR_PTR(-ENOMEM);
- goto out;
- }
- } else {
- root = d_obtain_root(inode);
+ root = d_make_root(inode);
+ if (!root) {
+ root = ERR_PTR(-ENOMEM);
+ goto out;
}
ceph_init_dentry(root);
dout("open_root_inode success, root dentry is %p\n", root);
@@ -825,17 +822,24 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
mutex_lock(&fsc->client->mount_mutex);
if (!fsc->sb->s_root) {
+ const char *path;
err = __ceph_open_session(fsc->client, started);
if (err < 0)
goto out;
- dout("mount opening root\n");
- root = open_root_dentry(fsc, "", started);
+ if (!fsc->mount_options->server_path) {
+ path = "";
+ dout("mount opening path \\t\n");
+ } else {
+ path = fsc->mount_options->server_path + 1;
+ dout("mount opening path %s\n", path);
+ }
+ root = open_root_dentry(fsc, path, started);
if (IS_ERR(root)) {
err = PTR_ERR(root);
goto out;
}
- fsc->sb->s_root = root;
+ fsc->sb->s_root = dget(root);
first = 1;
err = ceph_fs_debugfs_init(fsc);
@@ -843,19 +847,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
goto fail;
}
- if (!fsc->mount_options->server_path) {
- root = fsc->sb->s_root;
- dget(root);
- } else {
- const char *path = fsc->mount_options->server_path + 1;
- dout("mount opening path %s\n", path);
- root = open_root_dentry(fsc, path, started);
- if (IS_ERR(root)) {
- err = PTR_ERR(root);
- goto fail;
- }
- }
-
fsc->mount_state = CEPH_MOUNT_MOUNTED;
dout("mount success\n");
mutex_unlock(&fsc->client->mount_mutex);
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index adc231892b0d..40b703217977 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -1034,7 +1034,7 @@ retry:
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
&prealloc_cf);
ci->i_xattrs.dirty = true;
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
}
spin_unlock(&ci->i_ceph_lock);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 14ae4b8e1a3c..cca04e710421 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -896,35 +896,26 @@ const struct inode_operations cifs_dir_inode_ops = {
.link = cifs_hardlink,
.mkdir = cifs_mkdir,
.rmdir = cifs_rmdir,
- .rename2 = cifs_rename2,
+ .rename = cifs_rename2,
.permission = cifs_permission,
.setattr = cifs_setattr,
.symlink = cifs_symlink,
.mknod = cifs_mknod,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = cifs_listxattr,
- .removexattr = generic_removexattr,
};
const struct inode_operations cifs_file_inode_ops = {
.setattr = cifs_setattr,
.getattr = cifs_getattr,
.permission = cifs_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = cifs_listxattr,
- .removexattr = generic_removexattr,
};
const struct inode_operations cifs_symlink_inode_ops = {
.readlink = generic_readlink,
.get_link = cifs_get_link,
.permission = cifs_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = cifs_listxattr,
- .removexattr = generic_removexattr,
};
static int cifs_clone_file_range(struct file *src_file, loff_t off,
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 9dcf974acc47..c9c00a862036 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -41,6 +41,16 @@ cifs_uniqueid_to_ino_t(u64 fileid)
}
+static inline void cifs_set_time(struct dentry *dentry, unsigned long time)
+{
+ dentry->d_fsdata = (void *) time;
+}
+
+static inline unsigned long cifs_get_time(struct dentry *dentry)
+{
+ return (unsigned long) dentry->d_fsdata;
+}
+
extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 95dab43646f0..4ead72a001f9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -392,8 +392,7 @@ extern int CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, char **buf,
int *return_buf_type);
extern int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, const char *buf,
- const char __user *ubuf, const int long_op);
+ unsigned int *nbytes, const char *buf);
extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, const int nvec);
extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d47197ea4ab6..f82d2823622f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1228,7 +1228,6 @@ OldOpenRetry:
inc_rfc1001_len(pSMB, count);
pSMB->ByteCount = cpu_to_le16(count);
- /* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
@@ -1768,8 +1767,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
int
CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, const char *buf,
- const char __user *ubuf, const int long_op)
+ unsigned int *nbytes, const char *buf)
{
int rc = -EACCES;
WRITE_REQ *pSMB = NULL;
@@ -1838,12 +1836,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
if (buf)
memcpy(pSMB->Data, buf, bytes_sent);
- else if (ubuf) {
- if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
- cifs_buf_release(pSMB);
- return -EFAULT;
- }
- } else if (count != 0) {
+ else if (count != 0) {
/* No buffer */
cifs_buf_release(pSMB);
return -EINVAL;
@@ -1867,7 +1860,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
}
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
if (rc) {
cifs_dbg(FYI, "Send error in write = %d\n", rc);
@@ -3334,7 +3327,7 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
#ifdef CONFIG_CIFS_POSIX
/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
-static void cifs_convert_ace(posix_acl_xattr_entry *ace,
+static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
struct cifs_posix_ace *cifs_ace)
{
/* u8 cifs fields do not need le conversion */
@@ -3358,7 +3351,7 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
__u16 count;
struct cifs_posix_ace *pACE;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
- posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
+ struct posix_acl_xattr_header *local_acl = (void *)trgt;
if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
return -EOPNOTSUPP;
@@ -3396,9 +3389,11 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
} else if (size > buflen) {
return -ERANGE;
} else /* buffer big enough */ {
+ struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
+
local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
for (i = 0; i < count ; i++) {
- cifs_convert_ace(&local_acl->a_entries[i], pACE);
+ cifs_convert_ace(&ace[i], pACE);
pACE++;
}
}
@@ -3406,7 +3401,7 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
}
static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
- const posix_acl_xattr_entry *local_ace)
+ const struct posix_acl_xattr_entry *local_ace)
{
__u16 rc = 0; /* 0 = ACL converted ok */
@@ -3431,7 +3426,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
{
__u16 rc = 0;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
- posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
+ struct posix_acl_xattr_header *local_acl = (void *)pACL;
int count;
int i;
@@ -3459,7 +3454,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
}
for (i = 0; i < count; i++) {
rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
- &local_acl->a_entries[i]);
+ (struct posix_acl_xattr_entry *)(local_acl + 1));
if (rc != 0) {
/* ACE not converted */
break;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 4716c54dbfc6..789ff1df2d8d 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -40,7 +40,7 @@ renew_parental_timestamps(struct dentry *direntry)
/* BB check if there is a way to get the kernel to do this or if we
really need this */
do {
- direntry->d_time = jiffies;
+ cifs_set_time(direntry, jiffies);
direntry = direntry->d_parent;
} while (!IS_ROOT(direntry));
}
@@ -802,7 +802,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} else if (rc == -ENOENT) {
rc = 0;
- direntry->d_time = jiffies;
+ cifs_set_time(direntry, jiffies);
d_add(direntry, NULL);
/* if it was once a directory (but how can we tell?) we could do
shrink_dcache_parent(direntry); */
@@ -862,7 +862,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
return 0;
- if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
+ if (time_after(jiffies, cifs_get_time(direntry) + HZ) || !lookupCacheEnabled)
return 0;
return 1;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 579e41b350a2..a95fe8b1afe9 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1878,7 +1878,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
write_data, to - from, &offset);
cifsFileInfo_put(open_file);
/* Does mm or vfs already set times? */
- inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
+ inode->i_atime = inode->i_mtime = current_time(inode);
if ((bytes_written > 0) && (offset))
rc = 0;
else if (bytes_written < 0)
@@ -2478,7 +2478,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
size_t cur_len;
unsigned long nr_pages, num_pages, i;
struct cifs_writedata *wdata;
- struct iov_iter saved_from;
+ struct iov_iter saved_from = *from;
loff_t saved_offset = offset;
pid_t pid;
struct TCP_Server_Info *server;
@@ -2489,7 +2489,6 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
pid = current->tgid;
server = tlink_tcon(open_file->tlink)->ses->server;
- memcpy(&saved_from, from, sizeof(struct iov_iter));
do {
unsigned int wsize, credits;
@@ -2551,8 +2550,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
kref_put(&wdata->refcount,
cifs_uncached_writedata_release);
if (rc == -EAGAIN) {
- memcpy(from, &saved_from,
- sizeof(struct iov_iter));
+ *from = saved_from;
iov_iter_advance(from, offset - saved_offset);
continue;
}
@@ -2576,7 +2574,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from)
struct cifs_sb_info *cifs_sb;
struct cifs_writedata *wdata, *tmp;
struct list_head wdata_list;
- struct iov_iter saved_from;
+ struct iov_iter saved_from = *from;
int rc;
/*
@@ -2597,8 +2595,6 @@ ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from)
if (!tcon->ses->server->ops->async_writev)
return -ENOSYS;
- memcpy(&saved_from, from, sizeof(struct iov_iter));
-
rc = cifs_write_from_iter(iocb->ki_pos, iov_iter_count(from), from,
open_file, cifs_sb, &wdata_list);
@@ -2631,13 +2627,11 @@ restart_loop:
/* resend call if it's a retryable error */
if (rc == -EAGAIN) {
struct list_head tmp_list;
- struct iov_iter tmp_from;
+ struct iov_iter tmp_from = saved_from;
INIT_LIST_HEAD(&tmp_list);
list_del_init(&wdata->list);
- memcpy(&tmp_from, &saved_from,
- sizeof(struct iov_iter));
iov_iter_advance(&tmp_from,
wdata->offset - iocb->ki_pos);
@@ -3571,7 +3565,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
cifs_dbg(FYI, "Bytes read %d\n", rc);
file_inode(file)->i_atime =
- current_fs_time(file_inode(file)->i_sb);
+ current_time(file_inode(file));
if (PAGE_SIZE > rc)
memset(read_data + rc, 0, PAGE_SIZE - rc);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index b87efd0c92d6..7ab5be7944aa 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1951,7 +1951,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n",
full_path, inode, inode->i_count.counter,
- dentry, dentry->d_time, jiffies);
+ dentry, cifs_get_time(dentry), jiffies);
if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
@@ -2154,7 +2154,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
- rc = inode_change_ok(inode, attrs);
+ rc = setattr_prepare(direntry, attrs);
if (rc < 0)
goto out;
@@ -2294,7 +2294,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
- rc = inode_change_ok(inode, attrs);
+ rc = setattr_prepare(direntry, attrs);
if (rc < 0) {
free_xid(xid);
return rc;
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 062c2375549a..d031af8d3d4d 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -399,7 +399,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
- rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf, NULL, 0);
+ rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf);
CIFSSMBClose(xid, tcon, fid.netfid);
return rc;
}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 6fb8672c0892..c0474ac6cbf2 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -109,7 +109,7 @@ static inline void coda_dir_update_mtime(struct inode *dir)
/* optimistically we can also act as if our nose bleeds. The
* granularity of the mtime is coarse anyways so we might actually be
* right most of the time. Note: we only do this for directories. */
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
#endif
}
@@ -291,7 +291,8 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
/* rename */
static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
const char *old_name = old_dentry->d_name.name;
const char *new_name = new_dentry->d_name.name;
@@ -299,6 +300,9 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
int new_length = new_dentry->d_name.len;
int error;
+ if (flags)
+ return -EINVAL;
+
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
coda_i2f(new_dir), old_length, new_length,
(const char *) old_name, (const char *)new_name);
diff --git a/fs/coda/file.c b/fs/coda/file.c
index f47c7483863b..6e0154eb6fcc 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -38,27 +38,6 @@ coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
}
static ssize_t
-coda_file_splice_read(struct file *coda_file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t count,
- unsigned int flags)
-{
- ssize_t (*splice_read)(struct file *, loff_t *,
- struct pipe_inode_info *, size_t, unsigned int);
- struct coda_file_info *cfi;
- struct file *host_file;
-
- cfi = CODA_FTOC(coda_file);
- BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
- host_file = cfi->cfi_container;
-
- splice_read = host_file->f_op->splice_read;
- if (!splice_read)
- splice_read = default_file_splice_read;
-
- return splice_read(host_file, ppos, pipe, count, flags);
-}
-
-static ssize_t
coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *coda_file = iocb->ki_filp;
@@ -75,7 +54,7 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos);
coda_inode->i_size = file_inode(host_file)->i_size;
coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
- coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME_SEC;
+ coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
inode_unlock(coda_inode);
file_end_write(host_file);
return ret;
@@ -225,6 +204,6 @@ const struct file_operations coda_file_operations = {
.open = coda_open,
.release = coda_release,
.fsync = coda_fsync,
- .splice_read = coda_file_splice_read,
+ .splice_read = generic_file_splice_read,
};
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 57e81cbba0fa..71dbe7e287ce 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -271,7 +271,7 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
memset(&vattr, 0, sizeof(vattr));
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
coda_iattr_to_vattr(iattr, &vattr);
vattr.va_type = C_VNON; /* cannot set type */
diff --git a/fs/compat.c b/fs/compat.c
index be6e48b0a46c..bd064a2c3550 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -54,20 +54,6 @@
#include <asm/ioctls.h>
#include "internal.h"
-int compat_log = 1;
-
-int compat_printk(const char *fmt, ...)
-{
- va_list ap;
- int ret;
- if (!compat_log)
- return 0;
- va_start(ap, fmt);
- ret = vprintk(fmt, ap);
- va_end(ap);
- return ret;
-}
-
/*
* Not all architectures have sys_utime, so implement this in terms
* of sys_utimes.
@@ -562,7 +548,7 @@ ssize_t compat_rw_copy_check_uvector(int type,
goto out;
ret = -EINVAL;
- if (nr_segs > UIO_MAXIOV || nr_segs < 0)
+ if (nr_segs > UIO_MAXIOV)
goto out;
if (nr_segs > fast_segs) {
ret = -ENOMEM;
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 0387968e6f47..ad718e5e37bb 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -76,7 +76,7 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
sd_iattr->ia_uid = GLOBAL_ROOT_UID;
sd_iattr->ia_gid = GLOBAL_ROOT_GID;
sd_iattr->ia_atime = sd_iattr->ia_mtime =
- sd_iattr->ia_ctime = current_fs_time(inode->i_sb);
+ sd_iattr->ia_ctime = current_time(inode);
sd->s_iattr = sd_iattr;
}
/* attributes were changed atleast once in past */
@@ -113,7 +113,7 @@ static inline void set_default_inode_attr(struct inode * inode, umode_t mode)
{
inode->i_mode = mode;
inode->i_atime = inode->i_mtime =
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
}
static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
@@ -197,7 +197,7 @@ int configfs_create(struct dentry * dentry, umode_t mode, void (*init)(struct in
return -ENOMEM;
p_inode = d_inode(dentry->d_parent);
- p_inode->i_mtime = p_inode->i_ctime = current_fs_time(p_inode->i_sb);
+ p_inode->i_mtime = p_inode->i_ctime = current_time(p_inode);
configfs_set_inode_lock_class(sd, inode);
init(inode);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index c502c116924c..61057b7dbddb 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -28,7 +28,6 @@
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/fscrypto.h>
-#include <linux/ecryptfs.h>
static unsigned int num_prealloc_crypto_pages = 32;
static unsigned int num_prealloc_crypto_ctxs = 128;
@@ -128,11 +127,11 @@ struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags)
EXPORT_SYMBOL(fscrypt_get_ctx);
/**
- * fscrypt_complete() - The completion callback for page encryption
- * @req: The asynchronous encryption request context
- * @res: The result of the encryption operation
+ * page_crypt_complete() - completion callback for page crypto
+ * @req: The asynchronous cipher request context
+ * @res: The result of the cipher operation
*/
-static void fscrypt_complete(struct crypto_async_request *req, int res)
+static void page_crypt_complete(struct crypto_async_request *req, int res)
{
struct fscrypt_completion_result *ecr = req->data;
@@ -170,7 +169,7 @@ static int do_page_crypto(struct inode *inode,
skcipher_request_set_callback(
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- fscrypt_complete, &ecr);
+ page_crypt_complete, &ecr);
BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index));
memcpy(xts_tweak, &index, sizeof(index));
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 5d6d49113efa..9a28133ac3b8 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -10,21 +10,16 @@
* This has not yet undergone a rigorous security audit.
*/
-#include <keys/encrypted-type.h>
-#include <keys/user-type.h>
#include <linux/scatterlist.h>
#include <linux/ratelimit.h>
#include <linux/fscrypto.h>
-static u32 size_round_up(size_t size, size_t blksize)
-{
- return ((size + blksize - 1) / blksize) * blksize;
-}
-
/**
- * dir_crypt_complete() -
+ * fname_crypt_complete() - completion callback for filename crypto
+ * @req: The asynchronous cipher request context
+ * @res: The result of the cipher operation
*/
-static void dir_crypt_complete(struct crypto_async_request *req, int res)
+static void fname_crypt_complete(struct crypto_async_request *req, int res)
{
struct fscrypt_completion_result *ecr = req->data;
@@ -35,11 +30,11 @@ static void dir_crypt_complete(struct crypto_async_request *req, int res)
}
/**
- * fname_encrypt() -
+ * fname_encrypt() - encrypt a filename
*
- * This function encrypts the input filename, and returns the length of the
- * ciphertext. Errors are returned as negative numbers. We trust the caller to
- * allocate sufficient memory to oname string.
+ * The caller must have allocated sufficient memory for the @oname string.
+ *
+ * Return: 0 on success, -errno on failure
*/
static int fname_encrypt(struct inode *inode,
const struct qstr *iname, struct fscrypt_str *oname)
@@ -60,10 +55,9 @@ static int fname_encrypt(struct inode *inode,
if (iname->len <= 0 || iname->len > lim)
return -EIO;
- ciphertext_len = (iname->len < FS_CRYPTO_BLOCK_SIZE) ?
- FS_CRYPTO_BLOCK_SIZE : iname->len;
- ciphertext_len = size_round_up(ciphertext_len, padding);
- ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len;
+ ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE);
+ ciphertext_len = round_up(ciphertext_len, padding);
+ ciphertext_len = min(ciphertext_len, lim);
if (ciphertext_len <= sizeof(buf)) {
workbuf = buf;
@@ -84,7 +78,7 @@ static int fname_encrypt(struct inode *inode,
}
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- dir_crypt_complete, &ecr);
+ fname_crypt_complete, &ecr);
/* Copy the input */
memcpy(workbuf, iname->name, iname->len);
@@ -105,20 +99,22 @@ static int fname_encrypt(struct inode *inode,
}
kfree(alloc_buf);
skcipher_request_free(req);
- if (res < 0)
+ if (res < 0) {
printk_ratelimited(KERN_ERR
"%s: Error (error code %d)\n", __func__, res);
+ return res;
+ }
oname->len = ciphertext_len;
- return res;
+ return 0;
}
-/*
- * fname_decrypt()
- * This function decrypts the input filename, and returns
- * the length of the plaintext.
- * Errors are returned as negative numbers.
- * We trust the caller to allocate sufficient memory to oname string.
+/**
+ * fname_decrypt() - decrypt a filename
+ *
+ * The caller must have allocated sufficient memory for the @oname string.
+ *
+ * Return: 0 on success, -errno on failure
*/
static int fname_decrypt(struct inode *inode,
const struct fscrypt_str *iname,
@@ -146,7 +142,7 @@ static int fname_decrypt(struct inode *inode,
}
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- dir_crypt_complete, &ecr);
+ fname_crypt_complete, &ecr);
/* Initialize IV */
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
@@ -168,7 +164,7 @@ static int fname_decrypt(struct inode *inode,
}
oname->len = strnlen(oname->name, iname->len);
- return oname->len;
+ return 0;
}
static const char *lookup_table =
@@ -231,9 +227,8 @@ u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen)
if (ci)
padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
- if (ilen < FS_CRYPTO_BLOCK_SIZE)
- ilen = FS_CRYPTO_BLOCK_SIZE;
- return size_round_up(ilen, padding);
+ ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE);
+ return round_up(ilen, padding);
}
EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
@@ -279,6 +274,10 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer);
/**
* fscrypt_fname_disk_to_usr() - converts a filename from disk space to user
* space
+ *
+ * The caller must have allocated sufficient memory for the @oname string.
+ *
+ * Return: 0 on success, -errno on failure
*/
int fscrypt_fname_disk_to_usr(struct inode *inode,
u32 hash, u32 minor_hash,
@@ -287,13 +286,12 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
{
const struct qstr qname = FSTR_TO_QSTR(iname);
char buf[24];
- int ret;
if (fscrypt_is_dot_dotdot(&qname)) {
oname->name[0] = '.';
oname->name[iname->len - 1] = '.';
oname->len = iname->len;
- return oname->len;
+ return 0;
}
if (iname->len < FS_CRYPTO_BLOCK_SIZE)
@@ -303,9 +301,9 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
return fname_decrypt(inode, iname, oname);
if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) {
- ret = digest_encode(iname->name, iname->len, oname->name);
- oname->len = ret;
- return ret;
+ oname->len = digest_encode(iname->name, iname->len,
+ oname->name);
+ return 0;
}
if (hash) {
memcpy(buf, &hash, 4);
@@ -315,15 +313,18 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
}
memcpy(buf + 8, iname->name + iname->len - 16, 16);
oname->name[0] = '_';
- ret = digest_encode(buf, 24, oname->name + 1);
- oname->len = ret + 1;
- return ret + 1;
+ oname->len = 1 + digest_encode(buf, 24, oname->name + 1);
+ return 0;
}
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
/**
* fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
* space
+ *
+ * The caller must have allocated sufficient memory for the @oname string.
+ *
+ * Return: 0 on success, -errno on failure
*/
int fscrypt_fname_usr_to_disk(struct inode *inode,
const struct qstr *iname,
@@ -333,7 +334,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode,
oname->name[0] = '.';
oname->name[iname->len - 1] = '.';
oname->len = iname->len;
- return oname->len;
+ return 0;
}
if (inode->i_crypt_info)
return fname_encrypt(inode, iname, oname);
@@ -367,10 +368,10 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
if (dir->i_crypt_info) {
ret = fscrypt_fname_alloc_buffer(dir, iname->len,
&fname->crypto_buf);
- if (ret < 0)
+ if (ret)
return ret;
ret = fname_encrypt(dir, iname, &fname->crypto_buf);
- if (ret < 0)
+ if (ret)
goto errout;
fname->disk_name.name = fname->crypto_buf.name;
fname->disk_name.len = fname->crypto_buf.len;
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index 1ac263eddc4e..82f0285f5d08 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -8,11 +8,8 @@
* Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
*/
-#include <keys/encrypted-type.h>
#include <keys/user-type.h>
-#include <linux/random.h>
#include <linux/scatterlist.h>
-#include <uapi/linux/keyctl.h>
#include <linux/fscrypto.h>
static void derive_crypt_complete(struct crypto_async_request *req, int rc)
@@ -139,6 +136,38 @@ out:
return res;
}
+static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
+ const char **cipher_str_ret, int *keysize_ret)
+{
+ if (S_ISREG(inode->i_mode)) {
+ if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) {
+ *cipher_str_ret = "xts(aes)";
+ *keysize_ret = FS_AES_256_XTS_KEY_SIZE;
+ return 0;
+ }
+ pr_warn_once("fscrypto: unsupported contents encryption mode "
+ "%d for inode %lu\n",
+ ci->ci_data_mode, inode->i_ino);
+ return -ENOKEY;
+ }
+
+ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
+ if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
+ *cipher_str_ret = "cts(cbc(aes))";
+ *keysize_ret = FS_AES_256_CTS_KEY_SIZE;
+ return 0;
+ }
+ pr_warn_once("fscrypto: unsupported filenames encryption mode "
+ "%d for inode %lu\n",
+ ci->ci_filename_mode, inode->i_ino);
+ return -ENOKEY;
+ }
+
+ pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n",
+ (inode->i_mode & S_IFMT), inode->i_ino);
+ return -ENOKEY;
+}
+
static void put_crypt_info(struct fscrypt_info *ci)
{
if (!ci)
@@ -155,8 +184,8 @@ int get_crypt_info(struct inode *inode)
struct fscrypt_context ctx;
struct crypto_skcipher *ctfm;
const char *cipher_str;
+ int keysize;
u8 raw_key[FS_MAX_KEY_SIZE];
- u8 mode;
int res;
res = fscrypt_initialize();
@@ -179,13 +208,19 @@ retry:
if (res < 0) {
if (!fscrypt_dummy_context_enabled(inode))
return res;
+ ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
ctx.flags = 0;
} else if (res != sizeof(ctx)) {
return -EINVAL;
}
- res = 0;
+
+ if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
+ return -EINVAL;
+
+ if (ctx.flags & ~FS_POLICY_FLAGS_VALID)
+ return -EINVAL;
crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS);
if (!crypt_info)
@@ -198,27 +233,11 @@ retry:
crypt_info->ci_keyring_key = NULL;
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
sizeof(crypt_info->ci_master_key));
- if (S_ISREG(inode->i_mode))
- mode = crypt_info->ci_data_mode;
- else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
- mode = crypt_info->ci_filename_mode;
- else
- BUG();
-
- switch (mode) {
- case FS_ENCRYPTION_MODE_AES_256_XTS:
- cipher_str = "xts(aes)";
- break;
- case FS_ENCRYPTION_MODE_AES_256_CTS:
- cipher_str = "cts(cbc(aes))";
- break;
- default:
- printk_once(KERN_WARNING
- "%s: unsupported key mode %d (ino %u)\n",
- __func__, mode, (unsigned) inode->i_ino);
- res = -ENOKEY;
+
+ res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
+ if (res)
goto out;
- }
+
if (fscrypt_dummy_context_enabled(inode)) {
memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
goto got_key;
@@ -253,7 +272,7 @@ got_key:
crypt_info->ci_ctfm = ctfm;
crypto_skcipher_clear_flags(ctfm, ~0);
crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
- res = crypto_skcipher_setkey(ctfm, raw_key, fscrypt_key_size(mode));
+ res = crypto_skcipher_setkey(ctfm, raw_key, keysize);
if (res)
goto out;
diff --git a/fs/dax.c b/fs/dax.c
index cc025f82ef07..014defd2e744 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1036,7 +1036,7 @@ int dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
if (!write && !buffer_mapped(&bh)) {
spinlock_t *ptl;
pmd_t entry;
- struct page *zero_page = get_huge_zero_page();
+ struct page *zero_page = mm_get_huge_zero_page(vma->vm_mm);
if (unlikely(!zero_page)) {
dax_pmd_dbg(&bh, address, "no zero page");
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 72361baf9da7..f17fcf89e18e 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -45,7 +45,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb)
if (inode) {
inode->i_ino = get_next_ino();
inode->i_atime = inode->i_mtime =
- inode->i_ctime = current_fs_time(sb);
+ inode->i_ctime = current_time(inode);
}
return inode;
}
@@ -748,7 +748,7 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir),
- dentry);
+ dentry, 0);
if (error) {
fsnotify_oldname_free(old_name);
goto exit;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 442d1a7e671b..108df2e3602c 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -300,7 +300,7 @@ static int mknod_ptmx(struct super_block *sb)
}
inode->i_ino = 2;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
mode = S_IFCHR|opts->ptmxmode;
init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
@@ -412,7 +412,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
if (!inode)
goto fail;
inode->i_ino = 1;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
@@ -540,7 +540,7 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv)
inode->i_ino = index + 3;
inode->i_uid = opts->setuid ? opts->uid : current_fsuid();
inode->i_gid = opts->setgid ? opts->gid : current_fsgid();
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
init_special_inode(inode, S_IFCHR|opts->mode, MKDEV(UNIX98_PTY_SLAVE_MAJOR, index));
sprintf(s, "%d", index);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 7c3ce73cb617..fb9aa16a7727 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -246,6 +246,9 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, bool is_async)
if ((dio->op == REQ_OP_READ) &&
((offset + transferred) > dio->i_size))
transferred = dio->i_size - offset;
+ /* ignore EFAULT if some IO has been done */
+ if (unlikely(ret == -EFAULT) && transferred)
+ ret = 0;
}
if (ret == 0)
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 963016c8f3d1..609998de533e 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1656,16 +1656,12 @@ void dlm_lowcomms_stop(void)
mutex_lock(&connections_lock);
dlm_allow_conn = 0;
foreach_conn(stop_conn);
+ clean_writequeues();
+ foreach_conn(free_conn);
mutex_unlock(&connections_lock);
work_stop();
- mutex_lock(&connections_lock);
- clean_writequeues();
-
- foreach_conn(free_conn);
-
- mutex_unlock(&connections_lock);
kmem_cache_destroy(con_cache);
}
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 4ba1547bb9ad..599a29237cfe 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -715,4 +715,6 @@ int ecryptfs_set_f_namelen(long *namelen, long lower_namelen,
int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
loff_t offset);
+extern const struct xattr_handler *ecryptfs_xattr_handlers[];
+
#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 9d153b6a1d72..cf390dceddd2 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -577,7 +577,8 @@ out:
static int
ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
int rc;
struct dentry *lower_old_dentry;
@@ -587,6 +588,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct dentry *trap = NULL;
struct inode *target_inode;
+ if (flags)
+ return -EINVAL;
+
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
dget(lower_old_dentry);
@@ -927,7 +931,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
}
mutex_unlock(&crypt_stat->cs_mutex);
- rc = inode_change_ok(inode, ia);
+ rc = setattr_prepare(dentry, ia);
if (rc)
goto out;
if (ia->ia_valid & ATTR_SIZE) {
@@ -1005,15 +1009,14 @@ ecryptfs_setxattr(struct dentry *dentry, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
{
- int rc = 0;
+ int rc;
struct dentry *lower_dentry;
lower_dentry = ecryptfs_dentry_to_lower(dentry);
- if (!d_inode(lower_dentry)->i_op->setxattr) {
+ if (!(d_inode(lower_dentry)->i_opflags & IOP_XATTR)) {
rc = -EOPNOTSUPP;
goto out;
}
-
rc = vfs_setxattr(lower_dentry, name, value, size, flags);
if (!rc && inode)
fsstack_copy_attr_all(inode, d_inode(lower_dentry));
@@ -1025,15 +1028,14 @@ ssize_t
ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode,
const char *name, void *value, size_t size)
{
- int rc = 0;
+ int rc;
- if (!lower_inode->i_op->getxattr) {
+ if (!(lower_inode->i_opflags & IOP_XATTR)) {
rc = -EOPNOTSUPP;
goto out;
}
inode_lock(lower_inode);
- rc = lower_inode->i_op->getxattr(lower_dentry, lower_inode,
- name, value, size);
+ rc = __vfs_getxattr(lower_dentry, lower_inode, name, value, size);
inode_unlock(lower_inode);
out:
return rc;
@@ -1066,19 +1068,22 @@ out:
return rc;
}
-static int ecryptfs_removexattr(struct dentry *dentry, const char *name)
+static int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode,
+ const char *name)
{
- int rc = 0;
+ int rc;
struct dentry *lower_dentry;
+ struct inode *lower_inode;
lower_dentry = ecryptfs_dentry_to_lower(dentry);
- if (!d_inode(lower_dentry)->i_op->removexattr) {
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ if (!(lower_inode->i_opflags & IOP_XATTR)) {
rc = -EOPNOTSUPP;
goto out;
}
- inode_lock(d_inode(lower_dentry));
- rc = d_inode(lower_dentry)->i_op->removexattr(lower_dentry, name);
- inode_unlock(d_inode(lower_dentry));
+ inode_lock(lower_inode);
+ rc = __vfs_removexattr(lower_dentry, name);
+ inode_unlock(lower_inode);
out:
return rc;
}
@@ -1089,10 +1094,7 @@ const struct inode_operations ecryptfs_symlink_iops = {
.permission = ecryptfs_permission,
.setattr = ecryptfs_setattr,
.getattr = ecryptfs_getattr_link,
- .setxattr = ecryptfs_setxattr,
- .getxattr = ecryptfs_getxattr,
.listxattr = ecryptfs_listxattr,
- .removexattr = ecryptfs_removexattr
};
const struct inode_operations ecryptfs_dir_iops = {
@@ -1107,18 +1109,43 @@ const struct inode_operations ecryptfs_dir_iops = {
.rename = ecryptfs_rename,
.permission = ecryptfs_permission,
.setattr = ecryptfs_setattr,
- .setxattr = ecryptfs_setxattr,
- .getxattr = ecryptfs_getxattr,
.listxattr = ecryptfs_listxattr,
- .removexattr = ecryptfs_removexattr
};
const struct inode_operations ecryptfs_main_iops = {
.permission = ecryptfs_permission,
.setattr = ecryptfs_setattr,
.getattr = ecryptfs_getattr,
- .setxattr = ecryptfs_setxattr,
- .getxattr = ecryptfs_getxattr,
.listxattr = ecryptfs_listxattr,
- .removexattr = ecryptfs_removexattr
+};
+
+static int ecryptfs_xattr_get(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, void *buffer, size_t size)
+{
+ return ecryptfs_getxattr(dentry, inode, name, buffer, size);
+}
+
+static int ecryptfs_xattr_set(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ if (value)
+ return ecryptfs_setxattr(dentry, inode, name, value, size, flags);
+ else {
+ BUG_ON(flags != XATTR_REPLACE);
+ return ecryptfs_removexattr(dentry, inode, name);
+ }
+}
+
+const struct xattr_handler ecryptfs_xattr_handler = {
+ .prefix = "", /* match anything */
+ .get = ecryptfs_xattr_get,
+ .set = ecryptfs_xattr_set,
+};
+
+const struct xattr_handler *ecryptfs_xattr_handlers[] = {
+ &ecryptfs_xattr_handler,
+ NULL
};
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 612004495141..151872dcc1f4 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -529,6 +529,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
/* ->kill_sb() will take care of sbi after that point */
sbi = NULL;
s->s_op = &ecryptfs_sops;
+ s->s_xattr = ecryptfs_xattr_handlers;
s->s_d_op = &ecryptfs_dops;
err = "Reading sb failed";
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 9c3437c8a5b1..1f0c471b4ba3 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -32,6 +32,7 @@
#include <linux/file.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/xattr.h>
#include <asm/unaligned.h>
#include "ecryptfs_kernel.h"
@@ -422,7 +423,7 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
struct inode *lower_inode = d_inode(lower_dentry);
int rc;
- if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) {
+ if (!(lower_inode->i_opflags & IOP_XATTR)) {
printk(KERN_WARNING
"No support for setting xattr in lower filesystem\n");
rc = -ENOSYS;
@@ -436,15 +437,13 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
goto out;
}
inode_lock(lower_inode);
- size = lower_inode->i_op->getxattr(lower_dentry, lower_inode,
- ECRYPTFS_XATTR_NAME,
- xattr_virt, PAGE_SIZE);
+ size = __vfs_getxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
+ xattr_virt, PAGE_SIZE);
if (size < 0)
size = 8;
put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);
- rc = lower_inode->i_op->setxattr(lower_dentry, lower_inode,
- ECRYPTFS_XATTR_NAME,
- xattr_virt, size, 0);
+ rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
+ xattr_virt, size, 0);
inode_unlock(lower_inode);
if (rc)
printk(KERN_ERR "Error whilst attempting to write inode size "
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
index cbb50cadcffc..71fccccf317e 100644
--- a/fs/efivarfs/inode.c
+++ b/fs/efivarfs/inode.c
@@ -24,7 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb,
if (inode) {
inode->i_ino = get_next_ino();
inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
switch (mode & S_IFMT) {
case S_IFREG:
diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c
index f69a1b5826a5..79101651fe9e 100644
--- a/fs/exofs/dir.c
+++ b/fs/exofs/dir.c
@@ -416,7 +416,7 @@ int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
if (likely(!err))
err = exofs_commit_chunk(page, pos, len);
exofs_put_page(page);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
return err;
}
@@ -503,7 +503,7 @@ got_it:
de->inode_no = cpu_to_le64(inode->i_ino);
exofs_set_de_type(de, inode);
err = exofs_commit_chunk(page, pos, rec_len);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
sbi->s_numfiles++;
@@ -554,7 +554,7 @@ int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
dir->inode_no = 0;
if (likely(!err))
err = exofs_commit_chunk(page, pos, to - from);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
sbi->s_numfiles--;
out:
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index 9dc4c6dbf3c9..d42ff527ab21 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -1007,7 +1007,7 @@ static int _do_truncate(struct inode *inode, loff_t newsize)
struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
int ret;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
ret = ore_truncate(&sbi->layout, &oi->oc, (u64)newsize);
if (likely(!ret))
@@ -1034,7 +1034,7 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
if (unlikely(error))
return error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (unlikely(error))
return error;
@@ -1313,7 +1313,7 @@ struct inode *exofs_new_inode(struct inode *dir, umode_t mode)
inode_init_owner(inode, dir, mode);
inode->i_ino = sbi->s_nextid++;
inode->i_blkbits = EXOFS_BLKSHIFT;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
oi->i_commit_size = inode->i_size = 0;
spin_lock(&sbi->s_next_gen_lock);
inode->i_generation = sbi->s_next_generation++;
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index 622a686bb08b..7295cd722770 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -142,7 +142,7 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir,
{
struct inode *inode = d_inode(old_dentry);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
inode_inc_link_count(inode);
ihold(inode);
@@ -227,7 +227,8 @@ static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
}
static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
@@ -237,6 +238,9 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct exofs_dir_entry *old_de;
int err = -ENOENT;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
if (!old_de)
goto out;
@@ -261,7 +265,7 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!new_de)
goto out_dir;
err = exofs_set_link(new_dir, new_de, new_page, old_inode);
- new_inode->i_ctime = CURRENT_TIME;
+ new_inode->i_ctime = current_time(new_inode);
if (dir_de)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
@@ -275,7 +279,7 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
inode_inc_link_count(new_dir);
}
- old_inode->i_ctime = CURRENT_TIME;
+ old_inode->i_ctime = current_time(old_inode);
exofs_delete_entry(old_de, old_page);
mark_inode_dirty(old_inode);
@@ -310,7 +314,7 @@ const struct inode_operations exofs_dir_inode_operations = {
.mkdir = exofs_mkdir,
.rmdir = exofs_rmdir,
.mknod = exofs_mknod,
- .rename = exofs_rename,
+ .rename = exofs_rename,
.setattr = exofs_setattr,
};
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 42f1d1814083..79dafa71effd 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -190,15 +190,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- if (error == 0)
- acl = NULL;
- }
+ inode->i_ctime = current_time(inode);
+ mark_inode_dirty(inode);
}
break;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 61ad490ed67b..d9650c9508e4 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -471,7 +471,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
err = ext2_commit_chunk(page, pos, len);
ext2_put_page(page);
if (update_times)
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
}
@@ -561,7 +561,7 @@ got_it:
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type (de, inode);
err = ext2_commit_chunk(page, pos, rec_len);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
/* OFFSET_CACHE */
@@ -610,7 +610,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
pde->rec_len = ext2_rec_len_to_disk(to - from);
dir->inode = 0;
err = ext2_commit_chunk(page, pos, to - from);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(inode);
out:
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 423cc01c9d41..a0e1478dfd04 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -234,16 +234,14 @@ const struct file_operations ext2_file_operations = {
.open = dquot_file_open,
.release = ext2_release_file,
.fsync = ext2_fsync,
+ .get_unmapped_area = thp_get_unmapped_area,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
};
const struct inode_operations ext2_file_inode_operations = {
#ifdef CONFIG_EXT2_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
- .removexattr = generic_removexattr,
#endif
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 04e73a99902b..395fc074c0db 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -556,7 +556,7 @@ got:
inode->i_ino = ino;
inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
memset(ei->i_data, 0, sizeof(ei->i_data));
ei->i_flags =
ext2_mask_flags(mode, EXT2_I(dir)->i_flags & EXT2_FL_INHERITED);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 1e72d425fd3b..d831e24dc885 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -595,7 +595,7 @@ static void ext2_splice_branch(struct inode *inode,
if (where->bh)
mark_buffer_dirty_inode(where->bh, inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
}
@@ -1308,7 +1308,7 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
__ext2_truncate_blocks(inode, newsize);
dax_sem_up_write(EXT2_I(inode));
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
if (inode_needs_sync(inode)) {
sync_mapping_buffers(inode->i_mapping);
sync_inode_metadata(inode, 1);
@@ -1652,7 +1652,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index b386af2e45f4..9d617423e936 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -79,7 +79,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
ei->i_flags = flags;
ext2_set_inode_flags(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
inode_unlock(inode);
mark_inode_dirty(inode);
@@ -103,7 +103,7 @@ setflags_out:
}
inode_lock(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
inode->i_generation = generation;
inode_unlock(inode);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index d446203127fc..814e405a2da6 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -221,7 +221,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
if (err)
return err;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
inode_inc_link_count(inode);
ihold(inode);
@@ -328,7 +328,8 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
}
static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry )
+ struct inode * new_dir, struct dentry * new_dentry,
+ unsigned int flags)
{
struct inode * old_inode = d_inode(old_dentry);
struct inode * new_inode = d_inode(new_dentry);
@@ -338,6 +339,9 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
struct ext2_dir_entry_2 * old_de;
int err;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
err = dquot_initialize(old_dir);
if (err)
goto out;
@@ -372,7 +376,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
if (!new_de)
goto out_dir;
ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = current_time(new_inode);
if (dir_de)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
@@ -388,7 +392,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
* Like most other Unix systems, set the ctime for inodes on a
* rename.
*/
- old_inode->i_ctime = CURRENT_TIME_SEC;
+ old_inode->i_ctime = current_time(old_inode);
mark_inode_dirty(old_inode);
ext2_delete_entry (old_de, old_page);
@@ -428,10 +432,7 @@ const struct inode_operations ext2_dir_inode_operations = {
.mknod = ext2_mknod,
.rename = ext2_rename,
#ifdef CONFIG_EXT2_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
- .removexattr = generic_removexattr,
#endif
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
@@ -441,10 +442,7 @@ const struct inode_operations ext2_dir_inode_operations = {
const struct inode_operations ext2_special_inode_operations = {
#ifdef CONFIG_EXT2_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
- .removexattr = generic_removexattr,
#endif
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 1d9379568aa8..6cb042b53b5b 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1543,7 +1543,7 @@ out:
if (inode->i_size < off+len-towrite)
i_size_write(inode, off+len-towrite);
inode->i_version++;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
return len - towrite;
}
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 3495d8ae4b33..8437b191bf5d 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -25,10 +25,7 @@ const struct inode_operations ext2_symlink_inode_operations = {
.get_link = page_get_link,
.setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -37,9 +34,6 @@ const struct inode_operations ext2_fast_symlink_inode_operations = {
.get_link = simple_get_link,
.setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
- .removexattr = generic_removexattr,
#endif
};
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index b7f896f3f7a7..fbdb8f171893 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -691,7 +691,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
/* Update the inode. */
EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
if (IS_SYNC(inode)) {
error = sync_inode_metadata(inode, 1);
/* In case sync failed due to ENOSPC the inode was actually
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index c6601a476c02..dfa519979038 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -193,15 +193,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- if (error == 0)
- acl = NULL;
- }
+ inode->i_ctime = ext4_current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
}
break;
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 67415e0e6af0..e8b365000d73 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -260,11 +260,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
/* Directory is encrypted */
err = fscrypt_fname_disk_to_usr(inode,
0, 0, &de_name, &fstr);
+ de_name = fstr;
fstr.len = save_len;
- if (err < 0)
+ if (err)
goto errout;
if (!dir_emit(ctx,
- fstr.name, err,
+ de_name.name, de_name.len,
le32_to_cpu(de->inode),
get_dtype(sb, de->file_type)))
goto done;
@@ -627,7 +628,7 @@ int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
int buf_size)
{
struct ext4_dir_entry_2 *de;
- int nlen, rlen;
+ int rlen;
unsigned int offset = 0;
char *top;
@@ -637,7 +638,6 @@ int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
if (ext4_check_dir_entry(dir, NULL, de, bh,
buf, buf_size, offset))
return -EFSCORRUPTED;
- nlen = EXT4_DIR_REC_LEN(de->name_len);
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
offset += rlen;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index ea31931386ec..282a51b07c57 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -262,6 +262,9 @@ struct ext4_io_submit {
(s)->s_first_ino)
#endif
#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits)))
+#define EXT4_MAX_BLOCKS(size, offset, blkbits) \
+ ((EXT4_BLOCK_ALIGN(size + offset, blkbits) >> blkbits) - (offset >> \
+ blkbits))
/* Translate a block number to a cluster number */
#define EXT4_B2C(sbi, blk) ((blk) >> (sbi)->s_cluster_bits)
@@ -1117,9 +1120,15 @@ struct ext4_inode_info {
#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
-#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
-#define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
-#define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
+#define EXT4_MOUNT_QUOTA 0x40000 /* Some quota option set */
+#define EXT4_MOUNT_USRQUOTA 0x80000 /* "old" user quota,
+ * enable enforcement for hidden
+ * quota files */
+#define EXT4_MOUNT_GRPQUOTA 0x100000 /* "old" group quota, enable
+ * enforcement for hidden quota
+ * files */
+#define EXT4_MOUNT_PRJQUOTA 0x200000 /* Enable project quota
+ * enforcement */
#define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000 /* Enable support for dio read nolocking */
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
@@ -1636,26 +1645,6 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
* Feature set definitions
*/
-/* Use the ext4_{has,set,clear}_feature_* helpers; these will be removed */
-#define EXT4_HAS_COMPAT_FEATURE(sb,mask) \
- ((EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask)) != 0)
-#define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask) \
- ((EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask)) != 0)
-#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \
- ((EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask)) != 0)
-#define EXT4_SET_COMPAT_FEATURE(sb,mask) \
- EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
-#define EXT4_SET_RO_COMPAT_FEATURE(sb,mask) \
- EXT4_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
-#define EXT4_SET_INCOMPAT_FEATURE(sb,mask) \
- EXT4_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
-#define EXT4_CLEAR_COMPAT_FEATURE(sb,mask) \
- EXT4_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
-#define EXT4_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
- EXT4_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
-#define EXT4_CLEAR_INCOMPAT_FEATURE(sb,mask) \
- EXT4_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
-
#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index d7ccb7f51dfc..c930a0110fb4 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4679,6 +4679,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
unsigned int credits;
loff_t epos;
+ BUG_ON(!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS));
map.m_lblk = offset;
map.m_len = len;
/*
@@ -4693,13 +4694,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
* credits to insert 1 extent into extent tree
*/
credits = ext4_chunk_trans_blocks(inode, len);
- /*
- * We can only call ext_depth() on extent based inodes
- */
- if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
- depth = ext_depth(inode);
- else
- depth = -1;
+ depth = ext_depth(inode);
retry:
while (ret >= 0 && len) {
@@ -4966,13 +4961,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
trace_ext4_fallocate_enter(inode, offset, len, mode);
lblk = offset >> blkbits;
- /*
- * We can't just convert len to max_blocks because
- * If blocksize = 4096 offset = 3072 and len = 2048
- */
- max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
- - lblk;
+ max_blocks = EXT4_MAX_BLOCKS(len, offset, blkbits);
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
if (mode & FALLOC_FL_KEEP_SIZE)
flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
@@ -5035,12 +5025,8 @@ int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
unsigned int credits, blkbits = inode->i_blkbits;
map.m_lblk = offset >> blkbits;
- /*
- * We can't just convert len to max_blocks because
- * If blocksize = 4096 offset = 3072 and len = 2048
- */
- max_blocks = ((EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) -
- map.m_lblk);
+ max_blocks = EXT4_MAX_BLOCKS(len, offset, blkbits);
+
/*
* This is somewhat ugly but the idea is clear: When transaction is
* reserved, everything goes into it. Otherwise we rather start several
@@ -5734,6 +5720,9 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
up_write(&EXT4_I(inode)->i_data_sem);
goto out_stop;
}
+ } else {
+ ext4_ext_drop_refs(path);
+ kfree(path);
}
ret = ext4_es_remove_extent(inode, offset_lblk,
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 261ac3734c58..2a822d30e73f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -91,9 +91,7 @@ ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos)
static ssize_t
ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
- struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(iocb->ki_filp);
- struct blk_plug plug;
int o_direct = iocb->ki_flags & IOCB_DIRECT;
int unaligned_aio = 0;
int overwrite = 0;
@@ -134,18 +132,16 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (o_direct) {
size_t length = iov_iter_count(from);
loff_t pos = iocb->ki_pos;
- blk_start_plug(&plug);
/* 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)) {
+ 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;
+ map.m_len = EXT4_MAX_BLOCKS(length, pos, blkbits);
len = map.m_len;
err = ext4_map_blocks(NULL, inode, &map, 0);
@@ -171,8 +167,6 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (ret > 0)
ret = generic_write_sync(iocb, ret);
- if (o_direct)
- blk_finish_plug(&plug);
return ret;
@@ -703,6 +697,7 @@ const struct file_operations ext4_file_operations = {
.open = ext4_file_open,
.release = ext4_release_file,
.fsync = ext4_sync_file,
+ .get_unmapped_area = thp_get_unmapped_area,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = ext4_fallocate,
@@ -711,10 +706,7 @@ const struct file_operations ext4_file_operations = {
const struct inode_operations ext4_file_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 5c4372512ef7..88effb1053c7 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -61,6 +61,13 @@ static int ext4_sync_parent(struct inode *inode)
break;
iput(inode);
inode = next;
+ /*
+ * The directory inode may have gone through rmdir by now. But
+ * the inode itself and its blocks are still allocated (we hold
+ * a reference to the inode so it didn't go through
+ * ext4_evict_inode()) and so we are safe to flush metadata
+ * blocks and the inode.
+ */
ret = sync_mapping_buffers(inode->i_mapping);
if (ret)
break;
@@ -107,7 +114,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
if (!journal) {
ret = __generic_file_fsync(file, start, end, datasync);
- if (!ret && !hlist_empty(&inode->i_dentry))
+ if (!ret)
ret = ext4_sync_parent(inode);
if (test_opt(inode->i_sb, BARRIER))
goto issue_flush;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 9e66cd1d7b78..170421edfdfe 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -802,7 +802,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
} else
inode_init_owner(inode, dir, mode);
- if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+ if (ext4_has_feature_project(sb) &&
ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT))
ei->i_projid = EXT4_I(dir)->i_projid;
else
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c6ea25a190f8..9c064727ed62 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -647,11 +647,19 @@ found:
/*
* We have to zeroout blocks before inserting them into extent
* status tree. Otherwise someone could look them up there and
- * use them before they are really zeroed.
+ * use them before they are really zeroed. We also have to
+ * unmap metadata before zeroing as otherwise writeback can
+ * overwrite zeros with stale data from block device.
*/
if (flags & EXT4_GET_BLOCKS_ZERO &&
map->m_flags & EXT4_MAP_MAPPED &&
map->m_flags & EXT4_MAP_NEW) {
+ ext4_lblk_t i;
+
+ for (i = 0; i < map->m_len; i++) {
+ unmap_underlying_metadata(inode->i_sb->s_bdev,
+ map->m_pblk + i);
+ }
ret = ext4_issue_zeroout(inode, map->m_lblk,
map->m_pblk, map->m_len);
if (ret) {
@@ -1649,6 +1657,8 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd,
BUG_ON(!PageLocked(page));
BUG_ON(PageWriteback(page));
if (invalidate) {
+ if (page_mapped(page))
+ clear_page_dirty_for_io(page);
block_invalidatepage(page, 0, PAGE_SIZE);
ClearPageUptodate(page);
}
@@ -3526,35 +3536,31 @@ out:
static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
{
- int unlocked = 0;
- struct inode *inode = iocb->ki_filp->f_mapping->host;
+ struct address_space *mapping = iocb->ki_filp->f_mapping;
+ struct inode *inode = mapping->host;
ssize_t ret;
- if (ext4_should_dioread_nolock(inode)) {
- /*
- * Nolock dioread optimization may be dynamically disabled
- * via ext4_inode_block_unlocked_dio(). Check inode's state
- * while holding extra i_dio_count ref.
- */
- inode_dio_begin(inode);
- smp_mb();
- if (unlikely(ext4_test_inode_state(inode,
- EXT4_STATE_DIOREAD_LOCK)))
- inode_dio_end(inode);
- else
- unlocked = 1;
- }
+ /*
+ * Shared inode_lock is enough for us - it protects against concurrent
+ * writes & truncates and since we take care of writing back page cache,
+ * we are protected against page writeback as well.
+ */
+ inode_lock_shared(inode);
if (IS_DAX(inode)) {
- ret = dax_do_io(iocb, inode, iter, ext4_dio_get_block,
- NULL, unlocked ? 0 : DIO_LOCKING);
+ ret = dax_do_io(iocb, inode, iter, ext4_dio_get_block, NULL, 0);
} else {
+ size_t count = iov_iter_count(iter);
+
+ ret = filemap_write_and_wait_range(mapping, iocb->ki_pos,
+ iocb->ki_pos + count);
+ if (ret)
+ goto out_unlock;
ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
iter, ext4_dio_get_block,
- NULL, NULL,
- unlocked ? 0 : DIO_LOCKING);
+ NULL, NULL, 0);
}
- if (unlocked)
- inode_dio_end(inode);
+out_unlock:
+ inode_unlock_shared(inode);
return ret;
}
@@ -3890,7 +3896,7 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
}
/*
- * ext4_punch_hole: punches a hole in a file by releaseing the blocks
+ * ext4_punch_hole: punches a hole in a file by releasing the blocks
* associated with the given offset and length
*
* @inode: File inode
@@ -3919,7 +3925,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
* Write out all dirty pages to avoid race conditions
* Then release them.
*/
- if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+ if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
ret = filemap_write_and_wait_range(mapping, offset,
offset + length - 1);
if (ret)
@@ -4414,7 +4420,7 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
int ext4_get_projid(struct inode *inode, kprojid_t *projid)
{
- if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
+ if (!ext4_has_feature_project(inode->i_sb))
return -EOPNOTSUPP;
*projid = EXT4_I(inode)->i_projid;
return 0;
@@ -4481,7 +4487,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
inode->i_mode = le16_to_cpu(raw_inode->i_mode);
i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
- if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+ if (ext4_has_feature_project(sb) &&
EXT4_INODE_SIZE(sb) > EXT4_GOOD_OLD_INODE_SIZE &&
EXT4_FITS_IN_INODE(raw_inode, ei, i_projid))
i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
@@ -4814,14 +4820,14 @@ static int ext4_do_update_inode(handle_t *handle,
* Fix up interoperability with old kernels. Otherwise, old inodes get
* re-used with the upper 16 bits of the uid/gid intact
*/
- if (!ei->i_dtime) {
+ if (ei->i_dtime && list_empty(&ei->i_orphan)) {
+ raw_inode->i_uid_high = 0;
+ raw_inode->i_gid_high = 0;
+ } else {
raw_inode->i_uid_high =
cpu_to_le16(high_16_bits(i_uid));
raw_inode->i_gid_high =
cpu_to_le16(high_16_bits(i_gid));
- } else {
- raw_inode->i_uid_high = 0;
- raw_inode->i_gid_high = 0;
}
} else {
raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
@@ -4885,8 +4891,7 @@ static int ext4_do_update_inode(handle_t *handle,
}
}
- BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
- EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+ BUG_ON(!ext4_has_feature_project(inode->i_sb) &&
i_projid != EXT4_DEF_PROJID);
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
@@ -5073,7 +5078,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
int orphan = 0;
const unsigned int ia_valid = attr->ia_valid;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 1bb7df5e4536..bf5ae8ebbc97 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -19,8 +19,6 @@
#include "ext4_jbd2.h"
#include "ext4.h"
-#define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
-
/**
* Swap memory between @a and @b for @len bytes.
*
@@ -310,8 +308,7 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
struct ext4_inode *raw_inode;
struct dquot *transfer_to[MAXQUOTAS] = { };
- if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
- EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+ if (!ext4_has_feature_project(sb)) {
if (projid != EXT4_DEF_PROJID)
return -EOPNOTSUPP;
else
@@ -772,6 +769,9 @@ resizefs_out:
#ifdef CONFIG_EXT4_FS_ENCRYPTION
struct fscrypt_policy policy;
+ if (!ext4_has_feature_encrypt(sb))
+ return -EOPNOTSUPP;
+
if (copy_from_user(&policy,
(struct fscrypt_policy __user *)arg,
sizeof(policy)))
@@ -842,8 +842,7 @@ resizefs_out:
ext4_get_inode_flags(ei);
fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE);
- if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
- EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+ if (ext4_has_feature_project(inode->i_sb)) {
fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
EXT4_I(inode)->i_projid);
}
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index a920c5d29fac..6fc14def0c70 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -598,6 +598,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
return -EOPNOTSUPP;
}
+ if (ext4_encrypted_inode(orig_inode) ||
+ ext4_encrypted_inode(donor_inode)) {
+ ext4_msg(orig_inode->i_sb, KERN_ERR,
+ "Online defrag not supported for encrypted files");
+ return -EOPNOTSUPP;
+ }
+
/* Protect orig and donor inodes against a truncate */
lock_two_nondirectories(orig_inode, donor_inode);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 34c0142caf6a..f92f10d4f66a 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -639,7 +639,7 @@ static struct stats dx_show_leaf(struct inode *dir,
res = fscrypt_fname_alloc_buffer(
dir, len,
&fname_crypto_str);
- if (res < 0)
+ if (res)
printk(KERN_WARNING "Error "
"allocating crypto "
"buffer--skipping "
@@ -647,7 +647,7 @@ static struct stats dx_show_leaf(struct inode *dir,
res = fscrypt_fname_disk_to_usr(dir,
0, 0, &de_name,
&fname_crypto_str);
- if (res < 0) {
+ if (res) {
printk(KERN_WARNING "Error "
"converting filename "
"from disk to usr"
@@ -1011,7 +1011,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
err = fscrypt_fname_disk_to_usr(dir, hinfo->hash,
hinfo->minor_hash, &de_name,
&fname_crypto_str);
- if (err < 0) {
+ if (err) {
count = err;
goto errout;
}
@@ -2044,33 +2044,31 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
frame->entries = entries;
frame->at = entries;
frame->bh = bh;
- bh = bh2;
retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
if (retval)
goto out_frames;
- retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
+ retval = ext4_handle_dirty_dirent_node(handle, dir, bh2);
if (retval)
goto out_frames;
- de = do_split(handle,dir, &bh, frame, &fname->hinfo);
+ de = do_split(handle,dir, &bh2, frame, &fname->hinfo);
if (IS_ERR(de)) {
retval = PTR_ERR(de);
goto out_frames;
}
- dx_release(frames);
- retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh);
- brelse(bh);
- return retval;
+ retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2);
out_frames:
/*
* Even if the block split failed, we have to properly write
* out all the changes we did so far. Otherwise we can end up
* with corrupted filesystem.
*/
- ext4_mark_inode_dirty(handle, dir);
+ if (retval)
+ ext4_mark_inode_dirty(handle, dir);
dx_release(frames);
+ brelse(bh2);
return retval;
}
@@ -3144,7 +3142,7 @@ static int ext4_symlink(struct inode *dir,
istr.name = (const unsigned char *) symname;
istr.len = len;
err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
- if (err < 0)
+ if (err)
goto err_drop_inode;
sd->len = cpu_to_le16(ostr.len);
disk_link.name = (char *) sd;
@@ -3880,12 +3878,9 @@ const struct inode_operations ext4_dir_inode_operations = {
.rmdir = ext4_rmdir,
.mknod = ext4_mknod,
.tmpfile = ext4_tmpfile,
- .rename2 = ext4_rename2,
+ .rename = ext4_rename2,
.setattr = ext4_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
@@ -3893,10 +3888,7 @@ const struct inode_operations ext4_dir_inode_operations = {
const struct inode_operations ext4_special_inode_operations = {
.setattr = ext4_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
};
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index a6132a730967..b4cbee936cf8 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -405,14 +405,12 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
{
struct page *data_page = NULL;
struct inode *inode = page->mapping->host;
- unsigned block_start, blocksize;
+ unsigned block_start;
struct buffer_head *bh, *head;
int ret = 0;
int nr_submitted = 0;
int nr_to_submit = 0;
- blocksize = 1 << inode->i_blkbits;
-
BUG_ON(!PageLocked(page));
BUG_ON(PageWriteback(page));
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 3ec8708989ca..6db81fbcbaa6 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -78,6 +78,8 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly);
static void ext4_destroy_lazyinit_thread(void);
static void ext4_unregister_li_request(struct super_block *sb);
static void ext4_clear_request_list(void);
+static struct inode *ext4_get_journal_inode(struct super_block *sb,
+ unsigned int journal_inum);
/*
* Lock ordering
@@ -1267,7 +1269,7 @@ enum {
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
- Opt_usrquota, Opt_grpquota, Opt_i_version, Opt_dax,
+ Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, Opt_dax,
Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
Opt_lazytime, Opt_nolazytime,
Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
@@ -1327,6 +1329,7 @@ static const match_table_t tokens = {
{Opt_noquota, "noquota"},
{Opt_quota, "quota"},
{Opt_usrquota, "usrquota"},
+ {Opt_prjquota, "prjquota"},
{Opt_barrier, "barrier=%u"},
{Opt_barrier, "barrier"},
{Opt_nobarrier, "nobarrier"},
@@ -1546,8 +1549,11 @@ static const struct mount_opts {
MOPT_SET | MOPT_Q},
{Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
MOPT_SET | MOPT_Q},
+ {Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA,
+ MOPT_SET | MOPT_Q},
{Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
- EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
+ EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA),
+ MOPT_CLEAR | MOPT_Q},
{Opt_usrjquota, 0, MOPT_Q},
{Opt_grpjquota, 0, MOPT_Q},
{Opt_offusrjquota, 0, MOPT_Q},
@@ -1836,13 +1842,17 @@ static int parse_options(char *options, struct super_block *sb,
return 0;
}
#ifdef CONFIG_QUOTA
- if (ext4_has_feature_quota(sb) &&
- (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
- ext4_msg(sb, KERN_INFO, "Quota feature enabled, usrquota and grpquota "
- "mount options ignored.");
- clear_opt(sb, USRQUOTA);
- clear_opt(sb, GRPQUOTA);
- } else if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+ /*
+ * We do the test below only for project quotas. 'usrquota' and
+ * 'grpquota' mount options are allowed even without quota feature
+ * to support legacy quotas in quota files.
+ */
+ if (test_opt(sb, PRJQUOTA) && !ext4_has_feature_project(sb)) {
+ ext4_msg(sb, KERN_ERR, "Project quota feature not enabled. "
+ "Cannot enable project quota enforcement.");
+ return 0;
+ }
+ if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
clear_opt(sb, USRQUOTA);
@@ -2741,7 +2751,6 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
sb = elr->lr_super;
ngroups = EXT4_SB(sb)->s_groups_count;
- sb_start_write(sb);
for (group = elr->lr_next_group; group < ngroups; group++) {
gdp = ext4_get_group_desc(sb, group, NULL);
if (!gdp) {
@@ -2768,8 +2777,6 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
elr->lr_next_sched = jiffies + elr->lr_timeout;
elr->lr_next_group = group + 1;
}
- sb_end_write(sb);
-
return ret;
}
@@ -2834,19 +2841,43 @@ cont_thread:
mutex_unlock(&eli->li_list_mtx);
goto exit_thread;
}
-
list_for_each_safe(pos, n, &eli->li_request_list) {
+ int err = 0;
+ int progress = 0;
elr = list_entry(pos, struct ext4_li_request,
lr_request);
- if (time_after_eq(jiffies, elr->lr_next_sched)) {
- if (ext4_run_li_request(elr) != 0) {
- /* error, remove the lazy_init job */
- ext4_remove_li_request(elr);
- continue;
+ if (time_before(jiffies, elr->lr_next_sched)) {
+ if (time_before(elr->lr_next_sched, next_wakeup))
+ next_wakeup = elr->lr_next_sched;
+ continue;
+ }
+ if (down_read_trylock(&elr->lr_super->s_umount)) {
+ if (sb_start_write_trylock(elr->lr_super)) {
+ progress = 1;
+ /*
+ * We hold sb->s_umount, sb can not
+ * be removed from the list, it is
+ * now safe to drop li_list_mtx
+ */
+ mutex_unlock(&eli->li_list_mtx);
+ err = ext4_run_li_request(elr);
+ sb_end_write(elr->lr_super);
+ mutex_lock(&eli->li_list_mtx);
+ n = pos->next;
}
+ up_read((&elr->lr_super->s_umount));
+ }
+ /* error, remove the lazy_init job */
+ if (err) {
+ ext4_remove_li_request(elr);
+ continue;
+ }
+ if (!progress) {
+ elr->lr_next_sched = jiffies +
+ (prandom_u32()
+ % (EXT4_DEF_LI_MAX_START_DELAY * HZ));
}
-
if (time_before(elr->lr_next_sched, next_wakeup))
next_wakeup = elr->lr_next_sched;
}
@@ -3179,6 +3210,8 @@ int ext4_calculate_overhead(struct super_block *sb)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es;
+ struct inode *j_inode;
+ unsigned int j_blocks, j_inum = le32_to_cpu(es->s_journal_inum);
ext4_group_t i, ngroups = ext4_get_groups_count(sb);
ext4_fsblk_t overhead = 0;
char *buf = (char *) get_zeroed_page(GFP_NOFS);
@@ -3209,10 +3242,23 @@ int ext4_calculate_overhead(struct super_block *sb)
memset(buf, 0, PAGE_SIZE);
cond_resched();
}
- /* Add the internal journal blocks as well */
+
+ /*
+ * Add the internal journal blocks whether the journal has been
+ * loaded or not
+ */
if (sbi->s_journal && !sbi->journal_bdev)
overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_maxlen);
-
+ else if (ext4_has_feature_journal(sb) && !sbi->s_journal) {
+ j_inode = ext4_get_journal_inode(sb, j_inum);
+ if (j_inode) {
+ j_blocks = j_inode->i_size >> sb->s_blocksize_bits;
+ overhead += EXT4_NUM_B2C(sbi, j_blocks);
+ iput(j_inode);
+ } else {
+ ext4_msg(sb, KERN_ERR, "can't get journal size");
+ }
+ }
sbi->s_overhead = overhead;
smp_wmb();
free_page((unsigned long) buf);
@@ -4208,18 +4254,16 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
write_unlock(&journal->j_state_lock);
}
-static journal_t *ext4_get_journal(struct super_block *sb,
- unsigned int journal_inum)
+static struct inode *ext4_get_journal_inode(struct super_block *sb,
+ unsigned int journal_inum)
{
struct inode *journal_inode;
- journal_t *journal;
-
- BUG_ON(!ext4_has_feature_journal(sb));
-
- /* First, test for the existence of a valid inode on disk. Bad
- * things happen if we iget() an unused inode, as the subsequent
- * iput() will try to delete it. */
+ /*
+ * Test for the existence of a valid inode on disk. Bad things
+ * happen if we iget() an unused inode, as the subsequent iput()
+ * will try to delete it.
+ */
journal_inode = ext4_iget(sb, journal_inum);
if (IS_ERR(journal_inode)) {
ext4_msg(sb, KERN_ERR, "no journal found");
@@ -4239,6 +4283,20 @@ static journal_t *ext4_get_journal(struct super_block *sb,
iput(journal_inode);
return NULL;
}
+ return journal_inode;
+}
+
+static journal_t *ext4_get_journal(struct super_block *sb,
+ unsigned int journal_inum)
+{
+ struct inode *journal_inode;
+ journal_t *journal;
+
+ BUG_ON(!ext4_has_feature_journal(sb));
+
+ journal_inode = ext4_get_journal_inode(sb, journal_inum);
+ if (!journal_inode)
+ return NULL;
journal = jbd2_journal_init_inode(journal_inode);
if (!journal) {
@@ -5250,12 +5308,18 @@ static int ext4_enable_quotas(struct super_block *sb)
le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
};
+ bool quota_mopt[EXT4_MAXQUOTAS] = {
+ test_opt(sb, USRQUOTA),
+ test_opt(sb, GRPQUOTA),
+ test_opt(sb, PRJQUOTA),
+ };
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
for (type = 0; type < EXT4_MAXQUOTAS; type++) {
if (qf_inums[type]) {
err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
- DQUOT_USAGE_ENABLED);
+ DQUOT_USAGE_ENABLED |
+ (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
if (err) {
ext4_warning(sb,
"Failed to enable quota tracking "
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index 4d83d9e05f2e..557b3b0d668c 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -30,7 +30,6 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
char *caddr, *paddr = NULL;
struct fscrypt_str cstr, pstr;
struct fscrypt_symlink_data *sd;
- loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
int res;
u32 max_size = inode->i_sb->s_blocksize;
@@ -49,7 +48,6 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
if (IS_ERR(cpage))
return ERR_CAST(cpage);
caddr = page_address(cpage);
- caddr[size] = 0;
}
/* Symlink is encrypted */
@@ -65,16 +63,14 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
if (res)
goto errout;
+ paddr = pstr.name;
res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
- if (res < 0)
+ if (res)
goto errout;
- paddr = pstr.name;
-
/* Null-terminate the name */
- if (res <= pstr.len)
- paddr[res] = '\0';
+ paddr[pstr.len] = '\0';
if (cpage)
put_page(cpage);
set_delayed_call(done, kfree_link, paddr);
@@ -90,28 +86,19 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = ext4_encrypted_get_link,
.setattr = ext4_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
- .removexattr = generic_removexattr,
};
const struct inode_operations ext4_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
.setattr = ext4_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
- .removexattr = generic_removexattr,
};
const struct inode_operations ext4_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link,
.setattr = ext4_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
- .removexattr = generic_removexattr,
};
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 2eb935ca5d9e..c15d63389957 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -199,6 +199,8 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
}
while (!IS_LAST_ENTRY(entry)) {
+ if (entry->e_value_block != 0)
+ return -EFSCORRUPTED;
if (entry->e_value_size != 0 &&
(value_start + le16_to_cpu(entry->e_value_offs) <
(void *)e + sizeof(__u32) ||
@@ -641,7 +643,7 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
size_t *min_offs, void *base, int *total)
{
for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
- if (!last->e_value_block && last->e_value_size) {
+ if (last->e_value_size) {
size_t offs = le16_to_cpu(last->e_value_offs);
if (offs < *min_offs)
*min_offs = offs;
@@ -661,7 +663,7 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
/* Compute min_offs and last. */
last = s->first;
for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
- if (!last->e_value_block && last->e_value_size) {
+ if (last->e_value_size) {
size_t offs = le16_to_cpu(last->e_value_offs);
if (offs < min_offs)
min_offs = offs;
@@ -669,7 +671,7 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
}
free = min_offs - ((void *)last - s->base) - sizeof(__u32);
if (!s->not_found) {
- if (!s->here->e_value_block && s->here->e_value_size) {
+ if (s->here->e_value_size) {
size_t size = le32_to_cpu(s->here->e_value_size);
free += EXT4_XATTR_SIZE(size);
}
@@ -691,7 +693,7 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
s->here->e_name_len = name_len;
memcpy(s->here->e_name, i->name, name_len);
} else {
- if (!s->here->e_value_block && s->here->e_value_size) {
+ if (s->here->e_value_size) {
void *first_val = s->base + min_offs;
size_t offs = le16_to_cpu(s->here->e_value_offs);
void *val = s->base + offs;
@@ -725,8 +727,7 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
last = s->first;
while (!IS_LAST_ENTRY(last)) {
size_t o = le16_to_cpu(last->e_value_offs);
- if (!last->e_value_block &&
- last->e_value_size && o < offs)
+ if (last->e_value_size && o < offs)
last->e_value_offs =
cpu_to_le16(o + size);
last = EXT4_XATTR_NEXT(last);
@@ -1318,18 +1319,19 @@ retry:
*/
static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
int value_offs_shift, void *to,
- void *from, size_t n, int blocksize)
+ void *from, size_t n)
{
struct ext4_xattr_entry *last = entry;
int new_offs;
+ /* We always shift xattr headers further thus offsets get lower */
+ BUG_ON(value_offs_shift > 0);
+
/* Adjust the value offsets of the entries */
for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
- if (!last->e_value_block && last->e_value_size) {
+ if (last->e_value_size) {
new_offs = le16_to_cpu(last->e_value_offs) +
value_offs_shift;
- BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
- > blocksize);
last->e_value_offs = cpu_to_le16(new_offs);
}
}
@@ -1338,6 +1340,141 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
}
/*
+ * Move xattr pointed to by 'entry' from inode into external xattr block
+ */
+static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
+ struct ext4_inode *raw_inode,
+ struct ext4_xattr_entry *entry)
+{
+ struct ext4_xattr_ibody_find *is = NULL;
+ struct ext4_xattr_block_find *bs = NULL;
+ char *buffer = NULL, *b_entry_name = NULL;
+ size_t value_offs, value_size;
+ struct ext4_xattr_info i = {
+ .value = NULL,
+ .value_len = 0,
+ .name_index = entry->e_name_index,
+ };
+ struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode);
+ int error;
+
+ value_offs = le16_to_cpu(entry->e_value_offs);
+ value_size = le32_to_cpu(entry->e_value_size);
+
+ is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
+ bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
+ buffer = kmalloc(value_size, GFP_NOFS);
+ b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
+ if (!is || !bs || !buffer || !b_entry_name) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ is->s.not_found = -ENODATA;
+ bs->s.not_found = -ENODATA;
+ is->iloc.bh = NULL;
+ bs->bh = NULL;
+
+ /* Save the entry name and the entry value */
+ memcpy(buffer, (void *)IFIRST(header) + value_offs, value_size);
+ memcpy(b_entry_name, entry->e_name, entry->e_name_len);
+ b_entry_name[entry->e_name_len] = '\0';
+ i.name = b_entry_name;
+
+ error = ext4_get_inode_loc(inode, &is->iloc);
+ if (error)
+ goto out;
+
+ error = ext4_xattr_ibody_find(inode, &i, is);
+ if (error)
+ goto out;
+
+ /* Remove the chosen entry from the inode */
+ error = ext4_xattr_ibody_set(handle, inode, &i, is);
+ if (error)
+ goto out;
+
+ i.name = b_entry_name;
+ i.value = buffer;
+ i.value_len = value_size;
+ error = ext4_xattr_block_find(inode, &i, bs);
+ if (error)
+ goto out;
+
+ /* Add entry which was removed from the inode into the block */
+ error = ext4_xattr_block_set(handle, inode, &i, bs);
+ if (error)
+ goto out;
+ error = 0;
+out:
+ kfree(b_entry_name);
+ kfree(buffer);
+ if (is)
+ brelse(is->iloc.bh);
+ kfree(is);
+ kfree(bs);
+
+ return error;
+}
+
+static int ext4_xattr_make_inode_space(handle_t *handle, struct inode *inode,
+ struct ext4_inode *raw_inode,
+ int isize_diff, size_t ifree,
+ size_t bfree, int *total_ino)
+{
+ struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode);
+ struct ext4_xattr_entry *small_entry;
+ struct ext4_xattr_entry *entry;
+ struct ext4_xattr_entry *last;
+ unsigned int entry_size; /* EA entry size */
+ unsigned int total_size; /* EA entry size + value size */
+ unsigned int min_total_size;
+ int error;
+
+ while (isize_diff > ifree) {
+ entry = NULL;
+ small_entry = NULL;
+ min_total_size = ~0U;
+ last = IFIRST(header);
+ /* Find the entry best suited to be pushed into EA block */
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ total_size =
+ EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
+ EXT4_XATTR_LEN(last->e_name_len);
+ if (total_size <= bfree &&
+ total_size < min_total_size) {
+ if (total_size + ifree < isize_diff) {
+ small_entry = last;
+ } else {
+ entry = last;
+ min_total_size = total_size;
+ }
+ }
+ }
+
+ if (entry == NULL) {
+ if (small_entry == NULL)
+ return -ENOSPC;
+ entry = small_entry;
+ }
+
+ entry_size = EXT4_XATTR_LEN(entry->e_name_len);
+ total_size = entry_size +
+ EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
+ error = ext4_xattr_move_to_block(handle, inode, raw_inode,
+ entry);
+ if (error)
+ return error;
+
+ *total_ino -= entry_size;
+ ifree += total_size;
+ bfree -= total_size;
+ }
+
+ return 0;
+}
+
+/*
* Expand an inode by new_extra_isize bytes when EAs are present.
* Returns 0 on success or negative error number on failure.
*/
@@ -1345,14 +1482,11 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
struct ext4_inode *raw_inode, handle_t *handle)
{
struct ext4_xattr_ibody_header *header;
- struct ext4_xattr_entry *entry, *last, *first;
struct buffer_head *bh = NULL;
- struct ext4_xattr_ibody_find *is = NULL;
- struct ext4_xattr_block_find *bs = NULL;
- char *buffer = NULL, *b_entry_name = NULL;
- size_t min_offs, free;
+ size_t min_offs;
+ size_t ifree, bfree;
int total_ino;
- void *base, *start, *end;
+ void *base, *end;
int error = 0, tried_min_extra_isize = 0;
int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize);
int isize_diff; /* How much do we need to grow i_extra_isize */
@@ -1368,34 +1502,24 @@ retry:
goto out;
header = IHDR(inode, raw_inode);
- entry = IFIRST(header);
/*
* Check if enough free space is available in the inode to shift the
* entries ahead by new_extra_isize.
*/
- base = start = entry;
+ base = IFIRST(header);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
min_offs = end - base;
- last = entry;
total_ino = sizeof(struct ext4_xattr_ibody_header);
error = xattr_check_inode(inode, header, end);
if (error)
goto cleanup;
- free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
- if (free >= isize_diff) {
- entry = IFIRST(header);
- ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
- - new_extra_isize, (void *)raw_inode +
- EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
- (void *)header, total_ino,
- inode->i_sb->s_blocksize);
- EXT4_I(inode)->i_extra_isize = new_extra_isize;
- goto out;
- }
+ ifree = ext4_xattr_free_space(base, &min_offs, base, &total_ino);
+ if (ifree >= isize_diff)
+ goto shift;
/*
* Enough free space isn't available in the inode, check if
@@ -1413,146 +1537,44 @@ retry:
goto cleanup;
}
base = BHDR(bh);
- first = BFIRST(bh);
end = bh->b_data + bh->b_size;
min_offs = end - base;
- free = ext4_xattr_free_space(first, &min_offs, base, NULL);
- if (free < isize_diff) {
+ bfree = ext4_xattr_free_space(BFIRST(bh), &min_offs, base,
+ NULL);
+ if (bfree + ifree < isize_diff) {
if (!tried_min_extra_isize && s_min_extra_isize) {
tried_min_extra_isize++;
new_extra_isize = s_min_extra_isize;
brelse(bh);
goto retry;
}
- error = -1;
+ error = -ENOSPC;
goto cleanup;
}
} else {
- free = inode->i_sb->s_blocksize;
+ bfree = inode->i_sb->s_blocksize;
}
- while (isize_diff > 0) {
- size_t offs, size, entry_size;
- struct ext4_xattr_entry *small_entry = NULL;
- struct ext4_xattr_info i = {
- .value = NULL,
- .value_len = 0,
- };
- unsigned int total_size; /* EA entry size + value size */
- unsigned int shift_bytes; /* No. of bytes to shift EAs by? */
- unsigned int min_total_size = ~0U;
-
- is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
- bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
- if (!is || !bs) {
- error = -ENOMEM;
- goto cleanup;
- }
-
- is->s.not_found = -ENODATA;
- bs->s.not_found = -ENODATA;
- is->iloc.bh = NULL;
- bs->bh = NULL;
-
- last = IFIRST(header);
- /* Find the entry best suited to be pushed into EA block */
- entry = NULL;
- for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
- total_size =
- EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
- EXT4_XATTR_LEN(last->e_name_len);
- if (total_size <= free && total_size < min_total_size) {
- if (total_size < isize_diff) {
- small_entry = last;
- } else {
- entry = last;
- min_total_size = total_size;
- }
- }
- }
-
- if (entry == NULL) {
- if (small_entry) {
- entry = small_entry;
- } else {
- if (!tried_min_extra_isize &&
- s_min_extra_isize) {
- tried_min_extra_isize++;
- new_extra_isize = s_min_extra_isize;
- kfree(is); is = NULL;
- kfree(bs); bs = NULL;
- brelse(bh);
- goto retry;
- }
- error = -1;
- goto cleanup;
- }
- }
- offs = le16_to_cpu(entry->e_value_offs);
- size = le32_to_cpu(entry->e_value_size);
- entry_size = EXT4_XATTR_LEN(entry->e_name_len);
- i.name_index = entry->e_name_index,
- buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
- b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
- if (!buffer || !b_entry_name) {
- error = -ENOMEM;
- goto cleanup;
+ error = ext4_xattr_make_inode_space(handle, inode, raw_inode,
+ isize_diff, ifree, bfree,
+ &total_ino);
+ if (error) {
+ if (error == -ENOSPC && !tried_min_extra_isize &&
+ s_min_extra_isize) {
+ tried_min_extra_isize++;
+ new_extra_isize = s_min_extra_isize;
+ brelse(bh);
+ goto retry;
}
- /* Save the entry name and the entry value */
- memcpy(buffer, (void *)IFIRST(header) + offs,
- EXT4_XATTR_SIZE(size));
- memcpy(b_entry_name, entry->e_name, entry->e_name_len);
- b_entry_name[entry->e_name_len] = '\0';
- i.name = b_entry_name;
-
- error = ext4_get_inode_loc(inode, &is->iloc);
- if (error)
- goto cleanup;
-
- error = ext4_xattr_ibody_find(inode, &i, is);
- if (error)
- goto cleanup;
-
- /* Remove the chosen entry from the inode */
- error = ext4_xattr_ibody_set(handle, inode, &i, is);
- if (error)
- goto cleanup;
- total_ino -= entry_size;
-
- entry = IFIRST(header);
- if (entry_size + EXT4_XATTR_SIZE(size) >= isize_diff)
- shift_bytes = isize_diff;
- else
- shift_bytes = entry_size + EXT4_XATTR_SIZE(size);
- /* Adjust the offsets and shift the remaining entries ahead */
- ext4_xattr_shift_entries(entry, -shift_bytes,
- (void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
- EXT4_I(inode)->i_extra_isize + shift_bytes,
- (void *)header, total_ino, inode->i_sb->s_blocksize);
-
- isize_diff -= shift_bytes;
- EXT4_I(inode)->i_extra_isize += shift_bytes;
- header = IHDR(inode, raw_inode);
-
- i.name = b_entry_name;
- i.value = buffer;
- i.value_len = size;
- error = ext4_xattr_block_find(inode, &i, bs);
- if (error)
- goto cleanup;
-
- /* Add entry which was removed from the inode into the block */
- error = ext4_xattr_block_set(handle, inode, &i, bs);
- if (error)
- goto cleanup;
- kfree(b_entry_name);
- kfree(buffer);
- b_entry_name = NULL;
- buffer = NULL;
- brelse(is->iloc.bh);
- kfree(is);
- kfree(bs);
+ goto cleanup;
}
+shift:
+ /* Adjust the offsets and shift the remaining entries ahead */
+ ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize
+ - new_extra_isize, (void *)raw_inode +
+ EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
+ (void *)header, total_ino);
+ EXT4_I(inode)->i_extra_isize = new_extra_isize;
brelse(bh);
out:
ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
@@ -1560,12 +1582,6 @@ out:
return 0;
cleanup:
- kfree(b_entry_name);
- kfree(buffer);
- if (is)
- brelse(is->iloc.bh);
- kfree(is);
- kfree(bs);
brelse(bh);
/*
* We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
@@ -1734,7 +1750,7 @@ static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
*name++;
}
- if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+ if (entry->e_value_size != 0) {
__le32 *value = (__le32 *)((char *)header +
le16_to_cpu(entry->e_value_offs));
for (n = (le32_to_cpu(entry->e_value_size) +
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 1e29630f49c1..6fe23af509e1 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -212,12 +212,10 @@ static int __f2fs_set_acl(struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
set_acl_inode(inode, inode->i_mode);
- if (error == 0)
- acl = NULL;
}
break;
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index cbf85f65ba63..369f4513be37 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -312,7 +312,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
f2fs_dentry_kunmap(dir, page);
set_page_dirty(page);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir);
f2fs_put_page(page, 1);
}
@@ -465,7 +465,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode,
f2fs_i_links_write(dir, true);
clear_inode_flag(inode, FI_NEW_INODE);
}
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir);
if (F2FS_I(dir)->i_current_depth != current_depth)
@@ -683,7 +683,7 @@ void f2fs_drop_nlink(struct inode *dir, struct inode *inode)
if (S_ISDIR(inode->i_mode))
f2fs_i_links_write(dir, false);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
f2fs_i_links_write(inode, false);
if (S_ISDIR(inode->i_mode)) {
@@ -730,7 +730,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
kunmap(page); /* kunmap - pair of f2fs_find_entry */
set_page_dirty(page);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir);
if (inode)
@@ -813,12 +813,12 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
if (f2fs_encrypted_inode(d->inode)) {
int save_len = fstr->len;
- int ret;
+ int err;
- ret = fscrypt_fname_disk_to_usr(d->inode,
+ err = fscrypt_fname_disk_to_usr(d->inode,
(u32)de->hash_code, 0,
&de_name, fstr);
- if (ret < 0)
+ if (err)
return true;
de_name = *fstr;
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index f8b4fe05385d..c7865073cd26 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -631,7 +631,7 @@ int f2fs_truncate(struct inode *inode)
if (err)
return err;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
f2fs_mark_inode_dirty_sync(inode);
return 0;
}
@@ -680,7 +680,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int err;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
@@ -708,7 +708,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
}
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
}
}
@@ -732,10 +732,7 @@ const struct inode_operations f2fs_file_inode_operations = {
.get_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
#ifdef CONFIG_F2FS_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = f2fs_listxattr,
- .removexattr = generic_removexattr,
#endif
.fiemap = f2fs_fiemap,
};
@@ -1395,7 +1392,7 @@ static long f2fs_fallocate(struct file *file, int mode,
}
if (!ret) {
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
f2fs_mark_inode_dirty_sync(inode);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
}
@@ -1487,7 +1484,7 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
fi->i_flags = flags;
inode_unlock(inode);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
f2fs_set_inode_flags(inode);
out:
mnt_drop_write_file(filp);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 34234d84a38b..5f1a67f756af 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -572,7 +572,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
set_page_dirty(page);
f2fs_put_page(page, 1);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir);
if (inode)
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 300aef8a2d5f..489fa0d5f914 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -46,7 +46,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
inode->i_ino = ino;
inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_generation = sbi->s_next_generation++;
err = insert_inode_locked(inode);
@@ -182,7 +182,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
f2fs_balance_fs(sbi, true);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
ihold(inode);
set_inode_flag(inode, FI_INC_LINK);
@@ -454,7 +454,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
ostr.name = sd->encrypted_path;
ostr.len = disk_link.len;
err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
- if (err < 0)
+ if (err)
goto err_out;
sd->len = cpu_to_le16(ostr.len);
@@ -723,7 +723,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
f2fs_set_link(new_dir, new_entry, new_page, old_inode);
- new_inode->i_ctime = CURRENT_TIME;
+ new_inode->i_ctime = current_time(new_inode);
down_write(&F2FS_I(new_inode)->i_sem);
if (old_dir_entry)
f2fs_i_links_write(new_inode, false);
@@ -777,7 +777,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
file_set_enc_name(old_inode);
up_write(&F2FS_I(old_inode)->i_sem);
- old_inode->i_ctime = CURRENT_TIME;
+ old_inode->i_ctime = current_time(old_inode);
f2fs_mark_inode_dirty_sync(old_inode);
f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
@@ -932,7 +932,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
file_lost_pino(old_inode);
up_write(&F2FS_I(old_inode)->i_sem);
- old_dir->i_ctime = CURRENT_TIME;
+ old_dir->i_ctime = current_time(old_dir);
if (old_nlink) {
down_write(&F2FS_I(old_dir)->i_sem);
f2fs_i_links_write(old_dir, old_nlink > 0);
@@ -947,7 +947,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
file_lost_pino(new_inode);
up_write(&F2FS_I(new_inode)->i_sem);
- new_dir->i_ctime = CURRENT_TIME;
+ new_dir->i_ctime = current_time(new_dir);
if (new_nlink) {
down_write(&F2FS_I(new_dir)->i_sem);
f2fs_i_links_write(new_dir, new_nlink > 0);
@@ -1051,7 +1051,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
goto errout;
res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
- if (res < 0)
+ if (res)
goto errout;
/* this is broken symlink case */
@@ -1063,7 +1063,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
paddr = pstr.name;
/* Null-terminate the name */
- paddr[res] = '\0';
+ paddr[pstr.len] = '\0';
put_page(cpage);
set_delayed_call(done, kfree_link, paddr);
@@ -1080,10 +1080,7 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = f2fs_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -1096,17 +1093,14 @@ const struct inode_operations f2fs_dir_inode_operations = {
.mkdir = f2fs_mkdir,
.rmdir = f2fs_rmdir,
.mknod = f2fs_mknod,
- .rename2 = f2fs_rename2,
+ .rename = f2fs_rename2,
.tmpfile = f2fs_tmpfile,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
.get_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
#ifdef CONFIG_F2FS_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = f2fs_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -1116,10 +1110,7 @@ const struct inode_operations f2fs_symlink_inode_operations = {
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = f2fs_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -1129,9 +1120,6 @@ const struct inode_operations f2fs_special_inode_operations = {
.get_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
#ifdef CONFIG_F2FS_FS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = f2fs_listxattr,
- .removexattr = generic_removexattr,
#endif
};
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 883103593f33..01177ecdeab8 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1525,7 +1525,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
{
pgoff_t index = 0, end = ULONG_MAX;
struct pagevec pvec;
- int ret2 = 0, ret = 0;
+ int ret2, ret = 0;
pagevec_init(&pvec, 0);
@@ -1554,10 +1554,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
cond_resched();
}
- if (unlikely(test_and_clear_bit(AS_ENOSPC, &NODE_MAPPING(sbi)->flags)))
- ret2 = -ENOSPC;
- if (unlikely(test_and_clear_bit(AS_EIO, &NODE_MAPPING(sbi)->flags)))
- ret2 = -EIO;
+ ret2 = filemap_check_errors(NODE_MAPPING(sbi));
if (!ret)
ret = ret2;
return ret;
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 1f74876233b6..3e1c0280f866 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -548,7 +548,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
if (is_inode_flag_set(inode, FI_ACL_MODE)) {
inode->i_mode = F2FS_I(inode)->i_acl_mode;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
clear_inode_flag(inode, FI_ACL_MODE);
}
if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 663e428596c6..81cecbe6d7cf 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -1071,7 +1071,7 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
}
}
- dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_atime = current_time(dir);
if (IS_DIRSYNC(dir))
(void)fat_sync_inode(dir);
else
diff --git a/fs/fat/file.c b/fs/fat/file.c
index f70185668832..3d04b124bce0 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -63,7 +63,7 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
/* Equivalent to a chmod() */
ia.ia_valid = ATTR_MODE | ATTR_CTIME;
- ia.ia_ctime = current_fs_time(inode->i_sb);
+ ia.ia_ctime = current_time(inode);
if (is_dir)
ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
else {
@@ -194,7 +194,7 @@ static int fat_cont_expand(struct inode *inode, loff_t size)
if (err)
goto out;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
if (IS_SYNC(inode)) {
int err2;
@@ -297,7 +297,7 @@ static int fat_free(struct inode *inode, int skip)
MSDOS_I(inode)->i_logstart = 0;
}
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
if (wait) {
err = fat_sync_inode(inode);
if (err) {
@@ -450,7 +450,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_valid &= ~TIMES_SET_FLAGS;
}
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
attr->ia_valid = ia_valid;
if (error) {
if (sbi->options.quiet)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index da04c0298fab..338d2f73eb29 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -237,7 +237,7 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
if (err < len)
fat_write_failed(mapping, pos + len);
if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
mark_inode_dirty(inode);
}
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 664655b2c55f..7d6a105d601b 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -283,7 +283,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
goto out;
}
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
if (err)
goto out;
@@ -330,7 +330,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
drop_nlink(dir);
clear_nlink(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
fat_detach(inode);
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -364,7 +364,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
goto out;
}
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
cluster = fat_alloc_new_dir(dir, &ts);
if (cluster < 0) {
err = cluster;
@@ -416,7 +416,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
if (err)
goto out;
clear_nlink(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
fat_detach(inode);
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -481,7 +481,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
mark_inode_dirty(old_inode);
old_dir->i_version++;
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
if (IS_DIRSYNC(old_dir))
(void)fat_sync_inode(old_dir);
else
@@ -490,7 +490,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
}
}
- ts = CURRENT_TIME_SEC;
+ ts = current_time(old_inode);
if (new_inode) {
if (err)
goto out;
@@ -596,12 +596,16 @@ error_inode:
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct super_block *sb = old_dir->i_sb;
unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
int err, is_hid;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
mutex_lock(&MSDOS_SB(sb)->s_lock);
err = msdos_format_name(old_dentry->d_name.name,
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 92b7363dafa9..6a7152d0c250 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -21,6 +21,17 @@
#include <linux/namei.h>
#include "fat.h"
+static inline unsigned long vfat_d_version(struct dentry *dentry)
+{
+ return (unsigned long) dentry->d_fsdata;
+}
+
+static inline void vfat_d_version_set(struct dentry *dentry,
+ unsigned long version)
+{
+ dentry->d_fsdata = (void *) version;
+}
+
/*
* If new entry was created in the parent, it could create the 8.3
* alias (the shortname of logname). So, the parent may have the
@@ -33,7 +44,7 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
{
int ret = 1;
spin_lock(&dentry->d_lock);
- if (dentry->d_time != d_inode(dentry->d_parent)->i_version)
+ if (vfat_d_version(dentry) != d_inode(dentry->d_parent)->i_version)
ret = 0;
spin_unlock(&dentry->d_lock);
return ret;
@@ -759,7 +770,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
if (!inode)
- dentry->d_time = dir->i_version;
+ vfat_d_version_set(dentry, dir->i_version);
return d_splice_alias(inode, dentry);
error:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -777,7 +788,7 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
mutex_lock(&MSDOS_SB(sb)->s_lock);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
if (err)
goto out;
@@ -821,9 +832,9 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
drop_nlink(dir);
clear_nlink(inode);
- inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = current_time(inode);
fat_detach(inode);
- dentry->d_time = dir->i_version;
+ vfat_d_version_set(dentry, dir->i_version);
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -847,9 +858,9 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
if (err)
goto out;
clear_nlink(inode);
- inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = current_time(inode);
fat_detach(inode);
- dentry->d_time = dir->i_version;
+ vfat_d_version_set(dentry, dir->i_version);
out:
mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -866,7 +877,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
mutex_lock(&MSDOS_SB(sb)->s_lock);
- ts = CURRENT_TIME_SEC;
+ ts = current_time(dir);
cluster = fat_alloc_new_dir(dir, &ts);
if (cluster < 0) {
err = cluster;
@@ -903,7 +914,8 @@ out:
}
static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct buffer_head *dotdot_bh;
struct msdos_dir_entry *dotdot_de;
@@ -914,6 +926,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
int err, is_dir, update_dotdot, corrupt = 0;
struct super_block *sb = old_dir->i_sb;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_inode = d_inode(old_dentry);
new_inode = d_inode(new_dentry);
@@ -931,7 +946,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
}
}
- ts = CURRENT_TIME_SEC;
+ ts = current_time(old_dir);
if (new_inode) {
if (is_dir) {
err = fat_dir_empty(new_inode);
diff --git a/fs/file.c b/fs/file.c
index 6b1acdfe59da..69d6990e3021 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -23,12 +23,12 @@
#include <linux/rcupdate.h>
#include <linux/workqueue.h>
-int sysctl_nr_open __read_mostly = 1024*1024;
-int sysctl_nr_open_min = BITS_PER_LONG;
+unsigned int sysctl_nr_open __read_mostly = 1024*1024;
+unsigned int sysctl_nr_open_min = BITS_PER_LONG;
/* our min() is unusable in constant expressions ;-/ */
#define __const_min(x, y) ((x) < (y) ? (x) : (y))
-int sysctl_nr_open_max = __const_min(INT_MAX, ~(size_t)0/sizeof(void *)) &
- -BITS_PER_LONG;
+unsigned int sysctl_nr_open_max =
+ __const_min(INT_MAX, ~(size_t)0/sizeof(void *)) & -BITS_PER_LONG;
static void *alloc_fdmem(size_t size)
{
@@ -163,7 +163,7 @@ out:
* Return <0 error code on error; 1 on successful completion.
* The files->file_lock should be held on entry, and will be held on exit.
*/
-static int expand_fdtable(struct files_struct *files, int nr)
+static int expand_fdtable(struct files_struct *files, unsigned int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
{
@@ -208,7 +208,7 @@ static int expand_fdtable(struct files_struct *files, int nr)
* expanded and execution may have blocked.
* The files->file_lock should be held on entry, and will be held on exit.
*/
-static int expand_files(struct files_struct *files, int nr)
+static int expand_files(struct files_struct *files, unsigned int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
{
@@ -243,12 +243,12 @@ repeat:
return expanded;
}
-static inline void __set_close_on_exec(int fd, struct fdtable *fdt)
+static inline void __set_close_on_exec(unsigned int fd, struct fdtable *fdt)
{
__set_bit(fd, fdt->close_on_exec);
}
-static inline void __clear_close_on_exec(int fd, struct fdtable *fdt)
+static inline void __clear_close_on_exec(unsigned int fd, struct fdtable *fdt)
{
if (test_bit(fd, fdt->close_on_exec))
__clear_bit(fd, fdt->close_on_exec);
@@ -268,10 +268,10 @@ static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt)
__clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits);
}
-static int count_open_files(struct fdtable *fdt)
+static unsigned int count_open_files(struct fdtable *fdt)
{
- int size = fdt->max_fds;
- int i;
+ unsigned int size = fdt->max_fds;
+ unsigned int i;
/* Find the last open fd */
for (i = size / BITS_PER_LONG; i > 0; ) {
@@ -291,7 +291,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
{
struct files_struct *newf;
struct file **old_fds, **new_fds;
- int open_files, i;
+ unsigned int open_files, i;
struct fdtable *old_fdt, *new_fdt;
*errorp = -ENOMEM;
@@ -391,7 +391,7 @@ static struct fdtable *close_files(struct files_struct * files)
* files structure.
*/
struct fdtable *fdt = rcu_dereference_raw(files->fdt);
- int i, j = 0;
+ unsigned int i, j = 0;
for (;;) {
unsigned long set;
@@ -477,11 +477,11 @@ struct files_struct init_files = {
.file_lock = __SPIN_LOCK_UNLOCKED(init_files.file_lock),
};
-static unsigned long find_next_fd(struct fdtable *fdt, unsigned long start)
+static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start)
{
- unsigned long maxfd = fdt->max_fds;
- unsigned long maxbit = maxfd / BITS_PER_LONG;
- unsigned long bitbit = start / BITS_PER_LONG;
+ unsigned int maxfd = fdt->max_fds;
+ unsigned int maxbit = maxfd / BITS_PER_LONG;
+ unsigned int bitbit = start / BITS_PER_LONG;
bitbit = find_next_zero_bit(fdt->full_fds_bits, maxbit, bitbit) * BITS_PER_LONG;
if (bitbit > maxfd)
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index f863ac6647ac..6e22748b0704 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -220,7 +220,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
inode->i_mode = mode;
inode->i_uid = fc->user_id;
inode->i_gid = fc->group_id;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
/* setting ->i_op to NULL is not allowed */
if (iop)
inode->i_op = iop;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index c41bde26c338..70ea57c7b6bb 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -728,7 +728,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
struct pipe_buffer *buf = cs->pipebufs;
if (!cs->write) {
- err = buf->ops->confirm(cs->pipe, buf);
+ err = pipe_buf_confirm(cs->pipe, buf);
if (err)
return err;
@@ -827,7 +827,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
fuse_copy_finish(cs);
- err = buf->ops->confirm(cs->pipe, buf);
+ err = pipe_buf_confirm(cs->pipe, buf);
if (err)
return err;
@@ -840,7 +840,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
if (cs->len != PAGE_SIZE)
goto out_fallback;
- if (buf->ops->steal(cs->pipe, buf) != 0)
+ if (pipe_buf_steal(cs->pipe, buf) != 0)
goto out_fallback;
newpage = buf->page;
@@ -1341,9 +1341,8 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe,
size_t len, unsigned int flags)
{
- int ret;
+ int total, ret;
int page_nr = 0;
- int do_wakeup = 0;
struct pipe_buffer *bufs;
struct fuse_copy_state cs;
struct fuse_dev *fud = fuse_get_dev(in);
@@ -1362,52 +1361,23 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
if (ret < 0)
goto out;
- ret = 0;
- pipe_lock(pipe);
-
- if (!pipe->readers) {
- send_sig(SIGPIPE, current, 0);
- if (!ret)
- ret = -EPIPE;
- goto out_unlock;
- }
-
if (pipe->nrbufs + cs.nr_segs > pipe->buffers) {
ret = -EIO;
- goto out_unlock;
+ goto out;
}
- while (page_nr < cs.nr_segs) {
- int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
- struct pipe_buffer *buf = pipe->bufs + newbuf;
-
- buf->page = bufs[page_nr].page;
- buf->offset = bufs[page_nr].offset;
- buf->len = bufs[page_nr].len;
+ for (ret = total = 0; page_nr < cs.nr_segs; total += ret) {
/*
* Need to be careful about this. Having buf->ops in module
* code can Oops if the buffer persists after module unload.
*/
- buf->ops = &nosteal_pipe_buf_ops;
-
- pipe->nrbufs++;
- page_nr++;
- ret += buf->len;
-
- if (pipe->files)
- do_wakeup = 1;
- }
-
-out_unlock:
- pipe_unlock(pipe);
-
- if (do_wakeup) {
- smp_mb();
- if (waitqueue_active(&pipe->wait))
- wake_up_interruptible(&pipe->wait);
- kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
+ bufs[page_nr].ops = &nosteal_pipe_buf_ops;
+ ret = add_to_pipe(pipe, &bufs[page_nr++]);
+ if (unlikely(ret < 0))
+ break;
}
-
+ if (total)
+ ret = total;
out:
for (; page_nr < cs.nr_segs; page_nr++)
put_page(bufs[page_nr].page);
@@ -1992,7 +1962,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
pipe->nrbufs--;
} else {
- ibuf->ops->get(pipe, ibuf);
+ pipe_buf_get(pipe, ibuf);
*obuf = *ibuf;
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
obuf->len = rem;
@@ -2014,10 +1984,9 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
ret = fuse_dev_do_write(fud, &cs, len);
- for (idx = 0; idx < nbuf; idx++) {
- struct pipe_buffer *buf = &bufs[idx];
- buf->ops->release(pipe, buf);
- }
+ for (idx = 0; idx < nbuf; idx++)
+ pipe_buf_release(pipe, &bufs[idx]);
+
out:
kfree(bufs);
return ret;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index f7c84ab835ca..6a4d0e5418a1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -647,7 +647,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
void fuse_update_ctime(struct inode *inode)
{
if (!IS_NOCMTIME(inode)) {
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
mark_inode_dirty_sync(inode);
}
}
@@ -1604,9 +1604,10 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
* vmtruncate() doesn't allow for this case, so do the rlimit checking
* and the actual truncation by hand.
*/
-int fuse_do_setattr(struct inode *inode, struct iattr *attr,
+int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
struct file *file)
{
+ struct inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
FUSE_ARGS(args);
@@ -1621,7 +1622,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
if (!fc->default_permissions)
attr->ia_valid |= ATTR_FORCE;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
@@ -1758,7 +1759,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
if (!attr->ia_valid)
return 0;
- ret = fuse_do_setattr(inode, attr, file);
+ ret = fuse_do_setattr(entry, attr, file);
if (!ret) {
/*
* If filesystem supports acls it may have updated acl xattrs in
@@ -1792,7 +1793,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
.symlink = fuse_symlink,
.unlink = fuse_unlink,
.rmdir = fuse_rmdir,
- .rename2 = fuse_rename2,
+ .rename = fuse_rename2,
.link = fuse_link,
.setattr = fuse_setattr,
.create = fuse_create,
@@ -1800,10 +1801,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
.mknod = fuse_mknod,
.permission = fuse_permission,
.getattr = fuse_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = fuse_listxattr,
- .removexattr = generic_removexattr,
.get_acl = fuse_get_acl,
.set_acl = fuse_set_acl,
};
@@ -1823,10 +1821,7 @@ static const struct inode_operations fuse_common_inode_operations = {
.setattr = fuse_setattr,
.permission = fuse_permission,
.getattr = fuse_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = fuse_listxattr,
- .removexattr = generic_removexattr,
.get_acl = fuse_get_acl,
.set_acl = fuse_set_acl,
};
@@ -1836,10 +1831,7 @@ static const struct inode_operations fuse_symlink_inode_operations = {
.get_link = fuse_get_link,
.readlink = generic_readlink,
.getattr = fuse_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = fuse_listxattr,
- .removexattr = generic_removexattr,
};
void fuse_init_common(struct inode *inode)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b7beb67bf005..abc66a6237fd 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2810,7 +2810,7 @@ static void fuse_do_truncate(struct file *file)
attr.ia_file = file;
attr.ia_valid |= ATTR_FILE;
- fuse_do_setattr(inode, &attr, file);
+ fuse_do_setattr(file_dentry(file), &attr, file);
}
static inline loff_t fuse_round_up(loff_t off)
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 24ada5dc4dae..0dfbb136e59a 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -961,7 +961,7 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos);
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,
+int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
struct file *file);
void fuse_set_initialized(struct fuse_conn *fc);
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 363ba9e9d8d0..2524807ee070 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -92,17 +92,11 @@ int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode(acl, &mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
-
- if (error == 0)
- acl = NULL;
-
- if (mode != inode->i_mode) {
- inode->i_mode = mode;
+ if (mode != inode->i_mode)
mark_inode_dirty(inode);
- }
}
if (acl) {
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 645721f3ff00..fc5da4cbe88c 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -836,7 +836,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
gfs2_quota_change(ip, -(s64)btotal, ip->i_inode.i_uid,
ip->i_inode.i_gid);
- ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_dinode_out(ip, dibh->b_data);
@@ -1063,7 +1063,7 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
}
i_size_write(inode, newsize);
- ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_dinode_out(ip, dibh->b_data);
if (journaled)
@@ -1142,7 +1142,7 @@ static int trunc_end(struct gfs2_inode *ip)
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
gfs2_ordered_del_inode(ip);
}
- ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
ip->i_diskflags &= ~GFS2_DIF_TRUNC_IN_PROG;
gfs2_trans_add_meta(ip->i_gl, dibh);
@@ -1252,7 +1252,7 @@ static int do_grow(struct inode *inode, u64 size)
goto do_end_trans;
i_size_write(inode, size);
- ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index db8fbeb62483..3cdde5f5d399 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -135,7 +135,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
if (ip->i_inode.i_size < offset + size)
i_size_write(&ip->i_inode, offset + size);
- ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -233,7 +233,7 @@ out:
if (ip->i_inode.i_size < offset + copied)
i_size_write(&ip->i_inode, offset + copied);
- ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
@@ -872,7 +872,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
struct gfs2_leaf *leaf;
struct gfs2_dirent *dent;
struct qstr name = { .name = "" };
- struct timespec tv = CURRENT_TIME;
+ struct timespec tv = current_time(inode);
error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
if (error)
@@ -1816,7 +1816,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name,
gfs2_inum_out(nip, dent);
dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode));
dent->de_rahead = cpu_to_be16(gfs2_inode_ra_len(nip));
- tv = CURRENT_TIME;
+ tv = current_time(&ip->i_inode);
if (ip->i_diskflags & GFS2_DIF_EXHASH) {
leaf = (struct gfs2_leaf *)bh->b_data;
be16_add_cpu(&leaf->lf_entries, 1);
@@ -1878,7 +1878,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
const struct qstr *name = &dentry->d_name;
struct gfs2_dirent *dent, *prev = NULL;
struct buffer_head *bh;
- struct timespec tv = CURRENT_TIME;
+ struct timespec tv = current_time(&dip->i_inode);
/* Returns _either_ the entry (if its first in block) or the
previous entry otherwise */
@@ -1960,7 +1960,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
gfs2_trans_add_meta(dip->i_gl, bh);
}
- dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
+ dip->i_inode.i_mtime = dip->i_inode.i_ctime = current_time(&dip->i_inode);
gfs2_dinode_out(dip, bh->b_data);
brelse(bh);
return 0;
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 360188f162bd..e23ff70b3435 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -954,30 +954,6 @@ out_uninit:
return ret;
}
-static ssize_t gfs2_file_splice_read(struct file *in, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags)
-{
- struct inode *inode = in->f_mapping->host;
- struct gfs2_inode *ip = GFS2_I(inode);
- struct gfs2_holder gh;
- int ret;
-
- inode_lock(inode);
-
- ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
- if (ret) {
- inode_unlock(inode);
- return ret;
- }
-
- gfs2_glock_dq_uninit(&gh);
- inode_unlock(inode);
-
- return generic_file_splice_read(in, ppos, pipe, len, flags);
-}
-
-
static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe,
struct file *out, loff_t *ppos,
size_t len, unsigned int flags)
@@ -1140,7 +1116,7 @@ const struct file_operations gfs2_file_fops = {
.fsync = gfs2_fsync,
.lock = gfs2_lock,
.flock = gfs2_flock,
- .splice_read = gfs2_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = gfs2_file_splice_write,
.setlease = simple_nosetlease,
.fallocate = gfs2_fallocate,
@@ -1168,7 +1144,7 @@ const struct file_operations gfs2_file_fops_nolock = {
.open = gfs2_open,
.release = gfs2_release,
.fsync = gfs2_fsync,
- .splice_read = gfs2_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = gfs2_file_splice_write,
.setlease = generic_setlease,
.fallocate = gfs2_fallocate,
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index fb3a810b506f..fe3f84995c48 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -656,7 +656,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
set_nlink(inode, S_ISDIR(mode) ? 2 : 1);
inode->i_rdev = dev;
inode->i_size = size;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
gfs2_set_inode_blocks(inode, 1);
munge_mode_uid_gid(dip, inode);
check_and_update_goal(dip);
@@ -983,7 +983,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
gfs2_trans_add_meta(ip->i_gl, dibh);
inc_nlink(&ip->i_inode);
- ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_ctime = current_time(&ip->i_inode);
ihold(inode);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
@@ -1067,7 +1067,7 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip,
return error;
ip->i_entries = 0;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
if (S_ISDIR(inode->i_mode))
clear_nlink(inode);
else
@@ -1330,7 +1330,7 @@ static int update_moved_ino(struct gfs2_inode *ip, struct gfs2_inode *ndip,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
return error;
- ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -1936,7 +1936,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out;
@@ -2040,10 +2040,7 @@ const struct inode_operations gfs2_file_iops = {
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = gfs2_listxattr,
- .removexattr = generic_removexattr,
.fiemap = gfs2_fiemap,
.get_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
@@ -2058,14 +2055,11 @@ const struct inode_operations gfs2_dir_iops = {
.mkdir = gfs2_mkdir,
.rmdir = gfs2_unlink,
.mknod = gfs2_mknod,
- .rename2 = gfs2_rename2,
+ .rename = gfs2_rename2,
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = gfs2_listxattr,
- .removexattr = generic_removexattr,
.fiemap = gfs2_fiemap,
.get_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
@@ -2078,10 +2072,7 @@ const struct inode_operations gfs2_symlink_iops = {
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = gfs2_listxattr,
- .removexattr = generic_removexattr,
.fiemap = gfs2_fiemap,
};
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 8af2dfa09236..c2ca9566b764 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -854,7 +854,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
size = loc + sizeof(struct gfs2_quota);
if (size > inode->i_size)
i_size_write(inode, size);
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = current_time(inode);
mark_inode_dirty(inode);
set_bit(QDF_REFRESH, &qd->qd_flags);
}
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 3a2853504084..a4a577088d19 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -309,7 +309,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
- ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -775,7 +775,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
- ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -910,7 +910,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out;
- ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -1133,7 +1133,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
- ip->i_inode.i_ctime = CURRENT_TIME;
+ ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
diff --git a/fs/hfs/attr.c b/fs/hfs/attr.c
index d9a86919fdf6..0933600e11c8 100644
--- a/fs/hfs/attr.c
+++ b/fs/hfs/attr.c
@@ -13,9 +13,13 @@
#include "hfs_fs.h"
#include "btree.h"
-int hfs_setxattr(struct dentry *unused, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags)
+enum hfs_xattr_type {
+ HFS_TYPE,
+ HFS_CREATOR,
+};
+
+static int __hfs_setxattr(struct inode *inode, enum hfs_xattr_type type,
+ const void *value, size_t size, int flags)
{
struct hfs_find_data fd;
hfs_cat_rec rec;
@@ -36,18 +40,22 @@ int hfs_setxattr(struct dentry *unused, struct inode *inode,
sizeof(struct hfs_cat_file));
file = &rec.file;
- if (!strcmp(name, "hfs.type")) {
+ switch (type) {
+ case HFS_TYPE:
if (size == 4)
memcpy(&file->UsrWds.fdType, value, 4);
else
res = -ERANGE;
- } else if (!strcmp(name, "hfs.creator")) {
+ break;
+
+ case HFS_CREATOR:
if (size == 4)
memcpy(&file->UsrWds.fdCreator, value, 4);
else
res = -ERANGE;
- } else
- res = -EOPNOTSUPP;
+ break;
+ }
+
if (!res)
hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
sizeof(struct hfs_cat_file));
@@ -56,8 +64,8 @@ out:
return res;
}
-ssize_t hfs_getxattr(struct dentry *unused, struct inode *inode,
- const char *name, void *value, size_t size)
+static ssize_t __hfs_getxattr(struct inode *inode, enum hfs_xattr_type type,
+ void *value, size_t size)
{
struct hfs_find_data fd;
hfs_cat_rec rec;
@@ -80,41 +88,64 @@ ssize_t hfs_getxattr(struct dentry *unused, struct inode *inode,
}
file = &rec.file;
- if (!strcmp(name, "hfs.type")) {
+ switch (type) {
+ case HFS_TYPE:
if (size >= 4) {
memcpy(value, &file->UsrWds.fdType, 4);
res = 4;
} else
res = size ? -ERANGE : 4;
- } else if (!strcmp(name, "hfs.creator")) {
+ break;
+
+ case HFS_CREATOR:
if (size >= 4) {
memcpy(value, &file->UsrWds.fdCreator, 4);
res = 4;
} else
res = size ? -ERANGE : 4;
- } else
- res = -ENODATA;
+ break;
+ }
+
out:
if (size)
hfs_find_exit(&fd);
return res;
}
-#define HFS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
-
-ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+static int hfs_xattr_get(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *name, void *value, size_t size)
{
- struct inode *inode = d_inode(dentry);
+ return __hfs_getxattr(inode, handler->flags, value, size);
+}
- if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
+static int hfs_xattr_set(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ if (!value)
return -EOPNOTSUPP;
- if (!buffer || !size)
- return HFS_ATTRLIST_SIZE;
- if (size < HFS_ATTRLIST_SIZE)
- return -ERANGE;
- strcpy(buffer, "hfs.type");
- strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
-
- return HFS_ATTRLIST_SIZE;
+ return __hfs_setxattr(inode, handler->flags, value, size, flags);
}
+
+static const struct xattr_handler hfs_creator_handler = {
+ .name = "hfs.creator",
+ .flags = HFS_CREATOR,
+ .get = hfs_xattr_get,
+ .set = hfs_xattr_set,
+};
+
+static const struct xattr_handler hfs_type_handler = {
+ .name = "hfs.type",
+ .flags = HFS_TYPE,
+ .get = hfs_xattr_get,
+ .set = hfs_xattr_set,
+};
+
+const struct xattr_handler *hfs_xattr_handlers[] = {
+ &hfs_creator_handler,
+ &hfs_type_handler,
+ NULL
+};
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 8f4afd3f5108..8a66405b0f8b 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -125,7 +125,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, const struct qstr *str, struct i
goto err1;
dir->i_size++;
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
hfs_find_exit(&fd);
return 0;
@@ -261,7 +261,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
}
dir->i_size--;
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
res = 0;
out:
@@ -321,7 +321,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
if (err)
goto out;
dst_dir->i_size++;
- dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
+ dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir);
mark_inode_dirty(dst_dir);
/* finally remove the old entry */
@@ -333,7 +333,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
if (err)
goto out;
src_dir->i_size--;
- src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
+ src_dir->i_mtime = src_dir->i_ctime = current_time(src_dir);
mark_inode_dirty(src_dir);
type = entry.type;
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 163190ecc0d2..5de5c48b418d 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -268,7 +268,7 @@ static int hfs_remove(struct inode *dir, struct dentry *dentry)
if (res)
return res;
clear_nlink(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
hfs_delete_inode(inode);
mark_inode_dirty(inode);
return 0;
@@ -286,10 +286,14 @@ static int hfs_remove(struct inode *dir, struct dentry *dentry)
* XXX: how do you handle must_be dir?
*/
static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
int res;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
/* Unlink destination if it already exists */
if (d_really_is_positive(new_dentry)) {
res = hfs_remove(new_dir, new_dentry);
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 16f5172ee40d..4cdec5a19347 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -212,11 +212,7 @@ extern void hfs_evict_inode(struct inode *);
extern void hfs_delete_inode(struct inode *);
/* attr.c */
-extern int hfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
- const void *value, size_t size, int flags);
-extern ssize_t hfs_getxattr(struct dentry *dentry, struct inode *inode,
- const char *name, void *value, size_t size);
-extern ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+extern const struct xattr_handler *hfs_xattr_handlers[];
/* mdb.c */
extern int hfs_mdb_get(struct super_block *);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index c6a32415735b..f776acf2378a 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -15,6 +15,7 @@
#include <linux/mpage.h>
#include <linux/sched.h>
#include <linux/uio.h>
+#include <linux/xattr.h>
#include "hfs_fs.h"
#include "btree.h"
@@ -193,7 +194,7 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
set_nlink(inode, 1);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
HFS_I(inode)->flags = 0;
HFS_I(inode)->rsrc_inode = NULL;
HFS_I(inode)->fs_blocks = 0;
@@ -605,7 +606,7 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
int error;
- error = inode_change_ok(inode, attr); /* basic permission checks */
+ error = setattr_prepare(dentry, attr); /* basic permission checks */
if (error)
return error;
@@ -687,7 +688,5 @@ static const struct file_operations hfs_file_operations = {
static const struct inode_operations hfs_file_inode_operations = {
.lookup = hfs_file_lookup,
.setattr = hfs_inode_setattr,
- .setxattr = hfs_setxattr,
- .getxattr = hfs_getxattr,
- .listxattr = hfs_listxattr,
+ .listxattr = generic_listxattr,
};
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 1ca95c232bb5..bf6304a350a6 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -406,6 +406,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
}
sb->s_op = &hfs_super_operations;
+ sb->s_xattr = hfs_xattr_handlers;
sb->s_flags |= MS_NODIRATIME;
mutex_init(&sbi->bitmap_lock);
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 142534d3c2d5..a5e00f7a4c14 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -303,7 +303,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
dir->i_size++;
if (S_ISDIR(inode->i_mode))
hfsplus_subfolders_inc(dir);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
hfs_find_exit(&fd);
@@ -400,7 +400,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str)
dir->i_size--;
if (type == HFSPLUS_FOLDER)
hfsplus_subfolders_dec(dir);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) {
@@ -469,7 +469,7 @@ int hfsplus_rename_cat(u32 cnid,
dst_dir->i_size++;
if (type == HFSPLUS_FOLDER)
hfsplus_subfolders_inc(dst_dir);
- dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
+ dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir);
/* finally remove the old entry */
err = hfsplus_cat_build_key(sb, src_fd.search_key,
@@ -486,7 +486,7 @@ int hfsplus_rename_cat(u32 cnid,
src_dir->i_size--;
if (type == HFSPLUS_FOLDER)
hfsplus_subfolders_dec(src_dir);
- src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
+ src_dir->i_mtime = src_dir->i_ctime = current_time(src_dir);
/* remove old thread entry */
hfsplus_cat_build_key_with_cnid(sb, src_fd.search_key, cnid);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 42e128661dc1..31d5e3f1fe17 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -347,7 +347,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
inc_nlink(inode);
hfsplus_instantiate(dst_dentry, inode, cnid);
ihold(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
sbi->file_count++;
hfsplus_mark_mdb_dirty(dst_dir->i_sb);
@@ -406,7 +406,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
hfsplus_delete_inode(inode);
} else
sbi->file_count--;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
out:
mutex_unlock(&sbi->vh_mutex);
@@ -427,7 +427,7 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
if (res)
goto out;
clear_nlink(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
hfsplus_delete_inode(inode);
mark_inode_dirty(inode);
out:
@@ -530,10 +530,14 @@ static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
}
static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
int res;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
/* Unlink destination if it already exists */
if (d_really_is_positive(new_dentry)) {
if (d_is_dir(new_dentry))
@@ -562,10 +566,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
.symlink = hfsplus_symlink,
.mknod = hfsplus_mknod,
.rename = hfsplus_rename,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = hfsplus_listxattr,
- .removexattr = generic_removexattr,
#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
.get_acl = hfsplus_get_posix_acl,
.set_acl = hfsplus_set_posix_acl,
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 19462d773fe2..2e796f8302ff 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -245,7 +245,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
@@ -333,10 +333,7 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
static const struct inode_operations hfsplus_file_inode_operations = {
.setattr = hfsplus_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = hfsplus_listxattr,
- .removexattr = generic_removexattr,
#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
.get_acl = hfsplus_get_posix_acl,
.set_acl = hfsplus_set_posix_acl,
@@ -369,7 +366,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
set_nlink(inode, 1);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
hip = HFSPLUS_I(inode);
INIT_LIST_HEAD(&hip->open_dir_list);
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index 32a49e292b6a..99627f8a0a18 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -122,7 +122,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
else
hip->userflags &= ~HFSPLUS_FLG_NODUMP;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
out_unlock_inode:
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
index ab7ea2506b4d..9b92058a1240 100644
--- a/fs/hfsplus/posix_acl.c
+++ b/fs/hfsplus/posix_acl.c
@@ -65,8 +65,8 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
case ACL_TYPE_ACCESS:
xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- err = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (err < 0)
+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (err)
return err;
}
err = 0;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 90e46cd752fe..23e15ea53e45 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -812,7 +812,7 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
int fd = HOSTFS_I(inode)->fd;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
@@ -885,7 +885,7 @@ static const struct inode_operations hostfs_dir_iops = {
.mkdir = hostfs_mkdir,
.rmdir = hostfs_rmdir,
.mknod = hostfs_mknod,
- .rename2 = hostfs_rename2,
+ .rename = hostfs_rename2,
.permission = hostfs_permission,
.setattr = hostfs_setattr,
};
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index d3bcdd975700..b3be1b5a62e2 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -189,6 +189,11 @@ static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
return generic_block_bmap(mapping, block, hpfs_get_block);
}
+static int hpfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len)
+{
+ return generic_block_fiemap(inode, fieinfo, start, len, hpfs_get_block);
+}
+
const struct address_space_operations hpfs_aops = {
.readpage = hpfs_readpage,
.writepage = hpfs_writepage,
@@ -214,4 +219,5 @@ const struct file_operations hpfs_file_ops =
const struct inode_operations hpfs_file_iops =
{
.setattr = hpfs_setattr,
+ .fiemap = hpfs_fiemap,
};
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 1f3c6d76200b..b9c724ed1e7e 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -273,7 +273,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
goto out_unlock;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out_unlock;
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index bb8d67e2740a..f30c14414518 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -507,7 +507,8 @@ const struct address_space_operations hpfs_symlink_aops = {
};
static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
const unsigned char *old_name = old_dentry->d_name.name;
unsigned old_len = old_dentry->d_name.len;
@@ -524,6 +525,9 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct fnode *fnode;
int err;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
if ((err = hpfs_chk_name(new_name, &new_len))) return err;
err = 0;
hpfs_adjust_length(old_name, &old_len);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 4ea71eba40a5..4fb7b10f3a05 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -416,7 +416,6 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
for (i = 0; i < pagevec_count(&pvec); ++i) {
struct page *page = pvec.pages[i];
- bool rsv_on_error;
u32 hash;
/*
@@ -458,18 +457,17 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
* cache (remove_huge_page) BEFORE removing the
* region/reserve map (hugetlb_unreserve_pages). In
* rare out of memory conditions, removal of the
- * region/reserve map could fail. Before free'ing
- * the page, note PagePrivate which is used in case
- * of error.
+ * region/reserve map could fail. Correspondingly,
+ * the subpool and global reserve usage count can need
+ * to be adjusted.
*/
- rsv_on_error = !PagePrivate(page);
+ VM_BUG_ON(PagePrivate(page));
remove_huge_page(page);
freed++;
if (!truncate_op) {
if (unlikely(hugetlb_unreserve_pages(inode,
next, next + 1, 1)))
- hugetlb_fix_reserve_counts(inode,
- rsv_on_error);
+ hugetlb_fix_reserve_counts(inode);
}
unlock_page(page);
@@ -657,7 +655,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size)
i_size_write(inode, offset + len);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
out:
inode_unlock(inode);
return error;
@@ -672,7 +670,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
BUG_ON(!inode);
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
@@ -702,7 +700,7 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,
inode->i_mode = S_IFDIR | config->mode;
inode->i_uid = config->uid;
inode->i_gid = config->gid;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
info = HUGETLBFS_I(inode);
mpol_shared_policy_init(&info->policy, NULL);
inode->i_op = &hugetlbfs_dir_inode_operations;
@@ -741,7 +739,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
lockdep_set_class(&inode->i_mapping->i_mmap_rwsem,
&hugetlbfs_i_mmap_rwsem_key);
inode->i_mapping->a_ops = &hugetlbfs_aops;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_mapping->private_data = resv_map;
info = HUGETLBFS_I(inode);
/*
@@ -790,7 +788,7 @@ static int hugetlbfs_mknod(struct inode *dir,
inode = hugetlbfs_get_inode(dir->i_sb, dir, mode, dev);
if (inode) {
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
d_instantiate(dentry, inode);
dget(dentry); /* Extra count - pin the dentry in core */
error = 0;
@@ -827,7 +825,7 @@ static int hugetlbfs_symlink(struct inode *dir,
} else
iput(inode);
}
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
return error;
}
diff --git a/fs/inode.c b/fs/inode.c
index 7e3ef3af3db9..88110fd0b282 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -140,6 +140,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
inode->i_fop = &no_open_fops;
inode->__i_nlink = 1;
inode->i_opflags = 0;
+ if (sb->s_xattr)
+ inode->i_opflags |= IOP_XATTR;
i_uid_write(inode, 0);
i_gid_write(inode, 0);
atomic_set(&inode->i_writecount, 0);
@@ -1021,13 +1023,17 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
{
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
struct inode *inode;
-
+again:
spin_lock(&inode_hash_lock);
inode = find_inode(sb, head, test, data);
spin_unlock(&inode_hash_lock);
if (inode) {
wait_on_inode(inode);
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ goto again;
+ }
return inode;
}
@@ -1064,6 +1070,10 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
destroy_inode(inode);
inode = old;
wait_on_inode(inode);
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ goto again;
+ }
}
return inode;
@@ -1091,12 +1101,16 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{
struct hlist_head *head = inode_hashtable + hash(sb, ino);
struct inode *inode;
-
+again:
spin_lock(&inode_hash_lock);
inode = find_inode_fast(sb, head, ino);
spin_unlock(&inode_hash_lock);
if (inode) {
wait_on_inode(inode);
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ goto again;
+ }
return inode;
}
@@ -1131,6 +1145,10 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
destroy_inode(inode);
inode = old;
wait_on_inode(inode);
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ goto again;
+ }
}
return inode;
}
@@ -1266,10 +1284,16 @@ EXPORT_SYMBOL(ilookup5_nowait);
struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
int (*test)(struct inode *, void *), void *data)
{
- struct inode *inode = ilookup5_nowait(sb, hashval, test, data);
-
- if (inode)
+ struct inode *inode;
+again:
+ inode = ilookup5_nowait(sb, hashval, test, data);
+ if (inode) {
wait_on_inode(inode);
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ goto again;
+ }
+ }
return inode;
}
EXPORT_SYMBOL(ilookup5);
@@ -1286,13 +1310,18 @@ struct inode *ilookup(struct super_block *sb, unsigned long ino)
{
struct hlist_head *head = inode_hashtable + hash(sb, ino);
struct inode *inode;
-
+again:
spin_lock(&inode_hash_lock);
inode = find_inode_fast(sb, head, ino);
spin_unlock(&inode_hash_lock);
- if (inode)
+ if (inode) {
wait_on_inode(inode);
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ goto again;
+ }
+ }
return inode;
}
EXPORT_SYMBOL(ilookup);
@@ -1536,16 +1565,36 @@ sector_t bmap(struct inode *inode, sector_t block)
EXPORT_SYMBOL(bmap);
/*
+ * Update times in overlayed inode from underlying real inode
+ */
+static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode,
+ bool rcu)
+{
+ if (!rcu) {
+ struct inode *realinode = d_real_inode(dentry);
+
+ if (unlikely(inode != realinode) &&
+ (!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
+ !timespec_equal(&inode->i_ctime, &realinode->i_ctime))) {
+ inode->i_mtime = realinode->i_mtime;
+ inode->i_ctime = realinode->i_ctime;
+ }
+ }
+}
+
+/*
* With relative atime, only update atime if the previous atime is
* earlier than either the ctime or mtime or if at least a day has
* passed since the last atime update.
*/
-static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
- struct timespec now)
+static int relatime_need_update(const struct path *path, struct inode *inode,
+ struct timespec now, bool rcu)
{
- if (!(mnt->mnt_flags & MNT_RELATIME))
+ if (!(path->mnt->mnt_flags & MNT_RELATIME))
return 1;
+
+ update_ovl_inode_times(path->dentry, inode, rcu);
/*
* Is mtime younger than atime? If yes, update atime:
*/
@@ -1612,7 +1661,8 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
* This function automatically handles read only file systems and media,
* as well as the "noatime" flag and inode specific "noatime" markers.
*/
-bool atime_needs_update(const struct path *path, struct inode *inode)
+bool __atime_needs_update(const struct path *path, struct inode *inode,
+ bool rcu)
{
struct vfsmount *mnt = path->mnt;
struct timespec now;
@@ -1636,9 +1686,9 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
return false;
- now = current_fs_time(inode->i_sb);
+ now = current_time(inode);
- if (!relatime_need_update(mnt, inode, now))
+ if (!relatime_need_update(path, inode, now, rcu))
return false;
if (timespec_equal(&inode->i_atime, &now))
@@ -1653,7 +1703,7 @@ void touch_atime(const struct path *path)
struct inode *inode = d_inode(path->dentry);
struct timespec now;
- if (!atime_needs_update(path, inode))
+ if (!__atime_needs_update(path, inode, false))
return;
if (!sb_start_write_trylock(inode->i_sb))
@@ -1670,7 +1720,7 @@ void touch_atime(const struct path *path)
* We may also fail on filesystems that have the ability to make parts
* of the fs read only, e.g. subvolumes in Btrfs.
*/
- now = current_fs_time(inode->i_sb);
+ now = current_time(inode);
update_time(inode, &now, S_ATIME);
__mnt_drop_write(mnt);
skip_update:
@@ -1793,7 +1843,7 @@ int file_update_time(struct file *file)
if (IS_NOCMTIME(inode))
return 0;
- now = current_fs_time(inode->i_sb);
+ now = current_time(inode);
if (!timespec_equal(&inode->i_mtime, &now))
sync_it = S_MTIME;
@@ -2049,3 +2099,26 @@ void inode_nohighmem(struct inode *inode)
mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
}
EXPORT_SYMBOL(inode_nohighmem);
+
+/**
+ * current_time - Return FS time
+ * @inode: inode.
+ *
+ * Return the current time truncated to the time granularity supported by
+ * the fs.
+ *
+ * Note that inode and inode->sb cannot be NULL.
+ * Otherwise, the function warns and returns time without truncation.
+ */
+struct timespec current_time(struct inode *inode)
+{
+ struct timespec now = current_kernel_time();
+
+ if (unlikely(!inode->i_sb)) {
+ WARN(1, "current_time() called with uninitialized super_block in the inode");
+ return now;
+ }
+
+ return timespec_trunc(now, inode->i_sb->s_time_gran);
+}
+EXPORT_SYMBOL(current_time);
diff --git a/fs/internal.h b/fs/internal.h
index 859178692ce4..f4da3341b4a3 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -121,6 +121,15 @@ extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
extern void inode_add_lru(struct inode *inode);
extern int dentry_needs_remove_privs(struct dentry *dentry);
+extern bool __atime_needs_update(const struct path *, struct inode *, bool);
+static inline bool atime_needs_update_rcu(const struct path *path,
+ struct inode *inode)
+{
+ return __atime_needs_update(path, inode, true);
+}
+
+extern bool atime_needs_update_rcu(const struct path *, struct inode *);
+
/*
* fs-writeback.c
*/
@@ -157,7 +166,7 @@ extern void mnt_pin_kill(struct mount *m);
/*
* fs/nsfs.c
*/
-extern struct dentry_operations ns_dentry_operations;
+extern const struct dentry_operations ns_dentry_operations;
/*
* fs/ioctl.c
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 46261a6f902d..927da4956a89 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1090,11 +1090,15 @@ static void jbd2_stats_proc_exit(journal_t *journal)
* very few fields yet: that has to wait until we have created the
* journal structures from from scratch, or loaded them from disk. */
-static journal_t * journal_init_common (void)
+static journal_t *journal_init_common(struct block_device *bdev,
+ struct block_device *fs_dev,
+ unsigned long long start, int len, int blocksize)
{
static struct lock_class_key jbd2_trans_commit_key;
journal_t *journal;
int err;
+ struct buffer_head *bh;
+ int n;
journal = kzalloc(sizeof(*journal), GFP_KERNEL);
if (!journal)
@@ -1131,6 +1135,32 @@ static journal_t * journal_init_common (void)
lockdep_init_map(&journal->j_trans_commit_map, "jbd2_handle",
&jbd2_trans_commit_key, 0);
+ /* journal descriptor can store up to n blocks -bzzz */
+ journal->j_blocksize = blocksize;
+ journal->j_dev = bdev;
+ journal->j_fs_dev = fs_dev;
+ journal->j_blk_offset = start;
+ journal->j_maxlen = len;
+ n = journal->j_blocksize / sizeof(journal_block_tag_t);
+ journal->j_wbufsize = n;
+ journal->j_wbuf = kmalloc_array(n, sizeof(struct buffer_head *),
+ GFP_KERNEL);
+ if (!journal->j_wbuf) {
+ kfree(journal);
+ return NULL;
+ }
+
+ bh = getblk_unmovable(journal->j_dev, start, journal->j_blocksize);
+ if (!bh) {
+ pr_err("%s: Cannot get buffer for journal superblock\n",
+ __func__);
+ kfree(journal->j_wbuf);
+ kfree(journal);
+ return NULL;
+ }
+ journal->j_sb_buffer = bh;
+ journal->j_superblock = (journal_superblock_t *)bh->b_data;
+
return journal;
}
@@ -1157,51 +1187,21 @@ static journal_t * journal_init_common (void)
* range of blocks on an arbitrary block device.
*
*/
-journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+journal_t *jbd2_journal_init_dev(struct block_device *bdev,
struct block_device *fs_dev,
unsigned long long start, int len, int blocksize)
{
- journal_t *journal = journal_init_common();
- struct buffer_head *bh;
- int n;
+ journal_t *journal;
+ journal = journal_init_common(bdev, fs_dev, start, len, blocksize);
if (!journal)
return NULL;
- /* journal descriptor can store up to n blocks -bzzz */
- journal->j_blocksize = blocksize;
- journal->j_dev = bdev;
- journal->j_fs_dev = fs_dev;
- journal->j_blk_offset = start;
- journal->j_maxlen = len;
bdevname(journal->j_dev, journal->j_devname);
strreplace(journal->j_devname, '/', '!');
jbd2_stats_proc_init(journal);
- n = journal->j_blocksize / sizeof(journal_block_tag_t);
- journal->j_wbufsize = n;
- journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
- if (!journal->j_wbuf) {
- printk(KERN_ERR "%s: Can't allocate bhs for commit thread\n",
- __func__);
- goto out_err;
- }
-
- bh = __getblk(journal->j_dev, start, journal->j_blocksize);
- if (!bh) {
- printk(KERN_ERR
- "%s: Cannot get buffer for journal superblock\n",
- __func__);
- goto out_err;
- }
- journal->j_sb_buffer = bh;
- journal->j_superblock = (journal_superblock_t *)bh->b_data;
return journal;
-out_err:
- kfree(journal->j_wbuf);
- jbd2_stats_proc_exit(journal);
- kfree(journal);
- return NULL;
}
/**
@@ -1212,67 +1212,36 @@ out_err:
* the journal. The inode must exist already, must support bmap() and
* must have all data blocks preallocated.
*/
-journal_t * jbd2_journal_init_inode (struct inode *inode)
+journal_t *jbd2_journal_init_inode(struct inode *inode)
{
- struct buffer_head *bh;
- journal_t *journal = journal_init_common();
+ journal_t *journal;
char *p;
- int err;
- int n;
unsigned long long blocknr;
+ blocknr = bmap(inode, 0);
+ if (!blocknr) {
+ pr_err("%s: Cannot locate journal superblock\n",
+ __func__);
+ return NULL;
+ }
+
+ jbd_debug(1, "JBD2: inode %s/%ld, size %lld, bits %d, blksize %ld\n",
+ inode->i_sb->s_id, inode->i_ino, (long long) inode->i_size,
+ inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
+
+ journal = journal_init_common(inode->i_sb->s_bdev, inode->i_sb->s_bdev,
+ blocknr, inode->i_size >> inode->i_sb->s_blocksize_bits,
+ inode->i_sb->s_blocksize);
if (!journal)
return NULL;
- journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
journal->j_inode = inode;
bdevname(journal->j_dev, journal->j_devname);
p = strreplace(journal->j_devname, '/', '!');
sprintf(p, "-%lu", journal->j_inode->i_ino);
- jbd_debug(1,
- "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
- journal, inode->i_sb->s_id, inode->i_ino,
- (long long) inode->i_size,
- inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
-
- journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
- journal->j_blocksize = inode->i_sb->s_blocksize;
jbd2_stats_proc_init(journal);
- /* journal descriptor can store up to n blocks -bzzz */
- n = journal->j_blocksize / sizeof(journal_block_tag_t);
- journal->j_wbufsize = n;
- journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
- if (!journal->j_wbuf) {
- printk(KERN_ERR "%s: Can't allocate bhs for commit thread\n",
- __func__);
- goto out_err;
- }
-
- err = jbd2_journal_bmap(journal, 0, &blocknr);
- /* If that failed, give up */
- if (err) {
- printk(KERN_ERR "%s: Cannot locate journal superblock\n",
- __func__);
- goto out_err;
- }
-
- bh = getblk_unmovable(journal->j_dev, blocknr, journal->j_blocksize);
- if (!bh) {
- printk(KERN_ERR
- "%s: Cannot get buffer for journal superblock\n",
- __func__);
- goto out_err;
- }
- journal->j_sb_buffer = bh;
- journal->j_superblock = (journal_superblock_t *)bh->b_data;
-
return journal;
-out_err:
- kfree(journal->j_wbuf);
- jbd2_stats_proc_exit(journal);
- kfree(journal);
- return NULL;
}
/*
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index b5bc3e249163..3d8246a9faa4 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -159,6 +159,7 @@ static void wait_transaction_locked(journal_t *journal)
read_unlock(&journal->j_state_lock);
if (need_to_start)
jbd2_log_start_commit(journal, tid);
+ jbd2_might_wait_for_commit(journal);
schedule();
finish_wait(&journal->j_wait_transaction_locked, &wait);
}
@@ -182,8 +183,6 @@ static int add_transaction_credits(journal_t *journal, int blocks,
int needed;
int total = blocks + rsv_blocks;
- jbd2_might_wait_for_commit(journal);
-
/*
* If the current transaction is locked down for commit, wait
* for the lock to be released.
@@ -214,6 +213,7 @@ static int add_transaction_credits(journal_t *journal, int blocks,
if (atomic_read(&journal->j_reserved_credits) + total >
journal->j_max_transaction_buffers) {
read_unlock(&journal->j_state_lock);
+ jbd2_might_wait_for_commit(journal);
wait_event(journal->j_wait_reserved,
atomic_read(&journal->j_reserved_credits) + total <=
journal->j_max_transaction_buffers);
@@ -238,6 +238,7 @@ static int add_transaction_credits(journal_t *journal, int blocks,
if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) {
atomic_sub(total, &t->t_outstanding_credits);
read_unlock(&journal->j_state_lock);
+ jbd2_might_wait_for_commit(journal);
write_lock(&journal->j_state_lock);
if (jbd2_log_space_left(journal) < jbd2_space_needed(journal))
__jbd2_log_wait_for_space(journal);
@@ -255,6 +256,7 @@ static int add_transaction_credits(journal_t *journal, int blocks,
sub_reserved_credits(journal, rsv_blocks);
atomic_sub(total, &t->t_outstanding_credits);
read_unlock(&journal->j_state_lock);
+ jbd2_might_wait_for_commit(journal);
wait_event(journal->j_wait_reserved,
atomic_read(&journal->j_reserved_credits) + rsv_blocks
<= journal->j_max_transaction_buffers / 2);
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index bc2693d56298..7ebacf14837f 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -233,22 +233,21 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
xprefix = JFFS2_XPREFIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- rc = posix_acl_equiv_mode(acl, &mode);
- if (rc < 0)
+ umode_t mode;
+
+ rc = posix_acl_update_mode(inode, &mode, &acl);
+ if (rc)
return rc;
if (inode->i_mode != mode) {
struct iattr attr;
attr.ia_valid = ATTR_MODE | ATTR_CTIME;
attr.ia_mode = mode;
- attr.ia_ctime = CURRENT_TIME_SEC;
+ attr.ia_ctime = current_time(inode);
rc = jffs2_do_setattr(inode, &attr);
if (rc < 0)
return rc;
}
- if (rc == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 30eb33ff8189..0a754f38462e 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -35,7 +35,8 @@ static int jffs2_mkdir (struct inode *,struct dentry *,umode_t);
static int jffs2_rmdir (struct inode *,struct dentry *);
static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
static int jffs2_rename (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
+ struct inode *, struct dentry *,
+ unsigned int);
const struct file_operations jffs2_dir_operations =
{
@@ -61,10 +62,7 @@ const struct inode_operations jffs2_dir_inode_operations =
.get_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
- .setxattr = jffs2_setxattr,
- .getxattr = jffs2_getxattr,
.listxattr = jffs2_listxattr,
- .removexattr = jffs2_removexattr
};
/***********************************************************************/
@@ -759,7 +757,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode
}
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
- struct inode *new_dir_i, struct dentry *new_dentry)
+ struct inode *new_dir_i, struct dentry *new_dentry,
+ unsigned int flags)
{
int ret;
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
@@ -767,6 +766,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
uint8_t type;
uint32_t now;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
/* The VFS will check for us and prevent trying to rename a
* file over a directory and vice versa, but if it's a directory,
* the VFS can't check whether the victim is empty. The filesystem
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 0e62dec3effc..c12476e309c6 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -66,10 +66,7 @@ const struct inode_operations jffs2_file_inode_operations =
.get_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
- .setxattr = jffs2_setxattr,
- .getxattr = jffs2_getxattr,
.listxattr = jffs2_listxattr,
- .removexattr = jffs2_removexattr
};
const struct address_space_operations jffs2_file_address_operations =
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index ae2ebb26b446..567653f7c0ce 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -193,7 +193,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry);
int rc;
- rc = inode_change_ok(inode, iattr);
+ rc = setattr_prepare(dentry, iattr);
if (rc)
return rc;
@@ -472,7 +472,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_r
inode->i_mode = jemode_to_cpu(ri->mode);
i_gid_write(inode, je16_to_cpu(ri->gid));
i_uid_write(inode, je16_to_cpu(ri->uid));
- inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_atime = inode->i_ctime = inode->i_mtime = current_time(inode);
ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
inode->i_blocks = 0;
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 2cabd649d4fb..8f3f0855fcd2 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -16,8 +16,5 @@ const struct inode_operations jffs2_symlink_inode_operations =
.readlink = generic_readlink,
.get_link = simple_get_link,
.setattr = jffs2_setattr,
- .setxattr = jffs2_setxattr,
- .getxattr = jffs2_getxattr,
.listxattr = jffs2_listxattr,
- .removexattr = jffs2_removexattr
};
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 467ff376ee26..720007b2fd65 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -99,9 +99,6 @@ extern const struct xattr_handler jffs2_user_xattr_handler;
extern const struct xattr_handler jffs2_trusted_xattr_handler;
extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
-#define jffs2_getxattr generic_getxattr
-#define jffs2_setxattr generic_setxattr
-#define jffs2_removexattr generic_removexattr
#else
@@ -116,9 +113,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
#define jffs2_xattr_handlers NULL
#define jffs2_listxattr NULL
-#define jffs2_getxattr NULL
-#define jffs2_setxattr NULL
-#define jffs2_removexattr NULL
#endif /* CONFIG_JFFS2_FS_XATTR */
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 21fa92ba2c19..7bc186f4ed4d 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -78,13 +78,11 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
case ACL_TYPE_ACCESS:
ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (rc < 0)
+ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (rc)
return rc;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
- if (rc == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 7f1a585a0a94..739492c7a3fd 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -103,7 +103,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry);
int rc;
- rc = inode_change_ok(inode, iattr);
+ rc = setattr_prepare(dentry, iattr);
if (rc)
return rc;
@@ -140,10 +140,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
}
const struct inode_operations jfs_file_inode_operations = {
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = jfs_listxattr,
- .removexattr = generic_removexattr,
.setattr = jfs_setattr,
#ifdef CONFIG_JFS_POSIX_ACL
.get_acl = jfs_get_acl,
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index ad3e7b1effc4..054cc761b426 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -403,7 +403,7 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length)
break;
}
- ip->i_mtime = ip->i_ctime = CURRENT_TIME;
+ ip->i_mtime = ip->i_ctime = current_time(ip);
mark_inode_dirty(ip);
txCommit(tid, 1, &ip, 0);
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 5e33cb9a190d..375dd257a34f 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -131,7 +131,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
jfs_inode->mode2 |= inode->i_mode;
inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
jfs_inode->otime = inode->i_ctime.tv_sec;
inode->i_generation = JFS_SBI(sb)->gengen++;
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 814b0c58016c..b41596d71858 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -162,7 +162,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
mark_inode_dirty(ip);
- dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ dip->i_ctime = dip->i_mtime = current_time(dip);
mark_inode_dirty(dip);
@@ -298,7 +298,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
/* update parent directory inode */
inc_nlink(dip); /* for '..' from child directory */
- dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ dip->i_ctime = dip->i_mtime = current_time(dip);
mark_inode_dirty(dip);
rc = txCommit(tid, 2, &iplist[0], 0);
@@ -406,7 +406,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
/* update parent directory's link count corresponding
* to ".." entry of the target directory deleted
*/
- dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ dip->i_ctime = dip->i_mtime = current_time(dip);
inode_dec_link_count(dip);
/*
@@ -528,7 +528,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
ASSERT(ip->i_nlink);
- ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ ip->i_ctime = dip->i_ctime = dip->i_mtime = current_time(ip);
mark_inode_dirty(dip);
/* update target's inode */
@@ -838,8 +838,8 @@ static int jfs_link(struct dentry *old_dentry,
/* update object inode */
inc_nlink(ip); /* for new link */
- ip->i_ctime = CURRENT_TIME;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ ip->i_ctime = current_time(ip);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
ihold(ip);
@@ -1039,7 +1039,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
mark_inode_dirty(ip);
- dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+ dip->i_ctime = dip->i_mtime = current_time(dip);
mark_inode_dirty(dip);
/*
* commit update of parent directory and link object
@@ -1078,7 +1078,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
* FUNCTION: rename a file or directory
*/
static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct btstack btstack;
ino_t ino;
@@ -1097,6 +1098,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
s64 new_size = 0;
int commit_flag;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
@@ -1215,7 +1218,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
tblk->xflag |= COMMIT_DELETE;
tblk->u.ip = new_ip;
} else {
- new_ip->i_ctime = CURRENT_TIME;
+ new_ip->i_ctime = current_time(new_ip);
mark_inode_dirty(new_ip);
}
} else {
@@ -1278,10 +1281,10 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/*
* Update ctime on changed/moved inodes & mark dirty
*/
- old_ip->i_ctime = CURRENT_TIME;
+ old_ip->i_ctime = current_time(old_ip);
mark_inode_dirty(old_ip);
- new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb);
+ new_dir->i_ctime = new_dir->i_mtime = current_time(new_dir);
mark_inode_dirty(new_dir);
/* Build list of inodes modified by this transaction */
@@ -1293,7 +1296,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (old_dir != new_dir) {
iplist[ipcount++] = new_dir;
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
mark_inode_dirty(old_dir);
}
@@ -1426,7 +1429,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
mark_inode_dirty(ip);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
@@ -1537,10 +1540,7 @@ const struct inode_operations jfs_dir_inode_operations = {
.rmdir = jfs_rmdir,
.mknod = jfs_mknod,
.rename = jfs_rename,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = jfs_listxattr,
- .removexattr = generic_removexattr,
.setattr = jfs_setattr,
#ifdef CONFIG_JFS_POSIX_ACL
.get_acl = jfs_get_acl,
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index cec8814a3b8b..85671f7f8518 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -830,7 +830,7 @@ out:
if (inode->i_size < off+len-towrite)
i_size_write(inode, off+len-towrite);
inode->i_version++;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
inode_unlock(inode);
return len - towrite;
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index c94c7e4a1323..c82404fee6cd 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -25,19 +25,13 @@ const struct inode_operations jfs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link,
.setattr = jfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = jfs_listxattr,
- .removexattr = generic_removexattr,
};
const struct inode_operations jfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
.setattr = jfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = jfs_listxattr,
- .removexattr = generic_removexattr,
};
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index 0bf3c33aedff..c60f3d32ee91 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -658,7 +658,7 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf,
if (old_blocks)
dquot_free_block(inode, old_blocks);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
return 0;
}
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index e57174d43683..dcd96aac02f5 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1096,13 +1096,17 @@ static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
}
static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct kernfs_node *kn = old_dentry->d_fsdata;
struct kernfs_node *new_parent = new_dir->i_private;
struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
int ret;
+ if (flags)
+ return -EINVAL;
+
if (!scops || !scops->rename)
return -EPERM;
@@ -1126,9 +1130,6 @@ const struct inode_operations kernfs_dir_iops = {
.permission = kernfs_iop_permission,
.setattr = kernfs_iop_setattr,
.getattr = kernfs_iop_getattr,
- .setxattr = kernfs_iop_setxattr,
- .removexattr = kernfs_iop_removexattr,
- .getxattr = kernfs_iop_getxattr,
.listxattr = kernfs_iop_listxattr,
.mkdir = kernfs_iop_mkdir,
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 63b925d5ba1e..a1982118f92f 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -28,9 +28,6 @@ static const struct inode_operations kernfs_iops = {
.permission = kernfs_iop_permission,
.setattr = kernfs_iop_setattr,
.getattr = kernfs_iop_getattr,
- .setxattr = kernfs_iop_setxattr,
- .removexattr = kernfs_iop_removexattr,
- .getxattr = kernfs_iop_getxattr,
.listxattr = kernfs_iop_listxattr,
};
@@ -122,7 +119,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
return -EINVAL;
mutex_lock(&kernfs_mutex);
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
goto out;
@@ -138,17 +135,12 @@ out:
return error;
}
-static int kernfs_node_setsecdata(struct kernfs_node *kn, void **secdata,
+static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
u32 *secdata_len)
{
- struct kernfs_iattrs *attrs;
void *old_secdata;
size_t old_secdata_len;
- attrs = kernfs_iattrs(kn);
- if (!attrs)
- return -ENOMEM;
-
old_secdata = attrs->ia_secdata;
old_secdata_len = attrs->ia_secdata_len;
@@ -160,71 +152,6 @@ static int kernfs_node_setsecdata(struct kernfs_node *kn, void **secdata,
return 0;
}
-int kernfs_iop_setxattr(struct dentry *unused, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags)
-{
- struct kernfs_node *kn = inode->i_private;
- struct kernfs_iattrs *attrs;
- void *secdata;
- int error;
- u32 secdata_len = 0;
-
- attrs = kernfs_iattrs(kn);
- if (!attrs)
- return -ENOMEM;
-
- if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) {
- const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
- error = security_inode_setsecurity(inode, suffix,
- value, size, flags);
- if (error)
- return error;
- error = security_inode_getsecctx(inode,
- &secdata, &secdata_len);
- if (error)
- return error;
-
- mutex_lock(&kernfs_mutex);
- error = kernfs_node_setsecdata(kn, &secdata, &secdata_len);
- mutex_unlock(&kernfs_mutex);
-
- if (secdata)
- security_release_secctx(secdata, secdata_len);
- return error;
- } else if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
- return simple_xattr_set(&attrs->xattrs, name, value, size,
- flags);
- }
-
- return -EINVAL;
-}
-
-int kernfs_iop_removexattr(struct dentry *dentry, const char *name)
-{
- struct kernfs_node *kn = dentry->d_fsdata;
- struct kernfs_iattrs *attrs;
-
- attrs = kernfs_iattrs(kn);
- if (!attrs)
- return -ENOMEM;
-
- return simple_xattr_set(&attrs->xattrs, name, NULL, 0, XATTR_REPLACE);
-}
-
-ssize_t kernfs_iop_getxattr(struct dentry *unused, struct inode *inode,
- const char *name, void *buf, size_t size)
-{
- struct kernfs_node *kn = inode->i_private;
- struct kernfs_iattrs *attrs;
-
- attrs = kernfs_iattrs(kn);
- if (!attrs)
- return -ENOMEM;
-
- return simple_xattr_get(&attrs->xattrs, name, buf, size);
-}
-
ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
{
struct kernfs_node *kn = dentry->d_fsdata;
@@ -241,7 +168,7 @@ static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
{
inode->i_mode = mode;
inode->i_atime = inode->i_mtime =
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
}
static inline void set_inode_attr(struct inode *inode, struct iattr *iattr)
@@ -376,3 +303,83 @@ int kernfs_iop_permission(struct inode *inode, int mask)
return generic_permission(inode, mask);
}
+
+static int kernfs_xattr_get(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *suffix, void *value, size_t size)
+{
+ const char *name = xattr_full_name(handler, suffix);
+ struct kernfs_node *kn = inode->i_private;
+ struct kernfs_iattrs *attrs;
+
+ attrs = kernfs_iattrs(kn);
+ if (!attrs)
+ return -ENOMEM;
+
+ return simple_xattr_get(&attrs->xattrs, name, value, size);
+}
+
+static int kernfs_xattr_set(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *suffix, const void *value,
+ size_t size, int flags)
+{
+ const char *name = xattr_full_name(handler, suffix);
+ struct kernfs_node *kn = inode->i_private;
+ struct kernfs_iattrs *attrs;
+
+ attrs = kernfs_iattrs(kn);
+ if (!attrs)
+ return -ENOMEM;
+
+ return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
+}
+
+const struct xattr_handler kernfs_trusted_xattr_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .get = kernfs_xattr_get,
+ .set = kernfs_xattr_set,
+};
+
+static int kernfs_security_xattr_set(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *suffix, const void *value,
+ size_t size, int flags)
+{
+ struct kernfs_node *kn = inode->i_private;
+ struct kernfs_iattrs *attrs;
+ void *secdata;
+ u32 secdata_len = 0;
+ int error;
+
+ attrs = kernfs_iattrs(kn);
+ if (!attrs)
+ return -ENOMEM;
+
+ error = security_inode_setsecurity(inode, suffix, value, size, flags);
+ if (error)
+ return error;
+ error = security_inode_getsecctx(inode, &secdata, &secdata_len);
+ if (error)
+ return error;
+
+ mutex_lock(&kernfs_mutex);
+ error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len);
+ mutex_unlock(&kernfs_mutex);
+
+ if (secdata)
+ security_release_secctx(secdata, secdata_len);
+ return error;
+}
+
+const struct xattr_handler kernfs_security_xattr_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .get = kernfs_xattr_get,
+ .set = kernfs_security_xattr_set,
+};
+
+const struct xattr_handler *kernfs_xattr_handlers[] = {
+ &kernfs_trusted_xattr_handler,
+ &kernfs_security_xattr_handler,
+ NULL
+};
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 37159235ac10..bfd551bbf231 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -76,17 +76,12 @@ extern struct kmem_cache *kernfs_node_cache;
/*
* inode.c
*/
+extern const struct xattr_handler *kernfs_xattr_handlers[];
void kernfs_evict_inode(struct inode *inode);
int kernfs_iop_permission(struct inode *inode, int mask);
int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr);
int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
-int kernfs_iop_setxattr(struct dentry *dentry, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags);
-int kernfs_iop_removexattr(struct dentry *dentry, const char *name);
-ssize_t kernfs_iop_getxattr(struct dentry *dentry, struct inode *inode,
- const char *name, void *buf, size_t size);
ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size);
/*
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index b3d73ad52b22..d5b149a45be1 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -158,6 +158,7 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = magic;
sb->s_op = &kernfs_sops;
+ sb->s_xattr = kernfs_xattr_handlers;
sb->s_time_gran = 1;
/* get root inode, initialize and unlock it */
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 117b8b3416f9..9b43ca02b7ab 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -134,9 +134,6 @@ static const char *kernfs_iop_get_link(struct dentry *dentry,
}
const struct inode_operations kernfs_symlink_iops = {
- .setxattr = kernfs_iop_setxattr,
- .removexattr = kernfs_iop_removexattr,
- .getxattr = kernfs_iop_getxattr,
.listxattr = kernfs_iop_listxattr,
.readlink = generic_readlink,
.get_link = kernfs_iop_get_link,
diff --git a/fs/libfs.c b/fs/libfs.c
index 74dc8b9e7f53..48826d4da189 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -236,8 +236,8 @@ static const struct super_operations simple_super_operations = {
* Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
* will never be mountable)
*/
-struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
- const struct super_operations *ops,
+struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
+ const struct super_operations *ops, const struct xattr_handler **xattr,
const struct dentry_operations *dops, unsigned long magic)
{
struct super_block *s;
@@ -254,6 +254,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
s->s_blocksize_bits = PAGE_SHIFT;
s->s_magic = magic;
s->s_op = ops ? ops : &simple_super_operations;
+ s->s_xattr = xattr;
s->s_time_gran = 1;
root = new_inode(s);
if (!root)
@@ -265,7 +266,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
*/
root->i_ino = 1;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
- root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+ root->i_atime = root->i_mtime = root->i_ctime = current_time(root);
dentry = __d_alloc(s, &d_name);
if (!dentry) {
iput(root);
@@ -281,7 +282,7 @@ Enomem:
deactivate_locked_super(s);
return ERR_PTR(-ENOMEM);
}
-EXPORT_SYMBOL(mount_pseudo);
+EXPORT_SYMBOL(mount_pseudo_xattr);
int simple_open(struct inode *inode, struct file *file)
{
@@ -295,7 +296,7 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
{
struct inode *inode = d_inode(old_dentry);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
inc_nlink(inode);
ihold(inode);
dget(dentry);
@@ -329,7 +330,7 @@ int simple_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
drop_nlink(inode);
dput(dentry);
return 0;
@@ -349,11 +350,15 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
EXPORT_SYMBOL(simple_rmdir);
int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *inode = d_inode(old_dentry);
int they_are_dirs = d_is_dir(old_dentry);
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
if (!simple_empty(new_dentry))
return -ENOTEMPTY;
@@ -369,7 +374,7 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
}
old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
- new_dir->i_mtime = inode->i_ctime = CURRENT_TIME;
+ new_dir->i_mtime = inode->i_ctime = current_time(old_dir);
return 0;
}
@@ -394,7 +399,7 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;
@@ -520,7 +525,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
*/
inode->i_ino = 1;
inode->i_mode = S_IFDIR | 0755;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
set_nlink(inode, 2);
@@ -546,7 +551,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
goto out;
}
inode->i_mode = S_IFREG | files->mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_fop = files->ops;
inode->i_ino = i;
d_add(dentry, inode);
@@ -1092,7 +1097,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_flags |= S_PRIVATE;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
return inode;
}
EXPORT_SYMBOL(alloc_anon_inode);
@@ -1149,24 +1154,6 @@ static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr)
return -EPERM;
}
-static int empty_dir_setxattr(struct dentry *dentry, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags)
-{
- return -EOPNOTSUPP;
-}
-
-static ssize_t empty_dir_getxattr(struct dentry *dentry, struct inode *inode,
- const char *name, void *value, size_t size)
-{
- return -EOPNOTSUPP;
-}
-
-static int empty_dir_removexattr(struct dentry *dentry, const char *name)
-{
- return -EOPNOTSUPP;
-}
-
static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size)
{
return -EOPNOTSUPP;
@@ -1177,9 +1164,6 @@ static const struct inode_operations empty_dir_inode_operations = {
.permission = generic_permission,
.setattr = empty_dir_setattr,
.getattr = empty_dir_getattr,
- .setxattr = empty_dir_setxattr,
- .getxattr = empty_dir_getxattr,
- .removexattr = empty_dir_removexattr,
.listxattr = empty_dir_listxattr,
};
@@ -1215,6 +1199,7 @@ void make_empty_dir_inode(struct inode *inode)
inode->i_blocks = 0;
inode->i_op = &empty_dir_inode_operations;
+ inode->i_opflags &= ~IOP_XATTR;
inode->i_fop = &empty_dir_operations;
}
diff --git a/fs/locks.c b/fs/locks.c
index 90ec67108b22..ce93b416b490 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -138,6 +138,11 @@
#define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
#define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK)
+static inline bool is_remote_lock(struct file *filp)
+{
+ return likely(!(filp->f_path.dentry->d_sb->s_flags & MS_NOREMOTELOCK));
+}
+
static bool lease_breaking(struct file_lock *fl)
{
return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
@@ -806,7 +811,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
struct file_lock_context *ctx;
- struct inode *inode = file_inode(filp);
+ struct inode *inode = locks_inode(filp);
ctx = smp_load_acquire(&inode->i_flctx);
if (!ctx || list_empty_careful(&ctx->flc_posix)) {
@@ -1211,7 +1216,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
int posix_lock_file(struct file *filp, struct file_lock *fl,
struct file_lock *conflock)
{
- return posix_lock_inode(file_inode(filp), fl, conflock);
+ return posix_lock_inode(locks_inode(filp), fl, conflock);
}
EXPORT_SYMBOL(posix_lock_file);
@@ -1251,7 +1256,7 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
int locks_mandatory_locked(struct file *file)
{
int ret;
- struct inode *inode = file_inode(file);
+ struct inode *inode = locks_inode(file);
struct file_lock_context *ctx;
struct file_lock *fl;
@@ -1564,7 +1569,7 @@ void lease_get_mtime(struct inode *inode, struct timespec *time)
}
if (has_lease)
- *time = current_fs_time(inode->i_sb);
+ *time = current_time(inode);
else
*time = inode->i_mtime;
}
@@ -1597,7 +1602,7 @@ EXPORT_SYMBOL(lease_get_mtime);
int fcntl_getlease(struct file *filp)
{
struct file_lock *fl;
- struct inode *inode = file_inode(filp);
+ struct inode *inode = locks_inode(filp);
struct file_lock_context *ctx;
int type = F_UNLCK;
LIST_HEAD(dispose);
@@ -1605,7 +1610,7 @@ int fcntl_getlease(struct file *filp)
ctx = smp_load_acquire(&inode->i_flctx);
if (ctx && !list_empty_careful(&ctx->flc_lease)) {
spin_lock(&ctx->flc_lock);
- time_out_leases(file_inode(filp), &dispose);
+ time_out_leases(inode, &dispose);
list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
if (fl->fl_file != filp)
continue;
@@ -1638,7 +1643,8 @@ check_conflicting_open(const struct dentry *dentry, const long arg, int flags)
if (flags & FL_LAYOUT)
return 0;
- if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
+ if ((arg == F_RDLCK) &&
+ (atomic_read(&d_real_inode(dentry)->i_writecount) > 0))
return -EAGAIN;
if ((arg == F_WRLCK) && ((d_count(dentry) > 1) ||
@@ -1653,7 +1659,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
{
struct file_lock *fl, *my_fl = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry;
- struct inode *inode = file_inode(filp);
+ struct inode *inode = dentry->d_inode;
struct file_lock_context *ctx;
bool is_deleg = (*flp)->fl_flags & FL_DELEG;
int error;
@@ -1769,7 +1775,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
{
int error = -EAGAIN;
struct file_lock *fl, *victim = NULL;
- struct inode *inode = file_inode(filp);
+ struct inode *inode = locks_inode(filp);
struct file_lock_context *ctx;
LIST_HEAD(dispose);
@@ -1811,7 +1817,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
void **priv)
{
- struct inode *inode = file_inode(filp);
+ struct inode *inode = locks_inode(filp);
int error;
if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
@@ -1859,7 +1865,7 @@ EXPORT_SYMBOL(generic_setlease);
int
vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
{
- if (filp->f_op->setlease)
+ if (filp->f_op->setlease && is_remote_lock(filp))
return filp->f_op->setlease(filp, arg, lease, priv);
else
return generic_setlease(filp, arg, lease, priv);
@@ -2008,7 +2014,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
if (error)
goto out_free;
- if (f.file->f_op->flock)
+ if (f.file->f_op->flock && is_remote_lock(f.file))
error = f.file->f_op->flock(f.file,
(can_sleep) ? F_SETLKW : F_SETLK,
lock);
@@ -2034,7 +2040,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
*/
int vfs_test_lock(struct file *filp, struct file_lock *fl)
{
- if (filp->f_op->lock)
+ if (filp->f_op->lock && is_remote_lock(filp))
return filp->f_op->lock(filp, F_GETLK, fl);
posix_test_lock(filp, fl);
return 0;
@@ -2158,7 +2164,7 @@ out:
*/
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
{
- if (filp->f_op->lock)
+ if (filp->f_op->lock && is_remote_lock(filp))
return filp->f_op->lock(filp, cmd, fl);
else
return posix_lock_file(filp, fl, conf);
@@ -2220,7 +2226,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
if (file_lock == NULL)
return -ENOLCK;
- inode = file_inode(filp);
+ inode = locks_inode(filp);
/*
* This might block, so we do it before checking the inode.
@@ -2372,7 +2378,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
- inode = file_inode(filp);
+ inode = locks_inode(filp);
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
@@ -2455,6 +2461,7 @@ out:
void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
int error;
+ struct inode *inode = locks_inode(filp);
struct file_lock lock;
struct file_lock_context *ctx;
@@ -2463,7 +2470,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
* posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway.
*/
- ctx = smp_load_acquire(&file_inode(filp)->i_flctx);
+ ctx = smp_load_acquire(&inode->i_flctx);
if (!ctx || list_empty(&ctx->flc_posix))
return;
@@ -2481,7 +2488,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock);
- trace_locks_remove_posix(file_inode(filp), &lock, error);
+ trace_locks_remove_posix(inode, &lock, error);
}
EXPORT_SYMBOL(locks_remove_posix);
@@ -2498,12 +2505,12 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
.fl_type = F_UNLCK,
.fl_end = OFFSET_MAX,
};
- struct inode *inode = file_inode(filp);
+ struct inode *inode = locks_inode(filp);
if (list_empty(&flctx->flc_flock))
return;
- if (filp->f_op->flock)
+ if (filp->f_op->flock && is_remote_lock(filp))
filp->f_op->flock(filp, F_SETLKW, &fl);
else
flock_lock_inode(inode, &fl);
@@ -2537,7 +2544,7 @@ void locks_remove_file(struct file *filp)
{
struct file_lock_context *ctx;
- ctx = smp_load_acquire(&file_inode(filp)->i_flctx);
+ ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
if (!ctx)
return;
@@ -2581,7 +2588,7 @@ EXPORT_SYMBOL(posix_unblock_lock);
*/
int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
{
- if (filp->f_op->lock)
+ if (filp->f_op->lock && is_remote_lock(filp))
return filp->f_op->lock(filp, F_CANCELLK, fl);
return 0;
}
@@ -2620,7 +2627,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
fl_pid = fl->fl_pid;
if (fl->fl_file != NULL)
- inode = file_inode(fl->fl_file);
+ inode = locks_inode(fl->fl_file);
seq_printf(f, "%lld:%s ", id, pfx);
if (IS_POSIX(fl)) {
@@ -2726,7 +2733,7 @@ static void __show_fd_locks(struct seq_file *f,
void show_fd_locks(struct seq_file *f,
struct file *filp, struct files_struct *files)
{
- struct inode *inode = file_inode(filp);
+ struct inode *inode = locks_inode(filp);
struct file_lock_context *ctx;
int id = 0;
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index 9568064ecadf..c87ea52de3d9 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -226,7 +226,7 @@ static int logfs_unlink(struct inode *dir, struct dentry *dentry)
ta->state = UNLINK_1;
ta->ino = inode->i_ino;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
page = logfs_get_dd_page(dir, dentry);
if (!page) {
@@ -540,7 +540,7 @@ static int logfs_link(struct dentry *old_dentry, struct inode *dir,
{
struct inode *inode = d_inode(old_dentry);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
ihold(inode);
inc_nlink(inode);
mark_inode_dirty_sync(inode);
@@ -573,7 +573,7 @@ static int logfs_delete_dd(struct inode *dir, loff_t pos)
* (crc-protected) journal.
*/
BUG_ON(beyond_eof(dir, pos));
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
log_dir(" Delete dentry (%lx, %llx)\n", dir->i_ino, pos);
return logfs_delete(dir, pos, NULL);
}
@@ -718,8 +718,12 @@ out:
}
static int logfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
if (d_really_is_positive(new_dentry))
return logfs_rename_target(old_dir, old_dentry,
new_dir, new_dentry);
diff --git a/fs/logfs/file.c b/fs/logfs/file.c
index f01ddfb1a03b..1db04930ad57 100644
--- a/fs/logfs/file.c
+++ b/fs/logfs/file.c
@@ -211,7 +211,7 @@ long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
li->li_flags = flags;
inode_unlock(inode);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty_sync(inode);
return 0;
@@ -244,7 +244,7 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int err = 0;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c
index db9cfc598883..f440a1525da8 100644
--- a/fs/logfs/inode.c
+++ b/fs/logfs/inode.c
@@ -213,8 +213,8 @@ static void logfs_init_inode(struct super_block *sb, struct inode *inode)
i_gid_write(inode, 0);
inode->i_size = 0;
inode->i_blocks = 0;
- inode->i_ctime = CURRENT_TIME;
- inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
+ inode->i_mtime = current_time(inode);
li->li_refcount = 1;
INIT_LIST_HEAD(&li->li_freeing_list);
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index 3fb8c6d67303..bf19bf4a243f 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -1546,7 +1546,7 @@ static int __logfs_write_buf(struct inode *inode, struct page *page, long flags)
int err;
flags |= WF_WRITE | WF_DELETE;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
logfs_unpack_index(index, &bix, &level);
if (logfs_block(page) && logfs_block(page)->reserved_bytes)
@@ -1578,7 +1578,7 @@ static int __logfs_delete(struct inode *inode, struct page *page)
long flags = WF_DELETE;
int err;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
if (page->index < I0_BLOCKS)
return logfs_write_direct(inode, page, flags);
diff --git a/fs/mbcache.c b/fs/mbcache.c
index eccda3a02de6..c5bd19ffa326 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -366,7 +366,11 @@ struct mb_cache *mb_cache_create(int bucket_bits)
cache->c_shrink.count_objects = mb_cache_count;
cache->c_shrink.scan_objects = mb_cache_scan;
cache->c_shrink.seeks = DEFAULT_SEEKS;
- register_shrinker(&cache->c_shrink);
+ if (register_shrinker(&cache->c_shrink)) {
+ kfree(cache->c_hash);
+ kfree(cache);
+ goto err_out;
+ }
INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker);
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 742942a983be..c2c3fd3277b5 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -253,7 +253,7 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
}
inode_init_owner(inode, dir, mode);
inode->i_ino = j;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_blocks = 0;
memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
insert_inode_hash(inode);
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 31dcd515b9d5..7edc9b395700 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -274,7 +274,7 @@ got_it:
de->inode = inode->i_ino;
}
err = dir_commit_chunk(page, pos, sbi->s_dirsize);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
out_put:
dir_put_page(page);
@@ -306,7 +306,7 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
unlock_page(page);
}
dir_put_page(page);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
return err;
}
@@ -430,7 +430,7 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
unlock_page(page);
}
dir_put_page(page);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
}
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 94f0eb9a6e2c..a6a4797aa0d4 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -26,7 +26,7 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c
index a731cabf1540..4c57c9af6946 100644
--- a/fs/minix/itree_common.c
+++ b/fs/minix/itree_common.c
@@ -124,7 +124,7 @@ static inline int splice_branch(struct inode *inode,
/* We are done with atomic stuff, now do the rest of housekeeping */
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
/* had we spliced it onto indirect block? */
if (where->bh)
@@ -343,7 +343,7 @@ do_indirects:
}
first_whole++;
}
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 2887d1d95ce2..1e0f11f5dac9 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -106,7 +106,7 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir,
{
struct inode *inode = d_inode(old_dentry);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
inode_inc_link_count(inode);
ihold(inode);
return add_nondir(dentry, inode);
@@ -185,7 +185,8 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
}
static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry)
+ struct inode * new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode * old_inode = d_inode(old_dentry);
struct inode * new_inode = d_inode(new_dentry);
@@ -195,6 +196,9 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
struct minix_dir_entry * old_de;
int err = -ENOENT;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
old_de = minix_find_entry(old_dentry, &old_page);
if (!old_de)
goto out;
@@ -219,7 +223,7 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
if (!new_de)
goto out_dir;
minix_set_link(new_de, new_page, old_inode);
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = current_time(new_inode);
if (dir_de)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
diff --git a/fs/namei.c b/fs/namei.c
index adb04146df09..a7f601cd521a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1015,7 +1015,7 @@ const char *get_link(struct nameidata *nd)
if (!(nd->flags & LOOKUP_RCU)) {
touch_atime(&last->link);
cond_resched();
- } else if (atime_needs_update(&last->link, inode)) {
+ } else if (atime_needs_update_rcu(&last->link, inode)) {
if (unlikely(unlazy_walk(nd, NULL, 0)))
return ERR_PTR(-ECHILD);
touch_atime(&last->link);
@@ -4369,12 +4369,9 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (error)
return error;
- if (!old_dir->i_op->rename && !old_dir->i_op->rename2)
+ if (!old_dir->i_op->rename)
return -EPERM;
- if (flags && !old_dir->i_op->rename2)
- return -EINVAL;
-
/*
* If we are going to change the parent - check write permissions,
* we'll need to flip '..'.
@@ -4428,14 +4425,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (error)
goto out;
}
- if (!old_dir->i_op->rename2) {
- error = old_dir->i_op->rename(old_dir, old_dentry,
- new_dir, new_dentry);
- } else {
- WARN_ON(old_dir->i_op->rename != NULL);
- error = old_dir->i_op->rename2(old_dir, old_dentry,
- new_dir, new_dentry, flags);
- }
+ error = old_dir->i_op->rename(old_dir, old_dentry,
+ new_dir, new_dentry, flags);
if (error)
goto out;
diff --git a/fs/namespace.c b/fs/namespace.c
index db1b5a38864e..58aca9c931ac 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2743,7 +2743,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
- MS_STRICTATIME);
+ MS_STRICTATIME | MS_NOREMOTELOCK);
if (flags & MS_REMOUNT)
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 17de5c13dfae..6df2a3827574 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -36,7 +36,7 @@ static int ncp_unlink(struct inode *, struct dentry *);
static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
static int ncp_rmdir(struct inode *, struct dentry *);
static int ncp_rename(struct inode *, struct dentry *,
- struct inode *, struct dentry *);
+ struct inode *, struct dentry *, unsigned int);
static int ncp_mknod(struct inode * dir, struct dentry *dentry,
umode_t mode, dev_t rdev);
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
@@ -133,12 +133,11 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
return 0;
if (!ncp_case_sensitive(inode)) {
- struct super_block *sb = dentry->d_sb;
struct nls_table *t;
unsigned long hash;
int i;
- t = NCP_IO_TABLE(sb);
+ t = NCP_IO_TABLE(dentry->d_sb);
hash = init_name_hash(dentry);
for (i=0; i<this->len ; i++)
hash = partial_name_hash(ncp_tolower(t, this->name[i]),
@@ -1106,13 +1105,17 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
}
static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct ncp_server *server = NCP_SERVER(old_dir);
int error;
int old_len, new_len;
__u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
+ if (flags)
+ return -EINVAL;
+
ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
ncp_age_dentry(server, old_dentry);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 1af15fcbe57b..f6cf4c7e92b1 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -884,7 +884,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
/* ageing the dentry to force validation */
ncp_age_dentry(server, dentry);
- result = inode_change_ok(inode, attr);
+ result = setattr_prepare(dentry, attr);
if (result < 0)
goto out;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 177fefb26c18..06e0bf092ba9 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2013,7 +2013,8 @@ EXPORT_SYMBOL_GPL(nfs_link);
* the rename.
*/
int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
@@ -2021,6 +2022,9 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct rpc_task *task;
int error = -EBUSY;
+ if (flags)
+ return -EINVAL;
+
dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n",
old_dentry, new_dentry,
d_count(new_dentry));
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index ca699ddc11c1..2efbdde36c3e 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -182,29 +182,6 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
}
EXPORT_SYMBOL_GPL(nfs_file_read);
-ssize_t
-nfs_file_splice_read(struct file *filp, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t count,
- unsigned int flags)
-{
- struct inode *inode = file_inode(filp);
- ssize_t res;
-
- dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
- filp, (unsigned long) count, (unsigned long long) *ppos);
-
- nfs_start_io_read(inode);
- res = nfs_revalidate_mapping(inode, filp->f_mapping);
- if (!res) {
- res = generic_file_splice_read(filp, ppos, pipe, count, flags);
- if (res > 0)
- nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res);
- }
- nfs_end_io_read(inode);
- return res;
-}
-EXPORT_SYMBOL_GPL(nfs_file_splice_read);
-
int
nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
{
@@ -871,7 +848,7 @@ const struct file_operations nfs_file_operations = {
.fsync = nfs_file_fsync,
.lock = nfs_lock,
.flock = nfs_flock,
- .splice_read = nfs_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags,
.setlease = simple_nosetlease,
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 74935a19e4bf..a6acce663219 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -359,14 +359,13 @@ int nfs_unlink(struct inode *, struct dentry *);
int nfs_symlink(struct inode *, struct dentry *, const char *);
int nfs_link(struct dentry *, struct inode *, struct dentry *);
int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
-int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+int nfs_rename(struct inode *, struct dentry *,
+ struct inode *, struct dentry *, unsigned int);
/* file.c */
int nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
loff_t nfs_file_llseek(struct file *, loff_t, int);
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 *, struct iov_iter *);
int nfs_file_release(struct inode *, struct file *);
@@ -681,11 +680,11 @@ unsigned int nfs_page_length(struct page *page)
loff_t i_size = i_size_read(page_file_mapping(page)->host);
if (i_size > 0) {
- pgoff_t page_index = page_file_index(page);
+ pgoff_t index = page_index(page);
pgoff_t end_index = (i_size - 1) >> PAGE_SHIFT;
- if (page_index < end_index)
+ if (index < end_index)
return PAGE_SIZE;
- if (page_index == end_index)
+ if (index == end_index)
return ((i_size - 1) & ~PAGE_MASK) + 1;
}
return 0;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 698be9361280..dc925b531f32 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -899,9 +899,6 @@ static const struct inode_operations nfs3_dir_inode_operations = {
.setattr = nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
- .getxattr = generic_getxattr,
- .setxattr = generic_setxattr,
- .removexattr = generic_removexattr,
.get_acl = nfs3_get_acl,
.set_acl = nfs3_set_acl,
#endif
@@ -913,9 +910,6 @@ static const struct inode_operations nfs3_file_inode_operations = {
.setattr = nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
- .getxattr = generic_getxattr,
- .setxattr = generic_setxattr,
- .removexattr = generic_removexattr,
.get_acl = nfs3_get_acl,
.set_acl = nfs3_set_acl,
#endif
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index d085ad794884..89a77950e0b0 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -248,7 +248,7 @@ const struct file_operations nfs4_file_operations = {
.fsync = nfs_file_fsync,
.lock = nfs_lock,
.flock = nfs_flock,
- .splice_read = nfs_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags,
.setlease = simple_nosetlease,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a9dec32ba9ba..0e327528a3ce 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -8941,20 +8941,14 @@ static const struct inode_operations nfs4_dir_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
- .getxattr = generic_getxattr,
- .setxattr = generic_setxattr,
.listxattr = nfs4_listxattr,
- .removexattr = generic_removexattr,
};
static const struct inode_operations nfs4_file_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
- .getxattr = generic_getxattr,
- .setxattr = generic_setxattr,
.listxattr = nfs4_listxattr,
- .removexattr = generic_removexattr,
};
const struct nfs_rpc_ops nfs_v4_clientops = {
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 174dd4cf5747..965db474f4b0 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -342,7 +342,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
* update_nfs_request below if the region is not locked. */
req->wb_page = page;
if (page) {
- req->wb_index = page_file_index(page);
+ req->wb_index = page_index(page);
get_page(page);
}
req->wb_offset = offset;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 572e5b3b06f1..defc9233e985 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -295,7 +295,7 @@ int nfs_readpage(struct file *file, struct page *page)
int error;
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
- page, PAGE_SIZE, page_file_index(page));
+ page, PAGE_SIZE, page_index(page));
nfs_inc_stats(inode, NFSIOS_VFSREADPAGE);
nfs_add_stats(inode, NFSIOS_READPAGES, 1);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 3a6724c6eb5f..53211838f72a 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -151,7 +151,7 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c
spin_lock(&inode->i_lock);
i_size = i_size_read(inode);
end_index = (i_size - 1) >> PAGE_SHIFT;
- if (i_size > 0 && page_file_index(page) < end_index)
+ if (i_size > 0 && page_index(page) < end_index)
goto out;
end = page_file_offset(page) + ((loff_t)offset+count);
if (i_size >= end)
@@ -603,7 +603,7 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc,
{
int ret;
- nfs_pageio_cond_complete(pgio, page_file_index(page));
+ nfs_pageio_cond_complete(pgio, page_index(page));
ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE,
launder);
if (ret == -EAGAIN) {
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 9d46a0bdd9f9..62469c60be23 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -55,10 +55,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
goto oom;
for (i = 0; i < rqgi->ngroups; i++) {
- if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i)))
- GROUP_AT(gi, i) = exp->ex_anon_gid;
+ if (gid_eq(GLOBAL_ROOT_GID, rqgi->gid[i]))
+ gi->gid[i] = exp->ex_anon_gid;
else
- GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+ gi->gid[i] = rqgi->gid[i];
}
} else {
gi = get_group_info(rqgi);
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index 5a1708441510..0780ff864539 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -123,7 +123,7 @@ nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp,
if (lcp->lc_mtime.tv_nsec == UTIME_NOW ||
timespec_compare(&lcp->lc_mtime, &inode->i_mtime) < 0)
- lcp->lc_mtime = current_fs_time(inode->i_sb);
+ lcp->lc_mtime = current_time(inode);
iattr.ia_valid |= ATTR_ATIME | ATTR_CTIME | ATTR_MTIME;
iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = lcp->lc_mtime;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a204d7e109d4..39bfaba9c99c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1903,7 +1903,7 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2)
if (g1->ngroups != g2->ngroups)
return false;
for (i=0; i<g1->ngroups; i++)
- if (!gid_eq(GROUP_AT(g1, i), GROUP_AT(g2, i)))
+ if (!gid_eq(g1->gid[i], g2->gid[i]))
return false;
return true;
}
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index e9214768cde9..08188743db53 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -74,10 +74,10 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
* which only requires access, and "set-[ac]time-to-X" which
* requires ownership.
* So if it looks like it might be "set both to the same time which
- * is close to now", and if inode_change_ok fails, then we
+ * is close to now", and if setattr_prepare fails, then we
* convert to "set to now" instead of "set to explicit time"
*
- * We only call inode_change_ok as the last test as technically
+ * We only call setattr_prepare as the last test as technically
* it is not an interface that we should be using.
*/
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
@@ -92,17 +92,15 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
* request is. We require it be within 30 minutes of now.
*/
time_t delta = iap->ia_atime.tv_sec - get_seconds();
- struct inode *inode;
nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
if (nfserr)
goto done;
- inode = d_inode(fhp->fh_dentry);
if (delta < 0)
delta = -delta;
if (delta < MAX_TOUCH_TIME_ERROR &&
- inode_change_ok(inode, iap) != 0) {
+ setattr_prepare(fhp->fh_dentry, iap) != 0) {
/*
* Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
* This will cause notify_change to set these times
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
index 908ebbf0ac7e..582831ab3eb9 100644
--- a/fs/nilfs2/dir.c
+++ b/fs/nilfs2/dir.c
@@ -438,7 +438,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
nilfs_set_de_type(de, inode);
nilfs_commit_chunk(page, mapping, from, to);
nilfs_put_page(page);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
}
/*
@@ -528,7 +528,7 @@ got_it:
de->inode = cpu_to_le64(inode->i_ino);
nilfs_set_de_type(de, inode);
nilfs_commit_chunk(page, page->mapping, from, to);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
nilfs_mark_inode_dirty(dir);
/* OFFSET_CACHE */
out_put:
@@ -576,7 +576,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
pde->rec_len = nilfs_rec_len_to_disk(to - from);
dir->inode = 0;
nilfs_commit_chunk(page, mapping, from, to);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
out:
nilfs_put_page(page);
return err;
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index af04f553d7c9..c7f4fef9ebf5 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -367,7 +367,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
atomic64_inc(&root->inodes_count);
inode_init_owner(inode, dir, mode);
inode->i_ino = ino;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
err = nilfs_bmap_read(ii->i_bmap, NULL);
@@ -749,7 +749,7 @@ void nilfs_truncate(struct inode *inode)
nilfs_truncate_bmap(ii, blkoff);
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
if (IS_SYNC(inode))
nilfs_set_transaction_flag(NILFS_TI_SYNC);
@@ -829,7 +829,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct super_block *sb = inode->i_sb;
int err;
- err = inode_change_ok(inode, iattr);
+ err = setattr_prepare(dentry, iattr);
if (err)
return err;
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index f1d7989459fd..1d2c3d7711fe 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -174,7 +174,7 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
(flags & FS_FL_USER_MODIFIABLE);
nilfs_set_inode_flags(inode);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
if (IS_SYNC(inode))
nilfs_set_transaction_flag(NILFS_TI_SYNC);
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index dbcf1dc93a51..2b71c60fe982 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -194,7 +194,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
if (err)
return err;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
inode_inc_link_count(inode);
ihold(inode);
@@ -350,7 +350,8 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
}
static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
@@ -361,6 +362,9 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct nilfs_transaction_info ti;
int err;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);
if (unlikely(err))
return err;
@@ -391,7 +395,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out_dir;
nilfs_set_link(new_dir, new_de, new_page, old_inode);
nilfs_mark_inode_dirty(new_dir);
- new_inode->i_ctime = CURRENT_TIME;
+ new_inode->i_ctime = current_time(new_inode);
if (dir_de)
drop_nlink(new_inode);
drop_nlink(new_inode);
@@ -410,7 +414,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* Like most other Unix systems, set the ctime for inodes on a
* rename.
*/
- old_inode->i_ctime = CURRENT_TIME;
+ old_inode->i_ctime = current_time(old_inode);
nilfs_delete_entry(old_de, old_page);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index a64313868d3a..7ebfca6a1427 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -49,12 +49,12 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
* enough to fit in "count". Return an error pointer if the count
* is not large enough.
*
- * Called with the group->notification_mutex held.
+ * Called with the group->notification_lock held.
*/
static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
size_t count)
{
- BUG_ON(!mutex_is_locked(&group->notification_mutex));
+ assert_spin_locked(&group->notification_lock);
pr_debug("%s: group=%p count=%zd\n", __func__, group, count);
@@ -64,7 +64,7 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
if (FAN_EVENT_METADATA_LEN > count)
return ERR_PTR(-EINVAL);
- /* held the notification_mutex the whole time, so this is the
+ /* held the notification_lock the whole time, so this is the
* same event we peeked above */
return fsnotify_remove_first_event(group);
}
@@ -147,7 +147,7 @@ static struct fanotify_perm_event_info *dequeue_event(
{
struct fanotify_perm_event_info *event, *return_e = NULL;
- spin_lock(&group->fanotify_data.access_lock);
+ spin_lock(&group->notification_lock);
list_for_each_entry(event, &group->fanotify_data.access_list,
fae.fse.list) {
if (event->fd != fd)
@@ -157,7 +157,7 @@ static struct fanotify_perm_event_info *dequeue_event(
return_e = event;
break;
}
- spin_unlock(&group->fanotify_data.access_lock);
+ spin_unlock(&group->notification_lock);
pr_debug("%s: found return_re=%p\n", __func__, return_e);
@@ -244,10 +244,10 @@ static unsigned int fanotify_poll(struct file *file, poll_table *wait)
int ret = 0;
poll_wait(file, &group->notification_waitq, wait);
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
if (!fsnotify_notify_queue_is_empty(group))
ret = POLLIN | POLLRDNORM;
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
return ret;
}
@@ -268,9 +268,9 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
add_wait_queue(&group->notification_waitq, &wait);
while (1) {
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
kevent = get_one_event(group, count);
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
if (IS_ERR(kevent)) {
ret = PTR_ERR(kevent);
@@ -309,10 +309,10 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
wake_up(&group->fanotify_data.access_waitq);
break;
}
- spin_lock(&group->fanotify_data.access_lock);
+ spin_lock(&group->notification_lock);
list_add_tail(&kevent->list,
&group->fanotify_data.access_list);
- spin_unlock(&group->fanotify_data.access_lock);
+ spin_unlock(&group->notification_lock);
#endif
}
buf += ret;
@@ -371,7 +371,7 @@ static int fanotify_release(struct inode *ignored, struct file *file)
* Process all permission events on access_list and notification queue
* and simulate reply from userspace.
*/
- spin_lock(&group->fanotify_data.access_lock);
+ spin_lock(&group->notification_lock);
list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
fae.fse.list) {
pr_debug("%s: found group=%p event=%p\n", __func__, group,
@@ -380,22 +380,22 @@ static int fanotify_release(struct inode *ignored, struct file *file)
list_del_init(&event->fae.fse.list);
event->response = FAN_ALLOW;
}
- spin_unlock(&group->fanotify_data.access_lock);
/*
* Destroy all non-permission events. For permission events just
* dequeue them and set the response. They will be freed once the
* response is consumed and fanotify_get_response() returns.
*/
- mutex_lock(&group->notification_mutex);
while (!fsnotify_notify_queue_is_empty(group)) {
fsn_event = fsnotify_remove_first_event(group);
- if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS))
+ if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) {
+ spin_unlock(&group->notification_lock);
fsnotify_destroy_event(group, fsn_event);
- else
+ spin_lock(&group->notification_lock);
+ } else
FANOTIFY_PE(fsn_event)->response = FAN_ALLOW;
}
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
/* Response for all permission events it set, wakeup waiters */
wake_up(&group->fanotify_data.access_waitq);
@@ -421,10 +421,10 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long ar
switch (cmd) {
case FIONREAD:
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
list_for_each_entry(fsn_event, &group->notification_list, list)
send_len += FAN_EVENT_METADATA_LEN;
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
ret = put_user(send_len, (int __user *) p);
break;
}
@@ -765,7 +765,6 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
event_f_flags |= O_LARGEFILE;
group->fanotify_data.f_flags = event_f_flags;
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
- spin_lock_init(&group->fanotify_data.access_lock);
init_waitqueue_head(&group->fanotify_data.access_waitq);
INIT_LIST_HEAD(&group->fanotify_data.access_list);
#endif
diff --git a/fs/notify/group.c b/fs/notify/group.c
index b47f7cfdcaa4..fbe3cbebec16 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -45,9 +45,9 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
*/
void fsnotify_group_stop_queueing(struct fsnotify_group *group)
{
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
group->shutdown = true;
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
}
/*
@@ -125,7 +125,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
atomic_set(&group->refcnt, 1);
atomic_set(&group->num_marks, 0);
- mutex_init(&group->notification_mutex);
+ spin_lock_init(&group->notification_lock);
INIT_LIST_HEAD(&group->notification_list);
init_waitqueue_head(&group->notification_waitq);
group->max_events = UINT_MAX;
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index b8d08d0d0a4d..69d1ea3d292a 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -115,10 +115,10 @@ static unsigned int inotify_poll(struct file *file, poll_table *wait)
int ret = 0;
poll_wait(file, &group->notification_waitq, wait);
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
if (!fsnotify_notify_queue_is_empty(group))
ret = POLLIN | POLLRDNORM;
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
return ret;
}
@@ -138,7 +138,7 @@ static int round_event_name_len(struct fsnotify_event *fsn_event)
* enough to fit in "count". Return an error pointer if
* not large enough.
*
- * Called with the group->notification_mutex held.
+ * Called with the group->notification_lock held.
*/
static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
size_t count)
@@ -157,7 +157,7 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
if (event_size > count)
return ERR_PTR(-EINVAL);
- /* held the notification_mutex the whole time, so this is the
+ /* held the notification_lock the whole time, so this is the
* same event we peeked above */
fsnotify_remove_first_event(group);
@@ -234,9 +234,9 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
add_wait_queue(&group->notification_waitq, &wait);
while (1) {
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
kevent = get_one_event(group, count);
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
pr_debug("%s: group=%p kevent=%p\n", __func__, group, kevent);
@@ -300,13 +300,13 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case FIONREAD:
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
list_for_each_entry(fsn_event, &group->notification_list,
list) {
send_len += sizeof(struct inotify_event);
send_len += round_event_name_len(fsn_event);
}
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
ret = put_user(send_len, (int __user *) p);
break;
}
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index e455e83ceeeb..66f85c651c52 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -63,7 +63,7 @@ EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
/* return true if the notify queue is empty, false otherwise */
bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
{
- BUG_ON(!mutex_is_locked(&group->notification_mutex));
+ assert_spin_locked(&group->notification_lock);
return list_empty(&group->notification_list) ? true : false;
}
@@ -73,8 +73,17 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
/* Overflow events are per-group and we don't want to free them */
if (!event || event->mask == FS_Q_OVERFLOW)
return;
- /* If the event is still queued, we have a problem... */
- WARN_ON(!list_empty(&event->list));
+ /*
+ * If the event is still queued, we have a problem... Do an unreliable
+ * lockless check first to avoid locking in the common case. The
+ * locking may be necessary for permission events which got removed
+ * from the list by a different CPU than the one freeing the event.
+ */
+ if (!list_empty(&event->list)) {
+ spin_lock(&group->notification_lock);
+ WARN_ON(!list_empty(&event->list));
+ spin_unlock(&group->notification_lock);
+ }
group->ops->free_event(event);
}
@@ -95,10 +104,10 @@ int fsnotify_add_event(struct fsnotify_group *group,
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
if (group->shutdown) {
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
return 2;
}
@@ -106,7 +115,7 @@ int fsnotify_add_event(struct fsnotify_group *group,
ret = 2;
/* Queue overflow event only if it isn't already queued */
if (!list_empty(&group->overflow_event->list)) {
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
return ret;
}
event = group->overflow_event;
@@ -116,7 +125,7 @@ int fsnotify_add_event(struct fsnotify_group *group,
if (!list_empty(list) && merge) {
ret = merge(list, event);
if (ret) {
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
return ret;
}
}
@@ -124,7 +133,7 @@ int fsnotify_add_event(struct fsnotify_group *group,
queue:
group->q_len++;
list_add_tail(&event->list, list);
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
wake_up(&group->notification_waitq);
kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
@@ -139,7 +148,7 @@ struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
{
struct fsnotify_event *event;
- BUG_ON(!mutex_is_locked(&group->notification_mutex));
+ assert_spin_locked(&group->notification_lock);
pr_debug("%s: group=%p\n", __func__, group);
@@ -161,7 +170,7 @@ struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
*/
struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group)
{
- BUG_ON(!mutex_is_locked(&group->notification_mutex));
+ assert_spin_locked(&group->notification_lock);
return list_first_entry(&group->notification_list,
struct fsnotify_event, list);
@@ -175,12 +184,14 @@ void fsnotify_flush_notify(struct fsnotify_group *group)
{
struct fsnotify_event *event;
- mutex_lock(&group->notification_mutex);
+ spin_lock(&group->notification_lock);
while (!fsnotify_notify_queue_is_empty(group)) {
event = fsnotify_remove_first_event(group);
+ spin_unlock(&group->notification_lock);
fsnotify_destroy_event(group, event);
+ spin_lock(&group->notification_lock);
}
- mutex_unlock(&group->notification_mutex);
+ spin_unlock(&group->notification_lock);
}
/*
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 30bb10034120..8718af895eab 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -78,7 +78,7 @@ slow:
return ERR_PTR(-ENOMEM);
}
inode->i_ino = ns->inum;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_flags |= S_IMMUTABLE;
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_fop = &ns_file_operations;
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index f548629dfaac..bf72a2c58b75 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -1850,7 +1850,7 @@ again:
* pages being swapped out between us bringing them into memory
* and doing the actual copying.
*/
- if (unlikely(iov_iter_fault_in_multipages_readable(i, bytes))) {
+ if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
status = -EFAULT;
break;
}
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index e01287c964a8..7c410f879412 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -2813,7 +2813,7 @@ done:
* for real.
*/
if (!IS_NOCMTIME(VFS_I(base_ni)) && !IS_RDONLY(VFS_I(base_ni))) {
- struct timespec now = current_fs_time(VFS_I(base_ni)->i_sb);
+ struct timespec now = current_time(VFS_I(base_ni));
int sync_it = 0;
if (!timespec_equal(&VFS_I(base_ni)->i_mtime, &now) ||
@@ -2893,7 +2893,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
int err;
unsigned int ia_valid = attr->ia_valid;
- err = inode_change_ok(vi, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
goto out;
/* We do not support NTFS ACLs yet. */
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index d15d492ce47b..d3c009626032 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -2692,7 +2692,7 @@ mft_rec_already_initialized:
/* Set the inode times to the current time. */
vi->i_atime = vi->i_mtime = vi->i_ctime =
- current_fs_time(vi->i_sb);
+ current_time(vi);
/*
* Set the file size to 0, the ntfs inode sizes are set to 0 by
* the call to ntfs_init_big_inode() below.
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index 2162434728c0..bed1fcb63088 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -201,7 +201,7 @@ static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
}
inode->i_mode = new_mode;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
di->i_mode = cpu_to_le16(inode->i_mode);
di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
@@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,
case ACL_TYPE_ACCESS:
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- ret = posix_acl_equiv_mode(acl, &mode);
- if (ret < 0)
- return ret;
+ umode_t mode;
- if (ret == 0)
- acl = NULL;
+ ret = posix_acl_update_mode(inode, &mode, &acl);
+ if (ret)
+ return ret;
ret = ocfs2_acl_set_mode(inode, di_bh,
handle, mode);
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index f165f867f332..f72712f6c28d 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -7293,7 +7293,7 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
}
inode->i_blocks = ocfs2_inode_sector_count(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index bbb4b3e5b4ff..c5c5b9748ea3 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -2030,7 +2030,7 @@ out_write_size:
}
inode->i_blocks = ocfs2_inode_sector_count(inode);
di->i_size = cpu_to_le64((u64)i_size_read(inode));
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
ocfs2_update_inode_fsync_trans(handle, inode, 1);
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 1d67fcbf7160..8abab16b4602 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -2104,7 +2104,7 @@ int o2net_start_listening(struct o2nm_node *node)
BUG_ON(o2net_listen_sock != NULL);
mlog(ML_KTHREAD, "starting o2net thread...\n");
- o2net_wq = create_singlethread_workqueue("o2net");
+ o2net_wq = alloc_ordered_workqueue("o2net", WQ_MEM_RECLAIM);
if (o2net_wq == NULL) {
mlog(ML_ERROR, "unable to launch o2net thread\n");
return -ENOMEM; /* ? */
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index e1adf285fc31..e7054e2ac922 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -1677,7 +1677,7 @@ int __ocfs2_add_entry(handle_t *handle,
offset, ocfs2_dir_trailer_blk_off(dir->i_sb));
if (ocfs2_dirent_would_fit(de, rec_len)) {
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
if (retval < 0) {
mlog_errno(retval);
@@ -2990,7 +2990,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
ocfs2_dinode_new_extent_list(dir, di);
i_size_write(dir, sb->s_blocksize);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
di->i_size = cpu_to_le64(sb->s_blocksize);
di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index 533bd524e41e..733e4e79c8e2 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -1904,7 +1904,7 @@ static int dlm_join_domain(struct dlm_ctxt *dlm)
}
snprintf(wq_name, O2NM_MAX_NAME_LEN, "dlm_wq-%s", dlm->name);
- dlm->dlm_worker = create_singlethread_workqueue(wq_name);
+ dlm->dlm_worker = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 0);
if (!dlm->dlm_worker) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index ef474cdd6404..1079fae5aa12 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -211,7 +211,7 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
attr->ia_valid &= ~ATTR_SIZE;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
@@ -398,7 +398,7 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
if (inode) {
inode->i_ino = get_next_ino();
inode_init_owner(inode, NULL, mode);
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inc_nlink(inode);
inode->i_fop = &simple_dir_operations;
@@ -421,7 +421,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
inode->i_ino = get_next_ino();
inode_init_owner(inode, parent, mode);
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
ip = DLMFS_I(inode);
ip->ip_conn = DLMFS_I(parent)->ip_conn;
@@ -646,7 +646,7 @@ static int __init init_dlmfs_fs(void)
}
cleanup_inode = 1;
- user_dlm_worker = create_singlethread_workqueue("user_dlm");
+ user_dlm_worker = alloc_workqueue("user_dlm", WQ_MEM_RECLAIM, 0);
if (!user_dlm_worker) {
status = -ENOMEM;
goto bail;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 0b055bfb8e86..000c234d7bbd 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -253,7 +253,7 @@ int ocfs2_should_update_atime(struct inode *inode,
return 0;
}
- now = CURRENT_TIME;
+ now = current_time(inode);
if ((now.tv_sec - inode->i_atime.tv_sec <= osb->s_atime_quantum))
return 0;
else
@@ -287,7 +287,7 @@ int ocfs2_update_inode_atime(struct inode *inode,
* have i_mutex to guard against concurrent changes to other
* inode fields.
*/
- inode->i_atime = CURRENT_TIME;
+ inode->i_atime = current_time(inode);
di->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
ocfs2_update_inode_fsync_trans(handle, inode, 0);
@@ -308,7 +308,7 @@ int ocfs2_set_inode_size(handle_t *handle,
i_size_write(inode, new_i_size);
inode->i_blocks = ocfs2_inode_sector_count(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
if (status < 0) {
@@ -429,7 +429,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
}
i_size_write(inode, new_i_size);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
di = (struct ocfs2_dinode *) fe_bh->b_data;
di->i_size = cpu_to_le64(new_i_size);
@@ -840,7 +840,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
i_size_write(inode, abs_to);
inode->i_blocks = ocfs2_inode_sector_count(inode);
di->i_size = cpu_to_le64((u64)i_size_read(inode));
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
di->i_mtime_nsec = di->i_ctime_nsec;
@@ -1155,7 +1155,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
return 0;
- status = inode_change_ok(inode, attr);
+ status = setattr_prepare(dentry, attr);
if (status)
return status;
@@ -1950,7 +1950,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
if (change_size && i_size_read(inode) < size)
i_size_write(inode, size);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
if (ret < 0)
mlog_errno(ret);
@@ -2321,36 +2321,6 @@ out_mutex:
return ret;
}
-static ssize_t ocfs2_file_splice_read(struct file *in,
- loff_t *ppos,
- struct pipe_inode_info *pipe,
- size_t len,
- unsigned int flags)
-{
- int ret = 0, lock_level = 0;
- struct inode *inode = file_inode(in);
-
- trace_ocfs2_file_splice_read(inode, in, in->f_path.dentry,
- (unsigned long long)OCFS2_I(inode)->ip_blkno,
- in->f_path.dentry->d_name.len,
- in->f_path.dentry->d_name.name, len);
-
- /*
- * See the comment in ocfs2_file_read_iter()
- */
- ret = ocfs2_inode_lock_atime(inode, in->f_path.mnt, &lock_level);
- if (ret < 0) {
- mlog_errno(ret);
- goto bail;
- }
- ocfs2_inode_unlock(inode, lock_level);
-
- ret = generic_file_splice_read(in, ppos, pipe, len, flags);
-
-bail:
- return ret;
-}
-
static ssize_t ocfs2_file_read_iter(struct kiocb *iocb,
struct iov_iter *to)
{
@@ -2474,10 +2444,7 @@ const struct inode_operations ocfs2_file_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ocfs2_listxattr,
- .removexattr = generic_removexattr,
.fiemap = ocfs2_fiemap,
.get_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
@@ -2509,7 +2476,7 @@ const struct file_operations ocfs2_fops = {
#endif
.lock = ocfs2_lock,
.flock = ocfs2_flock,
- .splice_read = ocfs2_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = ocfs2_fallocate,
};
@@ -2554,7 +2521,7 @@ const struct file_operations ocfs2_fops_no_plocks = {
.compat_ioctl = ocfs2_compat_ioctl,
#endif
.flock = ocfs2_flock,
- .splice_read = ocfs2_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = ocfs2_fallocate,
};
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index 50cc55047443..5af68fcdf9d3 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -123,8 +123,6 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
#define INODE_JOURNAL(i) (OCFS2_I(i)->ip_flags & OCFS2_INODE_JOURNAL)
#define SET_INODE_JOURNAL(i) (OCFS2_I(i)->ip_flags |= OCFS2_INODE_JOURNAL)
-extern struct kmem_cache *ocfs2_inode_cache;
-
extern const struct address_space_operations ocfs2_aops;
extern const struct ocfs2_caching_operations ocfs2_inode_caching_ops;
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index e3d05d9901a3..4e8f32eb0bdb 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -953,7 +953,7 @@ static int ocfs2_move_extents(struct ocfs2_move_extents_context *context)
}
di = (struct ocfs2_dinode *)di_bh->b_data;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
ocfs2_update_inode_fsync_trans(handle, inode, 0);
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index a8f1225e6d9b..8d887c75765c 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -798,7 +798,7 @@ static int ocfs2_link(struct dentry *old_dentry,
}
inc_nlink(inode);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
ocfs2_set_links_count(fe, inode->i_nlink);
fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
fe->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
@@ -1000,7 +1000,7 @@ static int ocfs2_unlink(struct inode *dir,
ocfs2_set_links_count(fe, inode->i_nlink);
ocfs2_journal_dirty(handle, fe_bh);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
if (S_ISDIR(inode->i_mode))
drop_nlink(dir);
@@ -1203,7 +1203,8 @@ static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
static int ocfs2_rename(struct inode *old_dir,
struct dentry *old_dentry,
struct inode *new_dir,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ unsigned int flags)
{
int status = 0, rename_lock = 0, parents_locked = 0, target_exists = 0;
int old_child_locked = 0, new_child_locked = 0, update_dot_dot = 0;
@@ -1228,6 +1229,9 @@ static int ocfs2_rename(struct inode *old_dir,
struct ocfs2_dir_lookup_result target_insert = { NULL, };
bool should_add_orphan = false;
+ if (flags)
+ return -EINVAL;
+
/* At some point it might be nice to break this function up a
* bit. */
@@ -1537,7 +1541,7 @@ static int ocfs2_rename(struct inode *old_dir,
new_dir_bh, &target_insert);
}
- old_inode->i_ctime = CURRENT_TIME;
+ old_inode->i_ctime = current_time(old_inode);
mark_inode_dirty(old_inode);
status = ocfs2_journal_access_di(handle, INODE_CACHE(old_inode),
@@ -1586,9 +1590,9 @@ static int ocfs2_rename(struct inode *old_dir,
if (new_inode) {
drop_nlink(new_inode);
- new_inode->i_ctime = CURRENT_TIME;
+ new_inode->i_ctime = current_time(new_inode);
}
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
if (update_dot_dot) {
status = ocfs2_update_entry(old_inode, handle,
@@ -2913,10 +2917,7 @@ const struct inode_operations ocfs2_dir_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ocfs2_listxattr,
- .removexattr = generic_removexattr,
.fiemap = ocfs2_fiemap,
.get_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
index f8f5fc5e6c05..0b58abcf1c6d 100644
--- a/fs/ocfs2/ocfs2_trace.h
+++ b/fs/ocfs2/ocfs2_trace.h
@@ -1314,8 +1314,6 @@ DEFINE_OCFS2_FILE_OPS(ocfs2_file_aio_write);
DEFINE_OCFS2_FILE_OPS(ocfs2_file_splice_write);
-DEFINE_OCFS2_FILE_OPS(ocfs2_file_splice_read);
-
DEFINE_OCFS2_FILE_OPS(ocfs2_file_aio_read);
DEFINE_OCFS2_ULL_ULL_ULL_EVENT(ocfs2_truncate_file);
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 92bbe93bfe10..19238512a324 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -3778,7 +3778,7 @@ static int ocfs2_change_ctime(struct inode *inode,
goto out_commit;
}
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
@@ -4094,7 +4094,7 @@ static int ocfs2_complete_reflink(struct inode *s_inode,
* we want mtime to appear identical to the source and
* update ctime.
*/
- t_inode->i_ctime = CURRENT_TIME;
+ t_inode->i_ctime = current_time(t_inode);
di->i_ctime = cpu_to_le64(t_inode->i_ctime.tv_sec);
di->i_ctime_nsec = cpu_to_le32(t_inode->i_ctime.tv_nsec);
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 603b28d6f008..f56fe39fab04 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -2329,7 +2329,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
}
cleancache_init_shared_fs(sb);
- osb->ocfs2_wq = create_singlethread_workqueue("ocfs2_wq");
+ osb->ocfs2_wq = alloc_ordered_workqueue("ocfs2_wq", WQ_MEM_RECLAIM);
if (!osb->ocfs2_wq) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 6c2a3e3c521c..6ad8eecefe21 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -91,9 +91,6 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
.get_link = page_get_link,
.getattr = ocfs2_getattr,
.setattr = ocfs2_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ocfs2_listxattr,
- .removexattr = generic_removexattr,
.fiemap = ocfs2_fiemap,
};
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 5bb44f7a78ee..cb157a34a656 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -3431,7 +3431,7 @@ static int __ocfs2_xattr_set_handle(struct inode *inode,
goto out;
}
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
ocfs2_journal_dirty(ctxt->handle, xis->inode_bh);
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
index c8cbf3b60645..b7146526afff 100644
--- a/fs/omfs/dir.c
+++ b/fs/omfs/dir.c
@@ -143,7 +143,7 @@ static int omfs_add_link(struct dentry *dentry, struct inode *inode)
mark_buffer_dirty(bh);
brelse(bh);
- dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_ctime = current_time(dir);
/* mark affected inodes dirty to rebuild checksums */
mark_inode_dirty(dir);
@@ -371,12 +371,16 @@ static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx,
}
static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *new_inode = d_inode(new_dentry);
struct inode *old_inode = d_inode(old_dentry);
int err;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
if (new_inode) {
/* overwriting existing file/dir */
err = omfs_remove(new_dir, new_dentry);
@@ -395,7 +399,7 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (err)
goto out;
- old_inode->i_ctime = CURRENT_TIME_SEC;
+ old_inode->i_ctime = current_time(old_inode);
mark_inode_dirty(old_inode);
out:
return err;
diff --git a/fs/omfs/file.c b/fs/omfs/file.c
index d9e26cfbb793..bf83e6644333 100644
--- a/fs/omfs/file.c
+++ b/fs/omfs/file.c
@@ -349,7 +349,7 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index 3d935c81789a..df7ea8543a2e 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -49,7 +49,7 @@ struct inode *omfs_new_inode(struct inode *dir, umode_t mode)
inode_init_owner(inode, NULL, mode);
inode->i_mapping->a_ops = &omfs_aops;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
switch (mode & S_IFMT) {
case S_IFDIR:
inode->i_op = &omfs_dir_inops;
diff --git a/fs/open.c b/fs/open.c
index 4fd6e256f4f4..8aeb08bb278b 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -68,6 +68,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
long vfs_truncate(const struct path *path, loff_t length)
{
struct inode *inode;
+ struct dentry *upperdentry;
long error;
inode = path->dentry->d_inode;
@@ -90,7 +91,17 @@ long vfs_truncate(const struct path *path, loff_t length)
if (IS_APPEND(inode))
goto mnt_drop_write_and_out;
- error = get_write_access(inode);
+ /*
+ * If this is an overlayfs then do as if opening the file so we get
+ * write access on the upper inode, not on the overlay inode. For
+ * non-overlay filesystems d_real() is an identity function.
+ */
+ upperdentry = d_real(path->dentry, NULL, O_WRONLY);
+ error = PTR_ERR(upperdentry);
+ if (IS_ERR(upperdentry))
+ goto mnt_drop_write_and_out;
+
+ error = get_write_access(upperdentry->d_inode);
if (error)
goto mnt_drop_write_and_out;
@@ -109,7 +120,7 @@ long vfs_truncate(const struct path *path, loff_t length)
error = do_truncate(path->dentry, length, 0, NULL);
put_write_and_out:
- put_write_access(inode);
+ put_write_access(upperdentry->d_inode);
mnt_drop_write_and_out:
mnt_drop_write(path->mnt);
out:
@@ -726,7 +737,7 @@ static int do_dentry_open(struct file *f,
if (error)
goto cleanup_all;
- error = break_lease(inode, f->f_flags);
+ error = break_lease(locks_inode(f), f->f_flags);
if (error)
goto cleanup_all;
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index c7a86993d97e..c003a667ed1a 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -355,7 +355,7 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
if (!inode)
return ERR_PTR(-ENOMEM);
if (inode->i_state & I_NEW) {
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
if (inode->i_ino == OPENPROM_ROOT_INO) {
inode->i_op = &openprom_inode_operations;
inode->i_fop = &openprom_operations;
diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c
index 28f2195cd798..7a3754488312 100644
--- a/fs/orangefs/acl.c
+++ b/fs/orangefs/acl.c
@@ -73,14 +73,11 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- /*
- * can we represent this with the traditional file
- * mode permission bits?
- */
- error = posix_acl_equiv_mode(acl, &mode);
- if (error < 0) {
- gossip_err("%s: posix_acl_equiv_mode err: %d\n",
+ umode_t mode;
+
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error) {
+ gossip_err("%s: posix_acl_update_mode err: %d\n",
__func__,
error);
return error;
@@ -90,8 +87,6 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
SetModeFlag(orangefs_inode);
inode->i_mode = mode;
mark_inode_dirty_sync(inode);
- if (error == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/orangefs/dir.c b/fs/orangefs/dir.c
index 324f0af40d7b..284373a57a08 100644
--- a/fs/orangefs/dir.c
+++ b/fs/orangefs/dir.c
@@ -177,8 +177,8 @@ static int orangefs_readdir(struct file *file, struct dir_context *ctx)
}
gossip_debug(GOSSIP_DIR_DEBUG,
- "orangefs_readdir called on %s (pos=%llu)\n",
- dentry->d_name.name, llu(pos));
+ "orangefs_readdir called on %pd (pos=%llu)\n",
+ dentry, llu(pos));
memset(&readdir_response, 0, sizeof(readdir_response));
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 3386886596d6..66ea0cc37b18 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -384,7 +384,7 @@ out:
file_accessed(file);
} else {
SetMtimeFlag(orangefs_inode);
- inode->i_mtime = CURRENT_TIME;
+ inode->i_mtime = current_time(inode);
mark_inode_dirty_sync(inode);
}
}
@@ -611,8 +611,8 @@ static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma)
static int orangefs_file_release(struct inode *inode, struct file *file)
{
gossip_debug(GOSSIP_FILE_DEBUG,
- "orangefs_file_release: called on %s\n",
- file->f_path.dentry->d_name.name);
+ "orangefs_file_release: called on %pD\n",
+ file);
orangefs_flush_inode(inode);
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 28a0557a69be..ef3b4eb54cf2 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -129,8 +129,8 @@ static ssize_t orangefs_direct_IO(struct kiocb *iocb,
struct iov_iter *iter)
{
gossip_debug(GOSSIP_INODE_DEBUG,
- "orangefs_direct_IO: %s\n",
- iocb->ki_filp->f_path.dentry->d_name.name);
+ "orangefs_direct_IO: %pD\n",
+ iocb->ki_filp);
return -EINVAL;
}
@@ -216,10 +216,10 @@ int orangefs_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = dentry->d_inode;
gossip_debug(GOSSIP_INODE_DEBUG,
- "orangefs_setattr: called on %s\n",
- dentry->d_name.name);
+ "orangefs_setattr: called on %pd\n",
+ dentry);
- ret = inode_change_ok(inode, iattr);
+ ret = setattr_prepare(dentry, iattr);
if (ret)
goto out;
@@ -259,8 +259,8 @@ int orangefs_getattr(struct vfsmount *mnt,
struct orangefs_inode_s *orangefs_inode = NULL;
gossip_debug(GOSSIP_INODE_DEBUG,
- "orangefs_getattr: called on %s\n",
- dentry->d_name.name);
+ "orangefs_getattr: called on %pd\n",
+ dentry);
ret = orangefs_inode_getattr(inode, 0, 0);
if (ret == 0) {
@@ -296,10 +296,7 @@ const struct inode_operations orangefs_file_inode_operations = {
.set_acl = orangefs_set_acl,
.setattr = orangefs_setattr,
.getattr = orangefs_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = orangefs_listxattr,
- .removexattr = generic_removexattr,
.permission = orangefs_permission,
};
@@ -438,7 +435,7 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_size = PAGE_SIZE;
inode->i_rdev = dev;
diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c
index 35269e31de92..d15d3d2dba62 100644
--- a/fs/orangefs/namei.c
+++ b/fs/orangefs/namei.c
@@ -24,9 +24,9 @@ static int orangefs_create(struct inode *dir,
struct inode *inode;
int ret;
- gossip_debug(GOSSIP_NAME_DEBUG, "%s: %s\n",
+ gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n",
__func__,
- dentry->d_name.name);
+ dentry);
new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
if (!new_op)
@@ -43,9 +43,9 @@ static int orangefs_create(struct inode *dir,
ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
gossip_debug(GOSSIP_NAME_DEBUG,
- "%s: %s: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
+ "%s: %pd: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
__func__,
- dentry->d_name.name,
+ dentry,
&new_op->downcall.resp.create.refn.khandle,
new_op->downcall.resp.create.refn.fs_id,
new_op,
@@ -57,18 +57,18 @@ static int orangefs_create(struct inode *dir,
inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0,
&new_op->downcall.resp.create.refn);
if (IS_ERR(inode)) {
- gossip_err("%s: Failed to allocate inode for file :%s:\n",
+ gossip_err("%s: Failed to allocate inode for file :%pd:\n",
__func__,
- dentry->d_name.name);
+ dentry);
ret = PTR_ERR(inode);
goto out;
}
gossip_debug(GOSSIP_NAME_DEBUG,
- "%s: Assigned inode :%pU: for file :%s:\n",
+ "%s: Assigned inode :%pU: for file :%pd:\n",
__func__,
get_khandle_from_ino(inode),
- dentry->d_name.name);
+ dentry);
d_instantiate(dentry, inode);
unlock_new_inode(inode);
@@ -76,20 +76,20 @@ static int orangefs_create(struct inode *dir,
ORANGEFS_I(inode)->getattr_time = jiffies - 1;
gossip_debug(GOSSIP_NAME_DEBUG,
- "%s: dentry instantiated for %s\n",
+ "%s: dentry instantiated for %pd\n",
__func__,
- dentry->d_name.name);
+ dentry);
SetMtimeFlag(parent);
- dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty_sync(dir);
ret = 0;
out:
op_release(new_op);
gossip_debug(GOSSIP_NAME_DEBUG,
- "%s: %s: returning %d\n",
+ "%s: %pd: returning %d\n",
__func__,
- dentry->d_name.name,
+ dentry,
ret);
return ret;
}
@@ -115,8 +115,8 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
* -EEXIST on O_EXCL opens, which is broken if we skip this lookup
* in the create path)
*/
- gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %s\n",
- __func__, dentry->d_name.name);
+ gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %pd\n",
+ __func__, dentry);
if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
return ERR_PTR(-ENAMETOOLONG);
@@ -169,9 +169,9 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
gossip_debug(GOSSIP_NAME_DEBUG,
"orangefs_lookup: Adding *negative* dentry "
- "%p for %s\n",
+ "%p for %pd\n",
dentry,
- dentry->d_name.name);
+ dentry);
d_add(dentry, NULL);
res = NULL;
@@ -224,10 +224,10 @@ static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
int ret;
gossip_debug(GOSSIP_NAME_DEBUG,
- "%s: called on %s\n"
+ "%s: called on %pd\n"
" (inode %pU): Parent is %pU | fs_id %d\n",
__func__,
- dentry->d_name.name,
+ dentry,
get_khandle_from_ino(inode),
&parent->refn.khandle,
parent->refn.fs_id);
@@ -254,7 +254,7 @@ static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
drop_nlink(inode);
SetMtimeFlag(parent);
- dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty_sync(dir);
}
return ret;
@@ -326,12 +326,12 @@ static int orangefs_symlink(struct inode *dir,
ORANGEFS_I(inode)->getattr_time = jiffies - 1;
gossip_debug(GOSSIP_NAME_DEBUG,
- "Inode (Symlink) %pU -> %s\n",
+ "Inode (Symlink) %pU -> %pd\n",
get_khandle_from_ino(inode),
- dentry->d_name.name);
+ dentry);
SetMtimeFlag(parent);
- dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty_sync(dir);
ret = 0;
out:
@@ -390,16 +390,16 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
ORANGEFS_I(inode)->getattr_time = jiffies - 1;
gossip_debug(GOSSIP_NAME_DEBUG,
- "Inode (Directory) %pU -> %s\n",
+ "Inode (Directory) %pU -> %pd\n",
get_khandle_from_ino(inode),
- dentry->d_name.name);
+ dentry);
/*
* NOTE: we have no good way to keep nlink consistent for directories
* across clients; keep constant at 1.
*/
SetMtimeFlag(parent);
- dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty_sync(dir);
out:
op_release(new_op);
@@ -409,11 +409,15 @@ out:
static int orangefs_rename(struct inode *old_dir,
struct dentry *old_dentry,
struct inode *new_dir,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ unsigned int flags)
{
struct orangefs_kernel_op_s *new_op;
int ret;
+ if (flags)
+ return -EINVAL;
+
gossip_debug(GOSSIP_NAME_DEBUG,
"orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
old_dentry, new_dentry, d_count(new_dentry));
@@ -443,7 +447,7 @@ static int orangefs_rename(struct inode *old_dir,
ret);
if (new_dentry->d_inode)
- new_dentry->d_inode->i_ctime = CURRENT_TIME;
+ new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
op_release(new_op);
return ret;
@@ -462,9 +466,6 @@ const struct inode_operations orangefs_dir_inode_operations = {
.rename = orangefs_rename,
.setattr = orangefs_setattr,
.getattr = orangefs_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = orangefs_listxattr,
.permission = orangefs_permission,
};
diff --git a/fs/orangefs/orangefs-debugfs.c b/fs/orangefs/orangefs-debugfs.c
index 9b24107c82a8..eb09aa026723 100644
--- a/fs/orangefs/orangefs-debugfs.c
+++ b/fs/orangefs/orangefs-debugfs.c
@@ -428,8 +428,8 @@ static ssize_t orangefs_debug_write(struct file *file,
struct client_debug_mask c_mask = { NULL, 0, 0 };
gossip_debug(GOSSIP_DEBUGFS_DEBUG,
- "orangefs_debug_write: %s\n",
- file->f_path.dentry->d_name.name);
+ "orangefs_debug_write: %pD\n",
+ file);
/*
* Thwart users who try to jamb a ridiculous number
diff --git a/fs/orangefs/symlink.c b/fs/orangefs/symlink.c
index 8fecf823f5ba..10b0b06e075e 100644
--- a/fs/orangefs/symlink.c
+++ b/fs/orangefs/symlink.c
@@ -14,6 +14,5 @@ const struct inode_operations orangefs_symlink_inode_operations = {
.setattr = orangefs_setattr,
.getattr = orangefs_getattr,
.listxattr = orangefs_listxattr,
- .setxattr = generic_setxattr,
.permission = orangefs_permission,
};
diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c
index 2a9f07f06d10..74a81b1daaac 100644
--- a/fs/orangefs/xattr.c
+++ b/fs/orangefs/xattr.c
@@ -73,6 +73,9 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
"%s: name %s, buffer_size %zd\n",
__func__, name, size);
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
gossip_err("Invalid key length (%d)\n",
(int)strlen(name));
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index db37a0e02d32..3f803b3a1f82 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -58,8 +58,8 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
char *buf, *name, *value = NULL;
int uninitialized_var(error);
- if (!old->d_inode->i_op->getxattr ||
- !new->d_inode->i_op->getxattr)
+ if (!(old->d_inode->i_opflags & IOP_XATTR) ||
+ !(new->d_inode->i_opflags & IOP_XATTR))
return 0;
list_size = vfs_listxattr(old, NULL, 0);
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index b0ffa1d1677e..5f90ddf778ba 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1006,17 +1006,14 @@ const struct inode_operations ovl_dir_inode_operations = {
.symlink = ovl_symlink,
.unlink = ovl_unlink,
.rmdir = ovl_rmdir,
- .rename2 = ovl_rename2,
+ .rename = ovl_rename2,
.link = ovl_link,
.setattr = ovl_setattr,
.create = ovl_create,
.mknod = ovl_mknod,
.permission = ovl_permission,
.getattr = ovl_dir_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ovl_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ovl_get_acl,
.update_time = ovl_update_time,
};
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index c75625c1efa3..c18d6a4ff456 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -53,7 +53,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
* inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
* check for a swapfile (which this won't be anyway).
*/
- err = inode_change_ok(dentry->d_inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
@@ -367,10 +367,7 @@ static const struct inode_operations ovl_file_inode_operations = {
.setattr = ovl_setattr,
.permission = ovl_permission,
.getattr = ovl_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ovl_listxattr,
- .removexattr = generic_removexattr,
.get_acl = ovl_get_acl,
.update_time = ovl_update_time,
};
@@ -380,10 +377,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
.get_link = ovl_get_link,
.readlink = ovl_readlink,
.getattr = ovl_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ovl_listxattr,
- .removexattr = generic_removexattr,
.update_time = ovl_update_time,
};
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 5813ccff8cd9..e218e741cb99 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -114,13 +114,13 @@ static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
{
int err;
- pr_debug("rename2(%pd2, %pd2, 0x%x)\n",
+ pr_debug("rename(%pd2, %pd2, 0x%x)\n",
olddentry, newdentry, flags);
err = vfs_rename(olddir, olddentry, newdir, newdentry, NULL, flags);
if (err) {
- pr_debug("...rename2(%pd2, %pd2, ...) = %i\n",
+ pr_debug("...rename(%pd2, %pd2, ...) = %i\n",
olddentry, newdentry, err);
}
return err;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index e2a94a26767b..7e3f0127fc1a 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -275,10 +275,10 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
char val;
struct inode *inode = dentry->d_inode;
- if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr)
+ if (!S_ISDIR(inode->i_mode) || !(inode->i_opflags & IOP_XATTR))
return false;
- res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
+ res = __vfs_getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
if (res == 1 && val == 'y')
return true;
@@ -1320,7 +1320,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
sb->s_xattr = ovl_xattr_handlers;
sb->s_root = root_dentry;
sb->s_fs_info = ufs;
- sb->s_flags |= MS_POSIXACL;
+ sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK;
return 0;
diff --git a/fs/pipe.c b/fs/pipe.c
index 4ebe6b2e5217..1f559f0608e1 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -267,7 +267,6 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
if (bufs) {
int curbuf = pipe->curbuf;
struct pipe_buffer *buf = pipe->bufs + curbuf;
- const struct pipe_buf_operations *ops = buf->ops;
size_t chars = buf->len;
size_t written;
int error;
@@ -275,7 +274,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
if (chars > total_len)
chars = total_len;
- error = ops->confirm(pipe, buf);
+ error = pipe_buf_confirm(pipe, buf);
if (error) {
if (!ret)
ret = error;
@@ -299,8 +298,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
}
if (!buf->len) {
- buf->ops = NULL;
- ops->release(pipe, buf);
+ pipe_buf_release(pipe, buf);
curbuf = (curbuf + 1) & (pipe->buffers - 1);
pipe->curbuf = curbuf;
pipe->nrbufs = --bufs;
@@ -383,11 +381,10 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) &
(pipe->buffers - 1);
struct pipe_buffer *buf = pipe->bufs + lastbuf;
- const struct pipe_buf_operations *ops = buf->ops;
int offset = buf->offset + buf->len;
- if (ops->can_merge && offset + chars <= PAGE_SIZE) {
- ret = ops->confirm(pipe, buf);
+ if (buf->ops->can_merge && offset + chars <= PAGE_SIZE) {
+ ret = pipe_buf_confirm(pipe, buf);
if (ret)
goto out;
@@ -664,7 +661,7 @@ void free_pipe_info(struct pipe_inode_info *pipe)
for (i = 0; i < pipe->buffers; i++) {
struct pipe_buffer *buf = pipe->bufs + i;
if (buf->ops)
- buf->ops->release(pipe, buf);
+ pipe_buf_release(pipe, buf);
}
if (pipe->tmp_page)
__free_page(pipe->tmp_page);
@@ -716,7 +713,7 @@ static struct inode * get_pipe_inode(void)
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
return inode;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 59d47ab0791a..595522022aca 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -598,13 +598,14 @@ posix_acl_create(struct inode *dir, umode_t *mode,
if (IS_ERR(p))
return PTR_ERR(p);
+ ret = -ENOMEM;
clone = posix_acl_clone(p, GFP_NOFS);
if (!clone)
- goto no_mem;
+ goto err_release;
ret = posix_acl_create_masq(clone, mode);
if (ret < 0)
- goto no_mem_clone;
+ goto err_release_clone;
if (ret == 0)
posix_acl_release(clone);
@@ -618,14 +619,45 @@ posix_acl_create(struct inode *dir, umode_t *mode,
return 0;
-no_mem_clone:
+err_release_clone:
posix_acl_release(clone);
-no_mem:
+err_release:
posix_acl_release(p);
- return -ENOMEM;
+ return ret;
}
EXPORT_SYMBOL_GPL(posix_acl_create);
+/**
+ * posix_acl_update_mode - update mode in set_acl
+ *
+ * Update the file mode when setting an ACL: compute the new file permission
+ * bits based on the ACL. In addition, if the ACL is equivalent to the new
+ * file mode, set *acl to NULL to indicate that no ACL should be set.
+ *
+ * As with chmod, clear the setgit bit if the caller is not in the owning group
+ * or capable of CAP_FSETID (see inode_change_ok).
+ *
+ * Called from set_acl inode operations.
+ */
+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
+ struct posix_acl **acl)
+{
+ umode_t mode = inode->i_mode;
+ int error;
+
+ error = posix_acl_equiv_mode(*acl, &mode);
+ if (error < 0)
+ return error;
+ if (error == 0)
+ *acl = NULL;
+ if (!in_group_p(inode->i_gid) &&
+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
+ mode &= ~S_ISGID;
+ *mode_p = mode;
+ return 0;
+}
+EXPORT_SYMBOL(posix_acl_update_mode);
+
/*
* Fix up the uids and gids in posix acl extended attributes in place.
*/
@@ -633,15 +665,15 @@ static void posix_acl_fix_xattr_userns(
struct user_namespace *to, struct user_namespace *from,
void *value, size_t size)
{
- posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
- posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
+ struct posix_acl_xattr_header *header = value;
+ struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
int count;
kuid_t uid;
kgid_t gid;
if (!value)
return;
- if (size < sizeof(posix_acl_xattr_header))
+ if (size < sizeof(struct posix_acl_xattr_header))
return;
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
return;
@@ -691,15 +723,15 @@ struct posix_acl *
posix_acl_from_xattr(struct user_namespace *user_ns,
const void *value, size_t size)
{
- posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
- posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
+ const struct posix_acl_xattr_header *header = value;
+ const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end;
int count;
struct posix_acl *acl;
struct posix_acl_entry *acl_e;
if (!value)
return NULL;
- if (size < sizeof(posix_acl_xattr_header))
+ if (size < sizeof(struct posix_acl_xattr_header))
return ERR_PTR(-EINVAL);
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
return ERR_PTR(-EOPNOTSUPP);
@@ -760,8 +792,8 @@ int
posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
void *buffer, size_t size)
{
- posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
- posix_acl_xattr_entry *ext_entry;
+ struct posix_acl_xattr_header *ext_acl = buffer;
+ struct posix_acl_xattr_entry *ext_entry;
int real_size, n;
real_size = posix_acl_xattr_size(acl->a_count);
@@ -770,7 +802,7 @@ posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
if (real_size > size)
return -ERANGE;
- ext_entry = ext_acl->a_entries;
+ ext_entry = (void *)(ext_acl + 1);
ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
for (n=0; n < acl->a_count; n++, ext_entry++) {
@@ -897,7 +929,7 @@ int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
acl = NULL;
}
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
set_cached_acl(inode, type, acl);
return 0;
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 88c7de12197b..89600fd5963d 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -186,51 +186,45 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
task_unlock(p);
rcu_read_unlock();
- seq_printf(m,
- "State:\t%s\n"
- "Tgid:\t%d\n"
- "Ngid:\t%d\n"
- "Pid:\t%d\n"
- "PPid:\t%d\n"
- "TracerPid:\t%d\n"
- "Uid:\t%d\t%d\t%d\t%d\n"
- "Gid:\t%d\t%d\t%d\t%d\n"
- "FDSize:\t%d\nGroups:\t",
- get_task_state(p),
- tgid, ngid, pid_nr_ns(pid, ns), ppid, tpid,
- from_kuid_munged(user_ns, cred->uid),
- from_kuid_munged(user_ns, cred->euid),
- from_kuid_munged(user_ns, cred->suid),
- from_kuid_munged(user_ns, cred->fsuid),
- from_kgid_munged(user_ns, cred->gid),
- from_kgid_munged(user_ns, cred->egid),
- from_kgid_munged(user_ns, cred->sgid),
- from_kgid_munged(user_ns, cred->fsgid),
- max_fds);
-
+ seq_printf(m, "State:\t%s", get_task_state(p));
+
+ seq_put_decimal_ull(m, "\nTgid:\t", tgid);
+ seq_put_decimal_ull(m, "\nNgid:\t", ngid);
+ seq_put_decimal_ull(m, "\nPid:\t", pid_nr_ns(pid, ns));
+ seq_put_decimal_ull(m, "\nPPid:\t", ppid);
+ seq_put_decimal_ull(m, "\nTracerPid:\t", tpid);
+ seq_put_decimal_ull(m, "\nUid:\t", from_kuid_munged(user_ns, cred->uid));
+ seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->euid));
+ seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->suid));
+ seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->fsuid));
+ seq_put_decimal_ull(m, "\nGid:\t", from_kgid_munged(user_ns, cred->gid));
+ seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->egid));
+ seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->sgid));
+ seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->fsgid));
+ seq_put_decimal_ull(m, "\nFDSize:\t", max_fds);
+
+ seq_puts(m, "\nGroups:\t");
group_info = cred->group_info;
for (g = 0; g < group_info->ngroups; g++)
- seq_printf(m, "%d ",
- from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
+ seq_put_decimal_ull(m, g ? " " : "",
+ from_kgid_munged(user_ns, group_info->gid[g]));
put_cred(cred);
+ /* Trailing space shouldn't have been added in the first place. */
+ seq_putc(m, ' ');
#ifdef CONFIG_PID_NS
seq_puts(m, "\nNStgid:");
for (g = ns->level; g <= pid->level; g++)
- seq_printf(m, "\t%d",
- task_tgid_nr_ns(p, pid->numbers[g].ns));
+ seq_put_decimal_ull(m, "\t", task_tgid_nr_ns(p, pid->numbers[g].ns));
seq_puts(m, "\nNSpid:");
for (g = ns->level; g <= pid->level; g++)
- seq_printf(m, "\t%d",
- task_pid_nr_ns(p, pid->numbers[g].ns));
+ seq_put_decimal_ull(m, "\t", task_pid_nr_ns(p, pid->numbers[g].ns));
seq_puts(m, "\nNSpgid:");
for (g = ns->level; g <= pid->level; g++)
- seq_printf(m, "\t%d",
- task_pgrp_nr_ns(p, pid->numbers[g].ns));
+ seq_put_decimal_ull(m, "\t", task_pgrp_nr_ns(p, pid->numbers[g].ns));
seq_puts(m, "\nNSsid:");
for (g = ns->level; g <= pid->level; g++)
- seq_printf(m, "\t%d",
- task_session_nr_ns(p, pid->numbers[g].ns));
+ seq_put_decimal_ull(m, "\t", task_session_nr_ns(p, pid->numbers[g].ns));
#endif
seq_putc(m, '\n');
}
@@ -299,11 +293,12 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
unlock_task_sighand(p, &flags);
}
- seq_printf(m, "Threads:\t%d\n", num_threads);
- seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim);
+ seq_put_decimal_ull(m, "Threads:\t", num_threads);
+ seq_put_decimal_ull(m, "\nSigQ:\t", qsize);
+ seq_put_decimal_ull(m, "/", qlim);
/* render them all */
- render_sigset_t(m, "SigPnd:\t", &pending);
+ render_sigset_t(m, "\nSigPnd:\t", &pending);
render_sigset_t(m, "ShdPnd:\t", &shpending);
render_sigset_t(m, "SigBlk:\t", &blocked);
render_sigset_t(m, "SigIgn:\t", &ignored);
@@ -348,17 +343,17 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p)
static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
{
#ifdef CONFIG_SECCOMP
- seq_printf(m, "Seccomp:\t%d\n", p->seccomp.mode);
+ seq_put_decimal_ull(m, "Seccomp:\t", p->seccomp.mode);
+ seq_putc(m, '\n');
#endif
}
static inline void task_context_switch_counts(struct seq_file *m,
struct task_struct *p)
{
- seq_printf(m, "voluntary_ctxt_switches:\t%lu\n"
- "nonvoluntary_ctxt_switches:\t%lu\n",
- p->nvcsw,
- p->nivcsw);
+ seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw);
+ seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw);
+ seq_putc(m, '\n');
}
static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
@@ -490,41 +485,41 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
start_time = nsec_to_clock_t(task->real_start_time);
seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state);
- seq_put_decimal_ll(m, ' ', ppid);
- seq_put_decimal_ll(m, ' ', pgid);
- seq_put_decimal_ll(m, ' ', sid);
- seq_put_decimal_ll(m, ' ', tty_nr);
- seq_put_decimal_ll(m, ' ', tty_pgrp);
- seq_put_decimal_ull(m, ' ', task->flags);
- seq_put_decimal_ull(m, ' ', min_flt);
- seq_put_decimal_ull(m, ' ', cmin_flt);
- seq_put_decimal_ull(m, ' ', maj_flt);
- seq_put_decimal_ull(m, ' ', cmaj_flt);
- seq_put_decimal_ull(m, ' ', cputime_to_clock_t(utime));
- seq_put_decimal_ull(m, ' ', cputime_to_clock_t(stime));
- seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cutime));
- seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cstime));
- seq_put_decimal_ll(m, ' ', priority);
- seq_put_decimal_ll(m, ' ', nice);
- seq_put_decimal_ll(m, ' ', num_threads);
- seq_put_decimal_ull(m, ' ', 0);
- seq_put_decimal_ull(m, ' ', start_time);
- seq_put_decimal_ull(m, ' ', vsize);
- seq_put_decimal_ull(m, ' ', mm ? get_mm_rss(mm) : 0);
- seq_put_decimal_ull(m, ' ', rsslim);
- seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0);
- seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->end_code : 1) : 0);
- seq_put_decimal_ull(m, ' ', (permitted && mm) ? mm->start_stack : 0);
- seq_put_decimal_ull(m, ' ', esp);
- seq_put_decimal_ull(m, ' ', eip);
+ seq_put_decimal_ll(m, " ", ppid);
+ seq_put_decimal_ll(m, " ", pgid);
+ seq_put_decimal_ll(m, " ", sid);
+ seq_put_decimal_ll(m, " ", tty_nr);
+ seq_put_decimal_ll(m, " ", tty_pgrp);
+ seq_put_decimal_ull(m, " ", task->flags);
+ seq_put_decimal_ull(m, " ", min_flt);
+ seq_put_decimal_ull(m, " ", cmin_flt);
+ seq_put_decimal_ull(m, " ", maj_flt);
+ seq_put_decimal_ull(m, " ", cmaj_flt);
+ seq_put_decimal_ull(m, " ", cputime_to_clock_t(utime));
+ seq_put_decimal_ull(m, " ", cputime_to_clock_t(stime));
+ seq_put_decimal_ll(m, " ", cputime_to_clock_t(cutime));
+ seq_put_decimal_ll(m, " ", cputime_to_clock_t(cstime));
+ seq_put_decimal_ll(m, " ", priority);
+ seq_put_decimal_ll(m, " ", nice);
+ seq_put_decimal_ll(m, " ", num_threads);
+ seq_put_decimal_ull(m, " ", 0);
+ seq_put_decimal_ull(m, " ", start_time);
+ seq_put_decimal_ull(m, " ", vsize);
+ seq_put_decimal_ull(m, " ", mm ? get_mm_rss(mm) : 0);
+ seq_put_decimal_ull(m, " ", rsslim);
+ seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->start_code : 1) : 0);
+ seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->end_code : 1) : 0);
+ seq_put_decimal_ull(m, " ", (permitted && mm) ? mm->start_stack : 0);
+ seq_put_decimal_ull(m, " ", esp);
+ seq_put_decimal_ull(m, " ", eip);
/* The signal information here is obsolete.
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
- seq_put_decimal_ull(m, ' ', task->pending.signal.sig[0] & 0x7fffffffUL);
- seq_put_decimal_ull(m, ' ', task->blocked.sig[0] & 0x7fffffffUL);
- seq_put_decimal_ull(m, ' ', sigign.sig[0] & 0x7fffffffUL);
- seq_put_decimal_ull(m, ' ', sigcatch.sig[0] & 0x7fffffffUL);
+ seq_put_decimal_ull(m, " ", task->pending.signal.sig[0] & 0x7fffffffUL);
+ seq_put_decimal_ull(m, " ", task->blocked.sig[0] & 0x7fffffffUL);
+ seq_put_decimal_ull(m, " ", sigign.sig[0] & 0x7fffffffUL);
+ seq_put_decimal_ull(m, " ", sigcatch.sig[0] & 0x7fffffffUL);
/*
* We used to output the absolute kernel address, but that's an
@@ -538,31 +533,31 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
else
seq_puts(m, " 0");
- seq_put_decimal_ull(m, ' ', 0);
- seq_put_decimal_ull(m, ' ', 0);
- seq_put_decimal_ll(m, ' ', task->exit_signal);
- seq_put_decimal_ll(m, ' ', task_cpu(task));
- seq_put_decimal_ull(m, ' ', task->rt_priority);
- seq_put_decimal_ull(m, ' ', task->policy);
- seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task));
- seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime));
- seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime));
+ seq_put_decimal_ull(m, " ", 0);
+ seq_put_decimal_ull(m, " ", 0);
+ seq_put_decimal_ll(m, " ", task->exit_signal);
+ seq_put_decimal_ll(m, " ", task_cpu(task));
+ seq_put_decimal_ull(m, " ", task->rt_priority);
+ seq_put_decimal_ull(m, " ", task->policy);
+ seq_put_decimal_ull(m, " ", delayacct_blkio_ticks(task));
+ seq_put_decimal_ull(m, " ", cputime_to_clock_t(gtime));
+ seq_put_decimal_ll(m, " ", cputime_to_clock_t(cgtime));
if (mm && permitted) {
- seq_put_decimal_ull(m, ' ', mm->start_data);
- seq_put_decimal_ull(m, ' ', mm->end_data);
- seq_put_decimal_ull(m, ' ', mm->start_brk);
- seq_put_decimal_ull(m, ' ', mm->arg_start);
- seq_put_decimal_ull(m, ' ', mm->arg_end);
- seq_put_decimal_ull(m, ' ', mm->env_start);
- seq_put_decimal_ull(m, ' ', mm->env_end);
+ seq_put_decimal_ull(m, " ", mm->start_data);
+ seq_put_decimal_ull(m, " ", mm->end_data);
+ seq_put_decimal_ull(m, " ", mm->start_brk);
+ seq_put_decimal_ull(m, " ", mm->arg_start);
+ seq_put_decimal_ull(m, " ", mm->arg_end);
+ seq_put_decimal_ull(m, " ", mm->env_start);
+ seq_put_decimal_ull(m, " ", mm->env_end);
} else
- seq_printf(m, " 0 0 0 0 0 0 0");
+ seq_puts(m, " 0 0 0 0 0 0 0");
if (permitted)
- seq_put_decimal_ll(m, ' ', task->exit_code);
+ seq_put_decimal_ll(m, " ", task->exit_code);
else
- seq_put_decimal_ll(m, ' ', 0);
+ seq_puts(m, " 0");
seq_putc(m, '\n');
if (mm)
@@ -598,13 +593,13 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
* seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
* size, resident, shared, text, data);
*/
- seq_put_decimal_ull(m, 0, size);
- seq_put_decimal_ull(m, ' ', resident);
- seq_put_decimal_ull(m, ' ', shared);
- seq_put_decimal_ull(m, ' ', text);
- seq_put_decimal_ull(m, ' ', 0);
- seq_put_decimal_ull(m, ' ', data);
- seq_put_decimal_ull(m, ' ', 0);
+ seq_put_decimal_ull(m, "", size);
+ seq_put_decimal_ull(m, " ", resident);
+ seq_put_decimal_ull(m, " ", shared);
+ seq_put_decimal_ull(m, " ", text);
+ seq_put_decimal_ull(m, " ", 0);
+ seq_put_decimal_ull(m, " ", data);
+ seq_put_decimal_ull(m, " ", 0);
seq_putc(m, '\n');
return 0;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 3b792ab3c0dc..c2964d890c9a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -400,23 +400,6 @@ static const struct file_operations proc_pid_cmdline_ops = {
.llseek = generic_file_llseek,
};
-static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
- struct pid *pid, struct task_struct *task)
-{
- struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
- if (mm && !IS_ERR(mm)) {
- unsigned int nwords = 0;
- do {
- nwords += 2;
- } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
- seq_write(m, mm->saved_auxv, nwords * sizeof(mm->saved_auxv[0]));
- mmput(mm);
- return 0;
- } else
- return PTR_ERR(mm);
-}
-
-
#ifdef CONFIG_KALLSYMS
/*
* Provides a wchan file via kallsyms in a proper one-value-per-file format.
@@ -709,7 +692,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_MODE)
return -EPERM;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
@@ -1014,6 +997,30 @@ static const struct file_operations proc_environ_operations = {
.release = mem_release,
};
+static int auxv_open(struct inode *inode, struct file *file)
+{
+ return __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS);
+}
+
+static ssize_t auxv_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct mm_struct *mm = file->private_data;
+ unsigned int nwords = 0;
+ do {
+ nwords += 2;
+ } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
+ return simple_read_from_buffer(buf, count, ppos, mm->saved_auxv,
+ nwords * sizeof(mm->saved_auxv[0]));
+}
+
+static const struct file_operations proc_auxv_operations = {
+ .open = auxv_open,
+ .read = auxv_read,
+ .llseek = generic_file_llseek,
+ .release = mem_release,
+};
+
static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
@@ -1664,7 +1671,7 @@ struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *t
/* Common stuff */
ei = PROC_I(inode);
inode->i_ino = get_next_ino();
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_op = &proc_def_inode_operations;
/*
@@ -2280,16 +2287,27 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
if (!p)
return -ESRCH;
- if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) {
- task_lock(p);
- if (slack_ns == 0)
- p->timer_slack_ns = p->default_timer_slack_ns;
- else
- p->timer_slack_ns = slack_ns;
- task_unlock(p);
- } else
- count = -EPERM;
+ if (p != current) {
+ if (!capable(CAP_SYS_NICE)) {
+ count = -EPERM;
+ goto out;
+ }
+
+ err = security_task_setscheduler(p);
+ if (err) {
+ count = err;
+ goto out;
+ }
+ }
+
+ task_lock(p);
+ if (slack_ns == 0)
+ p->timer_slack_ns = p->default_timer_slack_ns;
+ else
+ p->timer_slack_ns = slack_ns;
+ task_unlock(p);
+out:
put_task_struct(p);
return count;
@@ -2299,19 +2317,28 @@ static int timerslack_ns_show(struct seq_file *m, void *v)
{
struct inode *inode = m->private;
struct task_struct *p;
- int err = 0;
+ int err = 0;
p = get_proc_task(inode);
if (!p)
return -ESRCH;
- if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) {
- task_lock(p);
- seq_printf(m, "%llu\n", p->timer_slack_ns);
- task_unlock(p);
- } else
- err = -EPERM;
+ if (p != current) {
+
+ if (!capable(CAP_SYS_NICE)) {
+ err = -EPERM;
+ goto out;
+ }
+ err = security_task_getscheduler(p);
+ if (err)
+ goto out;
+ }
+ task_lock(p);
+ seq_printf(m, "%llu\n", p->timer_slack_ns);
+ task_unlock(p);
+
+out:
put_task_struct(p);
return err;
@@ -2822,7 +2849,7 @@ static const struct pid_entry tgid_base_stuff[] = {
DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
#endif
REG("environ", S_IRUSR, proc_environ_operations),
- ONE("auxv", S_IRUSR, proc_pid_auxv),
+ REG("auxv", S_IRUSR, proc_auxv_operations),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
ONE("limits", S_IRUGO, proc_pid_limits),
@@ -3210,7 +3237,7 @@ static const struct pid_entry tid_base_stuff[] = {
DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
#endif
REG("environ", S_IRUSR, proc_environ_operations),
- ONE("auxv", S_IRUSR, proc_pid_auxv),
+ REG("auxv", S_IRUSR, proc_auxv_operations),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
ONE("limits", S_IRUGO, proc_pid_limits),
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 01df23cc81f6..d21dafef3102 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -31,7 +31,7 @@ static int seq_show(struct seq_file *m, void *v)
put_task_struct(task);
if (files) {
- int fd = proc_fd(m->private);
+ unsigned int fd = proc_fd(m->private);
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
@@ -86,7 +86,7 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
struct task_struct *task;
const struct cred *cred;
struct inode *inode;
- int fd;
+ unsigned int fd;
if (flags & LOOKUP_RCU)
return -ECHILD;
@@ -158,7 +158,7 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
}
if (files) {
- int fd = proc_fd(d_inode(dentry));
+ unsigned int fd = proc_fd(d_inode(dentry));
struct file *fd_file;
spin_lock(&files->file_lock);
@@ -253,7 +253,7 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx,
continue;
rcu_read_unlock();
- len = snprintf(name, sizeof(name), "%d", fd);
+ len = snprintf(name, sizeof(name), "%u", fd);
if (!proc_fill_cache(file, ctx,
name, len, instantiate, p,
(void *)(unsigned long)fd))
diff --git a/fs/proc/fd.h b/fs/proc/fd.h
index 7c047f256ae2..46dafadd0083 100644
--- a/fs/proc/fd.h
+++ b/fs/proc/fd.h
@@ -11,7 +11,7 @@ extern const struct inode_operations proc_fdinfo_inode_operations;
extern int proc_fd_permission(struct inode *inode, int mask);
-static inline int proc_fd(struct inode *inode)
+static inline unsigned int proc_fd(struct inode *inode)
{
return PROC_I(inode)->fd;
}
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index bca66d83a765..5f2dc2032c79 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -105,7 +105,7 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
struct proc_dir_entry *de = PDE(inode);
int error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index c1b72388e571..e69ebe648a34 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -68,7 +68,6 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
ei->sysctl_entry = NULL;
ei->ns_ops = NULL;
inode = &ei->vfs_inode;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return inode;
}
@@ -421,7 +420,7 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
if (inode) {
inode->i_ino = de->low_ino;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
PROC_I(inode)->pde = de;
if (is_empty_pde(de)) {
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 7931c558c192..5378441ec1b7 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -60,7 +60,7 @@ union proc_op {
struct proc_inode {
struct pid *pid;
- int fd;
+ unsigned int fd;
union proc_op op;
struct proc_dir_entry *pde;
struct ctl_table_header *sysctl;
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index b9a8c813e5e6..8a428498d6b2 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -23,6 +23,25 @@ void __attribute__((weak)) arch_report_meminfo(struct seq_file *m)
{
}
+static void show_val_kb(struct seq_file *m, const char *s, unsigned long num)
+{
+ char v[32];
+ static const char blanks[7] = {' ', ' ', ' ', ' ',' ', ' ', ' '};
+ int len;
+
+ len = num_to_str(v, sizeof(v), num << (PAGE_SHIFT - 10));
+
+ seq_write(m, s, 16);
+
+ if (len > 0) {
+ if (len < 8)
+ seq_write(m, blanks, 8 - len);
+
+ seq_write(m, v, len);
+ }
+ seq_write(m, " kB\n", 4);
+}
+
static int meminfo_proc_show(struct seq_file *m, void *v)
{
struct sysinfo i;
@@ -32,10 +51,6 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
unsigned long pages[NR_LRU_LISTS];
int lru;
-/*
- * display in kilobytes.
- */
-#define K(x) ((x) << (PAGE_SHIFT - 10))
si_meminfo(&i);
si_swapinfo(&i);
committed = percpu_counter_read_positive(&vm_committed_as);
@@ -50,136 +65,100 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
available = si_mem_available();
- /*
- * Tagged format, for easy grepping and expansion.
- */
- seq_printf(m,
- "MemTotal: %8lu kB\n"
- "MemFree: %8lu kB\n"
- "MemAvailable: %8lu kB\n"
- "Buffers: %8lu kB\n"
- "Cached: %8lu kB\n"
- "SwapCached: %8lu kB\n"
- "Active: %8lu kB\n"
- "Inactive: %8lu kB\n"
- "Active(anon): %8lu kB\n"
- "Inactive(anon): %8lu kB\n"
- "Active(file): %8lu kB\n"
- "Inactive(file): %8lu kB\n"
- "Unevictable: %8lu kB\n"
- "Mlocked: %8lu kB\n"
-#ifdef CONFIG_HIGHMEM
- "HighTotal: %8lu kB\n"
- "HighFree: %8lu kB\n"
- "LowTotal: %8lu kB\n"
- "LowFree: %8lu kB\n"
-#endif
-#ifndef CONFIG_MMU
- "MmapCopy: %8lu kB\n"
-#endif
- "SwapTotal: %8lu kB\n"
- "SwapFree: %8lu kB\n"
- "Dirty: %8lu kB\n"
- "Writeback: %8lu kB\n"
- "AnonPages: %8lu kB\n"
- "Mapped: %8lu kB\n"
- "Shmem: %8lu kB\n"
- "Slab: %8lu kB\n"
- "SReclaimable: %8lu kB\n"
- "SUnreclaim: %8lu kB\n"
- "KernelStack: %8lu kB\n"
- "PageTables: %8lu kB\n"
-#ifdef CONFIG_QUICKLIST
- "Quicklists: %8lu kB\n"
-#endif
- "NFS_Unstable: %8lu kB\n"
- "Bounce: %8lu kB\n"
- "WritebackTmp: %8lu kB\n"
- "CommitLimit: %8lu kB\n"
- "Committed_AS: %8lu kB\n"
- "VmallocTotal: %8lu kB\n"
- "VmallocUsed: %8lu kB\n"
- "VmallocChunk: %8lu kB\n"
-#ifdef CONFIG_MEMORY_FAILURE
- "HardwareCorrupted: %5lu kB\n"
-#endif
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- "AnonHugePages: %8lu kB\n"
- "ShmemHugePages: %8lu kB\n"
- "ShmemPmdMapped: %8lu kB\n"
-#endif
-#ifdef CONFIG_CMA
- "CmaTotal: %8lu kB\n"
- "CmaFree: %8lu kB\n"
-#endif
- ,
- K(i.totalram),
- K(i.freeram),
- K(available),
- K(i.bufferram),
- K(cached),
- K(total_swapcache_pages()),
- K(pages[LRU_ACTIVE_ANON] + pages[LRU_ACTIVE_FILE]),
- K(pages[LRU_INACTIVE_ANON] + pages[LRU_INACTIVE_FILE]),
- K(pages[LRU_ACTIVE_ANON]),
- K(pages[LRU_INACTIVE_ANON]),
- K(pages[LRU_ACTIVE_FILE]),
- K(pages[LRU_INACTIVE_FILE]),
- K(pages[LRU_UNEVICTABLE]),
- K(global_page_state(NR_MLOCK)),
+ show_val_kb(m, "MemTotal: ", i.totalram);
+ show_val_kb(m, "MemFree: ", i.freeram);
+ show_val_kb(m, "MemAvailable: ", available);
+ show_val_kb(m, "Buffers: ", i.bufferram);
+ show_val_kb(m, "Cached: ", cached);
+ show_val_kb(m, "SwapCached: ", total_swapcache_pages());
+ show_val_kb(m, "Active: ", pages[LRU_ACTIVE_ANON] +
+ pages[LRU_ACTIVE_FILE]);
+ show_val_kb(m, "Inactive: ", pages[LRU_INACTIVE_ANON] +
+ pages[LRU_INACTIVE_FILE]);
+ show_val_kb(m, "Active(anon): ", pages[LRU_ACTIVE_ANON]);
+ show_val_kb(m, "Inactive(anon): ", pages[LRU_INACTIVE_ANON]);
+ show_val_kb(m, "Active(file): ", pages[LRU_ACTIVE_FILE]);
+ show_val_kb(m, "Inactive(file): ", pages[LRU_INACTIVE_FILE]);
+ show_val_kb(m, "Unevictable: ", pages[LRU_UNEVICTABLE]);
+ show_val_kb(m, "Mlocked: ", global_page_state(NR_MLOCK));
+
#ifdef CONFIG_HIGHMEM
- K(i.totalhigh),
- K(i.freehigh),
- K(i.totalram-i.totalhigh),
- K(i.freeram-i.freehigh),
+ show_val_kb(m, "HighTotal: ", i.totalhigh);
+ show_val_kb(m, "HighFree: ", i.freehigh);
+ show_val_kb(m, "LowTotal: ", i.totalram - i.totalhigh);
+ show_val_kb(m, "LowFree: ", i.freeram - i.freehigh);
#endif
+
#ifndef CONFIG_MMU
- K((unsigned long) atomic_long_read(&mmap_pages_allocated)),
+ show_val_kb(m, "MmapCopy: ",
+ (unsigned long)atomic_long_read(&mmap_pages_allocated));
#endif
- K(i.totalswap),
- K(i.freeswap),
- K(global_node_page_state(NR_FILE_DIRTY)),
- K(global_node_page_state(NR_WRITEBACK)),
- K(global_node_page_state(NR_ANON_MAPPED)),
- K(global_node_page_state(NR_FILE_MAPPED)),
- K(i.sharedram),
- K(global_page_state(NR_SLAB_RECLAIMABLE) +
- global_page_state(NR_SLAB_UNRECLAIMABLE)),
- K(global_page_state(NR_SLAB_RECLAIMABLE)),
- K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
- global_page_state(NR_KERNEL_STACK_KB),
- K(global_page_state(NR_PAGETABLE)),
+
+ show_val_kb(m, "SwapTotal: ", i.totalswap);
+ show_val_kb(m, "SwapFree: ", i.freeswap);
+ show_val_kb(m, "Dirty: ",
+ global_node_page_state(NR_FILE_DIRTY));
+ show_val_kb(m, "Writeback: ",
+ global_node_page_state(NR_WRITEBACK));
+ show_val_kb(m, "AnonPages: ",
+ global_node_page_state(NR_ANON_MAPPED));
+ show_val_kb(m, "Mapped: ",
+ global_node_page_state(NR_FILE_MAPPED));
+ show_val_kb(m, "Shmem: ", i.sharedram);
+ show_val_kb(m, "Slab: ",
+ global_page_state(NR_SLAB_RECLAIMABLE) +
+ global_page_state(NR_SLAB_UNRECLAIMABLE));
+
+ show_val_kb(m, "SReclaimable: ",
+ global_page_state(NR_SLAB_RECLAIMABLE));
+ show_val_kb(m, "SUnreclaim: ",
+ global_page_state(NR_SLAB_UNRECLAIMABLE));
+ seq_printf(m, "KernelStack: %8lu kB\n",
+ global_page_state(NR_KERNEL_STACK_KB));
+ show_val_kb(m, "PageTables: ",
+ global_page_state(NR_PAGETABLE));
#ifdef CONFIG_QUICKLIST
- K(quicklist_total_size()),
+ show_val_kb(m, "Quicklists: ", quicklist_total_size());
#endif
- K(global_node_page_state(NR_UNSTABLE_NFS)),
- K(global_page_state(NR_BOUNCE)),
- K(global_node_page_state(NR_WRITEBACK_TEMP)),
- K(vm_commit_limit()),
- K(committed),
- (unsigned long)VMALLOC_TOTAL >> 10,
- 0ul, // used to be vmalloc 'used'
- 0ul // used to be vmalloc 'largest_chunk'
+
+ show_val_kb(m, "NFS_Unstable: ",
+ global_node_page_state(NR_UNSTABLE_NFS));
+ show_val_kb(m, "Bounce: ",
+ global_page_state(NR_BOUNCE));
+ show_val_kb(m, "WritebackTmp: ",
+ global_node_page_state(NR_WRITEBACK_TEMP));
+ show_val_kb(m, "CommitLimit: ", vm_commit_limit());
+ show_val_kb(m, "Committed_AS: ", committed);
+ seq_printf(m, "VmallocTotal: %8lu kB\n",
+ (unsigned long)VMALLOC_TOTAL >> 10);
+ show_val_kb(m, "VmallocUsed: ", 0ul);
+ show_val_kb(m, "VmallocChunk: ", 0ul);
+
#ifdef CONFIG_MEMORY_FAILURE
- , atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10)
+ seq_printf(m, "HardwareCorrupted: %5lu kB\n",
+ atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10));
#endif
+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- , K(global_node_page_state(NR_ANON_THPS) * HPAGE_PMD_NR)
- , K(global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR)
- , K(global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR)
+ show_val_kb(m, "AnonHugePages: ",
+ global_node_page_state(NR_ANON_THPS) * HPAGE_PMD_NR);
+ show_val_kb(m, "ShmemHugePages: ",
+ global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR);
+ show_val_kb(m, "ShmemPmdMapped: ",
+ global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR);
#endif
+
#ifdef CONFIG_CMA
- , K(totalcma_pages)
- , K(global_page_state(NR_FREE_CMA_PAGES))
+ show_val_kb(m, "CmaTotal: ", totalcma_pages);
+ show_val_kb(m, "CmaFree: ",
+ global_page_state(NR_FREE_CMA_PAGES));
#endif
- );
hugetlb_report_meminfo(m);
arch_report_meminfo(m);
return 0;
-#undef K
}
static int meminfo_proc_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 71025b9e2a4e..55313d994895 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -445,7 +445,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
ei->sysctl = head;
ei->sysctl_entry = table;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_mode = table->mode;
if (!S_ISDIR(table->mode)) {
inode->i_mode |= S_IFREG;
@@ -759,7 +759,7 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
return -EPERM;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/proc/self.c b/fs/proc/self.c
index b6a8d3529fea..40245954c450 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -56,7 +56,7 @@ int proc_setup_self(struct super_block *s)
struct inode *inode = new_inode_pseudo(s);
if (inode) {
inode->i_ino = self_inum;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_mode = S_IFLNK | S_IRWXUGO;
inode->i_uid = GLOBAL_ROOT_UID;
inode->i_gid = GLOBAL_ROOT_GID;
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 7907e456ac4f..d700c42b3572 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -115,17 +115,16 @@ static int show_stat(struct seq_file *p, void *v)
}
sum += arch_irq_stat();
- seq_puts(p, "cpu ");
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
+ seq_put_decimal_ull(p, "cpu ", cputime64_to_clock_t(user));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(nice));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(system));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(idle));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(iowait));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(irq));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(softirq));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(steal));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest_nice));
seq_putc(p, '\n');
for_each_online_cpu(i) {
@@ -141,23 +140,23 @@ static int show_stat(struct seq_file *p, void *v)
guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
seq_printf(p, "cpu%d", i);
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest));
- seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(user));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(nice));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(system));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(idle));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(iowait));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(irq));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(softirq));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(steal));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest));
+ seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest_nice));
seq_putc(p, '\n');
}
- seq_printf(p, "intr %llu", (unsigned long long)sum);
+ seq_put_decimal_ull(p, "intr ", (unsigned long long)sum);
/* sum again ? it could be updated? */
for_each_irq_nr(j)
- seq_put_decimal_ull(p, ' ', kstat_irqs_usr(j));
+ seq_put_decimal_ull(p, " ", kstat_irqs_usr(j));
seq_printf(p,
"\nctxt %llu\n"
@@ -171,10 +170,10 @@ static int show_stat(struct seq_file *p, void *v)
nr_running(),
nr_iowait());
- seq_printf(p, "softirq %llu", (unsigned long long)sum_softirq);
+ seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq);
for (i = 0; i < NR_SOFTIRQS; i++)
- seq_put_decimal_ull(p, ' ', per_softirq_sums[i]);
+ seq_put_decimal_ull(p, " ", per_softirq_sums[i]);
seq_putc(p, '\n');
return 0;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index f6fa99eca515..6909582ce5e5 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -147,7 +147,7 @@ m_next_vma(struct proc_maps_private *priv, struct vm_area_struct *vma)
static void m_cache_vma(struct seq_file *m, struct vm_area_struct *vma)
{
if (m->count < m->size) /* vma is copied successfully */
- m->version = m_next_vma(m->private, vma) ? vma->vm_start : -1UL;
+ m->version = m_next_vma(m->private, vma) ? vma->vm_end : -1UL;
}
static void *m_start(struct seq_file *m, loff_t *ppos)
@@ -175,8 +175,10 @@ static void *m_start(struct seq_file *m, loff_t *ppos)
priv->tail_vma = get_gate_vma(mm);
if (last_addr) {
- vma = find_vma(mm, last_addr);
- if (vma && (vma = m_next_vma(priv, vma)))
+ vma = find_vma(mm, last_addr - 1);
+ if (vma && vma->vm_start <= last_addr)
+ vma = m_next_vma(priv, vma);
+ if (vma)
return vma;
}
@@ -1070,7 +1072,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
}
mmu_notifier_invalidate_range_start(mm, 0, -1);
}
- walk_page_range(0, ~0UL, &clear_refs_walk);
+ walk_page_range(0, mm->highest_vm_end, &clear_refs_walk);
if (type == CLEAR_REFS_SOFT_DIRTY)
mmu_notifier_invalidate_range_end(mm, 0, -1);
flush_tlb_mm(mm);
diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
index e58a31e8fb2a..595b90a9766c 100644
--- a/fs/proc/thread_self.c
+++ b/fs/proc/thread_self.c
@@ -58,7 +58,7 @@ int proc_setup_thread_self(struct super_block *s)
struct inode *inode = new_inode_pseudo(s);
if (inode) {
inode->i_ino = thread_self_inum;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_mode = S_IFLNK | S_IRWXUGO;
inode->i_uid = GLOBAL_ROOT_UID;
inode->i_gid = GLOBAL_ROOT_GID;
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index ec9ddef5ae75..1781dc50762e 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -230,7 +230,7 @@ static struct inode *pstore_get_inode(struct super_block *sb)
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_ino = get_next_ino();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
}
return inode;
}
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index be3ddd189cd4..2bcbf4e77982 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -169,7 +169,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
int ret = 0;
/* POSIX UID/GID verification for setting inode attributes */
- ret = inode_change_ok(inode, ia);
+ ret = setattr_prepare(dentry, ia);
if (ret)
return ret;
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 1ab6e6c2e60e..8621c039b536 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -61,7 +61,7 @@ struct inode *ramfs_get_inode(struct super_block *sb,
inode->i_mapping->a_ops = &ramfs_aops;
mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
mapping_set_unevictable(inode->i_mapping);
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
@@ -100,7 +100,7 @@ ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
d_instantiate(dentry, inode);
dget(dentry); /* Extra count - pin the dentry in core */
error = 0;
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
}
return error;
}
@@ -130,7 +130,7 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char *
if (!error) {
d_instantiate(dentry, inode);
dget(dentry);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
} else
iput(inode);
}
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 90f815bdfa8a..2f8c5c9bdaf6 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -260,10 +260,7 @@ const struct file_operations reiserfs_file_operations = {
const struct inode_operations reiserfs_file_inode_operations = {
.setattr = reiserfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = reiserfs_listxattr,
- .removexattr = generic_removexattr,
.permission = reiserfs_permission,
.get_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index c2c59f9ff04b..58b2dedb2a3a 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -2005,7 +2005,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
if (S_ISLNK(inode->i_mode))
inode->i_flags &= ~(S_IMMUTABLE | S_APPEND);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_size = i_size;
inode->i_blocks = 0;
inode->i_bytes = 0;
@@ -3312,7 +3312,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid;
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 2f1ddc908013..1f4692a505a0 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -94,7 +94,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
sd_attrs_to_i_attrs(flags, inode);
REISERFS_I(inode)->i_attrs = flags;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
setflags_out:
mnt_drop_write_file(filp);
@@ -115,7 +115,7 @@ setflags_out:
err = -EFAULT;
goto setversion_out;
}
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
setversion_out:
mnt_drop_write_file(filp);
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 8a36696d6df9..e6a2b406af36 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -570,7 +570,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
}
dir->i_size += paste_size;
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
if (!S_ISDIR(inode->i_mode) && visible)
/* reiserfs_mkdir or reiserfs_rename will do that by itself */
reiserfs_update_sd(th, dir);
@@ -963,7 +963,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
inode->i_nlink);
clear_nlink(inode);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(dir);
reiserfs_update_sd(&th, inode);
DEC_DIR_INODE_NLINK(dir)
@@ -1067,11 +1067,11 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
inc_nlink(inode);
goto end_unlink;
}
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
reiserfs_update_sd(&th, inode);
dir->i_size -= (de.de_entrylen + DEH_SIZE);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
reiserfs_update_sd(&th, dir);
if (!savelink)
@@ -1246,7 +1246,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
return err ? err : retval;
}
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
reiserfs_update_sd(&th, inode);
ihold(inode);
@@ -1306,7 +1306,8 @@ static void set_ino_in_dir_entry(struct reiserfs_dir_entry *de,
* get_empty_nodes or its clones
*/
static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
int retval;
INITIALIZE_PATH(old_entry_path);
@@ -1321,6 +1322,9 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
unsigned long savelink = 1;
struct timespec ctime;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
/*
* three balancings: (1) old name removal, (2) new name insertion
* and (3) maybe "save" link insertion
@@ -1567,7 +1571,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
mark_de_hidden(old_de.de_deh + old_de.de_entry_num);
journal_mark_dirty(&th, old_de.de_bh);
- ctime = CURRENT_TIME_SEC;
+ ctime = current_time(old_dir);
old_dir->i_ctime = old_dir->i_mtime = ctime;
new_dir->i_ctime = new_dir->i_mtime = ctime;
/*
@@ -1650,10 +1654,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
.mknod = reiserfs_mknod,
.rename = reiserfs_rename,
.setattr = reiserfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = reiserfs_listxattr,
- .removexattr = generic_removexattr,
.permission = reiserfs_permission,
.get_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
@@ -1667,10 +1668,7 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
.setattr = reiserfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = reiserfs_listxattr,
- .removexattr = generic_removexattr,
.permission = reiserfs_permission,
};
@@ -1679,10 +1677,7 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
*/
const struct inode_operations reiserfs_special_inode_operations = {
.setattr = reiserfs_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = reiserfs_listxattr,
- .removexattr = generic_removexattr,
.permission = reiserfs_permission,
.get_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index 4032d1e87c8f..a97e352d05d3 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -1987,8 +1987,8 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
pathrelse(&s_search_path);
if (update_timestamps) {
- inode->i_mtime = CURRENT_TIME_SEC;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = current_time(inode);
+ inode->i_ctime = current_time(inode);
}
reiserfs_update_sd(th, inode);
@@ -2012,8 +2012,8 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
update_and_out:
if (update_timestamps) {
/* this is truncate, not file closing */
- inode->i_mtime = CURRENT_TIME_SEC;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = current_time(inode);
+ inode->i_ctime = current_time(inode);
}
reiserfs_update_sd(th, inode);
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 74d5ddd26296..0a6ad4e71e88 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -2522,7 +2522,7 @@ out:
if (inode->i_size < off + len - towrite)
i_size_write(inode, off + len - towrite);
inode->i_version++;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
return len - towrite;
}
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index a33812ae9fad..e87aa21c30de 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -450,13 +450,13 @@ int reiserfs_commit_write(struct file *f, struct page *page,
static void update_ctime(struct inode *inode)
{
- struct timespec now = current_fs_time(inode->i_sb);
+ struct timespec now = current_time(inode);
if (inode_unhashed(inode) || !inode->i_nlink ||
timespec_equal(&inode->i_ctime, &now))
return;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
}
@@ -575,7 +575,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
new_size = buffer_size + sizeof(struct reiserfs_xattr_header);
if (!err && new_size < i_size_read(d_inode(dentry))) {
struct iattr newattrs = {
- .ia_ctime = current_fs_time(inode->i_sb),
+ .ia_ctime = current_time(inode),
.ia_size = new_size,
.ia_valid = ATTR_SIZE | ATTR_CTIME,
};
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index dbed42f755e0..3d2256a425ee 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -242,13 +242,9 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- if (error == 0)
- acl = NULL;
- }
}
break;
case ACL_TYPE_DEFAULT:
@@ -277,7 +273,7 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
if (error == -ENODATA) {
error = 0;
if (type == ACL_TYPE_ACCESS) {
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
}
}
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 6dc4296eed62..368bfb92b115 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -679,11 +679,11 @@ EXPORT_SYMBOL(seq_puts);
/*
* A helper routine for putting decimal numbers without rich format of printf().
* only 'unsigned long long' is supported.
- * This routine will put one byte delimiter + number into seq_file.
+ * This routine will put strlen(delimiter) + number into seq_file.
* This routine is very quick when you show lots of numbers.
* In usual cases, it will be better to use seq_printf(). It's easier to read.
*/
-void seq_put_decimal_ull(struct seq_file *m, char delimiter,
+void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
unsigned long long num)
{
int len;
@@ -691,8 +691,15 @@ void seq_put_decimal_ull(struct seq_file *m, char delimiter,
if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
goto overflow;
- if (delimiter)
- m->buf[m->count++] = delimiter;
+ len = strlen(delimiter);
+ if (m->count + len >= m->size)
+ goto overflow;
+
+ memcpy(m->buf + m->count, delimiter, len);
+ m->count += len;
+
+ if (m->count + 1 >= m->size)
+ goto overflow;
if (num < 10) {
m->buf[m->count++] = num + '0';
@@ -702,6 +709,7 @@ void seq_put_decimal_ull(struct seq_file *m, char delimiter,
len = num_to_str(m->buf + m->count, m->size - m->count, num);
if (!len)
goto overflow;
+
m->count += len;
return;
@@ -710,19 +718,42 @@ overflow:
}
EXPORT_SYMBOL(seq_put_decimal_ull);
-void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num)
+void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num)
{
+ int len;
+
+ if (m->count + 3 >= m->size) /* we'll write 2 bytes at least */
+ goto overflow;
+
+ len = strlen(delimiter);
+ if (m->count + len >= m->size)
+ goto overflow;
+
+ memcpy(m->buf + m->count, delimiter, len);
+ m->count += len;
+
+ if (m->count + 2 >= m->size)
+ goto overflow;
+
if (num < 0) {
- if (m->count + 3 >= m->size) {
- seq_set_overflow(m);
- return;
- }
- if (delimiter)
- m->buf[m->count++] = delimiter;
+ m->buf[m->count++] = '-';
num = -num;
- delimiter = '-';
}
- seq_put_decimal_ull(m, delimiter, num);
+
+ if (num < 10) {
+ m->buf[m->count++] = num + '0';
+ return;
+ }
+
+ len = num_to_str(m->buf + m->count, m->size - m->count, num);
+ if (!len)
+ goto overflow;
+
+ m->count += len;
+ return;
+
+overflow:
+ seq_set_overflow(m);
}
EXPORT_SYMBOL(seq_put_decimal_ll);
diff --git a/fs/splice.c b/fs/splice.c
index dd9bf7e410d2..153d4f3bd441 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -183,82 +183,39 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
struct splice_pipe_desc *spd)
{
unsigned int spd_pages = spd->nr_pages;
- int ret, do_wakeup, page_nr;
+ int ret = 0, page_nr = 0;
if (!spd_pages)
return 0;
- ret = 0;
- do_wakeup = 0;
- page_nr = 0;
-
- pipe_lock(pipe);
-
- for (;;) {
- if (!pipe->readers) {
- send_sig(SIGPIPE, current, 0);
- if (!ret)
- ret = -EPIPE;
- break;
- }
-
- if (pipe->nrbufs < pipe->buffers) {
- int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
- struct pipe_buffer *buf = pipe->bufs + newbuf;
-
- buf->page = spd->pages[page_nr];
- buf->offset = spd->partial[page_nr].offset;
- buf->len = spd->partial[page_nr].len;
- buf->private = spd->partial[page_nr].private;
- buf->ops = spd->ops;
- if (spd->flags & SPLICE_F_GIFT)
- buf->flags |= PIPE_BUF_FLAG_GIFT;
-
- pipe->nrbufs++;
- page_nr++;
- ret += buf->len;
-
- if (pipe->files)
- do_wakeup = 1;
+ if (unlikely(!pipe->readers)) {
+ send_sig(SIGPIPE, current, 0);
+ ret = -EPIPE;
+ goto out;
+ }
- if (!--spd->nr_pages)
- break;
- if (pipe->nrbufs < pipe->buffers)
- continue;
+ while (pipe->nrbufs < pipe->buffers) {
+ int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
+ struct pipe_buffer *buf = pipe->bufs + newbuf;
- break;
- }
+ buf->page = spd->pages[page_nr];
+ buf->offset = spd->partial[page_nr].offset;
+ buf->len = spd->partial[page_nr].len;
+ buf->private = spd->partial[page_nr].private;
+ buf->ops = spd->ops;
- if (spd->flags & SPLICE_F_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
+ pipe->nrbufs++;
+ page_nr++;
+ ret += buf->len;
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
+ if (!--spd->nr_pages)
break;
- }
-
- if (do_wakeup) {
- smp_mb();
- if (waitqueue_active(&pipe->wait))
- wake_up_interruptible_sync(&pipe->wait);
- kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
- do_wakeup = 0;
- }
-
- pipe->waiting_writers++;
- pipe_wait(pipe);
- pipe->waiting_writers--;
}
- pipe_unlock(pipe);
-
- if (do_wakeup)
- wakeup_pipe_readers(pipe);
+ if (!ret)
+ ret = -EAGAIN;
+out:
while (page_nr < spd_pages)
spd->spd_release(spd, page_nr++);
@@ -266,6 +223,26 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
}
EXPORT_SYMBOL_GPL(splice_to_pipe);
+ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
+{
+ int ret;
+
+ if (unlikely(!pipe->readers)) {
+ send_sig(SIGPIPE, current, 0);
+ ret = -EPIPE;
+ } else if (pipe->nrbufs == pipe->buffers) {
+ ret = -EAGAIN;
+ } else {
+ int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
+ pipe->bufs[newbuf] = *buf;
+ pipe->nrbufs++;
+ return buf->len;
+ }
+ pipe_buf_release(pipe, buf);
+ return ret;
+}
+EXPORT_SYMBOL(add_to_pipe);
+
void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
{
put_page(spd->pages[i]);
@@ -303,207 +280,6 @@ void splice_shrink_spd(struct splice_pipe_desc *spd)
kfree(spd->partial);
}
-static int
-__generic_file_splice_read(struct file *in, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags)
-{
- struct address_space *mapping = in->f_mapping;
- unsigned int loff, nr_pages, req_pages;
- struct page *pages[PIPE_DEF_BUFFERS];
- struct partial_page partial[PIPE_DEF_BUFFERS];
- struct page *page;
- pgoff_t index, end_index;
- loff_t isize;
- int error, page_nr;
- struct splice_pipe_desc spd = {
- .pages = pages,
- .partial = partial,
- .nr_pages_max = PIPE_DEF_BUFFERS,
- .flags = flags,
- .ops = &page_cache_pipe_buf_ops,
- .spd_release = spd_release_page,
- };
-
- if (splice_grow_spd(pipe, &spd))
- return -ENOMEM;
-
- index = *ppos >> PAGE_SHIFT;
- loff = *ppos & ~PAGE_MASK;
- req_pages = (len + loff + PAGE_SIZE - 1) >> PAGE_SHIFT;
- nr_pages = min(req_pages, spd.nr_pages_max);
-
- /*
- * Lookup the (hopefully) full range of pages we need.
- */
- spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, spd.pages);
- index += spd.nr_pages;
-
- /*
- * If find_get_pages_contig() returned fewer pages than we needed,
- * readahead/allocate the rest and fill in the holes.
- */
- if (spd.nr_pages < nr_pages)
- page_cache_sync_readahead(mapping, &in->f_ra, in,
- index, req_pages - spd.nr_pages);
-
- error = 0;
- while (spd.nr_pages < nr_pages) {
- /*
- * Page could be there, find_get_pages_contig() breaks on
- * the first hole.
- */
- page = find_get_page(mapping, index);
- if (!page) {
- /*
- * page didn't exist, allocate one.
- */
- page = page_cache_alloc_cold(mapping);
- if (!page)
- break;
-
- error = add_to_page_cache_lru(page, mapping, index,
- mapping_gfp_constraint(mapping, GFP_KERNEL));
- if (unlikely(error)) {
- put_page(page);
- if (error == -EEXIST)
- continue;
- break;
- }
- /*
- * add_to_page_cache() locks the page, unlock it
- * to avoid convoluting the logic below even more.
- */
- unlock_page(page);
- }
-
- spd.pages[spd.nr_pages++] = page;
- index++;
- }
-
- /*
- * Now loop over the map and see if we need to start IO on any
- * pages, fill in the partial map, etc.
- */
- index = *ppos >> PAGE_SHIFT;
- nr_pages = spd.nr_pages;
- spd.nr_pages = 0;
- for (page_nr = 0; page_nr < nr_pages; page_nr++) {
- unsigned int this_len;
-
- if (!len)
- break;
-
- /*
- * this_len is the max we'll use from this page
- */
- this_len = min_t(unsigned long, len, PAGE_SIZE - loff);
- page = spd.pages[page_nr];
-
- if (PageReadahead(page))
- page_cache_async_readahead(mapping, &in->f_ra, in,
- page, index, req_pages - page_nr);
-
- /*
- * If the page isn't uptodate, we may need to start io on it
- */
- if (!PageUptodate(page)) {
- lock_page(page);
-
- /*
- * Page was truncated, or invalidated by the
- * filesystem. Redo the find/create, but this time the
- * page is kept locked, so there's no chance of another
- * race with truncate/invalidate.
- */
- if (!page->mapping) {
- unlock_page(page);
-retry_lookup:
- page = find_or_create_page(mapping, index,
- mapping_gfp_mask(mapping));
-
- if (!page) {
- error = -ENOMEM;
- break;
- }
- put_page(spd.pages[page_nr]);
- spd.pages[page_nr] = page;
- }
- /*
- * page was already under io and is now done, great
- */
- if (PageUptodate(page)) {
- unlock_page(page);
- goto fill_it;
- }
-
- /*
- * need to read in the page
- */
- error = mapping->a_ops->readpage(in, page);
- if (unlikely(error)) {
- /*
- * Re-lookup the page
- */
- if (error == AOP_TRUNCATED_PAGE)
- goto retry_lookup;
-
- break;
- }
- }
-fill_it:
- /*
- * i_size must be checked after PageUptodate.
- */
- isize = i_size_read(mapping->host);
- end_index = (isize - 1) >> PAGE_SHIFT;
- if (unlikely(!isize || index > end_index))
- break;
-
- /*
- * if this is the last page, see if we need to shrink
- * the length and stop
- */
- if (end_index == index) {
- unsigned int plen;
-
- /*
- * max good bytes in this page
- */
- plen = ((isize - 1) & ~PAGE_MASK) + 1;
- if (plen <= loff)
- break;
-
- /*
- * force quit after adding this page
- */
- this_len = min(this_len, plen - loff);
- len = this_len;
- }
-
- spd.partial[page_nr].offset = loff;
- spd.partial[page_nr].len = this_len;
- len -= this_len;
- loff = 0;
- spd.nr_pages++;
- index++;
- }
-
- /*
- * Release any pages at the end, if we quit early. 'page_nr' is how far
- * we got, 'nr_pages' is how many pages are in the map.
- */
- while (page_nr < nr_pages)
- put_page(spd.pages[page_nr++]);
- in->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT;
-
- if (spd.nr_pages)
- error = splice_to_pipe(pipe, &spd);
-
- splice_shrink_spd(&spd);
- return error;
-}
-
/**
* generic_file_splice_read - splice data from file to a pipe
* @in: file to splice from
@@ -514,39 +290,47 @@ fill_it:
*
* Description:
* Will read pages from given file and fill them into a pipe. Can be
- * used as long as the address_space operations for the source implements
- * a readpage() hook.
+ * used as long as it has more or less sane ->read_iter().
*
*/
ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
- loff_t isize, left;
- int ret;
-
- if (IS_DAX(in->f_mapping->host))
- return default_file_splice_read(in, ppos, pipe, len, flags);
+ struct iov_iter to;
+ struct kiocb kiocb;
+ loff_t isize;
+ int idx, ret;
isize = i_size_read(in->f_mapping->host);
if (unlikely(*ppos >= isize))
return 0;
- left = isize - *ppos;
- if (unlikely(left < len))
- len = left;
-
- ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
+ iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len);
+ idx = to.idx;
+ init_sync_kiocb(&kiocb, in);
+ kiocb.ki_pos = *ppos;
+ ret = in->f_op->read_iter(&kiocb, &to);
if (ret > 0) {
- *ppos += ret;
+ *ppos = kiocb.ki_pos;
file_accessed(in);
+ } else if (ret < 0) {
+ to.idx = idx;
+ to.iov_offset = 0;
+ iov_iter_advance(&to, 0); /* to free what was emitted */
+ /*
+ * callers of ->splice_read() expect -EAGAIN on
+ * "can't put anything in there", rather than -EFAULT.
+ */
+ if (ret == -EFAULT)
+ ret = -EAGAIN;
}
return ret;
}
EXPORT_SYMBOL(generic_file_splice_read);
-static const struct pipe_buf_operations default_pipe_buf_ops = {
+const struct pipe_buf_operations default_pipe_buf_ops = {
.can_merge = 0,
.confirm = generic_pipe_buf_confirm,
.release = generic_pipe_buf_release,
@@ -570,7 +354,7 @@ const struct pipe_buf_operations nosteal_pipe_buf_ops = {
};
EXPORT_SYMBOL(nosteal_pipe_buf_ops);
-static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
+static ssize_t kernel_readv(struct file *file, const struct kvec *vec,
unsigned long vlen, loff_t offset)
{
mm_segment_t old_fs;
@@ -602,102 +386,70 @@ ssize_t kernel_write(struct file *file, const char *buf, size_t count,
}
EXPORT_SYMBOL(kernel_write);
-ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
+static ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
+ struct kvec *vec, __vec[PIPE_DEF_BUFFERS];
+ struct iov_iter to;
+ struct page **pages;
unsigned int nr_pages;
- unsigned int nr_freed;
- size_t offset;
- struct page *pages[PIPE_DEF_BUFFERS];
- struct partial_page partial[PIPE_DEF_BUFFERS];
- struct iovec *vec, __vec[PIPE_DEF_BUFFERS];
+ size_t offset, dummy, copied = 0;
ssize_t res;
- size_t this_len;
- int error;
int i;
- struct splice_pipe_desc spd = {
- .pages = pages,
- .partial = partial,
- .nr_pages_max = PIPE_DEF_BUFFERS,
- .flags = flags,
- .ops = &default_pipe_buf_ops,
- .spd_release = spd_release_page,
- };
- if (splice_grow_spd(pipe, &spd))
+ if (pipe->nrbufs == pipe->buffers)
+ return -EAGAIN;
+
+ /*
+ * Try to keep page boundaries matching to source pagecache ones -
+ * it probably won't be much help, but...
+ */
+ offset = *ppos & ~PAGE_MASK;
+
+ iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len + offset);
+
+ res = iov_iter_get_pages_alloc(&to, &pages, len + offset, &dummy);
+ if (res <= 0)
return -ENOMEM;
- res = -ENOMEM;
+ nr_pages = res / PAGE_SIZE;
+
vec = __vec;
- if (spd.nr_pages_max > PIPE_DEF_BUFFERS) {
- vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL);
- if (!vec)
- goto shrink_ret;
+ if (nr_pages > PIPE_DEF_BUFFERS) {
+ vec = kmalloc(nr_pages * sizeof(struct kvec), GFP_KERNEL);
+ if (unlikely(!vec)) {
+ res = -ENOMEM;
+ goto out;
+ }
}
- offset = *ppos & ~PAGE_MASK;
- nr_pages = (len + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
- for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) {
- struct page *page;
+ pipe->bufs[to.idx].offset = offset;
+ pipe->bufs[to.idx].len -= offset;
- page = alloc_page(GFP_USER);
- error = -ENOMEM;
- if (!page)
- goto err;
-
- this_len = min_t(size_t, len, PAGE_SIZE - offset);
- vec[i].iov_base = (void __user *) page_address(page);
+ for (i = 0; i < nr_pages; i++) {
+ size_t this_len = min_t(size_t, len, PAGE_SIZE - offset);
+ vec[i].iov_base = page_address(pages[i]) + offset;
vec[i].iov_len = this_len;
- spd.pages[i] = page;
- spd.nr_pages++;
len -= this_len;
offset = 0;
}
- res = kernel_readv(in, vec, spd.nr_pages, *ppos);
- if (res < 0) {
- error = res;
- goto err;
- }
-
- error = 0;
- if (!res)
- goto err;
-
- nr_freed = 0;
- for (i = 0; i < spd.nr_pages; i++) {
- this_len = min_t(size_t, vec[i].iov_len, res);
- spd.partial[i].offset = 0;
- spd.partial[i].len = this_len;
- if (!this_len) {
- __free_page(spd.pages[i]);
- spd.pages[i] = NULL;
- nr_freed++;
- }
- res -= this_len;
- }
- spd.nr_pages -= nr_freed;
-
- res = splice_to_pipe(pipe, &spd);
- if (res > 0)
+ res = kernel_readv(in, vec, nr_pages, *ppos);
+ if (res > 0) {
+ copied = res;
*ppos += res;
+ }
-shrink_ret:
if (vec != __vec)
kfree(vec);
- splice_shrink_spd(&spd);
+out:
+ for (i = 0; i < nr_pages; i++)
+ put_page(pages[i]);
+ kvfree(pages);
+ iov_iter_advance(&to, copied); /* truncates and discards */
return res;
-
-err:
- for (i = 0; i < spd.nr_pages; i++)
- __free_page(spd.pages[i]);
-
- res = error;
- goto shrink_ret;
}
-EXPORT_SYMBOL(default_file_splice_read);
/*
* Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
@@ -757,13 +509,12 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
while (pipe->nrbufs) {
struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
- const struct pipe_buf_operations *ops = buf->ops;
sd->len = buf->len;
if (sd->len > sd->total_len)
sd->len = sd->total_len;
- ret = buf->ops->confirm(pipe, buf);
+ ret = pipe_buf_confirm(pipe, buf);
if (unlikely(ret)) {
if (ret == -ENODATA)
ret = 0;
@@ -783,8 +534,7 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
sd->total_len -= ret;
if (!buf->len) {
- buf->ops = NULL;
- ops->release(pipe, buf);
+ pipe_buf_release(pipe, buf);
pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
pipe->nrbufs--;
if (pipe->files)
@@ -1003,7 +753,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
if (idx == pipe->buffers - 1)
idx = -1;
- ret = buf->ops->confirm(pipe, buf);
+ ret = pipe_buf_confirm(pipe, buf);
if (unlikely(ret)) {
if (ret == -ENODATA)
ret = 0;
@@ -1030,11 +780,9 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
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_buf_release(pipe, buf);
pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
pipe->nrbufs--;
if (pipe->files)
@@ -1273,10 +1021,8 @@ out_release:
for (i = 0; i < pipe->buffers; i++) {
struct pipe_buffer *buf = pipe->bufs + i;
- if (buf->ops) {
- buf->ops->release(pipe, buf);
- buf->ops = NULL;
- }
+ if (buf->ops)
+ pipe_buf_release(pipe, buf);
}
if (!bytes)
@@ -1342,6 +1088,20 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
}
EXPORT_SYMBOL(do_splice_direct);
+static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
+{
+ while (pipe->nrbufs == pipe->buffers) {
+ if (flags & SPLICE_F_NONBLOCK)
+ return -EAGAIN;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ pipe->waiting_writers++;
+ pipe_wait(pipe);
+ pipe->waiting_writers--;
+ }
+ return 0;
+}
+
static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
struct pipe_inode_info *opipe,
size_t len, unsigned int flags);
@@ -1424,8 +1184,13 @@ static long do_splice(struct file *in, loff_t __user *off_in,
offset = in->f_pos;
}
- ret = do_splice_to(in, &offset, opipe, len, flags);
-
+ pipe_lock(opipe);
+ ret = wait_for_space(opipe, flags);
+ if (!ret)
+ ret = do_splice_to(in, &offset, opipe, len, flags);
+ pipe_unlock(opipe);
+ if (ret > 0)
+ wakeup_pipe_readers(opipe);
if (!off_in)
in->f_pos = offset;
else if (copy_to_user(off_in, &offset, sizeof(loff_t)))
@@ -1437,106 +1202,50 @@ static long do_splice(struct file *in, loff_t __user *off_in,
return -EINVAL;
}
-/*
- * Map an iov into an array of pages and offset/length tupples. With the
- * partial_page structure, we can map several non-contiguous ranges into
- * our ones pages[] map instead of splitting that operation into pieces.
- * Could easily be exported as a generic helper for other users, in which
- * case one would probably want to add a 'max_nr_pages' parameter as well.
- */
-static int get_iovec_page_array(const struct iovec __user *iov,
- unsigned int nr_vecs, struct page **pages,
- struct partial_page *partial, bool aligned,
- unsigned int pipe_buffers)
+static int iter_to_pipe(struct iov_iter *from,
+ struct pipe_inode_info *pipe,
+ unsigned flags)
{
- int buffers = 0, error = 0;
-
- while (nr_vecs) {
- unsigned long off, npages;
- struct iovec entry;
- void __user *base;
- size_t len;
- int i;
-
- error = -EFAULT;
- if (copy_from_user(&entry, iov, sizeof(entry)))
- break;
-
- base = entry.iov_base;
- len = entry.iov_len;
-
- /*
- * Sanity check this iovec. 0 read succeeds.
- */
- error = 0;
- if (unlikely(!len))
- break;
- error = -EFAULT;
- if (!access_ok(VERIFY_READ, base, len))
- break;
-
- /*
- * Get this base offset and number of pages, then map
- * in the user pages.
- */
- off = (unsigned long) base & ~PAGE_MASK;
-
- /*
- * If asked for alignment, the offset must be zero and the
- * length a multiple of the PAGE_SIZE.
- */
- error = -EINVAL;
- if (aligned && (off || len & ~PAGE_MASK))
- break;
-
- npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
- if (npages > pipe_buffers - buffers)
- npages = pipe_buffers - buffers;
-
- error = get_user_pages_fast((unsigned long)base, npages,
- 0, &pages[buffers]);
-
- if (unlikely(error <= 0))
+ struct pipe_buffer buf = {
+ .ops = &user_page_pipe_buf_ops,
+ .flags = flags
+ };
+ size_t total = 0;
+ int ret = 0;
+ bool failed = false;
+
+ while (iov_iter_count(from) && !failed) {
+ struct page *pages[16];
+ ssize_t copied;
+ size_t start;
+ int n;
+
+ copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start);
+ if (copied <= 0) {
+ ret = copied;
break;
-
- /*
- * Fill this contiguous range into the partial page map.
- */
- for (i = 0; i < error; i++) {
- const int plen = min_t(size_t, len, PAGE_SIZE - off);
-
- partial[buffers].offset = off;
- partial[buffers].len = plen;
-
- off = 0;
- len -= plen;
- buffers++;
}
- /*
- * We didn't complete this iov, stop here since it probably
- * means we have to move some of this into a pipe to
- * be able to continue.
- */
- if (len)
- break;
-
- /*
- * Don't continue if we mapped fewer pages than we asked for,
- * or if we mapped the max number of pages that we have
- * room for.
- */
- if (error < npages || buffers == pipe_buffers)
- break;
-
- nr_vecs--;
- iov++;
+ for (n = 0; copied; n++, start = 0) {
+ int size = min_t(int, copied, PAGE_SIZE - start);
+ if (!failed) {
+ buf.page = pages[n];
+ buf.offset = start;
+ buf.len = size;
+ ret = add_to_pipe(pipe, &buf);
+ if (unlikely(ret < 0)) {
+ failed = true;
+ } else {
+ iov_iter_advance(from, ret);
+ total += ret;
+ }
+ } else {
+ put_page(pages[n]);
+ }
+ copied -= size;
+ }
}
-
- if (buffers)
- return buffers;
-
- return error;
+ return total ? total : ret;
}
static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
@@ -1590,38 +1299,36 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
* as splice-from-memory, where the regular splice is splice-from-file (or
* to file). In both cases the output is a pipe, naturally.
*/
-static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
+static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
unsigned long nr_segs, unsigned int flags)
{
struct pipe_inode_info *pipe;
- struct page *pages[PIPE_DEF_BUFFERS];
- struct partial_page partial[PIPE_DEF_BUFFERS];
- struct splice_pipe_desc spd = {
- .pages = pages,
- .partial = partial,
- .nr_pages_max = PIPE_DEF_BUFFERS,
- .flags = flags,
- .ops = &user_page_pipe_buf_ops,
- .spd_release = spd_release_page,
- };
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov = iovstack;
+ struct iov_iter from;
long ret;
+ unsigned buf_flag = 0;
+
+ if (flags & SPLICE_F_GIFT)
+ buf_flag = PIPE_BUF_FLAG_GIFT;
pipe = get_pipe_info(file);
if (!pipe)
return -EBADF;
- if (splice_grow_spd(pipe, &spd))
- return -ENOMEM;
-
- spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
- spd.partial, false,
- spd.nr_pages_max);
- if (spd.nr_pages <= 0)
- ret = spd.nr_pages;
- else
- ret = splice_to_pipe(pipe, &spd);
+ ret = import_iovec(WRITE, uiov, nr_segs,
+ ARRAY_SIZE(iovstack), &iov, &from);
+ if (ret < 0)
+ return ret;
- splice_shrink_spd(&spd);
+ pipe_lock(pipe);
+ ret = wait_for_space(pipe, flags);
+ if (!ret)
+ ret = iter_to_pipe(&from, pipe, buf_flag);
+ pipe_unlock(pipe);
+ if (ret > 0)
+ wakeup_pipe_readers(pipe);
+ kfree(iov);
return ret;
}
@@ -1876,7 +1583,7 @@ retry:
* Get a reference to this pipe buffer,
* so we can copy the contents over.
*/
- ibuf->ops->get(ipipe, ibuf);
+ pipe_buf_get(ipipe, ibuf);
*obuf = *ibuf;
/*
@@ -1948,7 +1655,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
* Get a reference to this pipe buffer,
* so we can copy the contents over.
*/
- ibuf->ops->get(ipipe, ibuf);
+ pipe_buf_get(ipipe, ibuf);
obuf = opipe->bufs + nbuf;
*obuf = *ibuf;
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index 0927b1e80ab6..e9793b1e49a5 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -425,7 +425,6 @@ failed_read:
const struct inode_operations squashfs_inode_ops = {
- .getxattr = generic_getxattr,
.listxattr = squashfs_listxattr
};
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index 67cad77fefb4..40c10d9974c9 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -247,6 +247,5 @@ failed:
const struct inode_operations squashfs_dir_inode_ops = {
.lookup = squashfs_lookup,
- .getxattr = generic_getxattr,
.listxattr = squashfs_listxattr
};
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
index d688ef42a6a1..79b9c31a0c8f 100644
--- a/fs/squashfs/symlink.c
+++ b/fs/squashfs/symlink.c
@@ -120,7 +120,6 @@ const struct address_space_operations squashfs_symlink_aops = {
const struct inode_operations squashfs_symlink_inode_ops = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .getxattr = generic_getxattr,
.listxattr = squashfs_listxattr
};
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h
index c83f5d9ec125..afe70f815e3d 100644
--- a/fs/squashfs/xattr.h
+++ b/fs/squashfs/xattr.h
@@ -42,6 +42,5 @@ static inline int squashfs_xattr_lookup(struct super_block *sb,
return 0;
}
#define squashfs_listxattr NULL
-#define generic_getxattr NULL
#define squashfs_xattr_handlers NULL
#endif
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 2661b77fc8a7..5bdae85ceef7 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -215,7 +215,7 @@ got_it:
memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
out_page:
dir_put_page(page);
@@ -239,7 +239,7 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
de->inode = 0;
err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
dir_put_page(page);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
return err;
}
@@ -337,7 +337,7 @@ void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
dir_put_page(page);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
}
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 82ddc09061e2..7ba997e31aeb 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -33,7 +33,7 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index f9db4eb31db4..53f1b78996dd 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -164,7 +164,7 @@ struct inode * sysv_new_inode(const struct inode * dir, umode_t mode)
dirty_sb(sb);
inode_init_owner(inode, dir, mode);
inode->i_ino = fs16_to_cpu(sbi, ino);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
inode->i_blocks = 0;
memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
SYSV_I(inode)->i_dir_start_lookup = 0;
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
index 2fde40acf024..08d3e630b49c 100644
--- a/fs/sysv/itree.c
+++ b/fs/sysv/itree.c
@@ -178,7 +178,7 @@ static inline int splice_branch(struct inode *inode,
*where->p = where->key;
write_unlock(&pointers_lock);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
/* had we spliced it onto indirect block? */
if (where->bh)
@@ -418,7 +418,7 @@ do_indirects:
}
n++;
}
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
if (IS_SYNC(inode))
sysv_sync_inode (inode);
else
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index a42de45ce40d..d8817f139763 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -120,7 +120,7 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir,
{
struct inode *inode = d_inode(old_dentry);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
inode_inc_link_count(inode);
ihold(inode);
@@ -206,7 +206,8 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
* higher-level routines.
*/
static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry)
+ struct inode * new_dir, struct dentry * new_dentry,
+ unsigned int flags)
{
struct inode * old_inode = d_inode(old_dentry);
struct inode * new_inode = d_inode(new_dentry);
@@ -216,6 +217,9 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
struct sysv_dir_entry * old_de;
int err = -ENOENT;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
old_de = sysv_find_entry(old_dentry, &old_page);
if (!old_de)
goto out;
@@ -240,7 +244,7 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
if (!new_de)
goto out_dir;
sysv_set_link(new_de, new_page, old_inode);
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = current_time(new_inode);
if (dir_de)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index ad40b64c5e2f..21d36d284735 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -133,7 +133,7 @@ static struct inode *tracefs_get_inode(struct super_block *sb)
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_ino = get_next_ino();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
}
return inode;
}
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 4b86d3a738e1..64902702b17d 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -966,7 +966,8 @@ static void unlock_3_inodes(struct inode *inode1, struct inode *inode2,
}
static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct ubifs_info *c = old_dir->i_sb->s_fs_info;
struct inode *old_inode = d_inode(old_dentry);
@@ -984,6 +985,9 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct timespec time;
unsigned int uninitialized_var(saved_nlink);
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
/*
* Budget request settings: deletion direntry, new direntry, removing
* the old inode, and changing old and new parent directory inodes.
@@ -1179,13 +1183,10 @@ const struct inode_operations ubifs_dir_inode_operations = {
.mkdir = ubifs_mkdir,
.rmdir = ubifs_rmdir,
.mknod = ubifs_mknod,
- .rename = ubifs_rename,
+ .rename = ubifs_rename,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ubifs_listxattr,
- .removexattr = generic_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time,
#endif
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 7bbf420d1289..a746982fbcda 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1262,7 +1262,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
dbg_gen("ino %lu, mode %#x, ia_valid %#x",
inode->i_ino, inode->i_mode, attr->ia_valid);
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
@@ -1621,10 +1621,7 @@ const struct address_space_operations ubifs_file_address_operations = {
const struct inode_operations ubifs_file_inode_operations = {
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ubifs_listxattr,
- .removexattr = generic_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time,
#endif
@@ -1635,10 +1632,7 @@ const struct inode_operations ubifs_symlink_inode_operations = {
.get_link = simple_get_link,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = ubifs_listxattr,
- .removexattr = generic_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time,
#endif
diff --git a/fs/udf/file.c b/fs/udf/file.c
index e855bf8d74b4..dbcb3a4a0cb9 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -261,7 +261,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index e77db621ec89..c1ed18a10ce4 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -121,7 +121,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode)
else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
inode->i_mtime = inode->i_atime = inode->i_ctime =
- iinfo->i_crtime = current_fs_time(inode->i_sb);
+ iinfo->i_crtime = current_time(inode);
if (unlikely(insert_inode_locked(inode) < 0)) {
make_bad_inode(inode);
iput(inode);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 55aa587bbc38..aad46401ede5 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -886,7 +886,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
*new = 1;
iinfo->i_next_alloc_block = block;
iinfo->i_next_alloc_goal = newblocknum;
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
if (IS_SYNC(inode))
udf_sync_inode(inode);
@@ -1268,7 +1268,7 @@ set_size:
up_write(&iinfo->i_data_sem);
}
update_time:
- inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_mtime = inode->i_ctime = current_time(inode);
if (IS_SYNC(inode))
udf_sync_inode(inode);
else
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index c3e5c9679371..2d65e280748b 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -616,7 +616,7 @@ static int udf_add_nondir(struct dentry *dentry, struct inode *inode)
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
@@ -730,7 +730,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
inc_nlink(dir);
- dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
unlock_new_inode(inode);
d_instantiate(dentry, inode);
@@ -845,7 +845,7 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
inode->i_size = 0;
inode_dec_link_count(dir);
inode->i_ctime = dir->i_ctime = dir->i_mtime =
- current_fs_time(dir->i_sb);
+ current_time(inode);
mark_inode_dirty(dir);
end_rmdir:
@@ -888,7 +888,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
retval = udf_delete_entry(dir, fi, &fibh, &cfi);
if (retval)
goto end_unlink;
- dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
inode_dec_link_count(inode);
inode->i_ctime = dir->i_ctime;
@@ -1079,9 +1079,9 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
brelse(fibh.ebh);
brelse(fibh.sbh);
inc_nlink(inode);
- inode->i_ctime = current_fs_time(inode->i_sb);
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
- dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ dir->i_ctime = dir->i_mtime = current_time(dir);
mark_inode_dirty(dir);
ihold(inode);
d_instantiate(dentry, inode);
@@ -1093,7 +1093,8 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
* higher-level routines.
*/
static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
@@ -1105,6 +1106,9 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
struct kernel_lb_addr tloc;
struct udf_inode_info *old_iinfo = UDF_I(old_inode);
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
if (IS_ERR(ofi)) {
retval = PTR_ERR(ofi);
@@ -1172,7 +1176,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
* Like most other Unix systems, set the ctime for inodes on a
* rename.
*/
- old_inode->i_ctime = current_fs_time(old_inode->i_sb);
+ old_inode->i_ctime = current_time(old_inode);
mark_inode_dirty(old_inode);
/*
@@ -1188,11 +1192,11 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
if (new_inode) {
- new_inode->i_ctime = current_fs_time(new_inode->i_sb);
+ new_inode->i_ctime = current_time(new_inode);
inode_dec_link_count(new_inode);
}
- old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
- new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb);
+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
+ new_dir->i_ctime = new_dir->i_mtime = current_time(new_dir);
mark_inode_dirty(old_dir);
mark_inode_dirty(new_dir);
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index fa3bda1a860f..de01b8f2aa78 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -100,7 +100,7 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
err = ufs_commit_chunk(page, pos, len);
ufs_put_page(page);
if (update_times)
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
}
@@ -389,7 +389,7 @@ got_it:
ufs_set_de_type(sb, de, inode->i_mode);
err = ufs_commit_chunk(page, pos, rec_len);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = current_time(dir);
mark_inode_dirty(dir);
/* OFFSET_CACHE */
@@ -530,7 +530,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
pde->d_reclen = cpu_to_fs16(sb, to - from);
dir->d_ino = 0;
err = ufs_commit_chunk(page, pos, to - from);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
out:
ufs_put_page(page);
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index fd0203ce1f7f..9774555b3721 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -290,7 +290,7 @@ cg_found:
inode_init_owner(inode, dir, mode);
inode->i_blocks = 0;
inode->i_generation = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
ufsi->i_flags = UFS_I(dir)->i_flags;
ufsi->i_lastfrag = 0;
ufsi->i_shadow = 0;
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 9f49431e798d..190d64be22ed 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -293,7 +293,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index,
if (new)
*new = 1;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
if (IS_SYNC(inode))
ufs_sync_inode (inode);
mark_inode_dirty(inode);
@@ -375,7 +375,7 @@ ufs_inode_getblock(struct inode *inode, u64 ind_block,
mark_buffer_dirty(bh);
if (IS_SYNC(inode))
sync_dirty_buffer(bh);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
out:
brelse (bh);
@@ -1185,7 +1185,7 @@ static int ufs_truncate(struct inode *inode, loff_t size)
truncate_setsize(inode, size);
__ufs_truncate_blocks(inode);
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = current_time(inode);
mark_inode_dirty(inode);
out:
UFSD("EXIT: err %d\n", err);
@@ -1208,7 +1208,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid = attr->ia_valid;
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index a1559f762805..8eca4eda8450 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -153,7 +153,7 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
struct inode *inode = d_inode(old_dentry);
int error;
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = current_time(inode);
inode_inc_link_count(inode);
ihold(inode);
@@ -245,7 +245,8 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
}
static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
{
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
@@ -255,6 +256,9 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct ufs_dir_entry *old_de;
int err = -ENOENT;
+ if (flags & ~RENAME_NOREPLACE)
+ return -EINVAL;
+
old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_de)
goto out;
@@ -279,7 +283,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!new_de)
goto out_dir;
ufs_set_link(new_dir, new_de, new_page, old_inode, 1);
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = current_time(new_inode);
if (dir_de)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
@@ -295,7 +299,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
* Like most other Unix systems, set the ctime for inodes on a
* rename.
*/
- old_inode->i_ctime = CURRENT_TIME_SEC;
+ old_inode->i_ctime = current_time(old_inode);
ufs_delete_entry(old_dir, old_de, old_page);
mark_inode_dirty(old_inode);
diff --git a/fs/utimes.c b/fs/utimes.c
index 794f5f5b1fb5..22307cdf7014 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -81,27 +81,13 @@ static int utimes_common(struct path *path, struct timespec *times)
newattrs.ia_valid |= ATTR_MTIME_SET;
}
/*
- * Tell inode_change_ok(), that this is an explicit time
+ * Tell setattr_prepare(), that this is an explicit time
* update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
* were used.
*/
newattrs.ia_valid |= ATTR_TIMES_SET;
} else {
- /*
- * If times is NULL (or both times are UTIME_NOW),
- * then we need to check permissions, because
- * inode_change_ok() won't do it.
- */
- error = -EPERM;
- if (IS_IMMUTABLE(inode))
- goto mnt_drop_write_and_out;
-
- error = -EACCES;
- if (!inode_owner_or_capable(inode)) {
- error = inode_permission(inode, MAY_WRITE);
- if (error)
- goto mnt_drop_write_and_out;
- }
+ newattrs.ia_valid |= ATTR_TOUCH;
}
retry_deleg:
inode_lock(inode);
@@ -113,7 +99,6 @@ retry_deleg:
goto retry_deleg;
}
-mnt_drop_write_and_out:
mnt_drop_write(path->mnt);
out:
return error;
diff --git a/fs/xattr.c b/fs/xattr.c
index c243905835ab..3368659c471e 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -24,6 +24,59 @@
#include <asm/uaccess.h>
+static const char *
+strcmp_prefix(const char *a, const char *a_prefix)
+{
+ while (*a_prefix && *a == *a_prefix) {
+ a++;
+ a_prefix++;
+ }
+ return *a_prefix ? NULL : a;
+}
+
+/*
+ * In order to implement different sets of xattr operations for each xattr
+ * prefix, a filesystem should create a null-terminated array of struct
+ * xattr_handler (one for each prefix) and hang a pointer to it off of the
+ * s_xattr field of the superblock.
+ */
+#define for_each_xattr_handler(handlers, handler) \
+ if (handlers) \
+ for ((handler) = *(handlers)++; \
+ (handler) != NULL; \
+ (handler) = *(handlers)++)
+
+/*
+ * Find the xattr_handler with the matching prefix.
+ */
+static const struct xattr_handler *
+xattr_resolve_name(struct inode *inode, const char **name)
+{
+ const struct xattr_handler **handlers = inode->i_sb->s_xattr;
+ const struct xattr_handler *handler;
+
+ if (!(inode->i_opflags & IOP_XATTR)) {
+ if (unlikely(is_bad_inode(inode)))
+ return ERR_PTR(-EIO);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ for_each_xattr_handler(handlers, handler) {
+ const char *n;
+
+ n = strcmp_prefix(*name, xattr_prefix(handler));
+ if (n) {
+ if (!handler->prefix ^ !*n) {
+ if (*n)
+ continue;
+ return ERR_PTR(-EINVAL);
+ }
+ *name = n;
+ return handler;
+ }
+ }
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
/*
* Check permissions for extended attribute access. This is a bit complicated
* because different namespaces have very different rules.
@@ -80,6 +133,23 @@ xattr_permission(struct inode *inode, const char *name, int mask)
return inode_permission(inode, mask);
}
+int
+__vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ const struct xattr_handler *handler;
+
+ handler = xattr_resolve_name(inode, &name);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ if (!handler->set)
+ return -EOPNOTSUPP;
+ if (size == 0)
+ value = ""; /* empty EA, do not remove */
+ return handler->set(handler, dentry, inode, name, value, size, flags);
+}
+EXPORT_SYMBOL(__vfs_setxattr);
+
/**
* __vfs_setxattr_noperm - perform setxattr operation without performing
* permission checks.
@@ -106,8 +176,8 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
if (issec)
inode->i_flags &= ~S_NOSEC;
- if (inode->i_op->setxattr) {
- error = inode->i_op->setxattr(dentry, inode, name, value, size, flags);
+ if (inode->i_opflags & IOP_XATTR) {
+ error = __vfs_setxattr(dentry, inode, name, value, size, flags);
if (!error) {
fsnotify_xattr(dentry);
security_inode_post_setxattr(dentry, name, value,
@@ -115,6 +185,9 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
}
} else if (issec) {
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
+
+ if (unlikely(is_bad_inode(inode)))
+ return -EIO;
error = security_inode_setsecurity(inode, suffix, value,
size, flags);
if (!error)
@@ -188,6 +261,7 @@ ssize_t
vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
size_t xattr_size, gfp_t flags)
{
+ const struct xattr_handler *handler;
struct inode *inode = dentry->d_inode;
char *value = *xattr_value;
int error;
@@ -196,10 +270,12 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
if (error)
return error;
- if (!inode->i_op->getxattr)
+ handler = xattr_resolve_name(inode, &name);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ if (!handler->get)
return -EOPNOTSUPP;
-
- error = inode->i_op->getxattr(dentry, inode, name, NULL, 0);
+ error = handler->get(handler, dentry, inode, name, NULL, 0);
if (error < 0)
return error;
@@ -210,12 +286,27 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
memset(value, 0, error + 1);
}
- error = inode->i_op->getxattr(dentry, inode, name, value, error);
+ error = handler->get(handler, dentry, inode, name, value, error);
*xattr_value = value;
return error;
}
ssize_t
+__vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
+ void *value, size_t size)
+{
+ const struct xattr_handler *handler;
+
+ handler = xattr_resolve_name(inode, &name);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ if (!handler->get)
+ return -EOPNOTSUPP;
+ return handler->get(handler, dentry, inode, name, value, size);
+}
+EXPORT_SYMBOL(__vfs_getxattr);
+
+ssize_t
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
@@ -242,28 +333,24 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
return ret;
}
nolsm:
- if (inode->i_op->getxattr)
- error = inode->i_op->getxattr(dentry, inode, name, value, size);
- else
- error = -EOPNOTSUPP;
-
- return error;
+ return __vfs_getxattr(dentry, inode, name, value, size);
}
EXPORT_SYMBOL_GPL(vfs_getxattr);
ssize_t
-vfs_listxattr(struct dentry *d, char *list, size_t size)
+vfs_listxattr(struct dentry *dentry, char *list, size_t size)
{
+ struct inode *inode = d_inode(dentry);
ssize_t error;
- error = security_inode_listxattr(d);
+ error = security_inode_listxattr(dentry);
if (error)
return error;
- error = -EOPNOTSUPP;
- if (d->d_inode->i_op->listxattr) {
- error = d->d_inode->i_op->listxattr(d, list, size);
+ if (inode->i_op->listxattr && (inode->i_opflags & IOP_XATTR)) {
+ error = -EOPNOTSUPP;
+ error = inode->i_op->listxattr(dentry, list, size);
} else {
- error = security_inode_listsecurity(d->d_inode, list, size);
+ error = security_inode_listsecurity(inode, list, size);
if (size && error > size)
error = -ERANGE;
}
@@ -272,14 +359,26 @@ vfs_listxattr(struct dentry *d, char *list, size_t size)
EXPORT_SYMBOL_GPL(vfs_listxattr);
int
+__vfs_removexattr(struct dentry *dentry, const char *name)
+{
+ struct inode *inode = d_inode(dentry);
+ const struct xattr_handler *handler;
+
+ handler = xattr_resolve_name(inode, &name);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ if (!handler->set)
+ return -EOPNOTSUPP;
+ return handler->set(handler, dentry, inode, name, NULL, 0, XATTR_REPLACE);
+}
+EXPORT_SYMBOL(__vfs_removexattr);
+
+int
vfs_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
int error;
- if (!inode->i_op->removexattr)
- return -EOPNOTSUPP;
-
error = xattr_permission(inode, name, MAY_WRITE);
if (error)
return error;
@@ -289,7 +388,7 @@ vfs_removexattr(struct dentry *dentry, const char *name)
if (error)
goto out;
- error = inode->i_op->removexattr(dentry, name);
+ error = __vfs_removexattr(dentry, name);
if (!error) {
fsnotify_xattr(dentry);
@@ -641,76 +740,6 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
return error;
}
-
-static const char *
-strcmp_prefix(const char *a, const char *a_prefix)
-{
- while (*a_prefix && *a == *a_prefix) {
- a++;
- a_prefix++;
- }
- return *a_prefix ? NULL : a;
-}
-
-/*
- * In order to implement different sets of xattr operations for each xattr
- * prefix with the generic xattr API, a filesystem should create a
- * null-terminated array of struct xattr_handler (one for each prefix) and
- * hang a pointer to it off of the s_xattr field of the superblock.
- *
- * The generic_fooxattr() functions will use this list to dispatch xattr
- * operations to the correct xattr_handler.
- */
-#define for_each_xattr_handler(handlers, handler) \
- if (handlers) \
- for ((handler) = *(handlers)++; \
- (handler) != NULL; \
- (handler) = *(handlers)++)
-
-/*
- * Find the xattr_handler with the matching prefix.
- */
-static const struct xattr_handler *
-xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
-{
- const struct xattr_handler *handler;
-
- if (!*name)
- return ERR_PTR(-EINVAL);
-
- for_each_xattr_handler(handlers, handler) {
- const char *n;
-
- n = strcmp_prefix(*name, xattr_prefix(handler));
- if (n) {
- if (!handler->prefix ^ !*n) {
- if (*n)
- continue;
- return ERR_PTR(-EINVAL);
- }
- *name = n;
- return handler;
- }
- }
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-/*
- * Find the handler for the prefix and dispatch its get() operation.
- */
-ssize_t
-generic_getxattr(struct dentry *dentry, struct inode *inode,
- const char *name, void *buffer, size_t size)
-{
- const struct xattr_handler *handler;
-
- handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
- if (IS_ERR(handler))
- return PTR_ERR(handler);
- return handler->get(handler, dentry, inode,
- name, buffer, size);
-}
-
/*
* Combine the results of the list() operation from every xattr_handler in the
* list.
@@ -747,44 +776,7 @@ generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
}
return size;
}
-
-/*
- * Find the handler for the prefix and dispatch its set() operation.
- */
-int
-generic_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
- const void *value, size_t size, int flags)
-{
- const struct xattr_handler *handler;
-
- if (size == 0)
- value = ""; /* empty EA, do not remove */
- handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
- if (IS_ERR(handler))
- return PTR_ERR(handler);
- return handler->set(handler, dentry, inode, name, value, size, flags);
-}
-
-/*
- * Find the handler for the prefix and dispatch its set() operation to remove
- * any associated extended attribute.
- */
-int
-generic_removexattr(struct dentry *dentry, const char *name)
-{
- const struct xattr_handler *handler;
-
- handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
- if (IS_ERR(handler))
- return PTR_ERR(handler);
- return handler->set(handler, dentry, d_inode(dentry), name, NULL,
- 0, XATTR_REPLACE);
-}
-
-EXPORT_SYMBOL(generic_getxattr);
EXPORT_SYMBOL(generic_listxattr);
-EXPORT_SYMBOL(generic_setxattr);
-EXPORT_SYMBOL(generic_removexattr);
/**
* xattr_full_name - Compute full attribute name from suffix
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index b6e527b8eccb..b468e041f207 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -236,7 +236,7 @@ xfs_set_mode(struct inode *inode, umode_t mode)
iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
iattr.ia_mode = mode;
- iattr.ia_ctime = current_fs_time(inode->i_sb);
+ iattr.ia_ctime = current_time(inode);
error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
}
@@ -257,16 +257,11 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return error;
if (type == ACL_TYPE_ACCESS) {
- umode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode(acl, &mode);
-
- if (error <= 0) {
- acl = NULL;
-
- if (error < 0)
- return error;
- }
+ umode_t mode;
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error)
+ return error;
error = xfs_set_mode(inode, mode);
if (error)
return error;
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index c68517b0f248..2bc58b3fd37d 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -319,7 +319,7 @@ xfs_file_dio_aio_read(
data = *to;
ret = __blockdev_direct_IO(iocb, inode, target->bt_bdev, &data,
xfs_get_blocks_direct, NULL, NULL, 0);
- if (ret > 0) {
+ if (ret >= 0) {
iocb->ki_pos += ret;
iov_iter_advance(to, ret);
}
@@ -393,45 +393,6 @@ xfs_file_read_iter(
return ret;
}
-STATIC ssize_t
-xfs_file_splice_read(
- struct file *infilp,
- loff_t *ppos,
- struct pipe_inode_info *pipe,
- size_t count,
- unsigned int flags)
-{
- struct xfs_inode *ip = XFS_I(infilp->f_mapping->host);
- ssize_t ret;
-
- XFS_STATS_INC(ip->i_mount, xs_read_calls);
-
- if (XFS_FORCED_SHUTDOWN(ip->i_mount))
- return -EIO;
-
- trace_xfs_file_splice_read(ip, count, *ppos);
-
- /*
- * DAX inodes cannot ues the page cache for splice, so we have to push
- * them through the VFS IO path. This means it goes through
- * ->read_iter, which for us takes the XFS_IOLOCK_SHARED. Hence we
- * cannot lock the splice operation at this level for DAX inodes.
- */
- if (IS_DAX(VFS_I(ip))) {
- ret = default_file_splice_read(infilp, ppos, pipe, count,
- flags);
- goto out;
- }
-
- xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
- ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
- xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
-out:
- if (ret > 0)
- XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
- return ret;
-}
-
/*
* Zero any on disk space between the current EOF and the new, larger EOF.
*
@@ -940,7 +901,7 @@ xfs_file_fallocate(
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = new_size;
- error = xfs_setattr_size(ip, &iattr);
+ error = xfs_vn_setattr_size(file_dentry(file), &iattr);
if (error)
goto out_unlock;
}
@@ -1608,7 +1569,7 @@ const struct file_operations xfs_file_operations = {
.llseek = xfs_file_llseek,
.read_iter = xfs_file_read_iter,
.write_iter = xfs_file_write_iter,
- .splice_read = xfs_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = xfs_file_ioctl,
#ifdef CONFIG_COMPAT
@@ -1618,6 +1579,7 @@ const struct file_operations xfs_file_operations = {
.open = xfs_file_open,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
+ .get_unmapped_area = thp_get_unmapped_area,
.fallocate = xfs_file_fallocate,
};
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index e08eaea6327b..624e1dfa716b 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -821,7 +821,7 @@ xfs_ialloc(
ip->i_d.di_nextents = 0;
ASSERT(ip->i_d.di_nblocks == 0);
- tv = current_fs_time(mp->m_super);
+ tv = current_time(inode);
inode->i_mtime = tv;
inode->i_atime = tv;
inode->i_ctime = tv;
@@ -1710,7 +1710,7 @@ xfs_inactive_truncate(
/*
* Log the inode size first to prevent stale data exposure in the event
* of a system crash before the truncate completes. See the related
- * comment in xfs_setattr_size() for details.
+ * comment in xfs_vn_setattr_size() for details.
*/
ip->i_d.di_size = 0;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 96a70fd1f5d6..0d9021f0551e 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -720,7 +720,7 @@ xfs_ioc_space(
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = bf->l_start;
- error = xfs_setattr_size(ip, &iattr);
+ error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
break;
default:
ASSERT(0);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index b24c3102fa93..c5da95eb79b8 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -542,6 +542,28 @@ xfs_setattr_time(
inode->i_mtime = iattr->ia_mtime;
}
+static int
+xfs_vn_change_ok(
+ struct dentry *dentry,
+ struct iattr *iattr)
+{
+ struct xfs_mount *mp = XFS_I(d_inode(dentry))->i_mount;
+
+ if (mp->m_flags & XFS_MOUNT_RDONLY)
+ return -EROFS;
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -EIO;
+
+ return setattr_prepare(dentry, iattr);
+}
+
+/*
+ * Set non-size attributes of an inode.
+ *
+ * Caution: The caller of this function is responsible for calling
+ * setattr_prepare() or otherwise verifying the change is fine.
+ */
int
xfs_setattr_nonsize(
struct xfs_inode *ip,
@@ -558,21 +580,6 @@ xfs_setattr_nonsize(
struct xfs_dquot *udqp = NULL, *gdqp = NULL;
struct xfs_dquot *olddquot1 = NULL, *olddquot2 = NULL;
- trace_xfs_setattr(ip);
-
- /* If acls are being inherited, we already have this checked */
- if (!(flags & XFS_ATTR_NOACL)) {
- if (mp->m_flags & XFS_MOUNT_RDONLY)
- return -EROFS;
-
- if (XFS_FORCED_SHUTDOWN(mp))
- return -EIO;
-
- error = inode_change_ok(inode, iattr);
- if (error)
- return error;
- }
-
ASSERT((mask & ATTR_SIZE) == 0);
/*
@@ -743,8 +750,27 @@ out_dqrele:
return error;
}
+int
+xfs_vn_setattr_nonsize(
+ struct dentry *dentry,
+ struct iattr *iattr)
+{
+ struct xfs_inode *ip = XFS_I(d_inode(dentry));
+ int error;
+
+ trace_xfs_setattr(ip);
+
+ error = xfs_vn_change_ok(dentry, iattr);
+ if (error)
+ return error;
+ return xfs_setattr_nonsize(ip, iattr, 0);
+}
+
/*
* Truncate file. Must have write permission and not be a directory.
+ *
+ * Caution: The caller of this function is responsible for calling
+ * setattr_prepare() or otherwise verifying the change is fine.
*/
int
xfs_setattr_size(
@@ -759,18 +785,6 @@ xfs_setattr_size(
uint lock_flags = 0;
bool did_zeroing = false;
- trace_xfs_setattr(ip);
-
- if (mp->m_flags & XFS_MOUNT_RDONLY)
- return -EROFS;
-
- if (XFS_FORCED_SHUTDOWN(mp))
- return -EIO;
-
- error = inode_change_ok(inode, iattr);
- if (error)
- return error;
-
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
ASSERT(S_ISREG(inode->i_mode));
@@ -882,7 +896,7 @@ xfs_setattr_size(
if (newsize != oldsize &&
!(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
iattr->ia_ctime = iattr->ia_mtime =
- current_fs_time(inode->i_sb);
+ current_time(inode);
iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
}
@@ -942,16 +956,32 @@ out_trans_cancel:
goto out_unlock;
}
+int
+xfs_vn_setattr_size(
+ struct dentry *dentry,
+ struct iattr *iattr)
+{
+ struct xfs_inode *ip = XFS_I(d_inode(dentry));
+ int error;
+
+ trace_xfs_setattr(ip);
+
+ error = xfs_vn_change_ok(dentry, iattr);
+ if (error)
+ return error;
+ return xfs_setattr_size(ip, iattr);
+}
+
STATIC int
xfs_vn_setattr(
struct dentry *dentry,
struct iattr *iattr)
{
- struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error;
if (iattr->ia_valid & ATTR_SIZE) {
- uint iolock = XFS_IOLOCK_EXCL;
+ struct xfs_inode *ip = XFS_I(d_inode(dentry));
+ uint iolock = XFS_IOLOCK_EXCL;
xfs_ilock(ip, iolock);
error = xfs_break_layouts(d_inode(dentry), &iolock, true);
@@ -959,11 +989,11 @@ xfs_vn_setattr(
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
iolock |= XFS_MMAPLOCK_EXCL;
- error = xfs_setattr_size(ip, iattr);
+ error = xfs_vn_setattr_size(dentry, iattr);
}
xfs_iunlock(ip, iolock);
} else {
- error = xfs_setattr_nonsize(ip, iattr, 0);
+ error = xfs_vn_setattr_nonsize(dentry, iattr);
}
return error;
@@ -1036,9 +1066,6 @@ static const struct inode_operations xfs_inode_operations = {
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.fiemap = xfs_vn_fiemap,
.update_time = xfs_vn_update_time,
@@ -1059,14 +1086,11 @@ static const struct inode_operations xfs_dir_inode_operations = {
*/
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
- .rename2 = xfs_vn_rename,
+ .rename = xfs_vn_rename,
.get_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
.tmpfile = xfs_vn_tmpfile,
@@ -1087,14 +1111,11 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
*/
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
- .rename2 = xfs_vn_rename,
+ .rename = xfs_vn_rename,
.get_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
.tmpfile = xfs_vn_tmpfile,
@@ -1105,9 +1126,6 @@ static const struct inode_operations xfs_symlink_inode_operations = {
.get_link = xfs_vn_get_link,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
};
@@ -1117,9 +1135,6 @@ static const struct inode_operations xfs_inline_symlink_inode_operations = {
.get_link = xfs_vn_get_link_inline,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
- .removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
};
diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h
index a0f84abb0d09..0259a383721a 100644
--- a/fs/xfs/xfs_iops.h
+++ b/fs/xfs/xfs_iops.h
@@ -33,6 +33,7 @@ extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr);
extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
int flags);
-extern int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap);
+extern int xfs_vn_setattr_nonsize(struct dentry *dentry, struct iattr *vap);
+extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap);
#endif /* __XFS_IOPS_H__ */
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index c6b2b1dcde75..16093c7dacde 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1170,7 +1170,6 @@ DEFINE_RW_EVENT(xfs_file_dax_read);
DEFINE_RW_EVENT(xfs_file_buffered_write);
DEFINE_RW_EVENT(xfs_file_direct_write);
DEFINE_RW_EVENT(xfs_file_dax_write);
-DEFINE_RW_EVENT(xfs_file_splice_read);
DECLARE_EVENT_CLASS(xfs_page_class,
TP_PROTO(struct inode *inode, struct page *page, unsigned long off,
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index 11a3af08b5c7..dab8daa676f9 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -73,7 +73,7 @@ xfs_trans_ichgtime(
ASSERT(tp);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
- tv = current_fs_time(inode->i_sb);
+ tv = current_time(inode);
if (flags & XFS_ICHGTIME_MOD)
inode->i_mtime = tv;
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index d4458b6dbfb4..c4f8fd2fd384 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -800,6 +800,9 @@ static inline int pmd_clear_huge(pmd_t *pmd)
#endif
#endif
+struct file;
+int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t *vma_prot);
#endif /* !__ASSEMBLY__ */
#ifndef io_remap_pfn_range
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 24563970ff7b..3e42bcdd014b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -454,6 +454,12 @@
*(.spinlock.text) \
VMLINUX_SYMBOL(__lock_text_end) = .;
+#define CPUIDLE_TEXT \
+ ALIGN_FUNCTION(); \
+ VMLINUX_SYMBOL(__cpuidle_text_start) = .; \
+ *(.cpuidle.text) \
+ VMLINUX_SYMBOL(__cpuidle_text_end) = .;
+
#define KPROBES_TEXT \
ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__kprobes_text_start) = .; \
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 8637cdfe382a..404e9558e879 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -15,7 +15,6 @@
#include <linux/crypto.h>
#include <linux/list.h>
#include <linux/kernel.h>
-#include <linux/kthread.h>
#include <linux/skbuff.h>
struct crypto_aead;
@@ -129,75 +128,6 @@ struct ablkcipher_walk {
unsigned int blocksize;
};
-#define ENGINE_NAME_LEN 30
-/*
- * struct crypto_engine - crypto hardware engine
- * @name: the engine name
- * @idling: the engine is entering idle state
- * @busy: request pump is busy
- * @running: the engine is on working
- * @cur_req_prepared: current request is prepared
- * @list: link with the global crypto engine list
- * @queue_lock: spinlock to syncronise access to request queue
- * @queue: the crypto queue of the engine
- * @rt: whether this queue is set to run as a realtime task
- * @prepare_crypt_hardware: a request will soon arrive from the queue
- * so the subsystem requests the driver to prepare the hardware
- * by issuing this call
- * @unprepare_crypt_hardware: there are currently no more requests on the
- * queue so the subsystem notifies the driver that it may relax the
- * hardware by issuing this call
- * @prepare_request: do some prepare if need before handle the current request
- * @unprepare_request: undo any work done by prepare_message()
- * @crypt_one_request: do encryption for current request
- * @kworker: thread struct for request pump
- * @kworker_task: pointer to task for request pump kworker thread
- * @pump_requests: work struct for scheduling work to the request pump
- * @priv_data: the engine private data
- * @cur_req: the current request which is on processing
- */
-struct crypto_engine {
- char name[ENGINE_NAME_LEN];
- bool idling;
- bool busy;
- bool running;
- bool cur_req_prepared;
-
- struct list_head list;
- spinlock_t queue_lock;
- struct crypto_queue queue;
-
- bool rt;
-
- int (*prepare_crypt_hardware)(struct crypto_engine *engine);
- int (*unprepare_crypt_hardware)(struct crypto_engine *engine);
-
- int (*prepare_request)(struct crypto_engine *engine,
- struct ablkcipher_request *req);
- int (*unprepare_request)(struct crypto_engine *engine,
- struct ablkcipher_request *req);
- int (*crypt_one_request)(struct crypto_engine *engine,
- struct ablkcipher_request *req);
-
- struct kthread_worker kworker;
- struct task_struct *kworker_task;
- struct kthread_work pump_requests;
-
- void *priv_data;
- struct ablkcipher_request *cur_req;
-};
-
-int crypto_transfer_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, bool need_pump);
-int crypto_transfer_request_to_engine(struct crypto_engine *engine,
- struct ablkcipher_request *req);
-void crypto_finalize_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, int err);
-int crypto_engine_start(struct crypto_engine *engine);
-int crypto_engine_stop(struct crypto_engine *engine);
-struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt);
-int crypto_engine_exit(struct crypto_engine *engine);
-
extern const struct crypto_type crypto_ablkcipher_type;
extern const struct crypto_type crypto_blkcipher_type;
diff --git a/include/crypto/engine.h b/include/crypto/engine.h
new file mode 100644
index 000000000000..04eb5c77addd
--- /dev/null
+++ b/include/crypto/engine.h
@@ -0,0 +1,107 @@
+/*
+ * Crypto engine API
+ *
+ * Copyright (c) 2016 Baolin Wang <baolin.wang@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#ifndef _CRYPTO_ENGINE_H
+#define _CRYPTO_ENGINE_H
+
+#include <linux/crypto.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+
+#define ENGINE_NAME_LEN 30
+/*
+ * struct crypto_engine - crypto hardware engine
+ * @name: the engine name
+ * @idling: the engine is entering idle state
+ * @busy: request pump is busy
+ * @running: the engine is on working
+ * @cur_req_prepared: current request is prepared
+ * @list: link with the global crypto engine list
+ * @queue_lock: spinlock to syncronise access to request queue
+ * @queue: the crypto queue of the engine
+ * @rt: whether this queue is set to run as a realtime task
+ * @prepare_crypt_hardware: a request will soon arrive from the queue
+ * so the subsystem requests the driver to prepare the hardware
+ * by issuing this call
+ * @unprepare_crypt_hardware: there are currently no more requests on the
+ * queue so the subsystem notifies the driver that it may relax the
+ * hardware by issuing this call
+ * @prepare_cipher_request: do some prepare if need before handle the current request
+ * @unprepare_cipher_request: undo any work done by prepare_cipher_request()
+ * @cipher_one_request: do encryption for current request
+ * @prepare_hash_request: do some prepare if need before handle the current request
+ * @unprepare_hash_request: undo any work done by prepare_hash_request()
+ * @hash_one_request: do hash for current request
+ * @kworker: thread struct for request pump
+ * @kworker_task: pointer to task for request pump kworker thread
+ * @pump_requests: work struct for scheduling work to the request pump
+ * @priv_data: the engine private data
+ * @cur_req: the current request which is on processing
+ */
+struct crypto_engine {
+ char name[ENGINE_NAME_LEN];
+ bool idling;
+ bool busy;
+ bool running;
+ bool cur_req_prepared;
+
+ struct list_head list;
+ spinlock_t queue_lock;
+ struct crypto_queue queue;
+
+ bool rt;
+
+ int (*prepare_crypt_hardware)(struct crypto_engine *engine);
+ int (*unprepare_crypt_hardware)(struct crypto_engine *engine);
+
+ int (*prepare_cipher_request)(struct crypto_engine *engine,
+ struct ablkcipher_request *req);
+ int (*unprepare_cipher_request)(struct crypto_engine *engine,
+ struct ablkcipher_request *req);
+ int (*prepare_hash_request)(struct crypto_engine *engine,
+ struct ahash_request *req);
+ int (*unprepare_hash_request)(struct crypto_engine *engine,
+ struct ahash_request *req);
+ int (*cipher_one_request)(struct crypto_engine *engine,
+ struct ablkcipher_request *req);
+ int (*hash_one_request)(struct crypto_engine *engine,
+ struct ahash_request *req);
+
+ struct kthread_worker kworker;
+ struct task_struct *kworker_task;
+ struct kthread_work pump_requests;
+
+ void *priv_data;
+ struct crypto_async_request *cur_req;
+};
+
+int crypto_transfer_cipher_request(struct crypto_engine *engine,
+ struct ablkcipher_request *req,
+ bool need_pump);
+int crypto_transfer_cipher_request_to_engine(struct crypto_engine *engine,
+ struct ablkcipher_request *req);
+int crypto_transfer_hash_request(struct crypto_engine *engine,
+ struct ahash_request *req, bool need_pump);
+int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine,
+ struct ahash_request *req);
+void crypto_finalize_cipher_request(struct crypto_engine *engine,
+ struct ablkcipher_request *req, int err);
+void crypto_finalize_hash_request(struct crypto_engine *engine,
+ struct ahash_request *req, int err);
+int crypto_engine_start(struct crypto_engine *engine);
+int crypto_engine_stop(struct crypto_engine *engine);
+struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt);
+int crypto_engine_exit(struct crypto_engine *engine);
+
+#endif /* _CRYPTO_ENGINE_H */
diff --git a/include/crypto/ghash.h b/include/crypto/ghash.h
new file mode 100644
index 000000000000..2a61c9bbab8f
--- /dev/null
+++ b/include/crypto/ghash.h
@@ -0,0 +1,23 @@
+/*
+ * Common values for GHASH algorithms
+ */
+
+#ifndef __CRYPTO_GHASH_H__
+#define __CRYPTO_GHASH_H__
+
+#include <linux/types.h>
+#include <crypto/gf128mul.h>
+
+#define GHASH_BLOCK_SIZE 16
+#define GHASH_DIGEST_SIZE 16
+
+struct ghash_ctx {
+ struct gf128mul_4k *gf128;
+};
+
+struct ghash_desc_ctx {
+ u8 buffer[GHASH_BLOCK_SIZE];
+ u32 bytes;
+};
+
+#endif
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index ce4ad637083d..baade6f429d0 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -11,7 +11,16 @@
#define CLKID_FCLK_DIV3 5
#define CLKID_FCLK_DIV4 6
#define CLKID_CLK81 12
+#define CLKID_MPLL2 15
+#define CLKID_SPI 34
+#define CLKID_I2C 22
#define CLKID_ETH 36
+#define CLKID_USB0 50
+#define CLKID_USB1 51
+#define CLKID_USB 55
+#define CLKID_USB1_DDR_BRIDGE 64
+#define CLKID_USB0_DDR_BRIDGE 65
+#define CLKID_AO_I2C 93
#define CLKID_SD_EMMC_A 94
#define CLKID_SD_EMMC_B 95
#define CLKID_SD_EMMC_C 96
diff --git a/include/dt-bindings/clock/r7s72100-clock.h b/include/dt-bindings/clock/r7s72100-clock.h
index 5128f4d94f44..3cd813896d08 100644
--- a/include/dt-bindings/clock/r7s72100-clock.h
+++ b/include/dt-bindings/clock/r7s72100-clock.h
@@ -25,6 +25,9 @@
#define R7S72100_CLK_SCIF6 1
#define R7S72100_CLK_SCIF7 0
+/* MSTP7 */
+#define R7S72100_CLK_ETHER 4
+
/* MSTP9 */
#define R7S72100_CLK_I2C0 7
#define R7S72100_CLK_I2C1 6
diff --git a/include/dt-bindings/clock/r8a7794-clock.h b/include/dt-bindings/clock/r8a7794-clock.h
index a3491ba2f6ec..9d02f5317c7c 100644
--- a/include/dt-bindings/clock/r8a7794-clock.h
+++ b/include/dt-bindings/clock/r8a7794-clock.h
@@ -67,6 +67,7 @@
#define R8A7794_CLK_IRQC 7
/* MSTP5 */
+#define R8A7794_CLK_AUDIO_DMAC0 2
#define R8A7794_CLK_PWM 23
/* MSTP7 */
@@ -107,6 +108,30 @@
#define R8A7794_CLK_I2C1 30
#define R8A7794_CLK_I2C0 31
+/* MSTP10 */
+#define R8A7794_CLK_SSI_ALL 5
+#define R8A7794_CLK_SSI9 6
+#define R8A7794_CLK_SSI8 7
+#define R8A7794_CLK_SSI7 8
+#define R8A7794_CLK_SSI6 9
+#define R8A7794_CLK_SSI5 10
+#define R8A7794_CLK_SSI4 11
+#define R8A7794_CLK_SSI3 12
+#define R8A7794_CLK_SSI2 13
+#define R8A7794_CLK_SSI1 14
+#define R8A7794_CLK_SSI0 15
+#define R8A7794_CLK_SCU_ALL 17
+#define R8A7794_CLK_SCU_DVC1 18
+#define R8A7794_CLK_SCU_DVC0 19
+#define R8A7794_CLK_SCU_CTU1_MIX1 20
+#define R8A7794_CLK_SCU_CTU0_MIX0 21
+#define R8A7794_CLK_SCU_SRC6 25
+#define R8A7794_CLK_SCU_SRC5 26
+#define R8A7794_CLK_SCU_SRC4 27
+#define R8A7794_CLK_SCU_SRC3 28
+#define R8A7794_CLK_SCU_SRC2 29
+#define R8A7794_CLK_SCU_SRC1 30
+
/* MSTP11 */
#define R8A7794_CLK_SCIFA3 6
#define R8A7794_CLK_SCIFA4 7
diff --git a/include/dt-bindings/mfd/qcom-rpm.h b/include/dt-bindings/mfd/qcom-rpm.h
index 13a9d4bf2662..54aef5e21763 100644
--- a/include/dt-bindings/mfd/qcom-rpm.h
+++ b/include/dt-bindings/mfd/qcom-rpm.h
@@ -147,6 +147,28 @@
#define QCOM_RPM_SMB208_S1b 137
#define QCOM_RPM_SMB208_S2a 138
#define QCOM_RPM_SMB208_S2b 139
+#define QCOM_RPM_PM8018_SMPS1 140
+#define QCOM_RPM_PM8018_SMPS2 141
+#define QCOM_RPM_PM8018_SMPS3 142
+#define QCOM_RPM_PM8018_SMPS4 143
+#define QCOM_RPM_PM8018_SMPS5 144
+#define QCOM_RPM_PM8018_LDO1 145
+#define QCOM_RPM_PM8018_LDO2 146
+#define QCOM_RPM_PM8018_LDO3 147
+#define QCOM_RPM_PM8018_LDO4 148
+#define QCOM_RPM_PM8018_LDO5 149
+#define QCOM_RPM_PM8018_LDO6 150
+#define QCOM_RPM_PM8018_LDO7 151
+#define QCOM_RPM_PM8018_LDO8 152
+#define QCOM_RPM_PM8018_LDO9 153
+#define QCOM_RPM_PM8018_LDO10 154
+#define QCOM_RPM_PM8018_LDO11 155
+#define QCOM_RPM_PM8018_LDO12 156
+#define QCOM_RPM_PM8018_LDO13 157
+#define QCOM_RPM_PM8018_LDO14 158
+#define QCOM_RPM_PM8018_LVS1 159
+#define QCOM_RPM_PM8018_NCP 160
+#define QCOM_RPM_VOLTAGE_CORNER 161
/*
* Constants used to select force mode for regulators.
diff --git a/include/dt-bindings/mfd/stm32f4-rcc.h b/include/dt-bindings/mfd/stm32f4-rcc.h
new file mode 100644
index 000000000000..e98942dc0d44
--- /dev/null
+++ b/include/dt-bindings/mfd/stm32f4-rcc.h
@@ -0,0 +1,98 @@
+/*
+ * This header provides constants for the STM32F4 RCC IP
+ */
+
+#ifndef _DT_BINDINGS_MFD_STM32F4_RCC_H
+#define _DT_BINDINGS_MFD_STM32F4_RCC_H
+
+/* AHB1 */
+#define STM32F4_RCC_AHB1_GPIOA 0
+#define STM32F4_RCC_AHB1_GPIOB 1
+#define STM32F4_RCC_AHB1_GPIOC 2
+#define STM32F4_RCC_AHB1_GPIOD 3
+#define STM32F4_RCC_AHB1_GPIOE 4
+#define STM32F4_RCC_AHB1_GPIOF 5
+#define STM32F4_RCC_AHB1_GPIOG 6
+#define STM32F4_RCC_AHB1_GPIOH 7
+#define STM32F4_RCC_AHB1_GPIOI 8
+#define STM32F4_RCC_AHB1_GPIOJ 9
+#define STM32F4_RCC_AHB1_GPIOK 10
+#define STM32F4_RCC_AHB1_CRC 12
+#define STM32F4_RCC_AHB1_DMA1 21
+#define STM32F4_RCC_AHB1_DMA2 22
+#define STM32F4_RCC_AHB1_DMA2D 23
+#define STM32F4_RCC_AHB1_ETHMAC 25
+#define STM32F4_RCC_AHB1_OTGHS 29
+
+#define STM32F4_AHB1_RESET(bit) (STM32F4_RCC_AHB1_##bit + (0x10 * 8))
+#define STM32F4_AHB1_CLOCK(bit) (STM32F4_RCC_AHB1_##bit + (0x30 * 8))
+
+
+/* AHB2 */
+#define STM32F4_RCC_AHB2_DCMI 0
+#define STM32F4_RCC_AHB2_CRYP 4
+#define STM32F4_RCC_AHB2_HASH 5
+#define STM32F4_RCC_AHB2_RNG 6
+#define STM32F4_RCC_AHB2_OTGFS 7
+
+#define STM32F4_AHB2_RESET(bit) (STM32F4_RCC_AHB2_##bit + (0x14 * 8))
+#define STM32F4_AHB2_CLOCK(bit) (STM32F4_RCC_AHB2_##bit + (0x34 * 8))
+
+/* AHB3 */
+#define STM32F4_RCC_AHB3_FMC 0
+
+#define STM32F4_AHB3_RESET(bit) (STM32F4_RCC_AHB3_##bit + (0x18 * 8))
+#define STM32F4_AHB3_CLOCK(bit) (STM32F4_RCC_AHB3_##bit + (0x38 * 8))
+
+/* APB1 */
+#define STM32F4_RCC_APB1_TIM2 0
+#define STM32F4_RCC_APB1_TIM3 1
+#define STM32F4_RCC_APB1_TIM4 2
+#define STM32F4_RCC_APB1_TIM5 3
+#define STM32F4_RCC_APB1_TIM6 4
+#define STM32F4_RCC_APB1_TIM7 5
+#define STM32F4_RCC_APB1_TIM12 6
+#define STM32F4_RCC_APB1_TIM13 7
+#define STM32F4_RCC_APB1_TIM14 8
+#define STM32F4_RCC_APB1_WWDG 11
+#define STM32F4_RCC_APB1_SPI2 14
+#define STM32F4_RCC_APB1_SPI3 15
+#define STM32F4_RCC_APB1_UART2 17
+#define STM32F4_RCC_APB1_UART3 18
+#define STM32F4_RCC_APB1_UART4 19
+#define STM32F4_RCC_APB1_UART5 20
+#define STM32F4_RCC_APB1_I2C1 21
+#define STM32F4_RCC_APB1_I2C2 22
+#define STM32F4_RCC_APB1_I2C3 23
+#define STM32F4_RCC_APB1_CAN1 25
+#define STM32F4_RCC_APB1_CAN2 26
+#define STM32F4_RCC_APB1_PWR 28
+#define STM32F4_RCC_APB1_DAC 29
+#define STM32F4_RCC_APB1_UART7 30
+#define STM32F4_RCC_APB1_UART8 31
+
+#define STM32F4_APB1_RESET(bit) (STM32F4_RCC_APB1_##bit + (0x20 * 8))
+#define STM32F4_APB1_CLOCK(bit) (STM32F4_RCC_APB1_##bit + (0x40 * 8))
+
+/* APB2 */
+#define STM32F4_RCC_APB2_TIM1 0
+#define STM32F4_RCC_APB2_TIM8 1
+#define STM32F4_RCC_APB2_USART1 4
+#define STM32F4_RCC_APB2_USART6 5
+#define STM32F4_RCC_APB2_ADC 8
+#define STM32F4_RCC_APB2_SDIO 11
+#define STM32F4_RCC_APB2_SPI1 12
+#define STM32F4_RCC_APB2_SPI4 13
+#define STM32F4_RCC_APB2_SYSCFG 14
+#define STM32F4_RCC_APB2_TIM9 16
+#define STM32F4_RCC_APB2_TIM10 17
+#define STM32F4_RCC_APB2_TIM11 18
+#define STM32F4_RCC_APB2_SPI5 20
+#define STM32F4_RCC_APB2_SPI6 21
+#define STM32F4_RCC_APB2_SAI1 22
+#define STM32F4_RCC_APB2_LTDC 26
+
+#define STM32F4_APB2_RESET(bit) (STM32F4_RCC_APB2_##bit + (0x24 * 8))
+#define STM32F4_APB2_CLOCK(bit) (STM32F4_RCC_APB2_##bit + (0x44 * 8))
+
+#endif /* _DT_BINDINGS_MFD_STM32F4_RCC_H */
diff --git a/include/dt-bindings/pinctrl/samsung.h b/include/dt-bindings/pinctrl/samsung.h
new file mode 100644
index 000000000000..6276eb785e2b
--- /dev/null
+++ b/include/dt-bindings/pinctrl/samsung.h
@@ -0,0 +1,57 @@
+/*
+ * Samsung's Exynos pinctrl bindings
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __DT_BINDINGS_PINCTRL_SAMSUNG_H__
+#define __DT_BINDINGS_PINCTRL_SAMSUNG_H__
+
+#define EXYNOS_PIN_PULL_NONE 0
+#define EXYNOS_PIN_PULL_DOWN 1
+#define EXYNOS_PIN_PULL_UP 3
+
+#define S3C64XX_PIN_PULL_NONE 0
+#define S3C64XX_PIN_PULL_DOWN 1
+#define S3C64XX_PIN_PULL_UP 2
+
+/* Pin function in power down mode */
+#define EXYNOS_PIN_PDN_OUT0 0
+#define EXYNOS_PIN_PDN_OUT1 1
+#define EXYNOS_PIN_PDN_INPUT 2
+#define EXYNOS_PIN_PDN_PREV 3
+
+/* Drive strengths for Exynos3250, Exynos4 (all) and Exynos5250 */
+#define EXYNOS4_PIN_DRV_LV1 0
+#define EXYNOS4_PIN_DRV_LV2 2
+#define EXYNOS4_PIN_DRV_LV3 1
+#define EXYNOS4_PIN_DRV_LV4 3
+
+/* Drive strengths for Exynos5260 */
+#define EXYNOS5260_PIN_DRV_LV1 0
+#define EXYNOS5260_PIN_DRV_LV2 1
+#define EXYNOS5260_PIN_DRV_LV4 2
+#define EXYNOS5260_PIN_DRV_LV6 3
+
+/* Drive strengths for Exynos5410, Exynos542x and Exynos5800 */
+#define EXYNOS5420_PIN_DRV_LV1 0
+#define EXYNOS5420_PIN_DRV_LV2 1
+#define EXYNOS5420_PIN_DRV_LV3 2
+#define EXYNOS5420_PIN_DRV_LV4 3
+
+#define EXYNOS_PIN_FUNC_INPUT 0
+#define EXYNOS_PIN_FUNC_OUTPUT 1
+#define EXYNOS_PIN_FUNC_2 2
+#define EXYNOS_PIN_FUNC_3 3
+#define EXYNOS_PIN_FUNC_4 4
+#define EXYNOS_PIN_FUNC_5 5
+#define EXYNOS_PIN_FUNC_6 6
+#define EXYNOS_PIN_FUNC_F 0xf
+
+#endif /* __DT_BINDINGS_PINCTRL_SAMSUNG_H__ */
diff --git a/include/dt-bindings/soc/rockchip,boot-mode.h b/include/dt-bindings/soc/rockchip,boot-mode.h
new file mode 100644
index 000000000000..ae7c867e736a
--- /dev/null
+++ b/include/dt-bindings/soc/rockchip,boot-mode.h
@@ -0,0 +1,15 @@
+#ifndef __ROCKCHIP_BOOT_MODE_H
+#define __ROCKCHIP_BOOT_MODE_H
+
+/*high 24 bits is tag, low 8 bits is type*/
+#define REBOOT_FLAG 0x5242C300
+/* normal boot */
+#define BOOT_NORMAL (REBOOT_FLAG + 0)
+/* enter bootloader rockusb mode */
+#define BOOT_BL_DOWNLOAD (REBOOT_FLAG + 1)
+/* enter recovery */
+#define BOOT_RECOVERY (REBOOT_FLAG + 3)
+ /* enter fastboot mode */
+#define BOOT_FASTBOOT (REBOOT_FLAG + 9)
+
+#endif
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 164049357e5c..04602cbe85dc 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -63,7 +63,7 @@ static inline int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
}
#endif
-void cper_print_aer(struct pci_dev *dev, int cper_severity,
+void cper_print_aer(struct pci_dev *dev, int aer_severity,
struct aer_capability_regs *aer);
int cper_severity_to_aer(int cper_severity);
void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 23ddf4b46a9b..97cb48f03dc7 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -1,6 +1,4 @@
/*
- * 2.5 block I/O model
- *
* Copyright (C) 2001 Jens Axboe <axboe@suse.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -461,6 +459,7 @@ static inline void bio_flush_dcache_pages(struct bio *bi)
extern void bio_copy_data(struct bio *dst, struct bio *src);
extern int bio_alloc_pages(struct bio *bio, gfp_t gfp);
+extern void bio_free_pages(struct bio *bio);
extern struct bio *bio_copy_user_iov(struct request_queue *,
struct rq_map_data *,
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 299e76b59fe9..a83c822c35c2 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -65,16 +65,6 @@ static inline int get_bitmask_order(unsigned int count)
return order; /* We could be slightly more clever with -1 here... */
}
-static inline int get_count_order(unsigned int count)
-{
- int order;
-
- order = fls(count) - 1;
- if (count & (count - 1))
- order++;
- return order;
-}
-
static __always_inline unsigned long hweight_long(unsigned long w)
{
return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
@@ -191,6 +181,32 @@ static inline unsigned fls_long(unsigned long l)
return fls64(l);
}
+static inline int get_count_order(unsigned int count)
+{
+ int order;
+
+ order = fls(count) - 1;
+ if (count & (count - 1))
+ order++;
+ return order;
+}
+
+/**
+ * get_count_order_long - get order after rounding @l up to power of 2
+ * @l: parameter
+ *
+ * it is same as get_count_order() but with long type parameter
+ */
+static inline int get_count_order_long(unsigned long l)
+{
+ if (l == 0UL)
+ return -1;
+ else if (l & (l - 1UL))
+ return (int)fls_long(l);
+ else
+ return (int)fls_long(l) - 1;
+}
+
/**
* __ffs64 - find first set bit in a 64 bit word
* @word: The 64 bit word
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h
index 10648e300c93..cbdbf34de5b6 100644
--- a/include/linux/blk-cgroup.h
+++ b/include/linux/blk-cgroup.h
@@ -45,7 +45,7 @@ struct blkcg {
spinlock_t lock;
struct radix_tree_root blkg_tree;
- struct blkcg_gq *blkg_hint;
+ struct blkcg_gq __rcu *blkg_hint;
struct hlist_head blkg_list;
struct blkcg_policy_data *cpd[BLKCG_MAX_POLS];
diff --git a/include/linux/blk-mq-pci.h b/include/linux/blk-mq-pci.h
new file mode 100644
index 000000000000..6ab595259112
--- /dev/null
+++ b/include/linux/blk-mq-pci.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_BLK_MQ_PCI_H
+#define _LINUX_BLK_MQ_PCI_H
+
+struct blk_mq_tag_set;
+struct pci_dev;
+
+int blk_mq_pci_map_queues(struct blk_mq_tag_set *set, struct pci_dev *pdev);
+
+#endif /* _LINUX_BLK_MQ_PCI_H */
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index e43bbffb5b7a..535ab2e13d2e 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -2,31 +2,19 @@
#define BLK_MQ_H
#include <linux/blkdev.h>
+#include <linux/sbitmap.h>
struct blk_mq_tags;
struct blk_flush_queue;
-struct blk_mq_cpu_notifier {
- struct list_head list;
- void *data;
- int (*notify)(void *data, unsigned long action, unsigned int cpu);
-};
-
-struct blk_mq_ctxmap {
- unsigned int size;
- unsigned int bits_per_word;
- struct blk_align_bitmap *map;
-};
-
struct blk_mq_hw_ctx {
struct {
spinlock_t lock;
struct list_head dispatch;
+ unsigned long state; /* BLK_MQ_S_* flags */
} ____cacheline_aligned_in_smp;
- unsigned long state; /* BLK_MQ_S_* flags */
- struct delayed_work run_work;
- struct delayed_work delay_work;
+ struct work_struct run_work;
cpumask_var_t cpumask;
int next_cpu;
int next_cpu_batch;
@@ -38,10 +26,10 @@ struct blk_mq_hw_ctx {
void *driver_data;
- struct blk_mq_ctxmap ctx_map;
+ struct sbitmap ctx_map;
- unsigned int nr_ctx;
struct blk_mq_ctx **ctxs;
+ unsigned int nr_ctx;
atomic_t wait_index;
@@ -49,7 +37,7 @@ struct blk_mq_hw_ctx {
unsigned long queued;
unsigned long run;
-#define BLK_MQ_MAX_DISPATCH_ORDER 10
+#define BLK_MQ_MAX_DISPATCH_ORDER 7
unsigned long dispatched[BLK_MQ_MAX_DISPATCH_ORDER];
unsigned int numa_node;
@@ -57,14 +45,18 @@ struct blk_mq_hw_ctx {
atomic_t nr_active;
- struct blk_mq_cpu_notifier cpu_notifier;
+ struct delayed_work delay_work;
+
+ struct hlist_node cpuhp_dead;
struct kobject kobj;
+ unsigned long poll_considered;
unsigned long poll_invoked;
unsigned long poll_success;
};
struct blk_mq_tag_set {
+ unsigned int *mq_map;
struct blk_mq_ops *ops;
unsigned int nr_hw_queues;
unsigned int queue_depth; /* max hw supported */
@@ -88,7 +80,6 @@ struct blk_mq_queue_data {
};
typedef int (queue_rq_fn)(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);
-typedef struct blk_mq_hw_ctx *(map_queue_fn)(struct request_queue *, const int);
typedef enum blk_eh_timer_return (timeout_fn)(struct request *, bool);
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);
@@ -102,6 +93,7 @@ typedef void (busy_iter_fn)(struct blk_mq_hw_ctx *, struct request *, void *,
bool);
typedef void (busy_tag_iter_fn)(struct request *, void *, bool);
typedef int (poll_fn)(struct blk_mq_hw_ctx *, unsigned int);
+typedef int (map_queues_fn)(struct blk_mq_tag_set *set);
struct blk_mq_ops {
@@ -111,11 +103,6 @@ struct blk_mq_ops {
queue_rq_fn *queue_rq;
/*
- * Map to specific hardware queue
- */
- map_queue_fn *map_queue;
-
- /*
* Called on request timeout
*/
timeout_fn *timeout;
@@ -147,6 +134,8 @@ struct blk_mq_ops {
init_request_fn *init_request;
exit_request_fn *exit_request;
reinit_request_fn *reinit_request;
+
+ map_queues_fn *map_queues;
};
enum {
@@ -158,6 +147,7 @@ enum {
BLK_MQ_F_TAG_SHARED = 1 << 1,
BLK_MQ_F_SG_MERGE = 1 << 2,
BLK_MQ_F_DEFER_ISSUE = 1 << 4,
+ BLK_MQ_F_BLOCKING = 1 << 5,
BLK_MQ_F_ALLOC_POLICY_START_BIT = 8,
BLK_MQ_F_ALLOC_POLICY_BITS = 1,
@@ -178,8 +168,8 @@ enum {
struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *);
struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
struct request_queue *q);
-int blk_mq_register_disk(struct gendisk *);
-void blk_mq_unregister_disk(struct gendisk *);
+int blk_mq_register_dev(struct device *, struct request_queue *);
+void blk_mq_unregister_dev(struct device *, struct request_queue *);
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set);
void blk_mq_free_tag_set(struct blk_mq_tag_set *set);
@@ -201,7 +191,6 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int op,
unsigned int flags, unsigned int hctx_idx);
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag);
-struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags);
enum {
BLK_MQ_UNIQUE_TAG_BITS = 16,
@@ -220,8 +209,6 @@ static inline u16 blk_mq_unique_tag_to_tag(u32 unique_tag)
return unique_tag & BLK_MQ_UNIQUE_TAG_MASK;
}
-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_tag_set *, unsigned int, int);
int blk_mq_request_started(struct request *rq);
void blk_mq_start_request(struct request *rq);
@@ -232,6 +219,7 @@ void blk_mq_requeue_request(struct request *rq);
void blk_mq_add_to_requeue_list(struct request *rq, bool at_head);
void blk_mq_cancel_requeue_work(struct request_queue *q);
void blk_mq_kick_requeue_list(struct request_queue *q);
+void blk_mq_delay_kick_requeue_list(struct request_queue *q, unsigned long msecs);
void blk_mq_abort_requeue_list(struct request_queue *q);
void blk_mq_complete_request(struct request *rq, int error);
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 436f43f87da9..cd395ecec99d 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -16,7 +16,6 @@ struct block_device;
struct io_context;
struct cgroup_subsys_state;
typedef void (bio_end_io_t) (struct bio *);
-typedef void (bio_destructor_t) (struct bio *);
#ifdef CONFIG_BLOCK
/*
@@ -89,14 +88,22 @@ struct bio {
struct bio_vec bi_inline_vecs[0];
};
-#define BIO_OP_SHIFT (8 * sizeof(unsigned int) - REQ_OP_BITS)
+#define BIO_OP_SHIFT (8 * FIELD_SIZEOF(struct bio, bi_opf) - REQ_OP_BITS)
+#define bio_flags(bio) ((bio)->bi_opf & ((1 << BIO_OP_SHIFT) - 1))
#define bio_op(bio) ((bio)->bi_opf >> BIO_OP_SHIFT)
-#define bio_set_op_attrs(bio, op, op_flags) do { \
- WARN_ON(op >= (1 << REQ_OP_BITS)); \
- (bio)->bi_opf &= ((1 << BIO_OP_SHIFT) - 1); \
- (bio)->bi_opf |= ((unsigned int) (op) << BIO_OP_SHIFT); \
- (bio)->bi_opf |= op_flags; \
+#define bio_set_op_attrs(bio, op, op_flags) do { \
+ if (__builtin_constant_p(op)) \
+ BUILD_BUG_ON((op) + 0U >= (1U << REQ_OP_BITS)); \
+ else \
+ WARN_ON_ONCE((op) + 0U >= (1U << REQ_OP_BITS)); \
+ if (__builtin_constant_p(op_flags)) \
+ BUILD_BUG_ON((op_flags) + 0U >= (1U << BIO_OP_SHIFT)); \
+ else \
+ WARN_ON_ONCE((op_flags) + 0U >= (1U << BIO_OP_SHIFT)); \
+ (bio)->bi_opf = bio_flags(bio); \
+ (bio)->bi_opf |= (((op) + 0U) << BIO_OP_SHIFT); \
+ (bio)->bi_opf |= (op_flags); \
} while (0)
#define BIO_RESET_BYTES offsetof(struct bio, bi_max_vecs)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e79055c8b577..c47c358ba052 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -449,7 +449,7 @@ struct request_queue {
struct list_head requeue_list;
spinlock_t requeue_lock;
- struct work_struct requeue_work;
+ struct delayed_work requeue_work;
struct mutex sysfs_lock;
@@ -1440,8 +1440,8 @@ static inline bool req_gap_front_merge(struct request *req, struct bio *bio)
return bio_will_gap(req->q, bio, req->bio);
}
-struct work_struct;
int kblockd_schedule_work(struct work_struct *work);
+int kblockd_schedule_work_on(int cpu, 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);
diff --git a/include/linux/blockgroup_lock.h b/include/linux/blockgroup_lock.h
index e44b88ba552b..225bdb7daec7 100644
--- a/include/linux/blockgroup_lock.h
+++ b/include/linux/blockgroup_lock.h
@@ -10,28 +10,10 @@
#include <linux/cache.h>
#ifdef CONFIG_SMP
-
-/*
- * We want a power-of-two. Is there a better way than this?
- */
-
-#if NR_CPUS >= 32
-#define NR_BG_LOCKS 128
-#elif NR_CPUS >= 16
-#define NR_BG_LOCKS 64
-#elif NR_CPUS >= 8
-#define NR_BG_LOCKS 32
-#elif NR_CPUS >= 4
-#define NR_BG_LOCKS 16
-#elif NR_CPUS >= 2
-#define NR_BG_LOCKS 8
+#define NR_BG_LOCKS (4 << ilog2(NR_CPUS < 32 ? NR_CPUS : 32))
#else
-#define NR_BG_LOCKS 4
-#endif
-
-#else /* CONFIG_SMP */
#define NR_BG_LOCKS 1
-#endif /* CONFIG_SMP */
+#endif
struct bgl_lock {
spinlock_t lock;
@@ -49,14 +31,10 @@ static inline void bgl_lock_init(struct blockgroup_lock *bgl)
spin_lock_init(&bgl->locks[i].lock);
}
-/*
- * The accessor is a macro so we can embed a blockgroup_lock into different
- * superblock types
- */
static inline spinlock_t *
bgl_lock_ptr(struct blockgroup_lock *bgl, unsigned int block_group)
{
- return &bgl->locks[(block_group) & (NR_BG_LOCKS-1)].lock;
+ return &bgl->locks[block_group & (NR_BG_LOCKS-1)].lock;
}
#endif
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index f9be32691718..962164d36506 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -7,6 +7,7 @@
#include <linux/mmzone.h>
#include <linux/mm_types.h>
#include <asm/dma.h>
+#include <asm/processor.h>
/*
* simple boot-time physical memory area allocator.
@@ -119,6 +120,10 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
#define BOOTMEM_LOW_LIMIT __pa(MAX_DMA_ADDRESS)
#endif
+#ifndef ARCH_LOW_ADDRESS_LIMIT
+#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
+#endif
+
#define alloc_bootmem(x) \
__alloc_bootmem(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
#define alloc_bootmem_align(x, align) \
@@ -180,10 +185,6 @@ static inline void * __init memblock_virt_alloc_nopanic(
NUMA_NO_NODE);
}
-#ifndef ARCH_LOW_ADDRESS_LIMIT
-#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
-#endif
-
static inline void * __init memblock_virt_alloc_low(
phys_addr_t size, phys_addr_t align)
{
diff --git a/include/linux/ccp.h b/include/linux/ccp.h
index 7c2bb27c067c..a7653339fedb 100644
--- a/include/linux/ccp.h
+++ b/include/linux/ccp.h
@@ -238,9 +238,6 @@ struct ccp_xts_aes_engine {
};
/***** SHA engine *****/
-#define CCP_SHA_BLOCKSIZE SHA256_BLOCK_SIZE
-#define CCP_SHA_CTXSIZE SHA256_DIGEST_SIZE
-
/**
* ccp_sha_type - type of SHA operation
*
diff --git a/include/linux/ceph/auth.h b/include/linux/ceph/auth.h
index 1563265d2097..374bb1c4ef52 100644
--- a/include/linux/ceph/auth.h
+++ b/include/linux/ceph/auth.h
@@ -104,7 +104,7 @@ extern int ceph_auth_build_hello(struct ceph_auth_client *ac,
extern int ceph_handle_auth_reply(struct ceph_auth_client *ac,
void *buf, size_t len,
void *reply_buf, size_t reply_len);
-extern int ceph_entity_name_encode(const char *name, void **p, void *end);
+int ceph_auth_entity_name_encode(const char *name, void **p, void *end);
extern int ceph_build_auth(struct ceph_auth_client *ac,
void *msg_buf, size_t msg_len);
diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h
index 7868d602c0a0..f96de8de4fa7 100644
--- a/include/linux/ceph/ceph_fs.h
+++ b/include/linux/ceph/ceph_fs.h
@@ -138,6 +138,9 @@ struct ceph_dir_layout {
#define CEPH_MSG_POOLOP_REPLY 48
#define CEPH_MSG_POOLOP 49
+/* mon commands */
+#define CEPH_MSG_MON_COMMAND 50
+#define CEPH_MSG_MON_COMMAND_ACK 51
/* osd */
#define CEPH_MSG_OSD_MAP 41
@@ -176,6 +179,14 @@ struct ceph_mon_statfs_reply {
struct ceph_statfs st;
} __attribute__ ((packed));
+struct ceph_mon_command {
+ struct ceph_mon_request_header monhdr;
+ struct ceph_fsid fsid;
+ __le32 num_strs; /* always 1 */
+ __le32 str_len;
+ char str[];
+} __attribute__ ((packed));
+
struct ceph_osd_getmap {
struct ceph_mon_request_header monhdr;
struct ceph_fsid fsid;
@@ -270,6 +281,7 @@ enum {
CEPH_SESSION_FLUSHMSG,
CEPH_SESSION_FLUSHMSG_ACK,
CEPH_SESSION_FORCE_RO,
+ CEPH_SESSION_REJECT,
};
extern const char *ceph_session_op_name(int op);
diff --git a/include/linux/ceph/cls_lock_client.h b/include/linux/ceph/cls_lock_client.h
new file mode 100644
index 000000000000..84884d8d4710
--- /dev/null
+++ b/include/linux/ceph/cls_lock_client.h
@@ -0,0 +1,49 @@
+#ifndef _LINUX_CEPH_CLS_LOCK_CLIENT_H
+#define _LINUX_CEPH_CLS_LOCK_CLIENT_H
+
+#include <linux/ceph/osd_client.h>
+
+enum ceph_cls_lock_type {
+ CEPH_CLS_LOCK_NONE = 0,
+ CEPH_CLS_LOCK_EXCLUSIVE = 1,
+ CEPH_CLS_LOCK_SHARED = 2,
+};
+
+struct ceph_locker_id {
+ struct ceph_entity_name name; /* locker's client name */
+ char *cookie; /* locker's cookie */
+};
+
+struct ceph_locker_info {
+ struct ceph_entity_addr addr; /* locker's address */
+};
+
+struct ceph_locker {
+ struct ceph_locker_id id;
+ struct ceph_locker_info info;
+};
+
+int ceph_cls_lock(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, u8 type, char *cookie,
+ char *tag, char *desc, u8 flags);
+int ceph_cls_unlock(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, char *cookie);
+int ceph_cls_break_lock(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, char *cookie,
+ struct ceph_entity_name *locker);
+
+void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers);
+
+int ceph_cls_lock_info(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, u8 *type, char **tag,
+ struct ceph_locker **lockers, u32 *num_lockers);
+
+#endif
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 83fc1fff7061..1816c5e26581 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -264,7 +264,8 @@ extern struct ceph_client *ceph_create_client(struct ceph_options *opt,
void *private,
u64 supported_features,
u64 required_features);
-extern u64 ceph_client_id(struct ceph_client *client);
+struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client);
+u64 ceph_client_gid(struct ceph_client *client);
extern void ceph_destroy_client(struct ceph_client *client);
extern int __ceph_open_session(struct ceph_client *client,
unsigned long started);
diff --git a/include/linux/ceph/mon_client.h b/include/linux/ceph/mon_client.h
index 24d704d1ea5c..d5a3ecea578d 100644
--- a/include/linux/ceph/mon_client.h
+++ b/include/linux/ceph/mon_client.h
@@ -141,6 +141,9 @@ int ceph_monc_get_version(struct ceph_mon_client *monc, const char *what,
int ceph_monc_get_version_async(struct ceph_mon_client *monc, const char *what,
ceph_monc_callback_t cb, u64 private_data);
+int ceph_monc_blacklist_add(struct ceph_mon_client *monc,
+ struct ceph_entity_addr *client_addr);
+
extern int ceph_monc_open_session(struct ceph_mon_client *monc);
extern int ceph_monc_validate_auth(struct ceph_mon_client *monc);
diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h
index 858932304260..96337b15a60d 100644
--- a/include/linux/ceph/osd_client.h
+++ b/include/linux/ceph/osd_client.h
@@ -121,6 +121,9 @@ struct ceph_osd_req_op {
struct ceph_osd_data response_data;
} notify;
struct {
+ struct ceph_osd_data response_data;
+ } list_watchers;
+ struct {
u64 expected_object_size;
u64 expected_write_size;
} alloc_hint;
@@ -249,6 +252,12 @@ struct ceph_osd_linger_request {
size_t *preply_len;
};
+struct ceph_watch_item {
+ struct ceph_entity_name name;
+ u64 cookie;
+ struct ceph_entity_addr addr;
+};
+
struct ceph_osd_client {
struct ceph_client *client;
@@ -346,7 +355,6 @@ extern void osd_req_op_cls_response_data_pages(struct ceph_osd_request *,
struct page **pages, u64 length,
u32 alignment, bool pages_from_pool,
bool own_pages);
-
extern void osd_req_op_cls_init(struct ceph_osd_request *osd_req,
unsigned int which, u16 opcode,
const char *class, const char *method);
@@ -389,6 +397,14 @@ extern void ceph_osdc_sync(struct ceph_osd_client *osdc);
extern void ceph_osdc_flush_notifies(struct ceph_osd_client *osdc);
void ceph_osdc_maybe_request_map(struct ceph_osd_client *osdc);
+int ceph_osdc_call(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ const char *class, const char *method,
+ unsigned int flags,
+ struct page *req_page, size_t req_len,
+ struct page *resp_page, size_t *resp_len);
+
extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
struct ceph_vino vino,
struct ceph_file_layout *layout,
@@ -434,5 +450,10 @@ int ceph_osdc_notify(struct ceph_osd_client *osdc,
size_t *preply_len);
int ceph_osdc_watch_check(struct ceph_osd_client *osdc,
struct ceph_osd_linger_request *lreq);
+int ceph_osdc_list_watchers(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ struct ceph_watch_item **watchers,
+ u32 *num_watchers);
#endif
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index d4e106b5dc27..0d8415820fc3 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -6,8 +6,10 @@
* Lower value means higher priority, analogically to reclaim priority.
*/
enum compact_priority {
+ COMPACT_PRIO_SYNC_FULL,
+ MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_FULL,
COMPACT_PRIO_SYNC_LIGHT,
- MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
+ MIN_COMPACT_COSTLY_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
COMPACT_PRIO_ASYNC,
INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC
@@ -49,14 +51,37 @@ enum compact_result {
COMPACT_CONTENDED,
/*
- * direct compaction partially compacted a zone and there might be
- * suitable pages
+ * direct compaction terminated after concluding that the allocation
+ * should now succeed
*/
- COMPACT_PARTIAL,
+ COMPACT_SUCCESS,
};
struct alloc_context; /* in mm/internal.h */
+/*
+ * Number of free order-0 pages that should be available above given watermark
+ * to make sure compaction has reasonable chance of not running out of free
+ * pages that it needs to isolate as migration target during its work.
+ */
+static inline unsigned long compact_gap(unsigned int order)
+{
+ /*
+ * Although all the isolations for migration are temporary, compaction
+ * free scanner may have up to 1 << order pages on its list and then
+ * try to split an (order - 1) free page. At that point, a gap of
+ * 1 << order might not be enough, so it's safer to require twice that
+ * amount. Note that the number of pages on the list is also
+ * effectively limited by COMPACT_CLUSTER_MAX, as that's the maximum
+ * that the migrate scanner can have isolated on migrate list, and free
+ * scanner is only invoked when the number of isolated free pages is
+ * lower than that. But it's not worth to complicate the formula here
+ * as a bigger gap for higher orders than strictly necessary can also
+ * improve chances of compaction success.
+ */
+ return 2UL << order;
+}
+
#ifdef CONFIG_COMPACTION
extern int sysctl_compact_memory;
extern int sysctl_compaction_handler(struct ctl_table *table, int write,
@@ -70,7 +95,6 @@ extern int fragmentation_index(struct zone *zone, unsigned int order);
extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
unsigned int order, unsigned int alloc_flags,
const struct alloc_context *ac, enum compact_priority prio);
-extern void compact_pgdat(pg_data_t *pgdat, int order);
extern void reset_isolation_suitable(pg_data_t *pgdat);
extern enum compact_result compaction_suitable(struct zone *zone, int order,
unsigned int alloc_flags, int classzone_idx);
@@ -89,7 +113,7 @@ static inline bool compaction_made_progress(enum compact_result result)
* that the compaction successfully isolated and migrated some
* pageblocks.
*/
- if (result == COMPACT_PARTIAL)
+ if (result == COMPACT_SUCCESS)
return true;
return false;
@@ -154,10 +178,6 @@ extern void kcompactd_stop(int nid);
extern void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx);
#else
-static inline void compact_pgdat(pg_data_t *pgdat, int order)
-{
-}
-
static inline void reset_isolation_suitable(pg_data_t *pgdat)
{
}
diff --git a/include/linux/compat.h b/include/linux/compat.h
index f964ef79e0ad..63609398ef9f 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -432,7 +432,6 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
-extern __printf(1, 2) int compat_printk(const char *fmt, ...);
extern void sigset_from_compat(sigset_t *set, const compat_sigset_t *compat);
extern void sigset_to_compat(compat_sigset_t *compat, const sigset_t *set);
diff --git a/include/linux/console.h b/include/linux/console.h
index d530c4627e54..3672809234a7 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -173,6 +173,12 @@ static inline void console_sysfs_notify(void)
#endif
extern bool console_suspend_enabled;
+#ifdef CONFIG_OF
+extern void console_set_by_of(void);
+#else
+static inline void console_set_by_of(void) {}
+#endif
+
/* Suspend and resume console messages over PM events */
extern void suspend_console(void);
extern void resume_console(void);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 7572d9e9dced..b886dc17f2f3 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -231,6 +231,11 @@ void cpu_startup_entry(enum cpuhp_state state);
void cpu_idle_poll_ctrl(bool enable);
+/* Attach to any functions which should be considered cpuidle. */
+#define __cpuidle __attribute__((__section__(".cpuidle.text")))
+
+bool cpu_in_idle(unsigned long pc);
+
void arch_cpu_idle(void);
void arch_cpu_idle_prepare(void);
void arch_cpu_idle_enter(void);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 257db64562e5..f0e70a1bb3ac 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -26,15 +26,10 @@ struct inode;
/*
* COW Supplementary groups list
*/
-#define NGROUPS_SMALL 32
-#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(kgid_t)))
-
struct group_info {
atomic_t usage;
int ngroups;
- int nblocks;
- kgid_t small_block[NGROUPS_SMALL];
- kgid_t *blocks[0];
+ kgid_t gid[0];
};
/**
@@ -88,10 +83,6 @@ extern void set_groups(struct cred *, struct group_info *);
extern int groups_search(const struct group_info *, kgid_t);
extern bool may_setgroups(void);
-/* access the groups "array" with this macro */
-#define GROUP_AT(gi, i) \
- ((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK])
-
/*
* The security context of a task
*
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 5ff3e9a4fe5f..5beed7b30561 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -584,9 +584,10 @@ static inline struct dentry *d_real(struct dentry *dentry,
* If dentry is on an union/overlay, then return the underlying, real inode.
* Otherwise return d_inode().
*/
-static inline struct inode *d_real_inode(struct dentry *dentry)
+static inline struct inode *d_real_inode(const struct dentry *dentry)
{
- return d_backing_inode(d_real(dentry, NULL, 0));
+ /* This usage of d_real() results in const dentry */
+ return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0));
}
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 91acfce74a22..ef7962e84444 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -590,6 +590,7 @@ extern struct ratelimit_state dm_ratelimit_state;
#define DM_MAPIO_SUBMITTED 0
#define DM_MAPIO_REMAPPED 1
#define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE
+#define DM_MAPIO_DELAY_REQUEUE 3
#define dm_sector_div64(x, y)( \
{ \
diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h
index fe8cb610deac..c7d844f09c3a 100644
--- a/include/linux/dma-debug.h
+++ b/include/linux/dma-debug.h
@@ -56,6 +56,13 @@ extern void debug_dma_alloc_coherent(struct device *dev, size_t size,
extern void debug_dma_free_coherent(struct device *dev, size_t size,
void *virt, dma_addr_t addr);
+extern void debug_dma_map_resource(struct device *dev, phys_addr_t addr,
+ size_t size, int direction,
+ dma_addr_t dma_addr);
+
+extern void debug_dma_unmap_resource(struct device *dev, dma_addr_t dma_addr,
+ size_t size, int direction);
+
extern void debug_dma_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
int direction);
@@ -141,6 +148,18 @@ static inline void debug_dma_free_coherent(struct device *dev, size_t size,
{
}
+static inline void debug_dma_map_resource(struct device *dev, phys_addr_t addr,
+ size_t size, int direction,
+ dma_addr_t dma_addr)
+{
+}
+
+static inline void debug_dma_unmap_resource(struct device *dev,
+ dma_addr_t dma_addr, size_t size,
+ int direction)
+{
+}
+
static inline void debug_dma_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle,
size_t size, int direction)
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index dc69df04abc1..0f90eb5e3c6b 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -95,6 +95,12 @@ struct dma_map_ops {
struct scatterlist *sg, int nents,
enum dma_data_direction dir,
unsigned long attrs);
+ dma_addr_t (*map_resource)(struct device *dev, phys_addr_t phys_addr,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+ void (*unmap_resource)(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
void (*sync_single_for_cpu)(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction dir);
@@ -258,6 +264,41 @@ static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
debug_dma_unmap_page(dev, addr, size, dir, false);
}
+static inline dma_addr_t dma_map_resource(struct device *dev,
+ phys_addr_t phys_addr,
+ size_t size,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ dma_addr_t addr;
+
+ BUG_ON(!valid_dma_direction(dir));
+
+ /* Don't allow RAM to be mapped */
+ BUG_ON(pfn_valid(PHYS_PFN(phys_addr)));
+
+ addr = phys_addr;
+ if (ops->map_resource)
+ addr = ops->map_resource(dev, phys_addr, size, dir, attrs);
+
+ debug_dma_map_resource(dev, phys_addr, size, dir, addr);
+
+ return addr;
+}
+
+static inline void dma_unmap_resource(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ BUG_ON(!valid_dma_direction(dir));
+ if (ops->unmap_resource)
+ ops->unmap_resource(dev, addr, size, dir, attrs);
+ debug_dma_unmap_resource(dev, addr, size, dir);
+}
+
static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
size_t size,
enum dma_data_direction dir)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 30de0197263a..cc535a478bae 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -441,6 +441,21 @@ typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
typedef void (*dma_async_tx_callback)(void *dma_async_param);
+enum dmaengine_tx_result {
+ DMA_TRANS_NOERROR = 0, /* SUCCESS */
+ DMA_TRANS_READ_FAILED, /* Source DMA read failed */
+ DMA_TRANS_WRITE_FAILED, /* Destination DMA write failed */
+ DMA_TRANS_ABORTED, /* Op never submitted / aborted */
+};
+
+struct dmaengine_result {
+ enum dmaengine_tx_result result;
+ u32 residue;
+};
+
+typedef void (*dma_async_tx_callback_result)(void *dma_async_param,
+ const struct dmaengine_result *result);
+
struct dmaengine_unmap_data {
u8 map_cnt;
u8 to_cnt;
@@ -478,6 +493,7 @@ struct dma_async_tx_descriptor {
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
int (*desc_free)(struct dma_async_tx_descriptor *tx);
dma_async_tx_callback callback;
+ dma_async_tx_callback_result callback_result;
void *callback_param;
struct dmaengine_unmap_data *unmap;
#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 5295535b60c6..aca2a6a1d035 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -30,12 +30,12 @@ struct fdtable {
struct rcu_head rcu;
};
-static inline bool close_on_exec(int fd, const struct fdtable *fdt)
+static inline bool close_on_exec(unsigned int fd, const struct fdtable *fdt)
{
return test_bit(fd, fdt->close_on_exec);
}
-static inline bool fd_is_open(int fd, const struct fdtable *fdt)
+static inline bool fd_is_open(unsigned int fd, const struct fdtable *fdt)
{
return test_bit(fd, fdt->open_fds);
}
@@ -57,7 +57,7 @@ struct files_struct {
* written part on a separate cache line in SMP
*/
spinlock_t file_lock ____cacheline_aligned_in_smp;
- int next_fd;
+ unsigned int next_fd;
unsigned long close_on_exec_init[1];
unsigned long open_fds_init[1];
unsigned long full_fds_bits_init[1];
diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h
new file mode 100644
index 000000000000..8e953c6f394a
--- /dev/null
+++ b/include/linux/firmware/meson/meson_sm.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MESON_SM_FW_H_
+#define _MESON_SM_FW_H_
+
+enum {
+ SM_EFUSE_READ,
+ SM_EFUSE_WRITE,
+ SM_EFUSE_USER_MAX,
+};
+
+struct meson_sm_firmware;
+
+int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, u32 arg1,
+ u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call_write(void *buffer, unsigned int b_size, unsigned int cmd_index,
+ u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0, u32 arg1,
+ u32 arg2, u32 arg3, u32 arg4);
+
+#endif /* _MESON_SM_FW_H_ */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 901e25d495cc..c145219286a8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -63,7 +63,7 @@ extern void __init files_maxfiles_init(void);
extern struct files_stat_struct files_stat;
extern unsigned long get_max_files(void);
-extern int sysctl_nr_open;
+extern unsigned int sysctl_nr_open;
extern struct inodes_stat_t inodes_stat;
extern int leases_enable, lease_break_time;
extern int sysctl_protected_symlinks;
@@ -224,6 +224,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
#define ATTR_KILL_PRIV (1 << 14)
#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */
#define ATTR_TIMES_SET (1 << 16)
+#define ATTR_TOUCH (1 << 17)
/*
* Whiteout is represented by a char device. The following constants define the
@@ -591,6 +592,7 @@ is_uncached_acl(struct posix_acl *acl)
#define IOP_FASTPERM 0x0001
#define IOP_LOOKUP 0x0002
#define IOP_NOFOLLOW 0x0004
+#define IOP_XATTR 0x0008
/*
* Keep mostly read-only and often accessed (especially for
@@ -1064,6 +1066,18 @@ struct file_lock_context {
extern void send_sigio(struct fown_struct *fown, int fd, int band);
+/*
+ * Return the inode to use for locking
+ *
+ * For overlayfs this should be the overlay inode, not the real inode returned
+ * by file_inode(). For any other fs file_inode(filp) and locks_inode(filp) are
+ * equal.
+ */
+static inline struct inode *locks_inode(const struct file *f)
+{
+ return f->f_path.dentry->d_inode;
+}
+
#ifdef CONFIG_FILE_LOCKING
extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *);
extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
@@ -1251,7 +1265,7 @@ static inline struct dentry *file_dentry(const struct file *file)
static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
{
- return locks_lock_inode_wait(file_inode(filp), fl);
+ return locks_lock_inode_wait(locks_inode(filp), fl);
}
struct fasync_struct {
@@ -1459,6 +1473,7 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
}
extern struct timespec current_fs_time(struct super_block *sb);
+extern struct timespec current_time(struct inode *inode);
/*
* Snapshotting support.
@@ -1733,17 +1748,10 @@ struct inode_operations {
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
- int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
- int (*setxattr) (struct dentry *, struct inode *,
- const char *, const void *, size_t, int);
- ssize_t (*getxattr) (struct dentry *, struct inode *,
- const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
- int (*removexattr) (struct dentry *, const char *);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
int (*update_time)(struct inode *, struct timespec *, int);
@@ -2006,7 +2014,6 @@ enum file_time_flags {
S_VERSION = 8,
};
-extern bool atime_needs_update(const struct path *, struct inode *);
extern void touch_atime(const struct path *);
static inline void file_accessed(struct file *file)
{
@@ -2075,10 +2082,19 @@ struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
int flags, void *data);
-extern struct dentry *mount_pseudo(struct file_system_type *, char *,
- const struct super_operations *ops,
- const struct dentry_operations *dops,
- unsigned long);
+extern struct dentry *mount_pseudo_xattr(struct file_system_type *, char *,
+ const struct super_operations *ops,
+ const struct xattr_handler **xattr,
+ const struct dentry_operations *dops,
+ unsigned long);
+
+static inline struct dentry *
+mount_pseudo(struct file_system_type *fs_type, char *name,
+ const struct super_operations *ops,
+ const struct dentry_operations *dops, unsigned long magic)
+{
+ return mount_pseudo_xattr(fs_type, name, ops, NULL, dops, magic);
+}
/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
#define fops_get(fops) \
@@ -2155,7 +2171,7 @@ static inline int mandatory_lock(struct inode *ino)
static inline int locks_verify_locked(struct file *file)
{
- if (mandatory_lock(file_inode(file)))
+ if (mandatory_lock(locks_inode(file)))
return locks_mandatory_locked(file);
return 0;
}
@@ -2794,8 +2810,6 @@ extern void block_sync_page(struct page *page);
/* fs/splice.c */
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 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,
@@ -2950,7 +2964,8 @@ extern int simple_open(struct inode *inode, struct file *file);
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
extern int simple_unlink(struct inode *, struct dentry *);
extern int simple_rmdir(struct inode *, struct dentry *);
-extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int simple_rename(struct inode *, struct dentry *,
+ struct inode *, struct dentry *, unsigned int);
extern int noop_fsync(struct file *, loff_t, loff_t, int);
extern int simple_empty(struct dentry *);
extern int simple_readpage(struct file *file, struct page *page);
@@ -2995,7 +3010,7 @@ extern int buffer_migrate_page(struct address_space *,
#define buffer_migrate_page NULL
#endif
-extern int inode_change_ok(const struct inode *, struct iattr *);
+extern int setattr_prepare(struct dentry *, struct iattr *);
extern int inode_newsize_ok(const struct inode *, loff_t offset);
extern void setattr_copy(struct inode *inode, const struct iattr *attr);
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
index 76cff18bb032..ff8b11b26f31 100644
--- a/include/linux/fscrypto.h
+++ b/include/linux/fscrypto.h
@@ -111,23 +111,6 @@ struct fscrypt_completion_result {
struct fscrypt_completion_result ecr = { \
COMPLETION_INITIALIZER((ecr).completion), 0 }
-static inline int fscrypt_key_size(int mode)
-{
- switch (mode) {
- case FS_ENCRYPTION_MODE_AES_256_XTS:
- return FS_AES_256_XTS_KEY_SIZE;
- case FS_ENCRYPTION_MODE_AES_256_GCM:
- return FS_AES_256_GCM_KEY_SIZE;
- case FS_ENCRYPTION_MODE_AES_256_CBC:
- return FS_AES_256_CBC_KEY_SIZE;
- case FS_ENCRYPTION_MODE_AES_256_CTS:
- return FS_AES_256_CTS_KEY_SIZE;
- default:
- BUG();
- }
- return 0;
-}
-
#define FS_FNAME_NUM_SCATTER_ENTRIES 4
#define FS_CRYPTO_BLOCK_SIZE 16
#define FS_FNAME_CRYPTO_DIGEST_SIZE 32
@@ -202,13 +185,6 @@ static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
}
-static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size)
-{
- if (size == fscrypt_key_size(mode))
- return size;
- return 0;
-}
-
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
{
if (str->len == 1 && str->name[0] == '.')
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index eed9e853a06f..b8bcc058e031 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -29,7 +29,11 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
static inline int fsnotify_perm(struct file *file, int mask)
{
struct path *path = &file->f_path;
- struct inode *inode = file_inode(file);
+ /*
+ * Do not use file_inode() here or anywhere in this file to get the
+ * inode. That would break *notity on overlayfs.
+ */
+ struct inode *inode = path->dentry->d_inode;
__u32 fsnotify_mask = 0;
int ret;
@@ -173,7 +177,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
static inline void fsnotify_access(struct file *file)
{
struct path *path = &file->f_path;
- struct inode *inode = file_inode(file);
+ struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode))
@@ -191,7 +195,7 @@ static inline void fsnotify_access(struct file *file)
static inline void fsnotify_modify(struct file *file)
{
struct path *path = &file->f_path;
- struct inode *inode = file_inode(file);
+ struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode))
@@ -209,7 +213,7 @@ static inline void fsnotify_modify(struct file *file)
static inline void fsnotify_open(struct file *file)
{
struct path *path = &file->f_path;
- struct inode *inode = file_inode(file);
+ struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode))
@@ -225,7 +229,7 @@ static inline void fsnotify_open(struct file *file)
static inline void fsnotify_close(struct file *file)
{
struct path *path = &file->f_path;
- struct inode *inode = file_inode(file);
+ struct inode *inode = path->dentry->d_inode;
fmode_t mode = file->f_mode;
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 7268ed076be8..79467b239fcf 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -135,7 +135,7 @@ struct fsnotify_group {
const struct fsnotify_ops *ops; /* how this group handles things */
/* needed to send notification to userspace */
- struct mutex notification_mutex; /* protect the notification_list */
+ spinlock_t notification_lock; /* protect the notification_list */
struct list_head notification_list; /* list of event_holder this group needs to send to userspace */
wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */
unsigned int q_len; /* events on the queue */
@@ -177,7 +177,6 @@ struct fsnotify_group {
struct fanotify_group_private_data {
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
/* allows a group to block waiting for a userspace response */
- spinlock_t access_lock;
struct list_head access_list;
wait_queue_head_t access_waitq;
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 75b66eccc692..b2ec82712baa 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -837,7 +837,7 @@ __u32 hid_field_extract(const struct hid_device *hid, __u8 *report,
*/
static inline void hid_device_io_start(struct hid_device *hid) {
if (hid->io_started) {
- dev_warn(&hid->dev, "io already started");
+ dev_warn(&hid->dev, "io already started\n");
return;
}
hid->io_started = true;
@@ -857,7 +857,7 @@ static inline void hid_device_io_start(struct hid_device *hid) {
*/
static inline void hid_device_io_stop(struct hid_device *hid) {
if (!hid->io_started) {
- dev_warn(&hid->dev, "io already stopped");
+ dev_warn(&hid->dev, "io already stopped\n");
return;
}
hid->io_started = false;
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index 6f14de45b5ce..9b9f65d99873 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -87,6 +87,10 @@ extern bool is_vma_temporary_stack(struct vm_area_struct *vma);
extern unsigned long transparent_hugepage_flags;
+extern unsigned long thp_get_unmapped_area(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags);
+
extern void prep_transhuge_page(struct page *page);
extern void free_transhuge_page(struct page *page);
@@ -152,8 +156,8 @@ static inline bool is_huge_zero_pmd(pmd_t pmd)
return is_huge_zero_page(pmd_page(pmd));
}
-struct page *get_huge_zero_page(void);
-void put_huge_zero_page(void);
+struct page *mm_get_huge_zero_page(struct mm_struct *mm);
+void mm_put_huge_zero_page(struct mm_struct *mm);
#define mk_huge_pmd(page, prot) pmd_mkhuge(mk_pmd(page, prot))
@@ -169,6 +173,9 @@ void put_huge_zero_page(void);
static inline void prep_transhuge_page(struct page *page) {}
#define transparent_hugepage_flags 0UL
+
+#define thp_get_unmapped_area NULL
+
static inline int
split_huge_page_to_list(struct page *page, struct list_head *list)
{
@@ -213,9 +220,9 @@ static inline bool is_huge_zero_page(struct page *page)
return false;
}
-static inline void put_huge_zero_page(void)
+static inline void mm_put_huge_zero_page(struct mm_struct *mm)
{
- BUILD_BUG();
+ return;
}
static inline struct page *follow_devmap_pmd(struct vm_area_struct *vma,
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index c26d4638f665..48c76d612d40 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -90,7 +90,7 @@ int dequeue_hwpoisoned_huge_page(struct page *page);
bool isolate_huge_page(struct page *page, struct list_head *list);
void putback_active_hugepage(struct page *page);
void free_huge_page(struct page *page);
-void hugetlb_fix_reserve_counts(struct inode *inode, bool restore_reserve);
+void hugetlb_fix_reserve_counts(struct inode *inode);
extern struct mutex *hugetlb_fault_mutex_table;
u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
struct vm_area_struct *vma,
@@ -450,8 +450,8 @@ static inline pgoff_t basepage_index(struct page *page)
return __basepage_index(page);
}
-extern void dissolve_free_huge_pages(unsigned long start_pfn,
- unsigned long end_pfn);
+extern int dissolve_free_huge_pages(unsigned long start_pfn,
+ unsigned long end_pfn);
static inline bool hugepage_migration_supported(struct hstate *h)
{
#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
@@ -518,7 +518,7 @@ static inline pgoff_t basepage_index(struct page *page)
{
return page->index;
}
-#define dissolve_free_huge_pages(s, e) do {} while (0)
+#define dissolve_free_huge_pages(s, e) 0
#define hugepage_migration_supported(h) false
static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 4f7d8f4b1e9a..34a0dc18f327 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -29,7 +29,9 @@
* Returns the number of lower random bytes in "data".
* Must not be NULL. *OBSOLETE*
* @read: New API. drivers can fill up to max bytes of data
- * into the buffer. The buffer is aligned for any type.
+ * into the buffer. The buffer is aligned for any type
+ * and max is guaranteed to be >= to that alignment
+ * (either 4 or 8 depending on architecture).
* @priv: Private data, for use by the RNG driver.
* @quality: Estimation of true entropy in RNG's bitstream
* (per mill).
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index d4c1d12f900d..bd74d5706f3b 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -32,7 +32,9 @@
struct i2c_mux_core {
struct i2c_adapter *parent;
struct device *dev;
- bool mux_locked;
+ unsigned int mux_locked:1;
+ unsigned int arbitrator:1;
+ unsigned int gate:1;
void *priv;
@@ -51,7 +53,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
int (*deselect)(struct i2c_mux_core *, u32));
/* flags for i2c_mux_alloc */
-#define I2C_MUX_LOCKED BIT(0)
+#define I2C_MUX_LOCKED BIT(0)
+#define I2C_MUX_ARBITRATOR BIT(1)
+#define I2C_MUX_GATE BIT(2)
static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
{
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index fffdc270ca18..6422eef428c4 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -427,6 +427,20 @@ struct i2c_algorithm {
};
/**
+ * struct i2c_lock_operations - represent I2C locking operations
+ * @lock_bus: Get exclusive access to an I2C bus segment
+ * @trylock_bus: Try to get exclusive access to an I2C bus segment
+ * @unlock_bus: Release exclusive access to an I2C bus segment
+ *
+ * The main operations are wrapped by i2c_lock_bus and i2c_unlock_bus.
+ */
+struct i2c_lock_operations {
+ void (*lock_bus)(struct i2c_adapter *, unsigned int flags);
+ int (*trylock_bus)(struct i2c_adapter *, unsigned int flags);
+ void (*unlock_bus)(struct i2c_adapter *, unsigned int flags);
+};
+
+/**
* struct i2c_timings - I2C timing information
* @bus_freq_hz: the bus frequency in Hz
* @scl_rise_ns: time SCL signal takes to rise in ns; t(r) in the I2C specification
@@ -536,6 +550,7 @@ struct i2c_adapter {
void *algo_data;
/* data fields that are valid for all devices */
+ const struct i2c_lock_operations *lock_ops;
struct rt_mutex bus_lock;
struct rt_mutex mux_lock;
@@ -552,10 +567,6 @@ struct i2c_adapter {
struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
-
- void (*lock_bus)(struct i2c_adapter *, unsigned int flags);
- int (*trylock_bus)(struct i2c_adapter *, unsigned int flags);
- void (*unlock_bus)(struct i2c_adapter *, unsigned int flags);
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
@@ -597,7 +608,21 @@ int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
static inline void
i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
- adapter->lock_bus(adapter, flags);
+ adapter->lock_ops->lock_bus(adapter, flags);
+}
+
+/**
+ * i2c_trylock_bus - Try to get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER tries to locks the root i2c adapter,
+ * I2C_LOCK_SEGMENT tries to lock only this branch in the adapter tree
+ *
+ * Return: true if the I2C bus segment is locked, false otherwise
+ */
+static inline int
+i2c_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+ return adapter->lock_ops->trylock_bus(adapter, flags);
}
/**
@@ -609,7 +634,7 @@ i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
static inline void
i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
- adapter->unlock_bus(adapter, flags);
+ adapter->lock_ops->unlock_bus(adapter, flags);
}
static inline void
@@ -673,6 +698,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap,
extern struct i2c_adapter *i2c_get_adapter(int nr);
extern void i2c_put_adapter(struct i2c_adapter *adap);
+extern unsigned int i2c_adapter_depth(struct i2c_adapter *adapter);
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults);
@@ -766,4 +792,13 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node
}
#endif /* CONFIG_OF */
+#if IS_ENABLED(CONFIG_ACPI)
+u32 i2c_acpi_find_bus_speed(struct device *dev);
+#else
+static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_ACPI */
+
#endif /* _LINUX_I2C_H */
diff --git a/include/linux/init.h b/include/linux/init.h
index 6935d02474aa..5a3321a7909b 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -41,22 +41,11 @@
discard it in modules) */
#define __init __section(.init.text) __cold notrace
#define __initdata __section(.init.data)
-#define __initconst __constsection(.init.rodata)
+#define __initconst __section(.init.rodata)
#define __exitdata __section(.exit.data)
#define __exit_call __used __section(.exitcall.exit)
/*
- * Some architecture have tool chains which do not handle rodata attributes
- * correctly. For those disable special sections for const, so that other
- * architectures can annotate correctly.
- */
-#ifdef CONFIG_BROKEN_RODATA
-#define __constsection(x)
-#else
-#define __constsection(x) __section(x)
-#endif
-
-/*
* modpost check for section mismatches during the kernel build.
* A section mismatch happens when there are references from a
* code or data section to an init section (both code or data).
@@ -75,7 +64,7 @@
*/
#define __ref __section(.ref.text) noinline
#define __refdata __section(.ref.data)
-#define __refconst __constsection(.ref.rodata)
+#define __refconst __section(.ref.rodata)
#ifdef MODULE
#define __exitused
@@ -88,10 +77,10 @@
/* Used for MEMORY_HOTPLUG */
#define __meminit __section(.meminit.text) __cold notrace
#define __meminitdata __section(.meminit.data)
-#define __meminitconst __constsection(.meminit.rodata)
+#define __meminitconst __section(.meminit.rodata)
#define __memexit __section(.memexit.text) __exitused __cold notrace
#define __memexitdata __section(.memexit.data)
-#define __memexitconst __constsection(.memexit.rodata)
+#define __memexitconst __section(.memexit.rodata)
/* For assembly routines */
#define __HEAD .section ".head.text","ax"
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
index beb9ce1c2c23..8c1239020d79 100644
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -7,7 +7,6 @@
/*
* Gives us 8 prio classes with 13-bits of data for each class
*/
-#define IOPRIO_BITS (16)
#define IOPRIO_CLASS_SHIFT (13)
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 5fdc55312334..589d14e970ad 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -150,15 +150,19 @@ static inline u64 get_jiffies_64(void)
/* time_is_before_jiffies(a) return true if a is before jiffies */
#define time_is_before_jiffies(a) time_after(jiffies, a)
+#define time_is_before_jiffies64(a) time_after64(get_jiffies_64(), a)
/* time_is_after_jiffies(a) return true if a is after jiffies */
#define time_is_after_jiffies(a) time_before(jiffies, a)
+#define time_is_after_jiffies64(a) time_before64(get_jiffies_64(), a)
/* time_is_before_eq_jiffies(a) return true if a is before or equal to jiffies*/
#define time_is_before_eq_jiffies(a) time_after_eq(jiffies, a)
+#define time_is_before_eq_jiffies64(a) time_after_eq64(get_jiffies_64(), a)
/* time_is_after_eq_jiffies(a) return true if a is after or equal to jiffies*/
#define time_is_after_eq_jiffies(a) time_before_eq(jiffies, a)
+#define time_is_after_eq_jiffies64(a) time_before_eq64(get_jiffies_64(), a)
/*
* Have the 32 bit jiffies value wrap 5 minutes after boot
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
index c2ce155d83cc..f282d4e87258 100644
--- a/include/linux/kern_levels.h
+++ b/include/linux/kern_levels.h
@@ -20,7 +20,7 @@
* line that had no enclosing \n). Only to be used by core/arch code
* during early bootup (a continued line is not SMP-safe otherwise).
*/
-#define KERN_CONT ""
+#define KERN_CONT KERN_SOH "c"
/* integer equivalents of KERN_<LEVEL> */
#define LOGLEVEL_SCHED -2 /* Deferred messages from sched code
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 74fd6f05bc5b..bc6ed52a39b9 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -733,17 +733,25 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
-#define min(x, y) ({ \
- typeof(x) _min1 = (x); \
- typeof(y) _min2 = (y); \
- (void) (&_min1 == &_min2); \
- _min1 < _min2 ? _min1 : _min2; })
-
-#define max(x, y) ({ \
- typeof(x) _max1 = (x); \
- typeof(y) _max2 = (y); \
- (void) (&_max1 == &_max2); \
- _max1 > _max2 ? _max1 : _max2; })
+#define __min(t1, t2, min1, min2, x, y) ({ \
+ t1 min1 = (x); \
+ t2 min2 = (y); \
+ (void) (&min1 == &min2); \
+ min1 < min2 ? min1 : min2; })
+#define min(x, y) \
+ __min(typeof(x), typeof(y), \
+ __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \
+ x, y)
+
+#define __max(t1, t2, max1, max2, x, y) ({ \
+ t1 max1 = (x); \
+ t2 max2 = (y); \
+ (void) (&max1 == &max2); \
+ max1 > max2 ? max1 : max2; })
+#define max(x, y) \
+ __max(typeof(x), typeof(y), \
+ __UNIQUE_ID(max1_), __UNIQUE_ID(max2_), \
+ x, y)
#define min3(x, y, z) min((typeof(x))min(x, y), z)
#define max3(x, y, z) max((typeof(x))max(x, y), z)
@@ -775,15 +783,15 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
*
* Or not use min/max/clamp at all, of course.
*/
-#define min_t(type, x, y) ({ \
- type __min1 = (x); \
- type __min2 = (y); \
- __min1 < __min2 ? __min1: __min2; })
-
-#define max_t(type, x, y) ({ \
- type __max1 = (x); \
- type __max2 = (y); \
- __max1 > __max2 ? __max1: __max2; })
+#define min_t(type, x, y) \
+ __min(type, type, \
+ __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \
+ x, y)
+
+#define max_t(type, x, y) \
+ __max(type, type, \
+ __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \
+ x, y)
/**
* clamp_t - return a value clamped to a given range using a given type
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index ba78b8306674..d190786e4ad8 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -352,7 +352,10 @@ struct nvm_dev {
/* Backend device */
struct request_queue *q;
+ struct device dev;
+ struct device *parent_dev;
char name[DISK_NAME_LEN];
+ void *private_data;
struct mutex mlock;
spinlock_t lock;
@@ -524,9 +527,9 @@ extern struct nvm_block *nvm_get_blk(struct nvm_dev *, struct nvm_lun *,
unsigned long);
extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *);
-extern int nvm_register(struct request_queue *, char *,
- struct nvm_dev_ops *);
-extern void nvm_unregister(char *);
+extern struct nvm_dev *nvm_alloc_dev(int);
+extern int nvm_register(struct nvm_dev *);
+extern void nvm_unregister(struct nvm_dev *);
void nvm_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type);
@@ -575,11 +578,14 @@ extern int nvm_dev_factory(struct nvm_dev *, int flags);
#else /* CONFIG_NVM */
struct nvm_dev_ops;
-static inline int nvm_register(struct request_queue *q, char *disk_name,
- struct nvm_dev_ops *ops)
+static inline struct nvm_dev *nvm_alloc_dev(int node)
+{
+ return ERR_PTR(-EINVAL);
+}
+static inline int nvm_register(struct nvm_dev *dev)
{
return -EINVAL;
}
-static inline void nvm_unregister(char *disk_name) {}
+static inline void nvm_unregister(struct nvm_dev *dev) {}
#endif /* CONFIG_NVM */
#endif /* LIGHTNVM.H */
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index a93a0b23dc8d..9072f04db616 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -116,6 +116,9 @@ int klp_unregister_patch(struct klp_patch *);
int klp_enable_patch(struct klp_patch *);
int klp_disable_patch(struct klp_patch *);
+void arch_klp_init_object_loaded(struct klp_patch *patch,
+ struct klp_object *obj);
+
/* Called from the module loader during module coming/going states */
int klp_module_coming(struct module *mod);
void klp_module_going(struct module *mod);
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index eabe0138eb06..c1458fede1f9 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -16,6 +16,8 @@ struct lockdep_map;
extern int prove_locking;
extern int lock_stat;
+#define MAX_LOCKDEP_SUBCLASSES 8UL
+
#ifdef CONFIG_LOCKDEP
#include <linux/linkage.h>
@@ -29,8 +31,6 @@ extern int lock_stat;
*/
#define XXX_LOCK_USAGE_STATES (1+3*4)
-#define MAX_LOCKDEP_SUBCLASSES 8UL
-
/*
* NR_LOCKDEP_CACHING_CLASSES ... Number of classes
* cached in the instance of lockdep_map
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index d610232762e3..2931aa43dab1 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -11,6 +11,8 @@
#ifndef __LINUX_MBUS_H
#define __LINUX_MBUS_H
+#include <linux/errno.h>
+
struct resource;
struct mbus_dram_target_info
@@ -55,6 +57,8 @@ struct mbus_dram_target_info
#ifdef CONFIG_PLAT_ORION
extern const struct mbus_dram_target_info *mv_mbus_dram_info(void);
extern const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(void);
+int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
+ u8 *attr);
#else
static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)
{
@@ -64,14 +68,24 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(vo
{
return NULL;
}
+static inline int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size,
+ u8 *target, u8 *attr)
+{
+ /*
+ * On all ARM32 MVEBU platforms with MBus support, this stub
+ * function will not get called. The real function from the
+ * MBus driver is called instead. ARM64 MVEBU platforms like
+ * the Armada 3700 could use the mv_xor device driver which calls
+ * into this function
+ */
+ return -EINVAL;
+}
#endif
int mvebu_mbus_save_cpu_target(u32 __iomem *store_addr);
void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr);
-int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
- u8 *attr);
int mvebu_mbus_add_window_remap_by_id(unsigned int target,
unsigned int attribute,
phys_addr_t base, size_t size,
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 2925da23505d..5b759c9acf97 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -328,6 +328,7 @@ phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align,
phys_addr_t __memblock_alloc_base(phys_addr_t size, phys_addr_t align,
phys_addr_t max_addr);
phys_addr_t memblock_phys_mem_size(void);
+phys_addr_t memblock_reserved_size(void);
phys_addr_t memblock_mem_size(unsigned long limit_pfn);
phys_addr_t memblock_start_of_DRAM(void);
phys_addr_t memblock_end_of_DRAM(void);
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 5d8ca6e02e39..61d20c17f3b7 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -366,6 +366,8 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
struct mem_cgroup *,
struct mem_cgroup_reclaim_cookie *);
void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
+int mem_cgroup_scan_tasks(struct mem_cgroup *,
+ int (*)(struct task_struct *, void *), void *);
static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
{
@@ -446,6 +448,8 @@ unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
void mem_cgroup_handle_over_high(void);
+unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg);
+
void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
struct task_struct *p);
@@ -639,6 +643,12 @@ static inline void mem_cgroup_iter_break(struct mem_cgroup *root,
{
}
+static inline int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
+ int (*fn)(struct task_struct *, void *), void *arg)
+{
+ return 0;
+}
+
static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
{
return 0;
@@ -669,6 +679,11 @@ mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
return 0;
}
+static inline unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg)
+{
+ return 0;
+}
+
static inline void
mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
{
@@ -758,13 +773,13 @@ static inline void mem_cgroup_wb_stats(struct bdi_writeback *wb,
#endif /* CONFIG_CGROUP_WRITEBACK */
struct sock;
-void sock_update_memcg(struct sock *sk);
-void sock_release_memcg(struct sock *sk);
bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
#ifdef CONFIG_MEMCG
extern struct static_key_false memcg_sockets_enabled_key;
#define mem_cgroup_sockets_enabled static_branch_unlikely(&memcg_sockets_enabled_key)
+void mem_cgroup_sk_alloc(struct sock *sk);
+void mem_cgroup_sk_free(struct sock *sk);
static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
{
if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && memcg->tcpmem_pressure)
@@ -777,6 +792,8 @@ static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
}
#else
#define mem_cgroup_sockets_enabled 0
+static inline void mem_cgroup_sk_alloc(struct sock *sk) { };
+static inline void mem_cgroup_sk_free(struct sock *sk) { };
static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
{
return false;
diff --git a/include/linux/mfd/88pm80x.h b/include/linux/mfd/88pm80x.h
index d409ceb2231e..c118a7ec94d6 100644
--- a/include/linux/mfd/88pm80x.h
+++ b/include/linux/mfd/88pm80x.h
@@ -350,7 +350,7 @@ static inline int pm80x_dev_suspend(struct device *dev)
int irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(dev))
- set_bit((1 << irq), &chip->wu_flag);
+ set_bit(irq, &chip->wu_flag);
return 0;
}
@@ -362,7 +362,7 @@ static inline int pm80x_dev_resume(struct device *dev)
int irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(dev))
- clear_bit((1 << irq), &chip->wu_flag);
+ clear_bit(irq, &chip->wu_flag);
return 0;
}
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 9475fee2bfc5..d33c245e75ca 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -63,6 +63,8 @@ enum ab8500_version {
#define AB8500_STE_TEST 0x14
#define AB8500_OTP_EMUL 0x15
+#define AB8500_DEBUG_FIELD_LAST 0x16
+
/*
* Interrupts
* Values used to index into array ab8500_irq_regoffset[] defined in
diff --git a/include/linux/mfd/ac100.h b/include/linux/mfd/ac100.h
new file mode 100644
index 000000000000..3c148f196b9f
--- /dev/null
+++ b/include/linux/mfd/ac100.h
@@ -0,0 +1,178 @@
+/*
+ * Functions and registers to access AC100 codec / RTC combo IC.
+ *
+ * Copyright (C) 2016 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_AC100_H
+#define __LINUX_MFD_AC100_H
+
+#include <linux/regmap.h>
+
+struct ac100_dev {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+/* Audio codec related registers */
+#define AC100_CHIP_AUDIO_RST 0x00
+#define AC100_PLL_CTRL1 0x01
+#define AC100_PLL_CTRL2 0x02
+#define AC100_SYSCLK_CTRL 0x03
+#define AC100_MOD_CLK_ENA 0x04
+#define AC100_MOD_RST_CTRL 0x05
+#define AC100_I2S_SR_CTRL 0x06
+
+/* I2S1 interface */
+#define AC100_I2S1_CLK_CTRL 0x10
+#define AC100_I2S1_SND_OUT_CTRL 0x11
+#define AC100_I2S1_SND_IN_CTRL 0x12
+#define AC100_I2S1_MXR_SRC 0x13
+#define AC100_I2S1_VOL_CTRL1 0x14
+#define AC100_I2S1_VOL_CTRL2 0x15
+#define AC100_I2S1_VOL_CTRL3 0x16
+#define AC100_I2S1_VOL_CTRL4 0x17
+#define AC100_I2S1_MXR_GAIN 0x18
+
+/* I2S2 interface */
+#define AC100_I2S2_CLK_CTRL 0x20
+#define AC100_I2S2_SND_OUT_CTRL 0x21
+#define AC100_I2S2_SND_IN_CTRL 0x22
+#define AC100_I2S2_MXR_SRC 0x23
+#define AC100_I2S2_VOL_CTRL1 0x24
+#define AC100_I2S2_VOL_CTRL2 0x25
+#define AC100_I2S2_VOL_CTRL3 0x26
+#define AC100_I2S2_VOL_CTRL4 0x27
+#define AC100_I2S2_MXR_GAIN 0x28
+
+/* I2S3 interface */
+#define AC100_I2S3_CLK_CTRL 0x30
+#define AC100_I2S3_SND_OUT_CTRL 0x31
+#define AC100_I2S3_SND_IN_CTRL 0x32
+#define AC100_I2S3_SIG_PATH_CTRL 0x33
+
+/* ADC digital controls */
+#define AC100_ADC_DIG_CTRL 0x40
+#define AC100_ADC_VOL_CTRL 0x41
+
+/* HMIC plug sensing / key detection */
+#define AC100_HMIC_CTRL1 0x44
+#define AC100_HMIC_CTRL2 0x45
+#define AC100_HMIC_STATUS 0x46
+
+/* DAC digital controls */
+#define AC100_DAC_DIG_CTRL 0x48
+#define AC100_DAC_VOL_CTRL 0x49
+#define AC100_DAC_MXR_SRC 0x4c
+#define AC100_DAC_MXR_GAIN 0x4d
+
+/* Analog controls */
+#define AC100_ADC_APC_CTRL 0x50
+#define AC100_ADC_SRC 0x51
+#define AC100_ADC_SRC_BST_CTRL 0x52
+#define AC100_OUT_MXR_DAC_A_CTRL 0x53
+#define AC100_OUT_MXR_SRC 0x54
+#define AC100_OUT_MXR_SRC_BST 0x55
+#define AC100_HPOUT_CTRL 0x56
+#define AC100_ERPOUT_CTRL 0x57
+#define AC100_SPKOUT_CTRL 0x58
+#define AC100_LINEOUT_CTRL 0x59
+
+/* ADC digital audio processing (high pass filter & auto gain control */
+#define AC100_ADC_DAP_L_STA 0x80
+#define AC100_ADC_DAP_R_STA 0x81
+#define AC100_ADC_DAP_L_CTRL 0x82
+#define AC100_ADC_DAP_R_CTRL 0x83
+#define AC100_ADC_DAP_L_T_L 0x84 /* Left Target Level */
+#define AC100_ADC_DAP_R_T_L 0x85 /* Right Target Level */
+#define AC100_ADC_DAP_L_H_A_C 0x86 /* Left High Avg. Coef */
+#define AC100_ADC_DAP_L_L_A_C 0x87 /* Left Low Avg. Coef */
+#define AC100_ADC_DAP_R_H_A_C 0x88 /* Right High Avg. Coef */
+#define AC100_ADC_DAP_R_L_A_C 0x89 /* Right Low Avg. Coef */
+#define AC100_ADC_DAP_L_D_T 0x8a /* Left Decay Time */
+#define AC100_ADC_DAP_L_A_T 0x8b /* Left Attack Time */
+#define AC100_ADC_DAP_R_D_T 0x8c /* Right Decay Time */
+#define AC100_ADC_DAP_R_A_T 0x8d /* Right Attack Time */
+#define AC100_ADC_DAP_N_TH 0x8e /* Noise Threshold */
+#define AC100_ADC_DAP_L_H_N_A_C 0x8f /* Left High Noise Avg. Coef */
+#define AC100_ADC_DAP_L_L_N_A_C 0x90 /* Left Low Noise Avg. Coef */
+#define AC100_ADC_DAP_R_H_N_A_C 0x91 /* Right High Noise Avg. Coef */
+#define AC100_ADC_DAP_R_L_N_A_C 0x92 /* Right Low Noise Avg. Coef */
+#define AC100_ADC_DAP_H_HPF_C 0x93 /* High High-Pass-Filter Coef */
+#define AC100_ADC_DAP_L_HPF_C 0x94 /* Low High-Pass-Filter Coef */
+#define AC100_ADC_DAP_OPT 0x95 /* AGC Optimum */
+
+/* DAC digital audio processing (high pass filter & dynamic range control) */
+#define AC100_DAC_DAP_CTRL 0xa0
+#define AC100_DAC_DAP_H_HPF_C 0xa1 /* High High-Pass-Filter Coef */
+#define AC100_DAC_DAP_L_HPF_C 0xa2 /* Low High-Pass-Filter Coef */
+#define AC100_DAC_DAP_L_H_E_A_C 0xa3 /* Left High Energy Avg Coef */
+#define AC100_DAC_DAP_L_L_E_A_C 0xa4 /* Left Low Energy Avg Coef */
+#define AC100_DAC_DAP_R_H_E_A_C 0xa5 /* Right High Energy Avg Coef */
+#define AC100_DAC_DAP_R_L_E_A_C 0xa6 /* Right Low Energy Avg Coef */
+#define AC100_DAC_DAP_H_G_D_T_C 0xa7 /* High Gain Delay Time Coef */
+#define AC100_DAC_DAP_L_G_D_T_C 0xa8 /* Low Gain Delay Time Coef */
+#define AC100_DAC_DAP_H_G_A_T_C 0xa9 /* High Gain Attack Time Coef */
+#define AC100_DAC_DAP_L_G_A_T_C 0xaa /* Low Gain Attack Time Coef */
+#define AC100_DAC_DAP_H_E_TH 0xab /* High Energy Threshold */
+#define AC100_DAC_DAP_L_E_TH 0xac /* Low Energy Threshold */
+#define AC100_DAC_DAP_H_G_K 0xad /* High Gain K parameter */
+#define AC100_DAC_DAP_L_G_K 0xae /* Low Gain K parameter */
+#define AC100_DAC_DAP_H_G_OFF 0xaf /* High Gain offset */
+#define AC100_DAC_DAP_L_G_OFF 0xb0 /* Low Gain offset */
+#define AC100_DAC_DAP_OPT 0xb1 /* DRC optimum */
+
+/* Digital audio processing enable */
+#define AC100_ADC_DAP_ENA 0xb4
+#define AC100_DAC_DAP_ENA 0xb5
+
+/* SRC control */
+#define AC100_SRC1_CTRL1 0xb8
+#define AC100_SRC1_CTRL2 0xb9
+#define AC100_SRC1_CTRL3 0xba
+#define AC100_SRC1_CTRL4 0xbb
+#define AC100_SRC2_CTRL1 0xbc
+#define AC100_SRC2_CTRL2 0xbd
+#define AC100_SRC2_CTRL3 0xbe
+#define AC100_SRC2_CTRL4 0xbf
+
+/* RTC clk control */
+#define AC100_CLK32K_ANALOG_CTRL 0xc0
+#define AC100_CLKOUT_CTRL1 0xc1
+#define AC100_CLKOUT_CTRL2 0xc2
+#define AC100_CLKOUT_CTRL3 0xc3
+
+/* RTC module */
+#define AC100_RTC_RST 0xc6
+#define AC100_RTC_CTRL 0xc7
+#define AC100_RTC_SEC 0xc8 /* second */
+#define AC100_RTC_MIN 0xc9 /* minute */
+#define AC100_RTC_HOU 0xca /* hour */
+#define AC100_RTC_WEE 0xcb /* weekday */
+#define AC100_RTC_DAY 0xcc /* day */
+#define AC100_RTC_MON 0xcd /* month */
+#define AC100_RTC_YEA 0xce /* year */
+#define AC100_RTC_UPD 0xcf /* update trigger */
+
+/* RTC alarm */
+#define AC100_ALM_INT_ENA 0xd0
+#define AC100_ALM_INT_STA 0xd1
+#define AC100_ALM_SEC 0xd8
+#define AC100_ALM_MIN 0xd9
+#define AC100_ALM_HOU 0xda
+#define AC100_ALM_WEE 0xdb
+#define AC100_ALM_DAY 0xdc
+#define AC100_ALM_MON 0xdd
+#define AC100_ALM_YEA 0xde
+#define AC100_ALM_UPD 0xdf
+
+/* RTC general purpose register 0 ~ 15 */
+#define AC100_RTC_GP(x) (0xe0 + (x))
+
+#endif /* __LINUX_MFD_AC100_H */
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
index 58ab4c0fe761..b31b3be7f8c9 100644
--- a/include/linux/mfd/arizona/core.h
+++ b/include/linux/mfd/arizona/core.h
@@ -13,6 +13,7 @@
#ifndef _WM_ARIZONA_CORE_H
#define _WM_ARIZONA_CORE_H
+#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/regmap.h>
@@ -21,6 +22,12 @@
#define ARIZONA_MAX_CORE_SUPPLIES 2
+enum {
+ ARIZONA_MCLK1,
+ ARIZONA_MCLK2,
+ ARIZONA_NUM_MCLK
+};
+
enum arizona_type {
WM5102 = 1,
WM5110 = 2,
@@ -139,6 +146,8 @@ struct arizona {
struct mutex clk_lock;
int clk32k_ref;
+ struct clk *mclk[ARIZONA_NUM_MCLK];
+
bool ctrlif_error;
struct snd_soc_dapm_context *dapm;
@@ -182,7 +191,4 @@ int cs47l24_patch(struct arizona *arizona);
int wm8997_patch(struct arizona *arizona);
int wm8998_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/axp20x.h b/include/linux/mfd/axp20x.h
index 0be4982f08fe..fec597fb34cb 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -20,6 +20,7 @@ enum {
AXP221_ID,
AXP223_ID,
AXP288_ID,
+ AXP806_ID,
AXP809_ID,
NR_AXP20X_VARIANTS,
};
@@ -91,6 +92,30 @@ enum {
#define AXP22X_ALDO3_V_OUT 0x2a
#define AXP22X_CHRG_CTRL3 0x35
+#define AXP806_STARTUP_SRC 0x00
+#define AXP806_CHIP_ID 0x03
+#define AXP806_PWR_OUT_CTRL1 0x10
+#define AXP806_PWR_OUT_CTRL2 0x11
+#define AXP806_DCDCA_V_CTRL 0x12
+#define AXP806_DCDCB_V_CTRL 0x13
+#define AXP806_DCDCC_V_CTRL 0x14
+#define AXP806_DCDCD_V_CTRL 0x15
+#define AXP806_DCDCE_V_CTRL 0x16
+#define AXP806_ALDO1_V_CTRL 0x17
+#define AXP806_ALDO2_V_CTRL 0x18
+#define AXP806_ALDO3_V_CTRL 0x19
+#define AXP806_DCDC_MODE_CTRL1 0x1a
+#define AXP806_DCDC_MODE_CTRL2 0x1b
+#define AXP806_DCDC_FREQ_CTRL 0x1c
+#define AXP806_BLDO1_V_CTRL 0x20
+#define AXP806_BLDO2_V_CTRL 0x21
+#define AXP806_BLDO3_V_CTRL 0x22
+#define AXP806_BLDO4_V_CTRL 0x23
+#define AXP806_CLDO1_V_CTRL 0x24
+#define AXP806_CLDO2_V_CTRL 0x25
+#define AXP806_CLDO3_V_CTRL 0x26
+#define AXP806_VREF_TEMP_WARN_L 0xf3
+
/* Interrupt */
#define AXP152_IRQ1_EN 0x40
#define AXP152_IRQ2_EN 0x41
@@ -266,6 +291,26 @@ enum {
};
enum {
+ AXP806_DCDCA = 0,
+ AXP806_DCDCB,
+ AXP806_DCDCC,
+ AXP806_DCDCD,
+ AXP806_DCDCE,
+ AXP806_ALDO1,
+ AXP806_ALDO2,
+ AXP806_ALDO3,
+ AXP806_BLDO1,
+ AXP806_BLDO2,
+ AXP806_BLDO3,
+ AXP806_BLDO4,
+ AXP806_CLDO1,
+ AXP806_CLDO2,
+ AXP806_CLDO3,
+ AXP806_SW,
+ AXP806_REG_ID_MAX,
+};
+
+enum {
AXP809_DCDC1 = 0,
AXP809_DCDC2,
AXP809_DCDC3,
@@ -414,6 +459,21 @@ enum axp288_irqs {
AXP288_IRQ_BC_USB_CHNG,
};
+enum axp806_irqs {
+ AXP806_IRQ_DIE_TEMP_HIGH_LV1,
+ AXP806_IRQ_DIE_TEMP_HIGH_LV2,
+ AXP806_IRQ_DCDCA_V_LOW,
+ AXP806_IRQ_DCDCB_V_LOW,
+ AXP806_IRQ_DCDCC_V_LOW,
+ AXP806_IRQ_DCDCD_V_LOW,
+ AXP806_IRQ_DCDCE_V_LOW,
+ AXP806_IRQ_PWROK_LONG,
+ AXP806_IRQ_PWROK_SHORT,
+ AXP806_IRQ_WAKEUP,
+ AXP806_IRQ_PWROK_FALL,
+ AXP806_IRQ_PWROK_RISE,
+};
+
enum axp809_irqs {
AXP809_IRQ_ACIN_OVER_V = 1,
AXP809_IRQ_ACIN_PLUGIN,
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index d641a18abacb..76f7ef4d3a0d 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -109,6 +109,10 @@ struct cros_ec_command {
* should check msg.result for the EC's result code.
* @pkt_xfer: send packet to EC and get response
* @lock: one transaction at a time
+ * @mkbp_event_supported: true if this EC supports the MKBP event protocol.
+ * @event_notifier: interrupt event notifier for transport devices.
+ * @event_data: raw payload transferred with the MKBP event.
+ * @event_size: size in bytes of the event data.
*/
struct cros_ec_device {
@@ -137,6 +141,11 @@ struct cros_ec_device {
int (*pkt_xfer)(struct cros_ec_device *ec,
struct cros_ec_command *msg);
struct mutex lock;
+ bool mkbp_event_supported;
+ struct blocking_notifier_head event_notifier;
+
+ struct ec_response_get_next_event event_data;
+ int event_size;
};
/* struct cros_ec_platform - ChromeOS EC platform information
@@ -269,6 +278,15 @@ int cros_ec_register(struct cros_ec_device *ec_dev);
*/
int cros_ec_query_all(struct cros_ec_device *ec_dev);
+/**
+ * cros_ec_get_next_event - Fetch next event from the ChromeOS EC
+ *
+ * @ec_dev: Device to fetch event from
+ *
+ * Returns: 0 on success, Linux error number on failure
+ */
+int cros_ec_get_next_event(struct cros_ec_device *ec_dev);
+
/* sysfs stuff */
extern struct attribute_group cros_ec_attr_group;
extern struct attribute_group cros_ec_lightbar_attr_group;
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index 7e7a8d4b4551..76728ff37d01 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -1793,6 +1793,40 @@ struct ec_result_keyscan_seq_ctrl {
};
} __packed;
+/*
+ * Command for retrieving the next pending MKBP event from the EC device
+ *
+ * The device replies with UNAVAILABLE if there aren't any pending events.
+ */
+#define EC_CMD_GET_NEXT_EVENT 0x67
+
+enum ec_mkbp_event {
+ /* Keyboard matrix changed. The event data is the new matrix state. */
+ EC_MKBP_EVENT_KEY_MATRIX = 0,
+
+ /* New host event. The event data is 4 bytes of host event flags. */
+ EC_MKBP_EVENT_HOST_EVENT = 1,
+
+ /* New Sensor FIFO data. The event data is fifo_info structure. */
+ EC_MKBP_EVENT_SENSOR_FIFO = 2,
+
+ /* Number of MKBP events */
+ EC_MKBP_EVENT_COUNT,
+};
+
+union ec_response_get_next_data {
+ uint8_t key_matrix[13];
+
+ /* Unaligned */
+ uint32_t host_event;
+} __packed;
+
+struct ec_response_get_next_event {
+ uint8_t event_type;
+ /* Followed by event data if any */
+ union ec_response_get_next_data data;
+} __packed;
+
/*****************************************************************************/
/* Temperature sensor commands */
diff --git a/include/linux/mfd/da9063/core.h b/include/linux/mfd/da9063/core.h
index 621af82123c6..f3ae65db4c86 100644
--- a/include/linux/mfd/da9063/core.h
+++ b/include/linux/mfd/da9063/core.h
@@ -3,8 +3,8 @@
*
* Copyright 2012 Dialog Semiconductor Ltd.
*
- * Author: Michal Hajduk <michal.hajduk@diasemi.com>
- * Krystian Garbaciak <krystian.garbaciak@diasemi.com>
+ * Author: Michal Hajduk, Dialog Semiconductor
+ * Author: Krystian Garbaciak, Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/include/linux/mfd/da9063/pdata.h b/include/linux/mfd/da9063/pdata.h
index 612383bd80ae..8a125701ef7b 100644
--- a/include/linux/mfd/da9063/pdata.h
+++ b/include/linux/mfd/da9063/pdata.h
@@ -3,8 +3,8 @@
*
* Copyright 2012 Dialog Semiconductor Ltd.
*
- * Author: Michal Hajduk <michal.hajduk@diasemi.com>
- * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
+ * Author: Michal Hajduk, Dialog Semiconductor
+ * Author: Krystian Garbaciak, Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/include/linux/mfd/da9063/registers.h b/include/linux/mfd/da9063/registers.h
index 2e0ba6d5fbc3..5d42859cb441 100644
--- a/include/linux/mfd/da9063/registers.h
+++ b/include/linux/mfd/da9063/registers.h
@@ -3,8 +3,8 @@
*
* Copyright 2012 Dialog Semiconductor Ltd.
*
- * Author: Michal Hajduk <michal.hajduk@diasemi.com>
- * Krystian Garbaciak <krystian.garbaciak@diasemi.com>
+ * Author: Michal Hajduk, Dialog Semiconductor
+ * Author: Krystian Garbaciak, Dialog Semiconductor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
index 0bd69446bb05..7ba67b55b312 100644
--- a/include/linux/mfd/db8500-prcmu.h
+++ b/include/linux/mfd/db8500-prcmu.h
@@ -538,7 +538,6 @@ int db8500_prcmu_get_arm_opp(void);
int db8500_prcmu_set_ape_opp(u8 opp);
int db8500_prcmu_get_ape_opp(void);
int db8500_prcmu_request_ape_opp_100_voltage(bool enable);
-int db8500_prcmu_set_ddr_opp(u8 opp);
int db8500_prcmu_get_ddr_opp(void);
u32 db8500_prcmu_read(unsigned int reg);
@@ -594,11 +593,6 @@ static inline int prcmu_release_usb_wakeup_state(void)
return 0;
}
-static inline int db8500_prcmu_set_ddr_opp(u8 opp)
-{
- return 0;
-}
-
static inline int db8500_prcmu_get_ddr_opp(void)
{
return DDR_100_OPP;
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index 5d374601404c..2e2c6a63a065 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -269,10 +269,6 @@ unsigned long prcmu_clock_rate(u8 clock);
long prcmu_round_clock_rate(u8 clock, unsigned long rate);
int prcmu_set_clock_rate(u8 clock, unsigned long rate);
-static inline int prcmu_set_ddr_opp(u8 opp)
-{
- return db8500_prcmu_set_ddr_opp(opp);
-}
static inline int prcmu_get_ddr_opp(void)
{
return db8500_prcmu_get_ddr_opp();
@@ -489,11 +485,6 @@ static inline int prcmu_get_arm_opp(void)
return ARM_100_OPP;
}
-static inline int prcmu_set_ddr_opp(u8 opp)
-{
- return 0;
-}
-
static inline int prcmu_get_ddr_opp(void)
{
return DDR_100_OPP;
diff --git a/include/linux/mfd/lp873x.h b/include/linux/mfd/lp873x.h
index 83b1bd7588be..edbec8350a49 100644
--- a/include/linux/mfd/lp873x.h
+++ b/include/linux/mfd/lp873x.h
@@ -263,7 +263,6 @@ enum lp873x_regulator_id {
struct lp873x {
struct device *dev;
u8 rev;
- struct mutex lock; /* lock guarding the data structure */
struct regmap *regmap;
};
#endif /* __LINUX_MFD_LP873X_H */
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index f01c1fae4d84..df75234f979d 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.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
diff --git a/include/linux/mfd/max14577.h b/include/linux/mfd/max14577.h
index ccfaf952c31b..d81b52bb8bee 100644
--- a/include/linux/mfd/max14577.h
+++ b/include/linux/mfd/max14577.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.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
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
index 441b6ee72691..6d435a3c06bc 100644
--- a/include/linux/mfd/rk808.h
+++ b/include/linux/mfd/rk808.h
@@ -1,11 +1,15 @@
/*
- * rk808.h for Rockchip RK808
+ * Register definitions for Rockchip's RK808/RK818 PMIC
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
* Author: Chris Zhong <zyw@rock-chips.com>
* Author: Zhang Qing <zhangqing@rock-chips.com>
*
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ *
* 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.
@@ -16,8 +20,8 @@
* more details.
*/
-#ifndef __LINUX_REGULATOR_rk808_H
-#define __LINUX_REGULATOR_rk808_H
+#ifndef __LINUX_REGULATOR_RK808_H
+#define __LINUX_REGULATOR_RK808_H
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
@@ -28,7 +32,7 @@
#define RK808_DCDC1 0 /* (0+RK808_START) */
#define RK808_LDO1 4 /* (4+RK808_START) */
-#define RK808_NUM_REGULATORS 14
+#define RK808_NUM_REGULATORS 14
enum rk808_reg {
RK808_ID_DCDC1,
@@ -65,6 +69,8 @@ enum rk808_reg {
#define RK808_RTC_INT_REG 0x12
#define RK808_RTC_COMP_LSB_REG 0x13
#define RK808_RTC_COMP_MSB_REG 0x14
+#define RK808_ID_MSB 0x17
+#define RK808_ID_LSB 0x18
#define RK808_CLK32OUT_REG 0x20
#define RK808_VB_MON_REG 0x21
#define RK808_THERMAL_REG 0x22
@@ -115,7 +121,92 @@ enum rk808_reg {
#define RK808_INT_STS_MSK_REG2 0x4f
#define RK808_IO_POL_REG 0x50
-/* IRQ Definitions */
+/* RK818 */
+#define RK818_DCDC1 0
+#define RK818_LDO1 4
+#define RK818_NUM_REGULATORS 17
+
+enum rk818_reg {
+ RK818_ID_DCDC1,
+ RK818_ID_DCDC2,
+ RK818_ID_DCDC3,
+ RK818_ID_DCDC4,
+ RK818_ID_BOOST,
+ RK818_ID_LDO1,
+ RK818_ID_LDO2,
+ RK818_ID_LDO3,
+ RK818_ID_LDO4,
+ RK818_ID_LDO5,
+ RK818_ID_LDO6,
+ RK818_ID_LDO7,
+ RK818_ID_LDO8,
+ RK818_ID_LDO9,
+ RK818_ID_SWITCH,
+ RK818_ID_HDMI_SWITCH,
+ RK818_ID_OTG_SWITCH,
+};
+
+#define RK818_DCDC_EN_REG 0x23
+#define RK818_LDO_EN_REG 0x24
+#define RK818_SLEEP_SET_OFF_REG1 0x25
+#define RK818_SLEEP_SET_OFF_REG2 0x26
+#define RK818_DCDC_UV_STS_REG 0x27
+#define RK818_DCDC_UV_ACT_REG 0x28
+#define RK818_LDO_UV_STS_REG 0x29
+#define RK818_LDO_UV_ACT_REG 0x2a
+#define RK818_DCDC_PG_REG 0x2b
+#define RK818_LDO_PG_REG 0x2c
+#define RK818_VOUT_MON_TDB_REG 0x2d
+#define RK818_BUCK1_CONFIG_REG 0x2e
+#define RK818_BUCK1_ON_VSEL_REG 0x2f
+#define RK818_BUCK1_SLP_VSEL_REG 0x30
+#define RK818_BUCK2_CONFIG_REG 0x32
+#define RK818_BUCK2_ON_VSEL_REG 0x33
+#define RK818_BUCK2_SLP_VSEL_REG 0x34
+#define RK818_BUCK3_CONFIG_REG 0x36
+#define RK818_BUCK4_CONFIG_REG 0x37
+#define RK818_BUCK4_ON_VSEL_REG 0x38
+#define RK818_BUCK4_SLP_VSEL_REG 0x39
+#define RK818_BOOST_CONFIG_REG 0x3a
+#define RK818_LDO1_ON_VSEL_REG 0x3b
+#define RK818_LDO1_SLP_VSEL_REG 0x3c
+#define RK818_LDO2_ON_VSEL_REG 0x3d
+#define RK818_LDO2_SLP_VSEL_REG 0x3e
+#define RK818_LDO3_ON_VSEL_REG 0x3f
+#define RK818_LDO3_SLP_VSEL_REG 0x40
+#define RK818_LDO4_ON_VSEL_REG 0x41
+#define RK818_LDO4_SLP_VSEL_REG 0x42
+#define RK818_LDO5_ON_VSEL_REG 0x43
+#define RK818_LDO5_SLP_VSEL_REG 0x44
+#define RK818_LDO6_ON_VSEL_REG 0x45
+#define RK818_LDO6_SLP_VSEL_REG 0x46
+#define RK818_LDO7_ON_VSEL_REG 0x47
+#define RK818_LDO7_SLP_VSEL_REG 0x48
+#define RK818_LDO8_ON_VSEL_REG 0x49
+#define RK818_LDO8_SLP_VSEL_REG 0x4a
+#define RK818_BOOST_LDO9_ON_VSEL_REG 0x54
+#define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55
+#define RK818_DEVCTRL_REG 0x4b
+#define RK818_INT_STS_REG1 0X4c
+#define RK818_INT_STS_MSK_REG1 0x4d
+#define RK818_INT_STS_REG2 0x4e
+#define RK818_INT_STS_MSK_REG2 0x4f
+#define RK818_IO_POL_REG 0x50
+#define RK818_H5V_EN_REG 0x52
+#define RK818_SLEEP_SET_OFF_REG3 0x53
+#define RK818_BOOST_LDO9_ON_VSEL_REG 0x54
+#define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55
+#define RK818_BOOST_CTRL_REG 0x56
+#define RK818_DCDC_ILMAX 0x90
+#define RK818_USB_CTRL_REG 0xa1
+
+#define RK818_H5V_EN BIT(0)
+#define RK818_REF_RDY_CTRL BIT(1)
+#define RK818_USB_ILIM_SEL_MASK 0xf
+#define RK818_USB_ILMIN_2000MA 0x7
+#define RK818_USB_CHG_SD_VSEL_MASK 0x70
+
+/* RK808 IRQ Definitions */
#define RK808_IRQ_VOUT_LO 0
#define RK808_IRQ_VB_LO 1
#define RK808_IRQ_PWRON 2
@@ -137,6 +228,43 @@ enum rk808_reg {
#define RK808_IRQ_PLUG_IN_INT_MSK BIT(0)
#define RK808_IRQ_PLUG_OUT_INT_MSK BIT(1)
+/* RK818 IRQ Definitions */
+#define RK818_IRQ_VOUT_LO 0
+#define RK818_IRQ_VB_LO 1
+#define RK818_IRQ_PWRON 2
+#define RK818_IRQ_PWRON_LP 3
+#define RK818_IRQ_HOTDIE 4
+#define RK818_IRQ_RTC_ALARM 5
+#define RK818_IRQ_RTC_PERIOD 6
+#define RK818_IRQ_USB_OV 7
+#define RK818_IRQ_PLUG_IN 8
+#define RK818_IRQ_PLUG_OUT 9
+#define RK818_IRQ_CHG_OK 10
+#define RK818_IRQ_CHG_TE 11
+#define RK818_IRQ_CHG_TS1 12
+#define RK818_IRQ_TS2 13
+#define RK818_IRQ_CHG_CVTLIM 14
+#define RK818_IRQ_DISCHG_ILIM 15
+
+#define RK818_IRQ_VOUT_LO_MSK BIT(0)
+#define RK818_IRQ_VB_LO_MSK BIT(1)
+#define RK818_IRQ_PWRON_MSK BIT(2)
+#define RK818_IRQ_PWRON_LP_MSK BIT(3)
+#define RK818_IRQ_HOTDIE_MSK BIT(4)
+#define RK818_IRQ_RTC_ALARM_MSK BIT(5)
+#define RK818_IRQ_RTC_PERIOD_MSK BIT(6)
+#define RK818_IRQ_USB_OV_MSK BIT(7)
+#define RK818_IRQ_PLUG_IN_MSK BIT(0)
+#define RK818_IRQ_PLUG_OUT_MSK BIT(1)
+#define RK818_IRQ_CHG_OK_MSK BIT(2)
+#define RK818_IRQ_CHG_TE_MSK BIT(3)
+#define RK818_IRQ_CHG_TS1_MSK BIT(4)
+#define RK818_IRQ_TS2_MSK BIT(5)
+#define RK818_IRQ_CHG_CVTLIM_MSK BIT(6)
+#define RK818_IRQ_DISCHG_ILIM_MSK BIT(7)
+
+#define RK818_NUM_IRQ 16
+
#define RK808_VBAT_LOW_2V8 0x00
#define RK808_VBAT_LOW_2V9 0x01
#define RK808_VBAT_LOW_3V0 0x02
@@ -191,9 +319,17 @@ enum {
BOOST_ILMIN_250MA,
};
+enum {
+ RK808_ID = 0x0000,
+ RK818_ID = 0x8181,
+};
+
struct rk808 {
- struct i2c_client *i2c;
- struct regmap_irq_chip_data *irq_data;
- struct regmap *regmap;
+ struct i2c_client *i2c;
+ struct regmap_irq_chip_data *irq_data;
+ struct regmap *regmap;
+ long variant;
+ const struct regmap_config *regmap_cfg;
+ const struct regmap_irq_chip *regmap_irq_chip;
};
-#endif /* __LINUX_REGULATOR_rk808_H */
+#endif /* __LINUX_REGULATOR_RK808_H */
diff --git a/include/linux/mfd/syscon/exynos5-pmu.h b/include/linux/mfd/syscon/exynos5-pmu.h
index 76f30f940c70..c28ff21ca4d2 100644
--- a/include/linux/mfd/syscon/exynos5-pmu.h
+++ b/include/linux/mfd/syscon/exynos5-pmu.h
@@ -43,8 +43,10 @@
#define EXYNOS5433_MIPI_PHY2_CONTROL (0x718)
#define EXYNOS5_PHY_ENABLE BIT(0)
-
#define EXYNOS5_MIPI_PHY_S_RESETN BIT(1)
#define EXYNOS5_MIPI_PHY_M_RESETN BIT(2)
+#define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028)
+#define EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR BIT(28)
+
#endif /* _LINUX_MFD_SYSCON_PMU_EXYNOS5_H_ */
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index 1c88231496d3..4ccda8969639 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -73,6 +73,7 @@
#define TPS65217_PPATH_AC_CURRENT_MASK 0x0C
#define TPS65217_PPATH_USB_CURRENT_MASK 0x03
+#define TPS65217_INT_RESERVEDM BIT(7)
#define TPS65217_INT_PBM BIT(6)
#define TPS65217_INT_ACM BIT(5)
#define TPS65217_INT_USBM BIT(4)
@@ -233,6 +234,13 @@ struct tps65217_bl_pdata {
int dft_brightness;
};
+enum tps65217_irq_type {
+ TPS65217_IRQ_PB,
+ TPS65217_IRQ_AC,
+ TPS65217_IRQ_USB,
+ TPS65217_NUM_IRQ
+};
+
/**
* struct tps65217_board - packages regulator init data
* @tps65217_regulator_data: regulator initialization values
@@ -258,6 +266,10 @@ struct tps65217 {
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
struct regmap *regmap;
u8 *strobes;
+ struct irq_domain *irq_domain;
+ struct mutex irq_lock;
+ u8 irq_mask;
+ int irq;
};
static inline struct tps65217 *dev_to_tps65217(struct device *dev)
diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h
index 36795a1be479..a2e88761c09f 100644
--- a/include/linux/mfd/twl6040.h
+++ b/include/linux/mfd/twl6040.h
@@ -168,7 +168,7 @@
#define TWL6040_VIBROCDET 0x20
#define TWL6040_TSHUTDET 0x40
-#define TWL6040_CELLS 3
+#define TWL6040_CELLS 4
#define TWL6040_REV_ES1_0 0x00
#define TWL6040_REV_ES1_1 0x01 /* Rev ES1.1 and ES1.2 */
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 59b50d3eedb4..f6a164297358 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -71,7 +71,8 @@ enum {
MLX4_FLAG_SLAVE = 1 << 3,
MLX4_FLAG_SRIOV = 1 << 4,
MLX4_FLAG_OLD_REG_MAC = 1 << 6,
- MLX4_FLAG_BONDED = 1 << 7
+ MLX4_FLAG_BONDED = 1 << 7,
+ MLX4_FLAG_SECURE_HOST = 1 << 8,
};
enum {
@@ -222,6 +223,7 @@ enum {
MLX4_DEV_CAP_FLAG2_DMFS_UC_MC_SNIFFER = 1ULL << 34,
MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT = 1ULL << 35,
MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP = 1ULL << 36,
+ MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT = 1ULL << 37,
};
enum {
@@ -449,6 +451,7 @@ enum {
MLX4_DEV_PMC_SUBTYPE_GUID_INFO = 0x14,
MLX4_DEV_PMC_SUBTYPE_PORT_INFO = 0x15,
MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE = 0x16,
+ MLX4_DEV_PMC_SUBTYPE_SL_TO_VL_MAP = 0x17,
};
/* Port mgmt change event handling */
@@ -460,6 +463,11 @@ enum {
MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK = 1 << 4,
};
+union sl2vl_tbl_to_u64 {
+ u8 sl8[8];
+ u64 sl64;
+};
+
enum {
MLX4_DEVICE_STATE_UP = 1 << 0,
MLX4_DEVICE_STATE_INTERNAL_ERROR = 1 << 1,
@@ -946,6 +954,9 @@ struct mlx4_eqe {
__be32 block_ptr;
__be32 tbl_entries_mask;
} __packed tbl_change_info;
+ struct {
+ u8 sl2vl_table[8];
+ } __packed sl2vl_tbl_change_info;
} params;
} __packed port_mgmt_change;
struct {
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5f14534f0c90..e9caec6a51e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -126,7 +126,7 @@ extern int overcommit_kbytes_handler(struct ctl_table *, int, void __user *,
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)
/* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */
-#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)addr, PAGE_SIZE)
+#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE)
/*
* Linux kernel virtual memory manager primitives.
@@ -1048,28 +1048,16 @@ struct address_space *page_file_mapping(struct page *page)
return page->mapping;
}
-/*
- * Return the pagecache index of the passed page. Regular pagecache pages
- * use ->index whereas swapcache pages use ->private
- */
-static inline pgoff_t page_index(struct page *page)
-{
- if (unlikely(PageSwapCache(page)))
- return page_private(page);
- return page->index;
-}
-
extern pgoff_t __page_file_index(struct page *page);
/*
- * Return the file index of the page. Regular pagecache pages use ->index
- * whereas swapcache pages use swp_offset(->private)
+ * Return the pagecache index of the passed page. Regular pagecache pages
+ * use ->index whereas swapcache pages use swp_offset(->private)
*/
-static inline pgoff_t page_file_index(struct page *page)
+static inline pgoff_t page_index(struct page *page)
{
if (unlikely(PageSwapCache(page)))
return __page_file_index(page);
-
return page->index;
}
@@ -1197,10 +1185,10 @@ void unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
* @pte_hole: if set, called for each hole at all levels
* @hugetlb_entry: if set, called for each hugetlb entry
* @test_walk: caller specific callback function to determine whether
- * we walk over the current vma or not. A positive returned
+ * we walk over the current vma or not. Returning 0
* value means "do page table walk over the current vma,"
* and a negative one means "abort current page table walk
- * right now." 0 means "skip the current vma."
+ * right now." 1 means "skip the current vma."
* @mm: mm_struct representing the target process of page table walk
* @vma: vma currently walked (NULL if walking outside vmas)
* @private: private data for callbacks' usage
@@ -1529,7 +1517,7 @@ static inline int pte_devmap(pte_t pte)
}
#endif
-int vma_wants_writenotify(struct vm_area_struct *vma);
+int vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot);
extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
spinlock_t **ptl);
@@ -1924,10 +1912,12 @@ extern void show_mem(unsigned int flags);
extern long si_mem_available(void);
extern void si_meminfo(struct sysinfo * val);
extern void si_meminfo_node(struct sysinfo *val, int nid);
+#ifdef __HAVE_ARCH_RESERVED_KERNEL_PAGES
+extern unsigned long arch_reserved_kernel_pages(void);
+#endif
-extern __printf(3, 4)
-void warn_alloc_failed(gfp_t gfp_mask, unsigned int order,
- const char *fmt, ...);
+extern __printf(2, 3)
+void warn_alloc(gfp_t gfp_mask, const char *fmt, ...);
extern void setup_per_cpu_pageset(void);
@@ -1977,8 +1967,14 @@ void anon_vma_interval_tree_verify(struct anon_vma_chain *node);
/* mmap.c */
extern int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin);
-extern int vma_adjust(struct vm_area_struct *vma, unsigned long start,
- unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert);
+extern int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert,
+ struct vm_area_struct *expand);
+static inline int vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert)
+{
+ return __vma_adjust(vma, start, end, pgoff, insert, NULL);
+}
extern struct vm_area_struct *vma_merge(struct mm_struct *,
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 903200f4ec41..4a8acedf4b7d 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -515,9 +515,7 @@ struct mm_struct {
#ifdef CONFIG_HUGETLB_PAGE
atomic_long_t hugetlb_usage;
#endif
-#ifdef CONFIG_MMU
struct work_struct async_put_work;
-#endif
};
static inline void mm_init_cpumask(struct mm_struct *mm)
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 29a170612203..13f8052b9ff9 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -127,6 +127,82 @@ struct mtd_ooblayout_ops {
struct mtd_oob_region *oobfree);
};
+/**
+ * struct mtd_pairing_info - page pairing information
+ *
+ * @pair: pair id
+ * @group: group id
+ *
+ * The term "pair" is used here, even though TLC NANDs might group pages by 3
+ * (3 bits in a single cell). A pair should regroup all pages that are sharing
+ * the same cell. Pairs are then indexed in ascending order.
+ *
+ * @group is defining the position of a page in a given pair. It can also be
+ * seen as the bit position in the cell: page attached to bit 0 belongs to
+ * group 0, page attached to bit 1 belongs to group 1, etc.
+ *
+ * Example:
+ * The H27UCG8T2BTR-BC datasheet describes the following pairing scheme:
+ *
+ * group-0 group-1
+ *
+ * pair-0 page-0 page-4
+ * pair-1 page-1 page-5
+ * pair-2 page-2 page-8
+ * ...
+ * pair-127 page-251 page-255
+ *
+ *
+ * Note that the "group" and "pair" terms were extracted from Samsung and
+ * Hynix datasheets, and might be referenced under other names in other
+ * datasheets (Micron is describing this concept as "shared pages").
+ */
+struct mtd_pairing_info {
+ int pair;
+ int group;
+};
+
+/**
+ * struct mtd_pairing_scheme - page pairing scheme description
+ *
+ * @ngroups: number of groups. Should be related to the number of bits
+ * per cell.
+ * @get_info: converts a write-unit (page number within an erase block) into
+ * mtd_pairing information (pair + group). This function should
+ * fill the info parameter based on the wunit index or return
+ * -EINVAL if the wunit parameter is invalid.
+ * @get_wunit: converts pairing information into a write-unit (page) number.
+ * This function should return the wunit index pointed by the
+ * pairing information described in the info argument. It should
+ * return -EINVAL, if there's no wunit corresponding to the
+ * passed pairing information.
+ *
+ * See mtd_pairing_info documentation for a detailed explanation of the
+ * pair and group concepts.
+ *
+ * The mtd_pairing_scheme structure provides a generic solution to represent
+ * NAND page pairing scheme. Instead of exposing two big tables to do the
+ * write-unit <-> (pair + group) conversions, we ask the MTD drivers to
+ * implement the ->get_info() and ->get_wunit() functions.
+ *
+ * MTD users will then be able to query these information by using the
+ * mtd_pairing_info_to_wunit() and mtd_wunit_to_pairing_info() helpers.
+ *
+ * @ngroups is here to help MTD users iterating over all the pages in a
+ * given pair. This value can be retrieved by MTD users using the
+ * mtd_pairing_groups() helper.
+ *
+ * Examples are given in the mtd_pairing_info_to_wunit() and
+ * mtd_wunit_to_pairing_info() documentation.
+ */
+struct mtd_pairing_scheme {
+ int ngroups;
+ int (*get_info)(struct mtd_info *mtd, int wunit,
+ struct mtd_pairing_info *info);
+ int (*get_wunit)(struct mtd_info *mtd,
+ const struct mtd_pairing_info *info);
+};
+
struct module; /* only needed for owner field in mtd_info */
struct mtd_info {
@@ -188,6 +264,9 @@ struct mtd_info {
/* OOB layout description */
const struct mtd_ooblayout_ops *ooblayout;
+ /* NAND pairing scheme, only provided for MLC/TLC NANDs */
+ const struct mtd_pairing_scheme *pairing;
+
/* the ecc step size. */
unsigned int ecc_step_size;
@@ -296,6 +375,12 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
mtd->ooblayout = ooblayout;
}
+static inline void mtd_set_pairing_scheme(struct mtd_info *mtd,
+ const struct mtd_pairing_scheme *pairing)
+{
+ mtd->pairing = pairing;
+}
+
static inline void mtd_set_of_node(struct mtd_info *mtd,
struct device_node *np)
{
@@ -312,6 +397,11 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
}
+int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
+ struct mtd_pairing_info *info);
+int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
+ const struct mtd_pairing_info *info);
+int mtd_pairing_groups(struct mtd_info *mtd);
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
void **virt, resource_size_t *phys);
@@ -397,6 +487,23 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
return do_div(sz, mtd->writesize);
}
+static inline int mtd_wunit_per_eb(struct mtd_info *mtd)
+{
+ return mtd->erasesize / mtd->writesize;
+}
+
+static inline int mtd_offset_to_wunit(struct mtd_info *mtd, loff_t offs)
+{
+ return mtd_div_by_ws(mtd_mod_by_eb(offs, mtd), mtd);
+}
+
+static inline loff_t mtd_wunit_to_offset(struct mtd_info *mtd, loff_t base,
+ int wunit)
+{
+ return base + (wunit * mtd->writesize);
+}
+
+
static inline int mtd_has_oob(const struct mtd_info *mtd)
{
return mtd->_read_oob && mtd->_write_oob;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8dd6e01f45c0..c5d3d5024fc8 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -29,26 +29,26 @@ struct nand_flash_dev;
struct device_node;
/* Scan and identify a NAND device */
-extern int nand_scan(struct mtd_info *mtd, int max_chips);
+int nand_scan(struct mtd_info *mtd, int max_chips);
/*
* Separate phases of nand_scan(), allowing board driver to intervene
* and override command or ECC setup according to flash type.
*/
-extern int nand_scan_ident(struct mtd_info *mtd, int max_chips,
+int nand_scan_ident(struct mtd_info *mtd, int max_chips,
struct nand_flash_dev *table);
-extern int nand_scan_tail(struct mtd_info *mtd);
+int nand_scan_tail(struct mtd_info *mtd);
-/* Free resources held by the NAND device */
-extern void nand_release(struct mtd_info *mtd);
+/* Unregister the MTD device and free resources held by the NAND device */
+void nand_release(struct mtd_info *mtd);
/* Internal helper for board drivers which need to override command function */
-extern void nand_wait_ready(struct mtd_info *mtd);
+void nand_wait_ready(struct mtd_info *mtd);
/* locks all blocks present in the device */
-extern int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
/* unlocks specified locked blocks */
-extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
/* The maximum number of NAND chips in an array */
#define NAND_MAX_CHIPS 8
@@ -141,6 +141,7 @@ enum nand_ecc_algo {
* pages and you want to rely on the default implementation.
*/
#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
+#define NAND_ECC_MAXIMIZE BIT(1)
/* Bit mask for flags passed to do_nand_read_ecc */
#define NAND_GET_DEVICE 0x80
@@ -460,6 +461,13 @@ struct nand_hw_control {
wait_queue_head_t wq;
};
+static inline void nand_hw_control_init(struct nand_hw_control *nfc)
+{
+ nfc->active = NULL;
+ spin_lock_init(&nfc->lock);
+ init_waitqueue_head(&nfc->wq);
+}
+
/**
* struct nand_ecc_ctrl - Control structure for ECC
* @mode: ECC mode
@@ -566,6 +574,123 @@ struct nand_buffers {
};
/**
+ * struct nand_sdr_timings - SDR NAND chip timings
+ *
+ * This struct defines the timing requirements of a SDR NAND chip.
+ * These information can be found in every NAND datasheets and the timings
+ * meaning are described in the ONFI specifications:
+ * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
+ * Parameters)
+ *
+ * All these timings are expressed in picoseconds.
+ *
+ * @tALH_min: ALE hold time
+ * @tADL_min: ALE to data loading time
+ * @tALS_min: ALE setup time
+ * @tAR_min: ALE to RE# delay
+ * @tCEA_max: CE# access time
+ * @tCEH_min:
+ * @tCH_min: CE# hold time
+ * @tCHZ_max: CE# high to output hi-Z
+ * @tCLH_min: CLE hold time
+ * @tCLR_min: CLE to RE# delay
+ * @tCLS_min: CLE setup time
+ * @tCOH_min: CE# high to output hold
+ * @tCS_min: CE# setup time
+ * @tDH_min: Data hold time
+ * @tDS_min: Data setup time
+ * @tFEAT_max: Busy time for Set Features and Get Features
+ * @tIR_min: Output hi-Z to RE# low
+ * @tITC_max: Interface and Timing Mode Change time
+ * @tRC_min: RE# cycle time
+ * @tREA_max: RE# access time
+ * @tREH_min: RE# high hold time
+ * @tRHOH_min: RE# high to output hold
+ * @tRHW_min: RE# high to WE# low
+ * @tRHZ_max: RE# high to output hi-Z
+ * @tRLOH_min: RE# low to output hold
+ * @tRP_min: RE# pulse width
+ * @tRR_min: Ready to RE# low (data only)
+ * @tRST_max: Device reset time, measured from the falling edge of R/B# to the
+ * rising edge of R/B#.
+ * @tWB_max: WE# high to SR[6] low
+ * @tWC_min: WE# cycle time
+ * @tWH_min: WE# high hold time
+ * @tWHR_min: WE# high to RE# low
+ * @tWP_min: WE# pulse width
+ * @tWW_min: WP# transition to WE# low
+ */
+struct nand_sdr_timings {
+ u32 tALH_min;
+ u32 tADL_min;
+ u32 tALS_min;
+ u32 tAR_min;
+ u32 tCEA_max;
+ u32 tCEH_min;
+ u32 tCH_min;
+ u32 tCHZ_max;
+ u32 tCLH_min;
+ u32 tCLR_min;
+ u32 tCLS_min;
+ u32 tCOH_min;
+ u32 tCS_min;
+ u32 tDH_min;
+ u32 tDS_min;
+ u32 tFEAT_max;
+ u32 tIR_min;
+ u32 tITC_max;
+ u32 tRC_min;
+ u32 tREA_max;
+ u32 tREH_min;
+ u32 tRHOH_min;
+ u32 tRHW_min;
+ u32 tRHZ_max;
+ u32 tRLOH_min;
+ u32 tRP_min;
+ u32 tRR_min;
+ u64 tRST_max;
+ u32 tWB_max;
+ u32 tWC_min;
+ u32 tWH_min;
+ u32 tWHR_min;
+ u32 tWP_min;
+ u32 tWW_min;
+};
+
+/**
+ * enum nand_data_interface_type - NAND interface timing type
+ * @NAND_SDR_IFACE: Single Data Rate interface
+ */
+enum nand_data_interface_type {
+ NAND_SDR_IFACE,
+};
+
+/**
+ * struct nand_data_interface - NAND interface timing
+ * @type: type of the timing
+ * @timings: The timing, type according to @type
+ */
+struct nand_data_interface {
+ enum nand_data_interface_type type;
+ union {
+ struct nand_sdr_timings sdr;
+ } timings;
+};
+
+/**
+ * nand_get_sdr_timings - get SDR timing from data interface
+ * @conf: The data interface
+ */
+static inline const struct nand_sdr_timings *
+nand_get_sdr_timings(const struct nand_data_interface *conf)
+{
+ if (conf->type != NAND_SDR_IFACE)
+ return ERR_PTR(-EINVAL);
+
+ return &conf->timings.sdr;
+}
+
+/**
* struct nand_chip - NAND Private Flash Chip Data
* @mtd: MTD device registered to the MTD framework
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
@@ -627,10 +752,9 @@ struct nand_buffers {
* also from the datasheet. It is the recommended ECC step
* size, if known; if unknown, set to zero.
* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
- * either deduced from the datasheet if the NAND
- * chip is not ONFI compliant or set to 0 if it is
- * (an ONFI chip is always configured in mode 0
- * after a NAND reset)
+ * set to the actually used ONFI mode if the chip is
+ * ONFI compliant or deduced from the datasheet if
+ * the NAND chip is not ONFI compliant.
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
@@ -650,6 +774,7 @@ struct nand_buffers {
* @read_retries: [INTERN] the number of read retry modes supported
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
+ * @setup_data_interface: [OPTIONAL] setup the data interface and timing
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup.
@@ -696,6 +821,10 @@ struct nand_chip {
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
+ int (*setup_data_interface)(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only);
+
int chip_delay;
unsigned int options;
@@ -725,6 +854,8 @@ struct nand_chip {
struct nand_jedec_params jedec_params;
};
+ struct nand_data_interface *data_interface;
+
int read_retries;
flstate_t state;
@@ -893,14 +1024,14 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
-extern int nand_default_bbt(struct mtd_info *mtd);
-extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
-extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
-extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
-extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
- int allowbbt);
-extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, uint8_t *buf);
+int nand_default_bbt(struct mtd_info *mtd);
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
+int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
+int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
+int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+ int allowbbt);
+int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, uint8_t *buf);
/**
* struct platform_nand_chip - chip level device structure
@@ -988,6 +1119,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
}
+int onfi_init_data_interface(struct nand_chip *chip,
+ struct nand_data_interface *iface,
+ enum nand_data_interface_type type,
+ int timing_mode);
+
/*
* Check if it is a SLC nand.
* The !nand_is_slc() can be used to check the MLC/TLC nand chips.
@@ -1023,57 +1159,10 @@ static inline int jedec_feature(struct nand_chip *chip)
: 0;
}
-/*
- * struct nand_sdr_timings - SDR NAND chip timings
- *
- * This struct defines the timing requirements of a SDR NAND chip.
- * These informations can be found in every NAND datasheets and the timings
- * meaning are described in the ONFI specifications:
- * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
- * Parameters)
- *
- * All these timings are expressed in picoseconds.
- */
-
-struct nand_sdr_timings {
- u32 tALH_min;
- u32 tADL_min;
- u32 tALS_min;
- u32 tAR_min;
- u32 tCEA_max;
- u32 tCEH_min;
- u32 tCH_min;
- u32 tCHZ_max;
- u32 tCLH_min;
- u32 tCLR_min;
- u32 tCLS_min;
- u32 tCOH_min;
- u32 tCS_min;
- u32 tDH_min;
- u32 tDS_min;
- u32 tFEAT_max;
- u32 tIR_min;
- u32 tITC_max;
- u32 tRC_min;
- u32 tREA_max;
- u32 tREH_min;
- u32 tRHOH_min;
- u32 tRHW_min;
- u32 tRHZ_max;
- u32 tRLOH_min;
- u32 tRP_min;
- u32 tRR_min;
- u64 tRST_max;
- u32 tWB_max;
- u32 tWC_min;
- u32 tWH_min;
- u32 tWHR_min;
- u32 tWP_min;
- u32 tWW_min;
-};
-
/* get timing characteristics from ONFI timing mode. */
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+/* get data interface from ONFI timing mode 0, used after reset. */
+const struct nand_data_interface *nand_get_default_data_interface(void);
int nand_check_erased_ecc_chunk(void *data, int datalen,
void *ecc, int ecclen,
@@ -1093,4 +1182,11 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
/* Default read_oob syndrome implementation */
int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page);
+
+/* Reset and initialize a NAND device */
+int nand_reset(struct nand_chip *chip);
+
+/* Free resources held by the NAND device */
+void nand_cleanup(struct nand_chip *chip);
+
#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 4630eeae18e0..a78c35cff1ae 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -35,21 +35,34 @@ static inline void hardlockup_detector_disable(void) {}
* base function. Return whether such support was available,
* to allow calling code to fall back to some other mechanism:
*/
-#ifdef arch_trigger_all_cpu_backtrace
+#ifdef arch_trigger_cpumask_backtrace
static inline bool trigger_all_cpu_backtrace(void)
{
- arch_trigger_all_cpu_backtrace(true);
-
+ arch_trigger_cpumask_backtrace(cpu_online_mask, false);
return true;
}
+
static inline bool trigger_allbutself_cpu_backtrace(void)
{
- arch_trigger_all_cpu_backtrace(false);
+ arch_trigger_cpumask_backtrace(cpu_online_mask, true);
+ return true;
+}
+
+static inline bool trigger_cpumask_backtrace(struct cpumask *mask)
+{
+ arch_trigger_cpumask_backtrace(mask, false);
+ return true;
+}
+
+static inline bool trigger_single_cpu_backtrace(int cpu)
+{
+ arch_trigger_cpumask_backtrace(cpumask_of(cpu), false);
return true;
}
/* generic implementation */
-void nmi_trigger_all_cpu_backtrace(bool include_self,
+void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
+ bool exclude_self,
void (*raise)(cpumask_t *mask));
bool nmi_cpu_backtrace(struct pt_regs *regs);
@@ -62,6 +75,14 @@ static inline bool trigger_allbutself_cpu_backtrace(void)
{
return false;
}
+static inline bool trigger_cpumask_backtrace(struct cpumask *mask)
+{
+ return false;
+}
+static inline bool trigger_single_cpu_backtrace(int cpu)
+{
+ return false;
+}
#endif
#ifdef CONFIG_LOCKUP_DETECTOR
diff --git a/include/linux/omap-dma.h b/include/linux/omap-dma.h
index 1d99b61adc65..290081620b3e 100644
--- a/include/linux/omap-dma.h
+++ b/include/linux/omap-dma.h
@@ -297,6 +297,7 @@ struct omap_system_dma_plat_info {
#define dma_omap15xx() __dma_omap15xx(d)
#define dma_omap16xx() __dma_omap16xx(d)
+#if defined(CONFIG_ARCH_OMAP)
extern struct omap_system_dma_plat_info *omap_get_plat_info(void);
extern void omap_set_dma_priority(int lch, int dst_port, int priority);
@@ -355,4 +356,22 @@ static inline int omap_lcd_dma_running(void)
}
#endif
+#else /* CONFIG_ARCH_OMAP */
+
+static inline struct omap_system_dma_plat_info *omap_get_plat_info(void)
+{
+ return NULL;
+}
+
+static inline int omap_request_dma(int dev_id, const char *dev_name,
+ void (*callback)(int lch, u16 ch_status, void *data),
+ void *data, int *dma_ch)
+{
+ return -ENODEV;
+}
+
+static inline void omap_free_dma(int ch) { }
+
+#endif /* CONFIG_ARCH_OMAP */
+
#endif /* __LINUX_OMAP_DMA_H */
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index 9e9d79e8efa5..35d0fd7a4948 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -29,8 +29,8 @@ struct gpmc_nand_regs;
struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
int cs);
#else
-static inline gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
- int cs)
+static inline struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
+ int cs)
{
return NULL;
}
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 5bc0457ee3a8..b4e36e92bc87 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -34,23 +34,11 @@ struct oom_control {
* for display purposes.
*/
const int order;
-};
-
-/*
- * Types of limitations to the nodes from which allocations may occur
- */
-enum oom_constraint {
- CONSTRAINT_NONE,
- CONSTRAINT_CPUSET,
- CONSTRAINT_MEMORY_POLICY,
- CONSTRAINT_MEMCG,
-};
-enum oom_scan_t {
- OOM_SCAN_OK, /* scan thread and find its badness */
- OOM_SCAN_CONTINUE, /* do not consider thread for oom kill */
- OOM_SCAN_ABORT, /* abort the iteration and return */
- OOM_SCAN_SELECT, /* always select this thread first */
+ /* Used by oom implementation, do not set */
+ unsigned long totalpages;
+ struct task_struct *chosen;
+ unsigned long chosen_points;
};
extern struct mutex oom_lock;
@@ -70,45 +58,27 @@ static inline bool oom_task_origin(const struct task_struct *p)
return p->signal->oom_flag_origin;
}
-extern void mark_oom_victim(struct task_struct *tsk);
-
-#ifdef CONFIG_MMU
-extern void wake_oom_reaper(struct task_struct *tsk);
-#else
-static inline void wake_oom_reaper(struct task_struct *tsk)
+static inline bool tsk_is_oom_victim(struct task_struct * tsk)
{
+ return tsk->signal->oom_mm;
}
-#endif
extern unsigned long oom_badness(struct task_struct *p,
struct mem_cgroup *memcg, const nodemask_t *nodemask,
unsigned long totalpages);
-extern void oom_kill_process(struct oom_control *oc, struct task_struct *p,
- unsigned int points, unsigned long totalpages,
- const char *message);
-
-extern void check_panic_on_oom(struct oom_control *oc,
- enum oom_constraint constraint);
-
-extern enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
- struct task_struct *task);
-
extern bool out_of_memory(struct oom_control *oc);
-extern void exit_oom_victim(struct task_struct *tsk);
+extern void exit_oom_victim(void);
extern int register_oom_notifier(struct notifier_block *nb);
extern int unregister_oom_notifier(struct notifier_block *nb);
-extern bool oom_killer_disabled;
-extern bool oom_killer_disable(void);
+extern bool oom_killer_disable(signed long timeout);
extern void oom_killer_enable(void);
extern struct task_struct *find_lock_task_mm(struct task_struct *p);
-bool task_will_free_mem(struct task_struct *task);
-
/* sysctls */
extern int sysctl_oom_dump_tasks;
extern int sysctl_oom_kill_allocating_task;
diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h
index 03f2a3e7d76d..9298c393ddaa 100644
--- a/include/linux/page_ext.h
+++ b/include/linux/page_ext.h
@@ -7,6 +7,8 @@
struct pglist_data;
struct page_ext_operations {
+ size_t offset;
+ size_t size;
bool (*need)(void);
void (*init)(void);
};
@@ -42,12 +44,6 @@ enum page_ext_flags {
*/
struct page_ext {
unsigned long flags;
-#ifdef CONFIG_PAGE_OWNER
- unsigned int order;
- gfp_t gfp_mask;
- int last_migrate_reason;
- depot_stack_handle_t handle;
-#endif
};
extern void pgdat_page_ext_init(struct pglist_data *pgdat);
diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
index 30583ab0ffb1..2be728d156b5 100644
--- a/include/linux/page_owner.h
+++ b/include/linux/page_owner.h
@@ -14,6 +14,8 @@ extern void __split_page_owner(struct page *page, unsigned int order);
extern void __copy_page_owner(struct page *oldpage, struct page *newpage);
extern void __set_page_owner_migrate_reason(struct page *page, int reason);
extern void __dump_page_owner(struct page *page);
+extern void pagetypeinfo_showmixedcount_print(struct seq_file *m,
+ pg_data_t *pgdat, struct zone *zone);
static inline void reset_page_owner(struct page *page, unsigned int order)
{
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 01e84436cddf..747f401cc312 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -25,6 +25,8 @@ enum mapping_flags {
AS_MM_ALL_LOCKS = __GFP_BITS_SHIFT + 2, /* under mm_take_all_locks() */
AS_UNEVICTABLE = __GFP_BITS_SHIFT + 3, /* e.g., ramdisk, SHM_LOCK */
AS_EXITING = __GFP_BITS_SHIFT + 4, /* final truncate in progress */
+ /* writeback related tags are not used */
+ AS_NO_WRITEBACK_TAGS = __GFP_BITS_SHIFT + 5,
};
static inline void mapping_set_error(struct address_space *mapping, int error)
@@ -64,6 +66,16 @@ static inline int mapping_exiting(struct address_space *mapping)
return test_bit(AS_EXITING, &mapping->flags);
}
+static inline void mapping_set_no_writeback_tags(struct address_space *mapping)
+{
+ set_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags);
+}
+
+static inline int mapping_use_writeback_tags(struct address_space *mapping)
+{
+ return !test_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags);
+}
+
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
{
return (__force gfp_t)mapping->flags & __GFP_BITS_MASK;
@@ -396,7 +408,7 @@ static inline loff_t page_offset(struct page *page)
static inline loff_t page_file_offset(struct page *page)
{
- return ((loff_t)page_file_index(page)) << PAGE_SHIFT;
+ return ((loff_t)page_index(page)) << PAGE_SHIFT;
}
extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
@@ -518,59 +530,10 @@ void page_endio(struct page *page, bool is_write, int err);
extern void add_page_wait_queue(struct page *page, wait_queue_t *waiter);
/*
- * Fault one or two userspace pages into pagetables.
- * Return -EINVAL if more than two pages would be needed.
- * Return non-zero on a fault.
+ * Fault everything in given userspace address range in.
*/
static inline int fault_in_pages_writeable(char __user *uaddr, int size)
{
- int span, ret;
-
- if (unlikely(size == 0))
- return 0;
-
- span = offset_in_page(uaddr) + size;
- if (span > 2 * PAGE_SIZE)
- return -EINVAL;
- /*
- * Writing zeroes into userspace here is OK, because we know that if
- * the zero gets there, we'll be overwriting it.
- */
- ret = __put_user(0, uaddr);
- if (ret == 0 && span > PAGE_SIZE)
- ret = __put_user(0, uaddr + size - 1);
- return ret;
-}
-
-static inline int fault_in_pages_readable(const char __user *uaddr, int size)
-{
- volatile char c;
- int ret;
-
- if (unlikely(size == 0))
- return 0;
-
- ret = __get_user(c, uaddr);
- if (ret == 0) {
- const char __user *end = uaddr + size - 1;
-
- if (((unsigned long)uaddr & PAGE_MASK) !=
- ((unsigned long)end & PAGE_MASK)) {
- ret = __get_user(c, end);
- (void)c;
- }
- }
- return ret;
-}
-
-/*
- * Multipage variants of the above prefault helpers, useful if more than
- * PAGE_SIZE of data needs to be prefaulted. These are separate from the above
- * functions (which only handle up to PAGE_SIZE) to avoid clobbering the
- * filemap.c hotpaths.
- */
-static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
-{
char __user *end = uaddr + size - 1;
if (unlikely(size == 0))
@@ -596,8 +559,7 @@ static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
return 0;
}
-static inline int fault_in_multipages_readable(const char __user *uaddr,
- int size)
+static inline int fault_in_pages_readable(const char __user *uaddr, int size)
{
volatile char c;
const char __user *end = uaddr + size - 1;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7cc0acba8939..0e49f70dbd9b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -187,8 +187,9 @@ enum pci_irq_reroute_variant {
typedef unsigned short __bitwise pci_bus_flags_t;
enum pci_bus_flags {
- PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
- PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
+ PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
+ PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
+ PCI_BUS_FLAGS_NO_AERSID = (__force pci_bus_flags_t) 4,
};
/* These values come from the PCI Express Spec */
@@ -268,6 +269,9 @@ struct pci_dev {
unsigned int class; /* 3 bytes: (base,sub,prog-if) */
u8 revision; /* PCI revision, low byte of class word */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */
+#ifdef CONFIG_PCIEAER
+ u16 aer_cap; /* AER capability offset */
+#endif
u8 pcie_cap; /* PCIe capability offset */
u8 msi_cap; /* MSI capability offset */
u8 msix_cap; /* MSI-X capability offset */
@@ -308,6 +312,9 @@ struct pci_dev {
powered on/off by the
corresponding bridge */
unsigned int ignore_hotplug:1; /* Ignore hotplug events */
+ unsigned int hotplug_user_indicators:1; /* SlotCtl indicators
+ controlled exclusively by
+ user sysfs */
unsigned int d3_delay; /* D3->D0 transition time in ms */
unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */
@@ -367,6 +374,12 @@ struct pci_dev {
int rom_attr_enabled; /* has display of the rom attribute been enabled? */
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
+
+#ifdef CONFIG_PCIE_PTM
+ unsigned int ptm_root:1;
+ unsigned int ptm_enabled:1;
+ u8 ptm_granularity;
+#endif
#ifdef CONFIG_PCI_MSI
const struct attribute_group **msi_irq_groups;
#endif
@@ -1368,9 +1381,11 @@ static inline bool pcie_aspm_support_enabled(void) { return false; }
#ifdef CONFIG_PCIEAER
void pci_no_aer(void);
bool pci_aer_available(void);
+int pci_aer_init(struct pci_dev *dev);
#else
static inline void pci_no_aer(void) { }
static inline bool pci_aer_available(void) { return false; }
+static inline int pci_aer_init(struct pci_dev *d) { return -ENODEV; }
#endif
#ifdef CONFIG_PCIE_ECRC
@@ -1402,6 +1417,13 @@ static inline void pci_disable_ats(struct pci_dev *d) { }
static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
#endif
+#ifdef CONFIG_PCIE_PTM
+int pci_enable_ptm(struct pci_dev *dev, u8 *granularity);
+#else
+static inline int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
+{ return -EINVAL; }
+#endif
+
void pci_cfg_access_lock(struct pci_dev *dev);
bool pci_cfg_access_trylock(struct pci_dev *dev);
void pci_cfg_access_unlock(struct pci_dev *dev);
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 24f5470d3944..e7497c9dde7f 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -66,15 +66,10 @@ struct pipe_inode_info {
*
* ->confirm()
* ->steal()
- * ...
- * ->map()
- * ...
- * ->unmap()
*
- * That is, ->map() must be called on a confirmed buffer,
- * same goes for ->steal(). See below for the meaning of each
- * operation. Also see kerneldoc in fs/pipe.c for the pipe
- * and generic variants of these hooks.
+ * That is, ->steal() must be called on a confirmed buffer.
+ * See below for the meaning of each operation. Also see kerneldoc
+ * in fs/pipe.c for the pipe and generic variants of these hooks.
*/
struct pipe_buf_operations {
/*
@@ -115,6 +110,53 @@ struct pipe_buf_operations {
void (*get)(struct pipe_inode_info *, struct pipe_buffer *);
};
+/**
+ * pipe_buf_get - get a reference to a pipe_buffer
+ * @pipe: the pipe that the buffer belongs to
+ * @buf: the buffer to get a reference to
+ */
+static inline void pipe_buf_get(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+ buf->ops->get(pipe, buf);
+}
+
+/**
+ * pipe_buf_release - put a reference to a pipe_buffer
+ * @pipe: the pipe that the buffer belongs to
+ * @buf: the buffer to put a reference to
+ */
+static inline void pipe_buf_release(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+ const struct pipe_buf_operations *ops = buf->ops;
+
+ buf->ops = NULL;
+ ops->release(pipe, buf);
+}
+
+/**
+ * pipe_buf_confirm - verify contents of the pipe buffer
+ * @pipe: the pipe that the buffer belongs to
+ * @buf: the buffer to confirm
+ */
+static inline int pipe_buf_confirm(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+ return buf->ops->confirm(pipe, buf);
+}
+
+/**
+ * pipe_buf_steal - attempt to take ownership of a pipe_buffer
+ * @pipe: the pipe that the buffer belongs to
+ * @buf: the buffer to attempt to steal
+ */
+static inline int pipe_buf_steal(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+ return buf->ops->steal(pipe, buf);
+}
+
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
memory allocation, whereas PIPE_BUF makes atomicity guarantees. */
#define PIPE_SIZE PAGE_SIZE
@@ -129,7 +171,6 @@ extern unsigned long pipe_user_pages_hard;
extern unsigned long pipe_user_pages_soft;
int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *);
-
/* Drop the inode semaphore and wait for a pipe event, atomically */
void pipe_wait(struct pipe_inode_info *pipe);
diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h
index 1d405a2b7272..e4c08c1ff0c5 100644
--- a/include/linux/pkeys.h
+++ b/include/linux/pkeys.h
@@ -4,11 +4,6 @@
#include <linux/mm_types.h>
#include <asm/mmu_context.h>
-#define PKEY_DISABLE_ACCESS 0x1
-#define PKEY_DISABLE_WRITE 0x2
-#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
- PKEY_DISABLE_WRITE)
-
#ifdef CONFIG_ARCH_HAS_PKEYS
#include <asm/pkeys.h>
#else /* ! CONFIG_ARCH_HAS_PKEYS */
@@ -16,18 +11,34 @@
#define execute_only_pkey(mm) (0)
#define arch_override_mprotect_pkey(vma, prot, pkey) (0)
#define PKEY_DEDICATED_EXECUTE_ONLY 0
-#endif /* ! CONFIG_ARCH_HAS_PKEYS */
+#define ARCH_VM_PKEY_FLAGS 0
+
+static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
+{
+ return (pkey == 0);
+}
+
+static inline int mm_pkey_alloc(struct mm_struct *mm)
+{
+ return -1;
+}
-/*
- * This is called from mprotect_pkey().
- *
- * Returns true if the protection keys is valid.
- */
-static inline bool validate_pkey(int pkey)
+static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
{
- if (pkey < 0)
- return false;
- return (pkey < arch_max_pkey());
+ WARN_ONCE(1, "free of protection key when disabled");
+ return -EINVAL;
}
+static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val)
+{
+ return 0;
+}
+
+static inline void copy_init_pkru_to_fpregs(void)
+{
+}
+
+#endif /* ! CONFIG_ARCH_HAS_PKEYS */
+
#endif /* _LINUX_PKEYS_H */
diff --git a/include/linux/platform_data/dma-mmp_tdma.h b/include/linux/platform_data/dma-mmp_tdma.h
index 0c72886030ef..422d4504dbac 100644
--- a/include/linux/platform_data/dma-mmp_tdma.h
+++ b/include/linux/platform_data/dma-mmp_tdma.h
@@ -28,7 +28,7 @@ struct sram_platdata {
int granularity;
};
-#ifdef CONFIG_ARM
+#ifdef CONFIG_MMP_SRAM
extern struct gen_pool *sram_get_gpool(char *pool_name);
#else
static inline struct gen_pool *sram_get_gpool(char *pool_name)
diff --git a/include/linux/platform_data/dma-s3c24xx.h b/include/linux/platform_data/dma-s3c24xx.h
index 89ba1b0c90e4..4f9aba405e96 100644
--- a/include/linux/platform_data/dma-s3c24xx.h
+++ b/include/linux/platform_data/dma-s3c24xx.h
@@ -30,16 +30,22 @@ struct s3c24xx_dma_channel {
u16 chansel;
};
+struct dma_slave_map;
+
/**
* struct s3c24xx_dma_platdata - platform specific settings
* @num_phy_channels: number of physical channels
* @channels: array of virtual channel descriptions
* @num_channels: number of virtual channels
+ * @slave_map: dma slave map matching table
+ * @slavecnt: number of elements in slave_map
*/
struct s3c24xx_dma_platdata {
int num_phy_channels;
struct s3c24xx_dma_channel *channels;
int num_channels;
+ const struct dma_slave_map *slave_map;
+ int slavecnt;
};
struct dma_chan;
diff --git a/include/linux/platform_data/remoteproc-omap.h b/include/linux/platform_data/remoteproc-omap.h
index bfbd12b41162..71a1b2399c48 100644
--- a/include/linux/platform_data/remoteproc-omap.h
+++ b/include/linux/platform_data/remoteproc-omap.h
@@ -39,9 +39,9 @@ struct omap_rproc_pdata {
const char *firmware;
const char *mbox_name;
const struct rproc_ops *ops;
- int (*device_enable) (struct platform_device *pdev);
- int (*device_shutdown) (struct platform_device *pdev);
- void(*set_bootaddr)(u32);
+ int (*device_enable)(struct platform_device *pdev);
+ int (*device_shutdown)(struct platform_device *pdev);
+ void (*set_bootaddr)(u32);
};
#if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE)
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index d5d3d741f028..5a9a739acdd5 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -11,27 +11,7 @@
#include <linux/bug.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
-
-#define ACL_UNDEFINED_ID (-1)
-
-/* a_type field in acl_user_posix_entry_t */
-#define ACL_TYPE_ACCESS (0x8000)
-#define ACL_TYPE_DEFAULT (0x4000)
-
-/* e_tag entry in struct posix_acl_entry */
-#define ACL_USER_OBJ (0x01)
-#define ACL_USER (0x02)
-#define ACL_GROUP_OBJ (0x04)
-#define ACL_GROUP (0x08)
-#define ACL_MASK (0x10)
-#define ACL_OTHER (0x20)
-
-/* permissions in the e_perm field */
-#define ACL_READ (0x04)
-#define ACL_WRITE (0x02)
-#define ACL_EXECUTE (0x01)
-//#define ACL_ADD (0x08)
-//#define ACL_DELETE (0x10)
+#include <uapi/linux/posix_acl.h>
struct posix_acl_entry {
short e_tag;
@@ -93,6 +73,7 @@ extern int set_posix_acl(struct inode *, int, struct posix_acl *);
extern int posix_acl_chmod(struct inode *, umode_t);
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
struct posix_acl **);
+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
extern int simple_set_acl(struct inode *, struct posix_acl *, int);
extern int simple_acl_create(struct inode *, struct inode *);
diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h
index e5e8ec40278d..8b867e3bf3aa 100644
--- a/include/linux/posix_acl_xattr.h
+++ b/include/linux/posix_acl_xattr.h
@@ -10,42 +10,25 @@
#define _POSIX_ACL_XATTR_H
#include <uapi/linux/xattr.h>
+#include <uapi/linux/posix_acl_xattr.h>
#include <linux/posix_acl.h>
-/* Supported ACL a_version fields */
-#define POSIX_ACL_XATTR_VERSION 0x0002
-
-/* An undefined entry e_id value */
-#define ACL_UNDEFINED_ID (-1)
-
-typedef struct {
- __le16 e_tag;
- __le16 e_perm;
- __le32 e_id;
-} posix_acl_xattr_entry;
-
-typedef struct {
- __le32 a_version;
- posix_acl_xattr_entry a_entries[0];
-} posix_acl_xattr_header;
-
-
static inline size_t
posix_acl_xattr_size(int count)
{
- return (sizeof(posix_acl_xattr_header) +
- (count * sizeof(posix_acl_xattr_entry)));
+ return (sizeof(struct posix_acl_xattr_header) +
+ (count * sizeof(struct posix_acl_xattr_entry)));
}
static inline int
posix_acl_xattr_count(size_t size)
{
- if (size < sizeof(posix_acl_xattr_header))
+ if (size < sizeof(struct posix_acl_xattr_header))
return -1;
- size -= sizeof(posix_acl_xattr_header);
- if (size % sizeof(posix_acl_xattr_entry))
+ size -= sizeof(struct posix_acl_xattr_header);
+ if (size % sizeof(struct posix_acl_xattr_entry))
return -1;
- return size / sizeof(posix_acl_xattr_entry);
+ return size / sizeof(struct posix_acl_xattr_entry);
}
#ifdef CONFIG_FS_POSIX_ACL
diff --git a/include/linux/power/bq24735-charger.h b/include/linux/power/bq24735-charger.h
index 6b750c1a45fa..b04be59f914c 100644
--- a/include/linux/power/bq24735-charger.h
+++ b/include/linux/power/bq24735-charger.h
@@ -28,10 +28,6 @@ struct bq24735_platform {
const char *name;
- int status_gpio;
- int status_gpio_active_low;
- bool status_gpio_valid;
-
bool ext_control;
char **supplied_to;
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index b50c0492629d..e30deb046156 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -58,6 +58,7 @@ struct bq27xxx_device_info {
unsigned long last_update;
struct delayed_work work;
struct power_supply *bat;
+ struct list_head list;
struct mutex lock;
u8 *regs;
};
diff --git a/include/linux/power/sbs-battery.h b/include/linux/power/sbs-battery.h
index 2b0a9d9ff57e..519b8b43239a 100644
--- a/include/linux/power/sbs-battery.h
+++ b/include/linux/power/sbs-battery.h
@@ -26,17 +26,13 @@
/**
* struct sbs_platform_data - platform data for sbs devices
- * @battery_detect: GPIO which is used to detect battery presence
- * @battery_detect_present: gpio state when battery is present (0 / 1)
* @i2c_retry_count: # of times to retry on i2c IO failure
* @poll_retry_count: # of times to retry looking for new status after
* external change notification
*/
struct sbs_platform_data {
- int battery_detect;
- int battery_detect_present;
- int i2c_retry_count;
- int poll_retry_count;
+ u32 i2c_retry_count;
+ u32 poll_retry_count;
};
#endif
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 696a56be7d3e..eac1af8502bb 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -16,6 +16,7 @@ static inline int printk_get_level(const char *buffer)
switch (buffer[1]) {
case '0' ... '7':
case 'd': /* KERN_DEFAULT */
+ case 'c': /* KERN_CONT */
return buffer[1];
}
}
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index 395a4c674168..4d57bbaaa1bf 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -102,6 +102,9 @@ extern const struct raid6_calls raid6_altivec8;
extern const struct raid6_calls raid6_avx2x1;
extern const struct raid6_calls raid6_avx2x2;
extern const struct raid6_calls raid6_avx2x4;
+extern const struct raid6_calls raid6_avx512x1;
+extern const struct raid6_calls raid6_avx512x2;
+extern const struct raid6_calls raid6_avx512x4;
extern const struct raid6_calls raid6_tilegx8;
extern const struct raid6_calls raid6_s390vx8;
@@ -116,6 +119,7 @@ struct raid6_recov_calls {
extern const struct raid6_recov_calls raid6_recov_intx1;
extern const struct raid6_recov_calls raid6_recov_ssse3;
extern const struct raid6_recov_calls raid6_recov_avx2;
+extern const struct raid6_recov_calls raid6_recov_avx512;
extern const struct raid6_recov_calls raid6_recov_s390xc;
extern const struct raid6_calls raid6_neonx1;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 1c457a8dd5a6..930023b7c825 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -118,7 +118,7 @@ enum fw_resource_type {
RSC_LAST = 4,
};
-#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF)
+#define FW_RSC_ADDR_ANY (-1)
/**
* struct fw_rsc_carveout - physically contiguous memory request
@@ -241,7 +241,7 @@ struct fw_rsc_trace {
* @notifyid is a unique rproc-wide notify index for this vring. This notify
* index is used when kicking a remote processor, to let it know that this
* vring is triggered.
- * @reserved: reserved (must be zero)
+ * @pa: physical address
*
* This descriptor is not a resource entry by itself; it is part of the
* vdev resource type (see below).
@@ -255,7 +255,7 @@ struct fw_rsc_vdev_vring {
u32 align;
u32 num;
u32 notifyid;
- u32 reserved;
+ u32 pa;
} __packed;
/**
@@ -409,7 +409,6 @@ enum rproc_crash_type {
* @max_notifyid: largest allocated notify id.
* @table_ptr: pointer to the resource table in effect
* @cached_table: copy of the resource table
- * @table_csum: checksum of the resource table
* @has_iommu: flag to indicate if remote processor is behind an MMU
*/
struct rproc {
@@ -435,14 +434,14 @@ struct rproc {
struct idr notifyids;
int index;
struct work_struct crash_handler;
- unsigned crash_cnt;
+ unsigned int crash_cnt;
struct completion crash_comp;
bool recovery_disabled;
int max_notifyid;
struct resource_table *table_ptr;
struct resource_table *cached_table;
- u32 table_csum;
bool has_iommu;
+ bool auto_boot;
};
/* we currently support only two vrings per rvdev */
@@ -489,11 +488,12 @@ struct rproc_vdev {
struct rproc *rproc_get_by_phandle(phandle phandle);
struct rproc *rproc_alloc(struct device *dev, const char *name,
- const struct rproc_ops *ops,
- const char *firmware, int len);
+ const struct rproc_ops *ops,
+ const char *firmware, int len);
void rproc_put(struct rproc *rproc);
int rproc_add(struct rproc *rproc);
int rproc_del(struct rproc *rproc);
+void rproc_free(struct rproc *rproc);
int rproc_boot(struct rproc *rproc);
void rproc_shutdown(struct rproc *rproc);
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index ada50ff36da0..452d393cc8dd 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -41,65 +41,27 @@
#include <linux/kref.h>
#include <linux/mutex.h>
-/* The feature bitmap for virtio rpmsg */
-#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
+#define RPMSG_ADDR_ANY 0xFFFFFFFF
+
+struct rpmsg_device;
+struct rpmsg_endpoint;
+struct rpmsg_device_ops;
+struct rpmsg_endpoint_ops;
/**
- * struct rpmsg_hdr - common header for all rpmsg messages
- * @src: source address
+ * struct rpmsg_channel_info - channel info representation
+ * @name: name of service
+ * @src: local address
* @dst: destination address
- * @reserved: reserved for future use
- * @len: length of payload (in bytes)
- * @flags: message flags
- * @data: @len bytes of message payload data
- *
- * Every message sent(/received) on the rpmsg bus begins with this header.
*/
-struct rpmsg_hdr {
+struct rpmsg_channel_info {
+ char name[RPMSG_NAME_SIZE];
u32 src;
u32 dst;
- u32 reserved;
- u16 len;
- u16 flags;
- u8 data[0];
-} __packed;
-
-/**
- * struct rpmsg_ns_msg - dynamic name service announcement message
- * @name: name of remote service that is published
- * @addr: address of remote service that is published
- * @flags: indicates whether service is created or destroyed
- *
- * This message is sent across to publish a new service, or announce
- * about its removal. When we receive these messages, an appropriate
- * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
- * or ->remove() handler of the appropriate rpmsg driver will be invoked
- * (if/as-soon-as one is registered).
- */
-struct rpmsg_ns_msg {
- char name[RPMSG_NAME_SIZE];
- u32 addr;
- u32 flags;
-} __packed;
-
-/**
- * enum rpmsg_ns_flags - dynamic name service announcement flags
- *
- * @RPMSG_NS_CREATE: a new remote service was just created
- * @RPMSG_NS_DESTROY: a known remote service was just destroyed
- */
-enum rpmsg_ns_flags {
- RPMSG_NS_CREATE = 0,
- RPMSG_NS_DESTROY = 1,
};
-#define RPMSG_ADDR_ANY 0xFFFFFFFF
-
-struct virtproc_info;
-
/**
- * rpmsg_channel - devices that belong to the rpmsg bus are called channels
- * @vrp: the remote processor this channel belongs to
+ * rpmsg_device - device that belong to the rpmsg bus
* @dev: the device struct
* @id: device id (used to match between rpmsg drivers and devices)
* @src: local address
@@ -107,17 +69,18 @@ struct virtproc_info;
* @ept: the rpmsg endpoint of this channel
* @announce: if set, rpmsg will announce the creation/removal of this channel
*/
-struct rpmsg_channel {
- struct virtproc_info *vrp;
+struct rpmsg_device {
struct device dev;
struct rpmsg_device_id id;
u32 src;
u32 dst;
struct rpmsg_endpoint *ept;
bool announce;
+
+ const struct rpmsg_device_ops *ops;
};
-typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
+typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
/**
* struct rpmsg_endpoint - binds a local rpmsg address to its user
@@ -143,12 +106,14 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
* create additional endpoints by themselves (see rpmsg_create_ept()).
*/
struct rpmsg_endpoint {
- struct rpmsg_channel *rpdev;
+ struct rpmsg_device *rpdev;
struct kref refcount;
rpmsg_rx_cb_t cb;
struct mutex cb_lock;
u32 addr;
void *priv;
+
+ const struct rpmsg_endpoint_ops *ops;
};
/**
@@ -162,20 +127,19 @@ struct rpmsg_endpoint {
struct rpmsg_driver {
struct device_driver drv;
const struct rpmsg_device_id *id_table;
- int (*probe)(struct rpmsg_channel *dev);
- void (*remove)(struct rpmsg_channel *dev);
- void (*callback)(struct rpmsg_channel *, void *, int, void *, u32);
+ int (*probe)(struct rpmsg_device *dev);
+ void (*remove)(struct rpmsg_device *dev);
+ int (*callback)(struct rpmsg_device *, void *, int, void *, u32);
};
-int register_rpmsg_device(struct rpmsg_channel *dev);
-void unregister_rpmsg_device(struct rpmsg_channel *dev);
+int register_rpmsg_device(struct rpmsg_device *dev);
+void unregister_rpmsg_device(struct rpmsg_device *dev);
int __register_rpmsg_driver(struct rpmsg_driver *drv, struct module *owner);
void unregister_rpmsg_driver(struct rpmsg_driver *drv);
void rpmsg_destroy_ept(struct rpmsg_endpoint *);
-struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *,
- rpmsg_rx_cb_t cb, void *priv, u32 addr);
-int
-rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo);
/* use a macro to avoid include chaining to get THIS_MODULE */
#define register_rpmsg_driver(drv) \
@@ -193,156 +157,14 @@ rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
module_driver(__rpmsg_driver, register_rpmsg_driver, \
unregister_rpmsg_driver)
-/**
- * rpmsg_send() - send a message across to the remote processor
- * @rpdev: the rpmsg channel
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len on the @rpdev channel.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source and destination addresses.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len)
-{
- u32 src = rpdev->src, dst = rpdev->dst;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
-}
-
-/**
- * rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @rpdev: the rpmsg channel
- * @data: payload of message
- * @len: length of payload
- * @dst: destination address
- *
- * This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source address.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
-{
- u32 src = rpdev->src;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
-}
-
-/**
- * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @rpdev: the rpmsg channel
- * @src: source address
- * @dst: destination address
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len to the remote @dst address,
- * and uses @src as the source address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
- void *data, int len)
-{
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
-}
-
-/**
- * rpmsg_send() - send a message across to the remote processor
- * @rpdev: the rpmsg channel
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len on the @rpdev channel.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source and destination addresses.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
-{
- u32 src = rpdev->src, dst = rpdev->dst;
+int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len);
+int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
-}
-
-/**
- * rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @rpdev: the rpmsg channel
- * @data: payload of message
- * @len: length of payload
- * @dst: destination address
- *
- * This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source address.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
-{
- u32 src = rpdev->src;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
-}
-
-/**
- * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @rpdev: the rpmsg channel
- * @src: source address
- * @dst: destination address
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len to the remote @dst address,
- * and uses @src as the source address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
- void *data, int len)
-{
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
-}
+int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
+int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
#endif /* _LINUX_RPMSG_H */
diff --git a/include/linux/sbitmap.h b/include/linux/sbitmap.h
new file mode 100644
index 000000000000..f017fd6e69c4
--- /dev/null
+++ b/include/linux/sbitmap.h
@@ -0,0 +1,373 @@
+/*
+ * Fast and scalable bitmaps.
+ *
+ * Copyright (C) 2016 Facebook
+ * Copyright (C) 2013-2014 Jens Axboe
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_SCALE_BITMAP_H
+#define __LINUX_SCALE_BITMAP_H
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+/**
+ * struct sbitmap_word - Word in a &struct sbitmap.
+ */
+struct sbitmap_word {
+ /**
+ * @word: The bitmap word itself.
+ */
+ unsigned long word;
+
+ /**
+ * @depth: Number of bits being used in @word.
+ */
+ unsigned long depth;
+} ____cacheline_aligned_in_smp;
+
+/**
+ * struct sbitmap - Scalable bitmap.
+ *
+ * A &struct sbitmap is spread over multiple cachelines to avoid ping-pong. This
+ * trades off higher memory usage for better scalability.
+ */
+struct sbitmap {
+ /**
+ * @depth: Number of bits used in the whole bitmap.
+ */
+ unsigned int depth;
+
+ /**
+ * @shift: log2(number of bits used per word)
+ */
+ unsigned int shift;
+
+ /**
+ * @map_nr: Number of words (cachelines) being used for the bitmap.
+ */
+ unsigned int map_nr;
+
+ /**
+ * @map: Allocated bitmap.
+ */
+ struct sbitmap_word *map;
+};
+
+#define SBQ_WAIT_QUEUES 8
+#define SBQ_WAKE_BATCH 8
+
+/**
+ * struct sbq_wait_state - Wait queue in a &struct sbitmap_queue.
+ */
+struct sbq_wait_state {
+ /**
+ * @wait_cnt: Number of frees remaining before we wake up.
+ */
+ atomic_t wait_cnt;
+
+ /**
+ * @wait: Wait queue.
+ */
+ wait_queue_head_t wait;
+} ____cacheline_aligned_in_smp;
+
+/**
+ * struct sbitmap_queue - Scalable bitmap with the added ability to wait on free
+ * bits.
+ *
+ * A &struct sbitmap_queue uses multiple wait queues and rolling wakeups to
+ * avoid contention on the wait queue spinlock. This ensures that we don't hit a
+ * scalability wall when we run out of free bits and have to start putting tasks
+ * to sleep.
+ */
+struct sbitmap_queue {
+ /**
+ * @sb: Scalable bitmap.
+ */
+ struct sbitmap sb;
+
+ /*
+ * @alloc_hint: Cache of last successfully allocated or freed bit.
+ *
+ * This is per-cpu, which allows multiple users to stick to different
+ * cachelines until the map is exhausted.
+ */
+ unsigned int __percpu *alloc_hint;
+
+ /**
+ * @wake_batch: Number of bits which must be freed before we wake up any
+ * waiters.
+ */
+ unsigned int wake_batch;
+
+ /**
+ * @wake_index: Next wait queue in @ws to wake up.
+ */
+ atomic_t wake_index;
+
+ /**
+ * @ws: Wait queues.
+ */
+ struct sbq_wait_state *ws;
+
+ /**
+ * @round_robin: Allocate bits in strict round-robin order.
+ */
+ bool round_robin;
+};
+
+/**
+ * sbitmap_init_node() - Initialize a &struct sbitmap on a specific memory node.
+ * @sb: Bitmap to initialize.
+ * @depth: Number of bits to allocate.
+ * @shift: Use 2^@shift bits per word in the bitmap; if a negative number if
+ * given, a good default is chosen.
+ * @flags: Allocation flags.
+ * @node: Memory node to allocate on.
+ *
+ * Return: Zero on success or negative errno on failure.
+ */
+int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
+ gfp_t flags, int node);
+
+/**
+ * sbitmap_free() - Free memory used by a &struct sbitmap.
+ * @sb: Bitmap to free.
+ */
+static inline void sbitmap_free(struct sbitmap *sb)
+{
+ kfree(sb->map);
+ sb->map = NULL;
+}
+
+/**
+ * sbitmap_resize() - Resize a &struct sbitmap.
+ * @sb: Bitmap to resize.
+ * @depth: New number of bits to resize to.
+ *
+ * Doesn't reallocate anything. It's up to the caller to ensure that the new
+ * depth doesn't exceed the depth that the sb was initialized with.
+ */
+void sbitmap_resize(struct sbitmap *sb, unsigned int depth);
+
+/**
+ * sbitmap_get() - Try to allocate a free bit from a &struct sbitmap.
+ * @sb: Bitmap to allocate from.
+ * @alloc_hint: Hint for where to start searching for a free bit.
+ * @round_robin: If true, be stricter about allocation order; always allocate
+ * starting from the last allocated bit. This is less efficient
+ * than the default behavior (false).
+ *
+ * Return: Non-negative allocated bit number if successful, -1 otherwise.
+ */
+int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin);
+
+/**
+ * sbitmap_any_bit_set() - Check for a set bit in a &struct sbitmap.
+ * @sb: Bitmap to check.
+ *
+ * Return: true if any bit in the bitmap is set, false otherwise.
+ */
+bool sbitmap_any_bit_set(const struct sbitmap *sb);
+
+/**
+ * sbitmap_any_bit_clear() - Check for an unset bit in a &struct
+ * sbitmap.
+ * @sb: Bitmap to check.
+ *
+ * Return: true if any bit in the bitmap is clear, false otherwise.
+ */
+bool sbitmap_any_bit_clear(const struct sbitmap *sb);
+
+typedef bool (*sb_for_each_fn)(struct sbitmap *, unsigned int, void *);
+
+/**
+ * sbitmap_for_each_set() - Iterate over each set bit in a &struct sbitmap.
+ * @sb: Bitmap to iterate over.
+ * @fn: Callback. Should return true to continue or false to break early.
+ * @data: Pointer to pass to callback.
+ *
+ * This is inline even though it's non-trivial so that the function calls to the
+ * callback will hopefully get optimized away.
+ */
+static inline void sbitmap_for_each_set(struct sbitmap *sb, sb_for_each_fn fn,
+ void *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < sb->map_nr; i++) {
+ struct sbitmap_word *word = &sb->map[i];
+ unsigned int off, nr;
+
+ if (!word->word)
+ continue;
+
+ nr = 0;
+ off = i << sb->shift;
+ while (1) {
+ nr = find_next_bit(&word->word, word->depth, nr);
+ if (nr >= word->depth)
+ break;
+
+ if (!fn(sb, off + nr, data))
+ return;
+
+ nr++;
+ }
+ }
+}
+
+#define SB_NR_TO_INDEX(sb, bitnr) ((bitnr) >> (sb)->shift)
+#define SB_NR_TO_BIT(sb, bitnr) ((bitnr) & ((1U << (sb)->shift) - 1U))
+
+static inline unsigned long *__sbitmap_word(struct sbitmap *sb,
+ unsigned int bitnr)
+{
+ return &sb->map[SB_NR_TO_INDEX(sb, bitnr)].word;
+}
+
+/* Helpers equivalent to the operations in asm/bitops.h and linux/bitmap.h */
+
+static inline void sbitmap_set_bit(struct sbitmap *sb, unsigned int bitnr)
+{
+ set_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr));
+}
+
+static inline void sbitmap_clear_bit(struct sbitmap *sb, unsigned int bitnr)
+{
+ clear_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr));
+}
+
+static inline int sbitmap_test_bit(struct sbitmap *sb, unsigned int bitnr)
+{
+ return test_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr));
+}
+
+unsigned int sbitmap_weight(const struct sbitmap *sb);
+
+/**
+ * sbitmap_queue_init_node() - Initialize a &struct sbitmap_queue on a specific
+ * memory node.
+ * @sbq: Bitmap queue to initialize.
+ * @depth: See sbitmap_init_node().
+ * @shift: See sbitmap_init_node().
+ * @round_robin: See sbitmap_get().
+ * @flags: Allocation flags.
+ * @node: Memory node to allocate on.
+ *
+ * Return: Zero on success or negative errno on failure.
+ */
+int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth,
+ int shift, bool round_robin, gfp_t flags, int node);
+
+/**
+ * sbitmap_queue_free() - Free memory used by a &struct sbitmap_queue.
+ *
+ * @sbq: Bitmap queue to free.
+ */
+static inline void sbitmap_queue_free(struct sbitmap_queue *sbq)
+{
+ kfree(sbq->ws);
+ free_percpu(sbq->alloc_hint);
+ sbitmap_free(&sbq->sb);
+}
+
+/**
+ * sbitmap_queue_resize() - Resize a &struct sbitmap_queue.
+ * @sbq: Bitmap queue to resize.
+ * @depth: New number of bits to resize to.
+ *
+ * Like sbitmap_resize(), this doesn't reallocate anything. It has to do
+ * some extra work on the &struct sbitmap_queue, so it's not safe to just
+ * resize the underlying &struct sbitmap.
+ */
+void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth);
+
+/**
+ * __sbitmap_queue_get() - Try to allocate a free bit from a &struct
+ * sbitmap_queue with preemption already disabled.
+ * @sbq: Bitmap queue to allocate from.
+ *
+ * Return: Non-negative allocated bit number if successful, -1 otherwise.
+ */
+int __sbitmap_queue_get(struct sbitmap_queue *sbq);
+
+/**
+ * sbitmap_queue_get() - Try to allocate a free bit from a &struct
+ * sbitmap_queue.
+ * @sbq: Bitmap queue to allocate from.
+ * @cpu: Output parameter; will contain the CPU we ran on (e.g., to be passed to
+ * sbitmap_queue_clear()).
+ *
+ * Return: Non-negative allocated bit number if successful, -1 otherwise.
+ */
+static inline int sbitmap_queue_get(struct sbitmap_queue *sbq,
+ unsigned int *cpu)
+{
+ int nr;
+
+ *cpu = get_cpu();
+ nr = __sbitmap_queue_get(sbq);
+ put_cpu();
+ return nr;
+}
+
+/**
+ * sbitmap_queue_clear() - Free an allocated bit and wake up waiters on a
+ * &struct sbitmap_queue.
+ * @sbq: Bitmap to free from.
+ * @nr: Bit number to free.
+ * @cpu: CPU the bit was allocated on.
+ */
+void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr,
+ unsigned int cpu);
+
+static inline int sbq_index_inc(int index)
+{
+ return (index + 1) & (SBQ_WAIT_QUEUES - 1);
+}
+
+static inline void sbq_index_atomic_inc(atomic_t *index)
+{
+ int old = atomic_read(index);
+ int new = sbq_index_inc(old);
+ atomic_cmpxchg(index, old, new);
+}
+
+/**
+ * sbq_wait_ptr() - Get the next wait queue to use for a &struct
+ * sbitmap_queue.
+ * @sbq: Bitmap queue to wait on.
+ * @wait_index: A counter per "user" of @sbq.
+ */
+static inline struct sbq_wait_state *sbq_wait_ptr(struct sbitmap_queue *sbq,
+ atomic_t *wait_index)
+{
+ struct sbq_wait_state *ws;
+
+ ws = &sbq->ws[atomic_read(wait_index)];
+ sbq_index_atomic_inc(wait_index);
+ return ws;
+}
+
+/**
+ * sbitmap_queue_wake_all() - Wake up everything waiting on a &struct
+ * sbitmap_queue.
+ * @sbq: Bitmap queue to wake up.
+ */
+void sbitmap_queue_wake_all(struct sbitmap_queue *sbq);
+
+#endif /* __LINUX_SCALE_BITMAP_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7543a476178b..348f51b0ec92 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -524,8 +524,9 @@ static inline int get_dumpable(struct mm_struct *mm)
#define MMF_HAS_UPROBES 19 /* has uprobes */
#define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */
-#define MMF_OOM_REAPED 21 /* mm has been already reaped */
-#define MMF_OOM_NOT_REAPABLE 22 /* mm couldn't be reaped */
+#define MMF_OOM_SKIP 21 /* mm is of no interest for the OOM killer */
+#define MMF_UNSTABLE 22 /* mm is unstable for copy_from_user */
+#define MMF_HUGE_ZERO_PAGE 23 /* mm has ever used the global huge zero page */
#define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
@@ -673,7 +674,6 @@ struct signal_struct {
atomic_t sigcnt;
atomic_t live;
int nr_threads;
- atomic_t oom_victims; /* # of TIF_MEDIE threads in this thread group */
struct list_head thread_head;
wait_queue_head_t wait_chldexit; /* for wait4() */
@@ -806,6 +806,8 @@ struct signal_struct {
short oom_score_adj; /* OOM kill score adjustment */
short oom_score_adj_min; /* OOM kill score adjustment min value.
* Only settable by CAP_SYS_RESOURCE. */
+ struct mm_struct *oom_mm; /* recorded mm when the thread group got
+ * killed by the oom killer */
struct mutex cred_guard_mutex; /* guard against foreign influences on
* credential calculations
@@ -2876,6 +2878,20 @@ static inline void mmdrop(struct mm_struct *mm)
__mmdrop(mm);
}
+static inline void mmdrop_async_fn(struct work_struct *work)
+{
+ struct mm_struct *mm = container_of(work, struct mm_struct, async_put_work);
+ __mmdrop(mm);
+}
+
+static inline void mmdrop_async(struct mm_struct *mm)
+{
+ if (unlikely(atomic_dec_and_test(&mm->mm_count))) {
+ INIT_WORK(&mm->async_put_work, mmdrop_async_fn);
+ schedule_work(&mm->async_put_work);
+ }
+}
+
static inline bool mmget_not_zero(struct mm_struct *mm)
{
return atomic_inc_not_zero(&mm->mm_users);
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index f3d45dd42695..e305b66a9fb9 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -117,9 +117,9 @@ __printf(2, 3)
void seq_printf(struct seq_file *m, const char *fmt, ...);
void seq_putc(struct seq_file *m, char c);
void seq_puts(struct seq_file *m, const char *s);
-void seq_put_decimal_ull(struct seq_file *m, char delimiter,
+void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
unsigned long long num);
-void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num);
+void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num);
void seq_escape(struct seq_file *m, const char *s, const char *esc);
void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9bf60b556bd2..601258f6e621 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3064,15 +3064,9 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
int len, __wsum csum);
-ssize_t skb_socket_splice(struct sock *sk,
- struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd);
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int len,
- unsigned int flags,
- ssize_t (*splice_cb)(struct sock *,
- struct pipe_inode_info *,
- struct splice_pipe_desc *));
+ unsigned int flags);
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h
index cbb0f06c41b2..f148e0ffbec7 100644
--- a/include/linux/soc/qcom/smd.h
+++ b/include/linux/soc/qcom/smd.h
@@ -55,11 +55,16 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
const char *name,
qcom_smd_cb_t cb);
+void qcom_smd_close_channel(struct qcom_smd_channel *channel);
void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
+struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
+ struct device_node *node);
+int qcom_smd_unregister_edge(struct qcom_smd_edge *edge);
+
#else
static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
@@ -83,14 +88,20 @@ qcom_smd_open_channel(struct qcom_smd_channel *channel,
return NULL;
}
-void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
+static inline void qcom_smd_close_channel(struct qcom_smd_channel *channel)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
+static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
{
/* This shouldn't be possible */
WARN_ON(1);
return NULL;
}
-void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
+static inline void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
{
/* This shouldn't be possible */
WARN_ON(1);
@@ -104,6 +115,20 @@ static inline int qcom_smd_send(struct qcom_smd_channel *channel,
return -ENXIO;
}
+static inline struct qcom_smd_edge *
+qcom_smd_register_edge(struct device *parent,
+ struct device_node *node)
+{
+ return ERR_PTR(-ENXIO);
+}
+
+static inline int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+ return -ENXIO;
+}
+
#endif
#define module_qcom_smd_driver(__smd_driver) \
diff --git a/include/linux/splice.h b/include/linux/splice.h
index da2751d3b93d..00a21166e268 100644
--- a/include/linux/splice.h
+++ b/include/linux/splice.h
@@ -72,6 +72,8 @@ extern ssize_t __splice_from_pipe(struct pipe_inode_info *,
struct splice_desc *, splice_actor *);
extern ssize_t splice_to_pipe(struct pipe_inode_info *,
struct splice_pipe_desc *);
+extern ssize_t add_to_pipe(struct pipe_inode_info *,
+ struct pipe_buffer *);
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
splice_direct_actor *);
@@ -83,4 +85,5 @@ extern void splice_shrink_spd(struct splice_pipe_desc *);
extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
+extern const struct pipe_buf_operations default_pipe_buf_ops;
#endif
diff --git a/include/linux/swap.h b/include/linux/swap.h
index e1d761463243..a56523cefb9b 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -191,6 +191,11 @@ struct percpu_cluster {
unsigned int next; /* Likely next allocation offset */
};
+struct swap_cluster_list {
+ struct swap_cluster_info head;
+ struct swap_cluster_info tail;
+};
+
/*
* The in-memory structure used to track swap areas.
*/
@@ -203,8 +208,7 @@ struct swap_info_struct {
unsigned int max; /* extent of the swap_map */
unsigned char *swap_map; /* vmalloc'ed array of usage counts */
struct swap_cluster_info *cluster_info; /* cluster info. Only for SSD */
- struct swap_cluster_info free_cluster_head; /* free cluster list head */
- struct swap_cluster_info free_cluster_tail; /* free cluster list tail */
+ struct swap_cluster_list free_clusters; /* free clusters list */
unsigned int lowest_bit; /* index of first free in swap_map */
unsigned int highest_bit; /* index of last free in swap_map */
unsigned int pages; /* total of usable pages of swap */
@@ -235,8 +239,7 @@ struct swap_info_struct {
* first.
*/
struct work_struct discard_work; /* discard worker */
- struct swap_cluster_info discard_cluster_head; /* list head of discard clusters */
- struct swap_cluster_info discard_cluster_tail; /* list tail of discard clusters */
+ struct swap_cluster_list discard_clusters; /* discard clusters list */
};
/* linux/mm/workingset.c */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index d02239022bd0..0d7abb8b7315 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -898,4 +898,12 @@ asmlinkage long sys_copy_file_range(int fd_in, loff_t __user *off_in,
asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags);
+asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len,
+ unsigned long prot, int pkey);
+asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
+asmlinkage long sys_pkey_free(int pkey);
+//asmlinkage long sys_pkey_get(int pkey, unsigned long flags);
+//asmlinkage long sys_pkey_set(int pkey, unsigned long access_rights,
+// unsigned long flags);
+
#endif
diff --git a/include/linux/t10-pi.h b/include/linux/t10-pi.h
index dd8de82cf5b5..9fba9dd33544 100644
--- a/include/linux/t10-pi.h
+++ b/include/linux/t10-pi.h
@@ -5,6 +5,26 @@
#include <linux/blkdev.h>
/*
+ * A T10 PI-capable target device can be formatted with different
+ * protection schemes. Currently 0 through 3 are defined:
+ *
+ * Type 0 is regular (unprotected) I/O
+ *
+ * Type 1 defines the contents of the guard and reference tags
+ *
+ * Type 2 defines the contents of the guard and reference tags and
+ * uses 32-byte commands to seed the latter
+ *
+ * Type 3 defines the contents of the guard tag only
+ */
+enum t10_dif_type {
+ T10_PI_TYPE0_PROTECTION = 0x0,
+ T10_PI_TYPE1_PROTECTION = 0x1,
+ T10_PI_TYPE2_PROTECTION = 0x2,
+ T10_PI_TYPE3_PROTECTION = 0x3,
+};
+
+/*
* T10 Protection Information tuple.
*/
struct t10_pi_tuple {
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 75b4aaf31a9d..6e22b544d039 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -13,6 +13,7 @@
#include <uapi/linux/uio.h>
struct page;
+struct pipe_inode_info;
struct kvec {
void *iov_base; /* and that should *never* hold a userland pointer */
@@ -23,6 +24,7 @@ enum {
ITER_IOVEC = 0,
ITER_KVEC = 2,
ITER_BVEC = 4,
+ ITER_PIPE = 8,
};
struct iov_iter {
@@ -33,8 +35,12 @@ struct iov_iter {
const struct iovec *iov;
const struct kvec *kvec;
const struct bio_vec *bvec;
+ struct pipe_inode_info *pipe;
+ };
+ union {
+ unsigned long nr_segs;
+ int idx;
};
- unsigned long nr_segs;
};
/*
@@ -64,7 +70,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)) \
+ if (!((start).type & (ITER_BVEC | ITER_PIPE))) \
for (iter = (start); \
(iter).count && \
((iov = iov_iter_iovec(&(iter))), 1); \
@@ -76,7 +82,6 @@ size_t iov_iter_copy_from_user_atomic(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);
-#define iov_iter_fault_in_multipages_readable iov_iter_fault_in_readable
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);
@@ -94,6 +99,8 @@ void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec,
unsigned long nr_segs, size_t count);
void iov_iter_bvec(struct iov_iter *i, int direction, const struct bio_vec *bvec,
unsigned long nr_segs, size_t count);
+void iov_iter_pipe(struct iov_iter *i, int direction, struct pipe_inode_info *pipe,
+ size_t count);
ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
size_t maxsize, unsigned maxpages, size_t *start);
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
@@ -102,14 +109,14 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages);
const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags);
-static inline size_t iov_iter_count(struct iov_iter *i)
+static inline size_t iov_iter_count(const struct iov_iter *i)
{
return i->count;
}
-static inline bool iter_is_iovec(struct iov_iter *i)
+static inline bool iter_is_iovec(const struct iov_iter *i)
{
- return !(i->type & (ITER_BVEC | ITER_KVEC));
+ return !(i->type & (ITER_BVEC | ITER_KVEC | ITER_PIPE));
}
/*
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 26cc1df280d6..fc6e22186405 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -442,6 +442,7 @@ extern int schedule_on_each_cpu(work_func_t func);
int execute_in_process_context(work_func_t fn, struct execute_work *);
extern bool flush_work(struct work_struct *work);
+extern bool cancel_work(struct work_struct *work);
extern bool cancel_work_sync(struct work_struct *work);
extern bool flush_delayed_work(struct delayed_work *dwork);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index fc1e16c25a29..797100e10010 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -319,7 +319,6 @@ void laptop_mode_timer_fn(unsigned long data);
#else
static inline void laptop_sync_completion(void) { }
#endif
-void throttle_vm_writeout(gfp_t gfp_mask);
bool node_dirty_ok(struct pglist_data *pgdat);
int wb_domain_init(struct wb_domain *dom, gfp_t gfp);
#ifdef CONFIG_CGROUP_WRITEBACK
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 94079bab9243..e77605a0c8da 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -46,17 +46,16 @@ struct xattr {
};
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
+ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
+int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, size_t, int);
int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int);
int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
+int __vfs_removexattr(struct dentry *, const char *);
int vfs_removexattr(struct dentry *, const char *);
-ssize_t generic_getxattr(struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size);
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
-int generic_setxattr(struct dentry *dentry, struct inode *inode,
- const char *name, const void *value, size_t size, int flags);
-int generic_removexattr(struct dentry *dentry, const char *name);
ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
char **xattr_value, size_t size, gfp_t flags);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index e1f96737c2a1..5ad43a487745 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -261,6 +261,16 @@ struct ib_odp_caps {
} per_transport_caps;
};
+struct ib_rss_caps {
+ /* Corresponding bit will be set if qp type from
+ * 'enum ib_qp_type' is supported, e.g.
+ * supported_qpts |= 1 << IB_QPT_UD
+ */
+ u32 supported_qpts;
+ u32 max_rwq_indirection_tables;
+ u32 max_rwq_indirection_table_size;
+};
+
enum ib_cq_creation_flags {
IB_CQ_FLAGS_TIMESTAMP_COMPLETION = 1 << 0,
IB_CQ_FLAGS_IGNORE_OVERRUN = 1 << 1,
@@ -318,6 +328,8 @@ struct ib_device_attr {
struct ib_odp_caps odp_caps;
uint64_t timestamp_mask;
uint64_t hca_core_clock; /* in KHZ */
+ struct ib_rss_caps rss_caps;
+ u32 max_wq_type_rq;
};
enum ib_mtu {
@@ -525,9 +537,11 @@ enum ib_device_modify_flags {
IB_DEVICE_MODIFY_NODE_DESC = 1 << 1
};
+#define IB_DEVICE_NODE_DESC_MAX 64
+
struct ib_device_modify {
u64 sys_image_guid;
- char node_desc[64];
+ char node_desc[IB_DEVICE_NODE_DESC_MAX];
};
enum ib_port_modify_flags {
@@ -1370,10 +1384,17 @@ struct ib_udata {
struct ib_pd {
u32 local_dma_lkey;
+ u32 flags;
struct ib_device *device;
struct ib_uobject *uobject;
atomic_t usecnt; /* count all resources */
- struct ib_mr *local_mr;
+
+ u32 unsafe_global_rkey;
+
+ /*
+ * Implementation details of the RDMA core, don't use in drivers:
+ */
+ struct ib_mr *__internal_mr;
};
struct ib_xrcd {
@@ -1604,6 +1625,8 @@ struct ib_flow_eth_filter {
u8 src_mac[6];
__be16 ether_type;
__be16 vlan_tag;
+ /* Must be last */
+ u8 real_sz[0];
};
struct ib_flow_spec_eth {
@@ -1616,6 +1639,8 @@ struct ib_flow_spec_eth {
struct ib_flow_ib_filter {
__be16 dlid;
__u8 sl;
+ /* Must be last */
+ u8 real_sz[0];
};
struct ib_flow_spec_ib {
@@ -1625,9 +1650,22 @@ struct ib_flow_spec_ib {
struct ib_flow_ib_filter mask;
};
+/* IPv4 header flags */
+enum ib_ipv4_flags {
+ IB_IPV4_DONT_FRAG = 0x2, /* Don't enable packet fragmentation */
+ IB_IPV4_MORE_FRAG = 0X4 /* For All fragmented packets except the
+ last have this flag set */
+};
+
struct ib_flow_ipv4_filter {
__be32 src_ip;
__be32 dst_ip;
+ u8 proto;
+ u8 tos;
+ u8 ttl;
+ u8 flags;
+ /* Must be last */
+ u8 real_sz[0];
};
struct ib_flow_spec_ipv4 {
@@ -1640,6 +1678,12 @@ struct ib_flow_spec_ipv4 {
struct ib_flow_ipv6_filter {
u8 src_ip[16];
u8 dst_ip[16];
+ __be32 flow_label;
+ u8 next_hdr;
+ u8 traffic_class;
+ u8 hop_limit;
+ /* Must be last */
+ u8 real_sz[0];
};
struct ib_flow_spec_ipv6 {
@@ -1652,6 +1696,8 @@ struct ib_flow_spec_ipv6 {
struct ib_flow_tcp_udp_filter {
__be16 dst_port;
__be16 src_port;
+ /* Must be last */
+ u8 real_sz[0];
};
struct ib_flow_spec_tcp_udp {
@@ -1739,6 +1785,14 @@ struct ib_dma_mapping_ops {
void (*unmap_sg)(struct ib_device *dev,
struct scatterlist *sg, int nents,
enum dma_data_direction direction);
+ int (*map_sg_attrs)(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
+ unsigned long attrs);
+ void (*unmap_sg_attrs)(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
+ unsigned long attrs);
void (*sync_single_for_cpu)(struct ib_device *dev,
u64 dma_handle,
size_t size,
@@ -2033,7 +2087,7 @@ struct ib_device {
u64 uverbs_cmd_mask;
u64 uverbs_ex_cmd_mask;
- char node_desc[64];
+ char node_desc[IB_DEVICE_NODE_DESC_MAX];
__be64 node_guid;
u32 local_dma_lkey;
u16 is_switch:1;
@@ -2497,8 +2551,23 @@ int ib_find_gid(struct ib_device *device, union ib_gid *gid,
int ib_find_pkey(struct ib_device *device,
u8 port_num, u16 pkey, u16 *index);
-struct ib_pd *ib_alloc_pd(struct ib_device *device);
+enum ib_pd_flags {
+ /*
+ * Create a memory registration for all memory in the system and place
+ * the rkey for it into pd->unsafe_global_rkey. This can be used by
+ * ULPs to avoid the overhead of dynamic MRs.
+ *
+ * This flag is generally considered unsafe and must only be used in
+ * extremly trusted environments. Every use of it will log a warning
+ * in the kernel log.
+ */
+ IB_PD_UNSAFE_GLOBAL_RKEY = 0x01,
+};
+struct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags,
+ const char *caller);
+#define ib_alloc_pd(device, flags) \
+ __ib_alloc_pd((device), (flags), __func__)
void ib_dealloc_pd(struct ib_pd *pd);
/**
@@ -2852,18 +2921,6 @@ static inline int ib_req_ncomp_notif(struct ib_cq *cq, int wc_cnt)
}
/**
- * ib_get_dma_mr - Returns a memory region for system memory that is
- * usable for DMA.
- * @pd: The protection domain associated with the memory region.
- * @mr_access_flags: Specifies the memory access rights.
- *
- * Note that the ib_dma_*() functions defined below must be used
- * to create/destroy addresses used with the Lkey or Rkey returned
- * by ib_get_dma_mr().
- */
-struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
-
-/**
* ib_dma_mapping_error - check a DMA addr for error
* @dev: The device for which the dma_addr was created
* @dma_addr: The DMA address to check
@@ -3000,8 +3057,12 @@ static inline int ib_dma_map_sg_attrs(struct ib_device *dev,
enum dma_data_direction direction,
unsigned long dma_attrs)
{
- return dma_map_sg_attrs(dev->dma_device, sg, nents, direction,
- dma_attrs);
+ if (dev->dma_ops)
+ return dev->dma_ops->map_sg_attrs(dev, sg, nents, direction,
+ dma_attrs);
+ else
+ return dma_map_sg_attrs(dev->dma_device, sg, nents, direction,
+ dma_attrs);
}
static inline void ib_dma_unmap_sg_attrs(struct ib_device *dev,
@@ -3009,7 +3070,12 @@ static inline void ib_dma_unmap_sg_attrs(struct ib_device *dev,
enum dma_data_direction direction,
unsigned long dma_attrs)
{
- dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction, dma_attrs);
+ if (dev->dma_ops)
+ return dev->dma_ops->unmap_sg_attrs(dev, sg, nents, direction,
+ dma_attrs);
+ else
+ dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction,
+ dma_attrs);
}
/**
* ib_sg_dma_address - Return the DMA address from a scatter/gather entry
diff --git a/include/trace/events/compaction.h b/include/trace/events/compaction.h
index c2ba402ab256..cbdb90b6b308 100644
--- a/include/trace/events/compaction.h
+++ b/include/trace/events/compaction.h
@@ -13,7 +13,7 @@
EM( COMPACT_SKIPPED, "skipped") \
EM( COMPACT_DEFERRED, "deferred") \
EM( COMPACT_CONTINUE, "continue") \
- EM( COMPACT_PARTIAL, "partial") \
+ EM( COMPACT_SUCCESS, "success") \
EM( COMPACT_PARTIAL_SKIPPED, "partial_skipped") \
EM( COMPACT_COMPLETE, "complete") \
EM( COMPACT_NO_SUITABLE_PAGE, "no_suitable_page") \
diff --git a/include/trace/events/intel_ish.h b/include/trace/events/intel_ish.h
new file mode 100644
index 000000000000..92f7d5b23177
--- /dev/null
+++ b/include/trace/events/intel_ish.h
@@ -0,0 +1,30 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM intel_ish
+
+#if !defined(_TRACE_INTEL_ISH_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INTEL_ISH_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(ishtp_dump,
+
+ TP_PROTO(const char *message),
+
+ TP_ARGS(message),
+
+ TP_STRUCT__entry(
+ __string(message, message)
+ ),
+
+ TP_fast_assign(
+ __assign_str(message, message);
+ ),
+
+ TP_printk("%s", __get_str(message))
+);
+
+
+#endif /* _TRACE_INTEL_ISH_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h
index f95f25e786ef..1c41b74581f7 100644
--- a/include/trace/events/irq.h
+++ b/include/trace/events/irq.h
@@ -75,7 +75,7 @@ TRACE_EVENT(irq_handler_entry,
* @ret: return value
*
* If the @ret value is set to IRQ_HANDLED, then we know that the corresponding
- * @action->handler scuccessully handled this irq. Otherwise, the irq might be
+ * @action->handler successfully handled this irq. Otherwise, the irq might be
* a shared irq line, or the irq was not handled successfully. Can be used in
* conjunction with the irq_handler_entry to understand irq handler latencies.
*/
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index 58274382a616..8c27db0c5c08 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -72,4 +72,9 @@
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
#endif /* __ASM_GENERIC_MMAN_COMMON_H */
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index a26415b5151c..dbfee7e86ba6 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -724,9 +724,19 @@ __SYSCALL(__NR_copy_file_range, sys_copy_file_range)
__SC_COMP(__NR_preadv2, sys_preadv2, compat_sys_preadv2)
#define __NR_pwritev2 287
__SC_COMP(__NR_pwritev2, sys_pwritev2, compat_sys_pwritev2)
+#define __NR_pkey_mprotect 288
+__SYSCALL(__NR_pkey_mprotect, sys_pkey_mprotect)
+#define __NR_pkey_alloc 289
+__SYSCALL(__NR_pkey_alloc, sys_pkey_alloc)
+#define __NR_pkey_free 290
+__SYSCALL(__NR_pkey_free, sys_pkey_free)
+#define __NR_pkey_get 291
+//__SYSCALL(__NR_pkey_get, sys_pkey_get)
+#define __NR_pkey_set 292
+//__SYSCALL(__NR_pkey_set, sys_pkey_set)
#undef __NR_syscalls
-#define __NR_syscalls 288
+#define __NR_syscalls 291
/*
* All syscalls below here should go away really,
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index d0352a971ebd..929aba253764 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -336,6 +336,8 @@ header-y += pkt_cls.h
header-y += pkt_sched.h
header-y += pmu.h
header-y += poll.h
+header-y += posix_acl.h
+header-y += posix_acl_xattr.h
header-y += posix_types.h
header-y += ppdev.h
header-y += ppp-comp.h
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 3b00f7c8943f..2473272169f2 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -132,6 +132,7 @@ struct inodes_stat_t {
#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */
/* These sb flags are internal to the kernel */
+#define MS_NOREMOTELOCK (1<<27)
#define MS_NOSEC (1<<28)
#define MS_BORN (1<<29)
#define MS_ACTIVE (1<<30)
diff --git a/include/uapi/linux/hsi/hsi_char.h b/include/uapi/linux/hsi/hsi_char.h
index 76160b4f455d..c00a463d55f9 100644
--- a/include/uapi/linux/hsi/hsi_char.h
+++ b/include/uapi/linux/hsi/hsi_char.h
@@ -20,10 +20,11 @@
* 02110-1301 USA
*/
-
#ifndef __HSI_CHAR_H
#define __HSI_CHAR_H
+#include <linux/types.h>
+
#define HSI_CHAR_MAGIC 'k'
#define HSC_IOW(num, dtype) _IOW(HSI_CHAR_MAGIC, num, dtype)
#define HSC_IOR(num, dtype) _IOR(HSI_CHAR_MAGIC, num, dtype)
@@ -48,16 +49,16 @@
#define HSC_ARB_PRIO 1
struct hsc_rx_config {
- uint32_t mode;
- uint32_t flow;
- uint32_t channels;
+ __u32 mode;
+ __u32 flow;
+ __u32 channels;
};
struct hsc_tx_config {
- uint32_t mode;
- uint32_t channels;
- uint32_t speed;
- uint32_t arb_mode;
+ __u32 mode;
+ __u32 channels;
+ __u32 speed;
+ __u32 arb_mode;
};
#endif /* __HSI_CHAR_H */
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index c51494119817..e794f7bee22f 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -248,6 +248,7 @@ struct input_mask {
#define BUS_SPI 0x1C
#define BUS_RMI 0x1D
#define BUS_CEC 0x1E
+#define BUS_INTEL_ISHTP 0x1F
/*
* MT_TOOL types
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 404095124ae2..d812172d1d7b 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -671,7 +671,8 @@
#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */
#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */
#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */
-#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DPC
+#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
+#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM
#define PCI_EXT_CAP_DSN_SIZEOF 12
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
@@ -964,4 +965,13 @@
#define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */
+/* Precision Time Measurement */
+#define PCI_PTM_CAP 0x04 /* PTM Capability */
+#define PCI_PTM_CAP_REQ 0x00000001 /* Requester capable */
+#define PCI_PTM_CAP_ROOT 0x00000004 /* Root capable */
+#define PCI_PTM_GRANULARITY_MASK 0x0000FF00 /* Clock granularity */
+#define PCI_PTM_CTRL 0x08 /* PTM Control */
+#define PCI_PTM_CTRL_ENABLE 0x00000001 /* PTM enable */
+#define PCI_PTM_CTRL_ROOT 0x00000002 /* Root select */
+
#endif /* LINUX_PCI_REGS_H */
diff --git a/include/uapi/linux/posix_acl.h b/include/uapi/linux/posix_acl.h
new file mode 100644
index 000000000000..1037cb19aa17
--- /dev/null
+++ b/include/uapi/linux/posix_acl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2002 Andreas Gruenbacher <a.gruenbacher@computer.org>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef __UAPI_POSIX_ACL_H
+#define __UAPI_POSIX_ACL_H
+
+#define ACL_UNDEFINED_ID (-1)
+
+/* a_type field in acl_user_posix_entry_t */
+#define ACL_TYPE_ACCESS (0x8000)
+#define ACL_TYPE_DEFAULT (0x4000)
+
+/* e_tag entry in struct posix_acl_entry */
+#define ACL_USER_OBJ (0x01)
+#define ACL_USER (0x02)
+#define ACL_GROUP_OBJ (0x04)
+#define ACL_GROUP (0x08)
+#define ACL_MASK (0x10)
+#define ACL_OTHER (0x20)
+
+/* permissions in the e_perm field */
+#define ACL_READ (0x04)
+#define ACL_WRITE (0x02)
+#define ACL_EXECUTE (0x01)
+
+#endif /* __UAPI_POSIX_ACL_H */
diff --git a/include/uapi/linux/posix_acl_xattr.h b/include/uapi/linux/posix_acl_xattr.h
new file mode 100644
index 000000000000..8b579844109b
--- /dev/null
+++ b/include/uapi/linux/posix_acl_xattr.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2002 Andreas Gruenbacher <a.gruenbacher@computer.org>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef __UAPI_POSIX_ACL_XATTR_H
+#define __UAPI_POSIX_ACL_XATTR_H
+
+#include <linux/types.h>
+
+/* Supported ACL a_version fields */
+#define POSIX_ACL_XATTR_VERSION 0x0002
+
+/* An undefined entry e_id value */
+#define ACL_UNDEFINED_ID (-1)
+
+struct posix_acl_xattr_entry {
+ __le16 e_tag;
+ __le16 e_perm;
+ __le32 e_id;
+};
+
+struct posix_acl_xattr_header {
+ __le32 a_version;
+};
+
+#endif /* __UAPI_POSIX_ACL_XATTR_H */
diff --git a/include/uapi/rdma/Kbuild b/include/uapi/rdma/Kbuild
index 4edb0f2b4f9f..f14ab7ff5fee 100644
--- a/include/uapi/rdma/Kbuild
+++ b/include/uapi/rdma/Kbuild
@@ -7,3 +7,10 @@ header-y += rdma_netlink.h
header-y += rdma_user_cm.h
header-y += hfi/
header-y += rdma_user_rxe.h
+header-y += cxgb3-abi.h
+header-y += cxgb4-abi.h
+header-y += mlx4-abi.h
+header-y += mlx5-abi.h
+header-y += mthca-abi.h
+header-y += nes-abi.h
+header-y += ocrdma-abi.h
diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/include/uapi/rdma/cxgb3-abi.h
index a277c31fcaf7..48a19bda071b 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_user.h
+++ b/include/uapi/rdma/cxgb3-abi.h
@@ -29,8 +29,10 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef __IWCH_USER_H__
-#define __IWCH_USER_H__
+#ifndef CXGB3_ABI_USER_H
+#define CXBG3_ABI_USER_H
+
+#include <linux/types.h>
#define IWCH_UVERBS_ABI_VERSION 1
@@ -71,4 +73,4 @@ struct iwch_create_qp_resp {
struct iwch_reg_user_mr_resp {
__u32 pbl_addr;
};
-#endif
+#endif /* CXGB3_ABI_USER_H */
diff --git a/drivers/infiniband/hw/cxgb4/user.h b/include/uapi/rdma/cxgb4-abi.h
index 295f422b9a3a..472b15990894 100644
--- a/drivers/infiniband/hw/cxgb4/user.h
+++ b/include/uapi/rdma/cxgb4-abi.h
@@ -29,8 +29,10 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef __C4IW_USER_H__
-#define __C4IW_USER_H__
+#ifndef CXGB4_ABI_USER_H
+#define CXGB4_ABI_USER_H
+
+#include <linux/types.h>
#define C4IW_UVERBS_ABI_VERSION 3
@@ -51,9 +53,8 @@ struct c4iw_create_cq_resp {
__u32 reserved; /* explicit padding (optional for i386) */
};
-
enum {
- C4IW_QPF_ONCHIP = (1<<0)
+ C4IW_QPF_ONCHIP = (1 << 0)
};
struct c4iw_create_qp_resp {
@@ -77,4 +78,4 @@ struct c4iw_alloc_ucontext_resp {
__u32 status_page_size;
__u32 reserved; /* explicit padding (optional for i386) */
};
-#endif
+#endif /* CXGB4_ABI_USER_H */
diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h
index 7f035f4b53b0..25225ebbc7d5 100644
--- a/include/uapi/rdma/ib_user_verbs.h
+++ b/include/uapi/rdma/ib_user_verbs.h
@@ -224,6 +224,17 @@ struct ib_uverbs_odp_caps {
__u32 reserved;
};
+struct ib_uverbs_rss_caps {
+ /* Corresponding bit will be set if qp type from
+ * 'enum ib_qp_type' is supported, e.g.
+ * supported_qpts |= 1 << IB_QPT_UD
+ */
+ __u32 supported_qpts;
+ __u32 max_rwq_indirection_tables;
+ __u32 max_rwq_indirection_table_size;
+ __u32 reserved;
+};
+
struct ib_uverbs_ex_query_device_resp {
struct ib_uverbs_query_device_resp base;
__u32 comp_mask;
@@ -232,6 +243,9 @@ struct ib_uverbs_ex_query_device_resp {
__u64 timestamp_mask;
__u64 hca_core_clock; /* in KHZ */
__u64 device_cap_flags_ex;
+ struct ib_uverbs_rss_caps rss_caps;
+ __u32 max_wq_type_rq;
+ __u32 reserved;
};
struct ib_uverbs_query_port {
@@ -834,6 +848,10 @@ struct ib_uverbs_flow_spec_eth {
struct ib_uverbs_flow_ipv4_filter {
__be32 src_ip;
__be32 dst_ip;
+ __u8 proto;
+ __u8 tos;
+ __u8 ttl;
+ __u8 flags;
};
struct ib_uverbs_flow_spec_ipv4 {
@@ -868,8 +886,13 @@ struct ib_uverbs_flow_spec_tcp_udp {
};
struct ib_uverbs_flow_ipv6_filter {
- __u8 src_ip[16];
- __u8 dst_ip[16];
+ __u8 src_ip[16];
+ __u8 dst_ip[16];
+ __be32 flow_label;
+ __u8 next_hdr;
+ __u8 traffic_class;
+ __u8 hop_limit;
+ __u8 reserved;
};
struct ib_uverbs_flow_spec_ipv6 {
diff --git a/drivers/infiniband/hw/mlx4/user.h b/include/uapi/rdma/mlx4-abi.h
index 07e6769ef43b..af431752655c 100644
--- a/drivers/infiniband/hw/mlx4/user.h
+++ b/include/uapi/rdma/mlx4-abi.h
@@ -31,8 +31,8 @@
* SOFTWARE.
*/
-#ifndef MLX4_IB_USER_H
-#define MLX4_IB_USER_H
+#ifndef MLX4_ABI_USER_H
+#define MLX4_ABI_USER_H
#include <linux/types.h>
@@ -104,4 +104,4 @@ struct mlx4_ib_create_qp {
__u8 reserved[5];
};
-#endif /* MLX4_IB_USER_H */
+#endif /* MLX4_ABI_USER_H */
diff --git a/drivers/infiniband/hw/mlx5/user.h b/include/uapi/rdma/mlx5-abi.h
index 188dac4301b5..f5d0f4e83b59 100644
--- a/drivers/infiniband/hw/mlx5/user.h
+++ b/include/uapi/rdma/mlx5-abi.h
@@ -30,13 +30,11 @@
* SOFTWARE.
*/
-#ifndef MLX5_IB_USER_H
-#define MLX5_IB_USER_H
+#ifndef MLX5_ABI_USER_H
+#define MLX5_ABI_USER_H
#include <linux/types.h>
-#include "mlx5_ib.h"
-
enum {
MLX5_QP_FLAG_SIGNATURE = 1 << 0,
MLX5_QP_FLAG_SCATTER_CQE = 1 << 1,
@@ -50,7 +48,6 @@ enum {
MLX5_WQ_FLAG_SIGNATURE = 1 << 0,
};
-
/* Increment this value if any changes that break userspace ABI
* compatibility are made.
*/
@@ -121,10 +118,17 @@ struct mlx5_ib_tso_caps {
__u32 supported_qpts;
};
+struct mlx5_ib_rss_caps {
+ __u64 rx_hash_fields_mask; /* enum mlx5_rx_hash_fields */
+ __u8 rx_hash_function; /* enum mlx5_rx_hash_function_flags */
+ __u8 reserved[7];
+};
+
struct mlx5_ib_query_device_resp {
__u32 comp_mask;
__u32 response_length;
struct mlx5_ib_tso_caps tso_caps;
+ struct mlx5_ib_rss_caps rss_caps;
};
struct mlx5_ib_create_cq {
@@ -242,40 +246,4 @@ struct mlx5_ib_modify_wq {
__u32 comp_mask;
__u32 reserved;
};
-
-static inline int get_qp_user_index(struct mlx5_ib_ucontext *ucontext,
- struct mlx5_ib_create_qp *ucmd,
- int inlen,
- u32 *user_index)
-{
- u8 cqe_version = ucontext->cqe_version;
-
- if (field_avail(struct mlx5_ib_create_qp, uidx, inlen) &&
- !cqe_version && (ucmd->uidx == MLX5_IB_DEFAULT_UIDX))
- return 0;
-
- if (!!(field_avail(struct mlx5_ib_create_qp, uidx, inlen) !=
- !!cqe_version))
- return -EINVAL;
-
- return verify_assign_uidx(cqe_version, ucmd->uidx, user_index);
-}
-
-static inline int get_srq_user_index(struct mlx5_ib_ucontext *ucontext,
- struct mlx5_ib_create_srq *ucmd,
- int inlen,
- u32 *user_index)
-{
- u8 cqe_version = ucontext->cqe_version;
-
- if (field_avail(struct mlx5_ib_create_srq, uidx, inlen) &&
- !cqe_version && (ucmd->uidx == MLX5_IB_DEFAULT_UIDX))
- return 0;
-
- if (!!(field_avail(struct mlx5_ib_create_srq, uidx, inlen) !=
- !!cqe_version))
- return -EINVAL;
-
- return verify_assign_uidx(cqe_version, ucmd->uidx, user_index);
-}
-#endif /* MLX5_IB_USER_H */
+#endif /* MLX5_ABI_USER_H */
diff --git a/include/uapi/rdma/mthca-abi.h b/include/uapi/rdma/mthca-abi.h
new file mode 100644
index 000000000000..bcbf4ff2f6d1
--- /dev/null
+++ b/include/uapi/rdma/mthca-abi.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MTHCA_ABI_USER_H
+#define MTHCA_ABI_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define MTHCA_UVERBS_ABI_VERSION 1
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+struct mthca_alloc_ucontext_resp {
+ __u32 qp_tab_size;
+ __u32 uarc_size;
+};
+
+struct mthca_alloc_pd_resp {
+ __u32 pdn;
+ __u32 reserved;
+};
+
+/*
+ * Mark the memory region with a DMA attribute that causes
+ * in-flight DMA to be flushed when the region is written to:
+ */
+#define MTHCA_MR_DMASYNC 0x1
+
+struct mthca_reg_mr {
+ __u32 mr_attrs;
+ __u32 reserved;
+};
+
+struct mthca_create_cq {
+ __u32 lkey;
+ __u32 pdn;
+ __u64 arm_db_page;
+ __u64 set_db_page;
+ __u32 arm_db_index;
+ __u32 set_db_index;
+};
+
+struct mthca_create_cq_resp {
+ __u32 cqn;
+ __u32 reserved;
+};
+
+struct mthca_resize_cq {
+ __u32 lkey;
+ __u32 reserved;
+};
+
+struct mthca_create_srq {
+ __u32 lkey;
+ __u32 db_index;
+ __u64 db_page;
+};
+
+struct mthca_create_srq_resp {
+ __u32 srqn;
+ __u32 reserved;
+};
+
+struct mthca_create_qp {
+ __u32 lkey;
+ __u32 reserved;
+ __u64 sq_db_page;
+ __u64 rq_db_page;
+ __u32 sq_db_index;
+ __u32 rq_db_index;
+};
+#endif /* MTHCA_ABI_USER_H */
diff --git a/drivers/infiniband/hw/nes/nes_user.h b/include/uapi/rdma/nes-abi.h
index 529c421bb15c..6eb3734394a2 100644
--- a/drivers/infiniband/hw/nes/nes_user.h
+++ b/include/uapi/rdma/nes-abi.h
@@ -34,8 +34,8 @@
*
*/
-#ifndef NES_USER_H
-#define NES_USER_H
+#ifndef NES_ABI_USER_H
+#define NES_ABI_USER_H
#include <linux/types.h>
@@ -111,4 +111,4 @@ struct nes_create_qp_resp {
__u32 nes_drv_opt;
};
-#endif /* NES_USER_H */
+#endif /* NES_ABI_USER_H */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_abi.h b/include/uapi/rdma/ocrdma-abi.h
index 430b1350fe96..9f28191bef4d 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_abi.h
+++ b/include/uapi/rdma/ocrdma-abi.h
@@ -40,110 +40,112 @@
* Costa Mesa, CA 92626
*/
-#ifndef __OCRDMA_ABI_H__
-#define __OCRDMA_ABI_H__
+#ifndef OCRDMA_ABI_USER_H
+#define OCRDMA_ABI_USER_H
+
+#include <linux/types.h>
#define OCRDMA_ABI_VERSION 2
#define OCRDMA_BE_ROCE_ABI_VERSION 1
/* user kernel communication data structures. */
struct ocrdma_alloc_ucontext_resp {
- u32 dev_id;
- u32 wqe_size;
- u32 max_inline_data;
- u32 dpp_wqe_size;
- u64 ah_tbl_page;
- u32 ah_tbl_len;
- u32 rqe_size;
- u8 fw_ver[32];
+ __u32 dev_id;
+ __u32 wqe_size;
+ __u32 max_inline_data;
+ __u32 dpp_wqe_size;
+ __u64 ah_tbl_page;
+ __u32 ah_tbl_len;
+ __u32 rqe_size;
+ __u8 fw_ver[32];
/* for future use/new features in progress */
- u64 rsvd1;
- u64 rsvd2;
+ __u64 rsvd1;
+ __u64 rsvd2;
};
struct ocrdma_alloc_pd_ureq {
- u64 rsvd1;
+ __u64 rsvd1;
};
struct ocrdma_alloc_pd_uresp {
- u32 id;
- u32 dpp_enabled;
- u32 dpp_page_addr_hi;
- u32 dpp_page_addr_lo;
- u64 rsvd1;
+ __u32 id;
+ __u32 dpp_enabled;
+ __u32 dpp_page_addr_hi;
+ __u32 dpp_page_addr_lo;
+ __u64 rsvd1;
};
struct ocrdma_create_cq_ureq {
- u32 dpp_cq;
- u32 rsvd; /* pad */
+ __u32 dpp_cq;
+ __u32 rsvd; /* pad */
};
#define MAX_CQ_PAGES 8
struct ocrdma_create_cq_uresp {
- u32 cq_id;
- u32 page_size;
- u32 num_pages;
- u32 max_hw_cqe;
- u64 page_addr[MAX_CQ_PAGES];
- u64 db_page_addr;
- u32 db_page_size;
- u32 phase_change;
+ __u32 cq_id;
+ __u32 page_size;
+ __u32 num_pages;
+ __u32 max_hw_cqe;
+ __u64 page_addr[MAX_CQ_PAGES];
+ __u64 db_page_addr;
+ __u32 db_page_size;
+ __u32 phase_change;
/* for future use/new features in progress */
- u64 rsvd1;
- u64 rsvd2;
+ __u64 rsvd1;
+ __u64 rsvd2;
};
#define MAX_QP_PAGES 8
#define MAX_UD_AV_PAGES 8
struct ocrdma_create_qp_ureq {
- u8 enable_dpp_cq;
- u8 rsvd;
- u16 dpp_cq_id;
- u32 rsvd1; /* pad */
+ __u8 enable_dpp_cq;
+ __u8 rsvd;
+ __u16 dpp_cq_id;
+ __u32 rsvd1; /* pad */
};
struct ocrdma_create_qp_uresp {
- u16 qp_id;
- u16 sq_dbid;
- u16 rq_dbid;
- u16 resv0; /* pad */
- u32 sq_page_size;
- u32 rq_page_size;
- u32 num_sq_pages;
- u32 num_rq_pages;
- u64 sq_page_addr[MAX_QP_PAGES];
- u64 rq_page_addr[MAX_QP_PAGES];
- u64 db_page_addr;
- u32 db_page_size;
- u32 dpp_credit;
- u32 dpp_offset;
- u32 num_wqe_allocated;
- u32 num_rqe_allocated;
- u32 db_sq_offset;
- u32 db_rq_offset;
- u32 db_shift;
- u64 rsvd[11];
+ __u16 qp_id;
+ __u16 sq_dbid;
+ __u16 rq_dbid;
+ __u16 resv0; /* pad */
+ __u32 sq_page_size;
+ __u32 rq_page_size;
+ __u32 num_sq_pages;
+ __u32 num_rq_pages;
+ __u64 sq_page_addr[MAX_QP_PAGES];
+ __u64 rq_page_addr[MAX_QP_PAGES];
+ __u64 db_page_addr;
+ __u32 db_page_size;
+ __u32 dpp_credit;
+ __u32 dpp_offset;
+ __u32 num_wqe_allocated;
+ __u32 num_rqe_allocated;
+ __u32 db_sq_offset;
+ __u32 db_rq_offset;
+ __u32 db_shift;
+ __u64 rsvd[11];
} __packed;
struct ocrdma_create_srq_uresp {
- u16 rq_dbid;
- u16 resv0; /* pad */
- u32 resv1;
+ __u16 rq_dbid;
+ __u16 resv0; /* pad */
+ __u32 resv1;
- u32 rq_page_size;
- u32 num_rq_pages;
+ __u32 rq_page_size;
+ __u32 num_rq_pages;
- u64 rq_page_addr[MAX_QP_PAGES];
- u64 db_page_addr;
+ __u64 rq_page_addr[MAX_QP_PAGES];
+ __u64 db_page_addr;
- u32 db_page_size;
- u32 num_rqe_allocated;
- u32 db_rq_offset;
- u32 db_shift;
+ __u32 db_page_size;
+ __u32 num_rqe_allocated;
+ __u32 db_rq_offset;
+ __u32 db_shift;
- u64 rsvd2;
- u64 rsvd3;
+ __u64 rsvd2;
+ __u64 rsvd3;
};
-#endif /* __OCRDMA_ABI_H__ */
+#endif /* OCRDMA_ABI_USER_H */
diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h
index 2302f3ce5f86..6bf1f8a022b1 100644
--- a/include/uapi/scsi/cxlflash_ioctl.h
+++ b/include/uapi/scsi/cxlflash_ioctl.h
@@ -39,19 +39,28 @@ struct dk_cxlflash_hdr {
* at this time, this provides future flexibility.
*/
#define DK_CXLFLASH_ALL_PORTS_ACTIVE 0x0000000000000001ULL
+#define DK_CXLFLASH_APP_CLOSE_ADAP_FD 0x0000000000000002ULL
/*
- * Notes:
- * -----
+ * General Notes:
+ * -------------
* The 'context_id' field of all ioctl structures contains the context
* identifier for a context in the lower 32-bits (upper 32-bits are not
* to be used when identifying a context to the AFU). That said, the value
* in its entirety (all 64-bits) is to be treated as an opaque cookie and
* should be presented as such when issuing ioctls.
+ */
+
+/*
+ * DK_CXLFLASH_ATTACH Notes:
+ * ------------------------
+ * Read/write access permissions are specified via the O_RDONLY, O_WRONLY,
+ * and O_RDWR flags defined in the fcntl.h header file.
*
- * For DK_CXLFLASH_ATTACH ioctl, user specifies read/write access
- * permissions via the O_RDONLY, O_WRONLY, and O_RDWR flags defined in
- * the fcntl.h header file.
+ * A valid adapter file descriptor (fd >= 0) is only returned on the initial
+ * attach (successful) of a context. When a context is shared(reused), the user
+ * is expected to already 'know' the adapter file descriptor associated with the
+ * context.
*/
#define DK_CXLFLASH_ATTACH_REUSE_CONTEXT 0x8000000000000000ULL
diff --git a/init/Kconfig b/init/Kconfig
index 3b9a47fe843b..d7fc22639665 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2118,12 +2118,6 @@ config PADATA
depends on SMP
bool
-# Can be selected by architectures with broken toolchains
-# that get confused by correct const<->read_only section
-# mappings
-config BROKEN_RODATA
- bool
-
config ASN1
tristate
help
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 0b13ace266f2..8cbd6e6894d5 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -225,7 +225,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
+ inode->i_mtime = inode->i_ctime = inode->i_atime = current_time(inode);
if (S_ISREG(mode)) {
struct mqueue_inode_info *info;
@@ -446,7 +446,7 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
put_ipc_ns(ipc_ns);
dir->i_size += DIRENT_SIZE;
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir);
d_instantiate(dentry, inode);
dget(dentry);
@@ -462,7 +462,7 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir);
dir->i_size -= DIRENT_SIZE;
drop_nlink(inode);
dput(dentry);
@@ -500,7 +500,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
if (ret <= 0)
return ret;
- file_inode(filp)->i_atime = file_inode(filp)->i_ctime = CURRENT_TIME;
+ file_inode(filp)->i_atime = file_inode(filp)->i_ctime = current_time(file_inode(filp));
return ret;
}
@@ -1060,7 +1060,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
__do_notify(info);
}
inode->i_atime = inode->i_mtime = inode->i_ctime =
- CURRENT_TIME;
+ current_time(inode);
}
out_unlock:
spin_unlock(&info->lock);
@@ -1156,7 +1156,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
msg_ptr = msg_get(info);
inode->i_atime = inode->i_mtime = inode->i_ctime =
- CURRENT_TIME;
+ current_time(inode);
/* There is now free space in queue. */
pipelined_receive(&wake_q, info);
@@ -1277,7 +1277,7 @@ retry:
if (u_notification == NULL) {
if (info->notify_owner == task_tgid(current)) {
remove_notification(info);
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = current_time(inode);
}
} else if (info->notify_owner != NULL) {
ret = -EBUSY;
@@ -1302,7 +1302,7 @@ retry:
info->notify_owner = get_pid(task_tgid(current));
info->notify_user_ns = get_user_ns(current_user_ns());
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = current_time(inode);
}
spin_unlock(&info->lock);
out_fput:
@@ -1359,7 +1359,7 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
f.file->f_flags &= ~O_NONBLOCK;
spin_unlock(&f.file->f_lock);
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = current_time(inode);
}
spin_unlock(&info->lock);
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index 5967b870a895..1ed8473ec537 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -97,7 +97,7 @@ static struct inode *bpf_get_inode(struct super_block *sb,
return ERR_PTR(-ENOSPC);
inode->i_ino = get_next_ino();
- inode->i_atime = CURRENT_TIME;
+ inode->i_atime = current_time(inode);
inode->i_mtime = inode->i_atime;
inode->i_ctime = inode->i_atime;
diff --git a/kernel/exit.c b/kernel/exit.c
index 1e1d913914c0..9d68c45ebbe3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -511,7 +511,7 @@ static void exit_mm(struct task_struct *tsk)
mm_update_next_owner(mm);
mmput(mm);
if (test_thread_flag(TIF_MEMDIE))
- exit_oom_victim(tsk);
+ exit_oom_victim();
}
static struct task_struct *find_alive_thread(struct task_struct *p)
diff --git a/kernel/fork.c b/kernel/fork.c
index 9a05bd93f8e7..6d42242485cb 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -359,6 +359,12 @@ static inline void free_signal_struct(struct signal_struct *sig)
{
taskstats_tgid_free(sig);
sched_autogroup_exit(sig);
+ /*
+ * __mmdrop is not safe to call from softirq context on x86 due to
+ * pgd_dtor so postpone it to the async context
+ */
+ if (sig->oom_mm)
+ mmdrop_async(sig->oom_mm);
kmem_cache_free(signal_cachep, sig);
}
@@ -848,6 +854,7 @@ static inline void __mmput(struct mm_struct *mm)
ksm_exit(mm);
khugepaged_exit(mm); /* must run before exit_mmap */
exit_mmap(mm);
+ mm_put_huge_zero_page(mm);
set_mm_exe_file(mm, NULL);
if (!list_empty(&mm->mmlist)) {
spin_lock(&mmlist_lock);
@@ -856,6 +863,7 @@ static inline void __mmput(struct mm_struct *mm)
}
if (mm->binfmt)
module_put(mm->binfmt->module);
+ set_bit(MMF_OOM_SKIP, &mm->flags);
mmdrop(mm);
}
diff --git a/kernel/groups.c b/kernel/groups.c
index 74d431d25251..2fcadd66a8fd 100644
--- a/kernel/groups.c
+++ b/kernel/groups.c
@@ -7,55 +7,31 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/user_namespace.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
struct group_info *groups_alloc(int gidsetsize)
{
- struct group_info *group_info;
- int nblocks;
- int i;
-
- nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK;
- /* Make sure we always allocate at least one indirect block pointer */
- nblocks = nblocks ? : 1;
- group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
- if (!group_info)
+ struct group_info *gi;
+ unsigned int len;
+
+ len = sizeof(struct group_info) + sizeof(kgid_t) * gidsetsize;
+ gi = kmalloc(len, GFP_KERNEL_ACCOUNT|__GFP_NOWARN|__GFP_NORETRY);
+ if (!gi)
+ gi = __vmalloc(len, GFP_KERNEL_ACCOUNT|__GFP_HIGHMEM, PAGE_KERNEL);
+ if (!gi)
return NULL;
- group_info->ngroups = gidsetsize;
- group_info->nblocks = nblocks;
- atomic_set(&group_info->usage, 1);
-
- if (gidsetsize <= NGROUPS_SMALL)
- group_info->blocks[0] = group_info->small_block;
- else {
- for (i = 0; i < nblocks; i++) {
- kgid_t *b;
- b = (void *)__get_free_page(GFP_USER);
- if (!b)
- goto out_undo_partial_alloc;
- group_info->blocks[i] = b;
- }
- }
- return group_info;
-out_undo_partial_alloc:
- while (--i >= 0) {
- free_page((unsigned long)group_info->blocks[i]);
- }
- kfree(group_info);
- return NULL;
+ atomic_set(&gi->usage, 1);
+ gi->ngroups = gidsetsize;
+ return gi;
}
EXPORT_SYMBOL(groups_alloc);
void groups_free(struct group_info *group_info)
{
- if (group_info->blocks[0] != group_info->small_block) {
- int i;
- for (i = 0; i < group_info->nblocks; i++)
- free_page((unsigned long)group_info->blocks[i]);
- }
- kfree(group_info);
+ kvfree(group_info);
}
EXPORT_SYMBOL(groups_free);
@@ -70,7 +46,7 @@ static int groups_to_user(gid_t __user *grouplist,
for (i = 0; i < count; i++) {
gid_t gid;
- gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i));
+ gid = from_kgid_munged(user_ns, group_info->gid[i]);
if (put_user(gid, grouplist+i))
return -EFAULT;
}
@@ -95,7 +71,7 @@ static int groups_from_user(struct group_info *group_info,
if (!gid_valid(kgid))
return -EINVAL;
- GROUP_AT(group_info, i) = kgid;
+ group_info->gid[i] = kgid;
}
return 0;
}
@@ -115,15 +91,14 @@ static void groups_sort(struct group_info *group_info)
for (base = 0; base < max; base++) {
int left = base;
int right = left + stride;
- kgid_t tmp = GROUP_AT(group_info, right);
+ kgid_t tmp = group_info->gid[right];
- while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) {
- GROUP_AT(group_info, right) =
- GROUP_AT(group_info, left);
+ while (left >= 0 && gid_gt(group_info->gid[left], tmp)) {
+ group_info->gid[right] = group_info->gid[left];
right = left;
left -= stride;
}
- GROUP_AT(group_info, right) = tmp;
+ group_info->gid[right] = tmp;
}
stride /= 3;
}
@@ -141,9 +116,9 @@ int groups_search(const struct group_info *group_info, kgid_t grp)
right = group_info->ngroups;
while (left < right) {
unsigned int mid = (left+right)/2;
- if (gid_gt(grp, GROUP_AT(group_info, mid)))
+ if (gid_gt(grp, group_info->gid[mid]))
left = mid + 1;
- else if (gid_lt(grp, GROUP_AT(group_info, mid)))
+ else if (gid_lt(grp, group_info->gid[mid]))
right = mid;
else
return 1;
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 8bbe50704621..af4643873e71 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -274,7 +274,6 @@ static int klp_write_object_relocations(struct module *pmod,
objname = klp_is_module(obj) ? obj->name : "vmlinux";
- module_disable_ro(pmod);
/* For each klp relocation section */
for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
sec = pmod->klp_info->sechdrs + i;
@@ -309,7 +308,6 @@ static int klp_write_object_relocations(struct module *pmod,
break;
}
- module_enable_ro(pmod, true);
return ret;
}
@@ -547,9 +545,6 @@ static int __klp_enable_patch(struct klp_patch *patch)
list_prev_entry(patch, list)->state == KLP_DISABLED)
return -EBUSY;
- pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n");
- add_taint(TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
-
pr_notice("enabling patch '%s'\n", patch->mod->name);
klp_for_each_object(patch, obj) {
@@ -763,6 +758,12 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
func->old_sympos ? func->old_sympos : 1);
}
+/* Arches may override this to finish any remaining arch-specific tasks */
+void __weak arch_klp_init_object_loaded(struct klp_patch *patch,
+ struct klp_object *obj)
+{
+}
+
/* parts of the initialization that is done only when the object is loaded */
static int klp_init_object_loaded(struct klp_patch *patch,
struct klp_object *obj)
@@ -770,9 +771,15 @@ static int klp_init_object_loaded(struct klp_patch *patch,
struct klp_func *func;
int ret;
+ module_disable_ro(patch->mod);
ret = klp_write_object_relocations(patch->mod, obj);
- if (ret)
+ if (ret) {
+ module_enable_ro(patch->mod, true);
return ret;
+ }
+
+ arch_klp_init_object_loaded(patch, obj);
+ module_enable_ro(patch->mod, true);
klp_for_each_func(obj, func) {
ret = klp_find_object_symbol(obj->name, func->old_name,
diff --git a/kernel/module.c b/kernel/module.c
index 529efae9f481..f57dd63186e6 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1149,6 +1149,8 @@ static size_t module_flags_taint(struct module *mod, char *buf)
buf[l++] = 'C';
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
buf[l++] = 'E';
+ if (mod->taints & (1 << TAINT_LIVEPATCH))
+ buf[l++] = 'K';
/*
* TAINT_FORCED_RMMOD: could be added.
* TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
@@ -2792,14 +2794,17 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
}
#ifdef CONFIG_LIVEPATCH
-static int find_livepatch_modinfo(struct module *mod, struct load_info *info)
+static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
{
- mod->klp = get_modinfo(info, "livepatch") ? true : false;
+ if (get_modinfo(info, "livepatch")) {
+ mod->klp = true;
+ add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
+ }
return 0;
}
#else /* !CONFIG_LIVEPATCH */
-static int find_livepatch_modinfo(struct module *mod, struct load_info *info)
+static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
{
if (get_modinfo(info, "livepatch")) {
pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
@@ -2969,7 +2974,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
"is unknown, you have been warned.\n", mod->name);
}
- err = find_livepatch_modinfo(mod, info);
+ err = check_modinfo_livepatch(mod, info);
if (err)
return err;
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 8f27d5a8adf6..2fba066e125f 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -144,23 +144,12 @@ int freeze_processes(void)
/*
* Now that the whole userspace is frozen we need to disbale
* the OOM killer to disallow any further interference with
- * killable tasks.
+ * killable tasks. There is no guarantee oom victims will
+ * ever reach a point they go away we have to wait with a timeout.
*/
- if (!error && !oom_killer_disable())
+ if (!error && !oom_killer_disable(msecs_to_jiffies(freeze_timeout_msecs)))
error = -EBUSY;
- /*
- * There is a hard to fix race between oom_reaper kernel thread
- * and oom_killer_disable. oom_reaper calls exit_oom_victim
- * before the victim reaches exit_mm so try to freeze all the tasks
- * again and catch such a left over task.
- */
- if (!error) {
- pr_info("Double checking all user space processes after OOM killer disable... ");
- error = try_to_freeze_tasks(true);
- pr_cont("\n");
- }
-
if (error)
thaw_processes();
return error;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index eea6dbc2d8cf..d5e397315473 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -253,6 +253,17 @@ static int preferred_console = -1;
int console_set_on_cmdline;
EXPORT_SYMBOL(console_set_on_cmdline);
+#ifdef CONFIG_OF
+static bool of_specified_console;
+
+void console_set_by_of(void)
+{
+ of_specified_console = true;
+}
+#else
+# define of_specified_console false
+#endif
+
/* Flag: console code may call schedule() */
static int console_may_schedule;
@@ -655,11 +666,8 @@ static ssize_t msg_print_ext_header(char *buf, size_t size,
* better readable output. 'c' in the record flags mark the first
* fragment of a line, '+' the following.
*/
- if (msg->flags & LOG_CONT && !(prev_flags & LOG_CONT))
- cont = 'c';
- else if ((msg->flags & LOG_CONT) ||
- ((prev_flags & LOG_CONT) && !(msg->flags & LOG_PREFIX)))
- cont = '+';
+ if (msg->flags & LOG_CONT)
+ cont = (prev_flags & LOG_CONT) ? '+' : 'c';
return scnprintf(buf, size, "%u,%llu,%llu,%c;",
(msg->facility << 3) | msg->level, seq, ts_usec, cont);
@@ -786,6 +794,8 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
return ret;
}
+static void cont_flush(void);
+
static ssize_t devkmsg_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -801,6 +811,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
if (ret)
return ret;
raw_spin_lock_irq(&logbuf_lock);
+ cont_flush();
while (user->seq == log_next_seq) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
@@ -863,6 +874,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
return -ESPIPE;
raw_spin_lock_irq(&logbuf_lock);
+ cont_flush();
switch (whence) {
case SEEK_SET:
/* the first record */
@@ -901,6 +913,7 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
poll_wait(file, &log_wait, wait);
raw_spin_lock_irq(&logbuf_lock);
+ cont_flush();
if (user->seq < log_next_seq) {
/* return error when data has vanished underneath us */
if (user->seq < log_first_seq)
@@ -1287,6 +1300,7 @@ static int syslog_print(char __user *buf, int size)
size_t skip;
raw_spin_lock_irq(&logbuf_lock);
+ cont_flush();
if (syslog_seq < log_first_seq) {
/* messages are gone, move to first one */
syslog_seq = log_first_seq;
@@ -1346,6 +1360,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
return -ENOMEM;
raw_spin_lock_irq(&logbuf_lock);
+ cont_flush();
if (buf) {
u64 next_seq;
u64 seq;
@@ -1507,6 +1522,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
/* Number of chars in the log buffer */
case SYSLOG_ACTION_SIZE_UNREAD:
raw_spin_lock_irq(&logbuf_lock);
+ cont_flush();
if (syslog_seq < log_first_seq) {
/* messages are gone, move to first one */
syslog_seq = log_first_seq;
@@ -1643,35 +1659,33 @@ static struct cont {
bool flushed:1; /* buffer sealed and committed */
} cont;
-static void cont_flush(enum log_flags flags)
+static void cont_flush(void)
{
if (cont.flushed)
return;
if (cont.len == 0)
return;
-
if (cont.cons) {
/*
* If a fragment of this line was directly flushed to the
* console; wait for the console to pick up the rest of the
* line. LOG_NOCONS suppresses a duplicated output.
*/
- log_store(cont.facility, cont.level, flags | LOG_NOCONS,
+ log_store(cont.facility, cont.level, cont.flags | LOG_NOCONS,
cont.ts_nsec, NULL, 0, cont.buf, cont.len);
- cont.flags = flags;
cont.flushed = true;
} else {
/*
* If no fragment of this line ever reached the console,
* just submit it to the store and free the buffer.
*/
- log_store(cont.facility, cont.level, flags, 0,
+ log_store(cont.facility, cont.level, cont.flags, 0,
NULL, 0, cont.buf, cont.len);
cont.len = 0;
}
}
-static bool cont_add(int facility, int level, const char *text, size_t len)
+static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len)
{
if (cont.len && cont.flushed)
return false;
@@ -1682,7 +1696,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
* the line gets too long, split it up in separate records.
*/
if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) {
- cont_flush(LOG_CONT);
+ cont_flush();
return false;
}
@@ -1691,7 +1705,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
cont.level = level;
cont.owner = current;
cont.ts_nsec = local_clock();
- cont.flags = 0;
+ cont.flags = flags;
cont.cons = 0;
cont.flushed = false;
}
@@ -1699,8 +1713,15 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
memcpy(cont.buf + cont.len, text, len);
cont.len += len;
+ // The original flags come from the first line,
+ // but later continuations can add a newline.
+ if (flags & LOG_NEWLINE) {
+ cont.flags |= LOG_NEWLINE;
+ cont_flush();
+ }
+
if (cont.len > (sizeof(cont.buf) * 80) / 100)
- cont_flush(LOG_CONT);
+ cont_flush();
return true;
}
@@ -1733,6 +1754,31 @@ static size_t cont_print_text(char *text, size_t size)
return textlen;
}
+static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
+{
+ /*
+ * If an earlier line was buffered, and we're a continuation
+ * write from the same process, try to add it to the buffer.
+ */
+ if (cont.len) {
+ if (cont.owner == current && (lflags & LOG_CONT)) {
+ if (cont_add(facility, level, lflags, text, text_len))
+ return text_len;
+ }
+ /* Otherwise, make sure it's flushed */
+ cont_flush();
+ }
+
+ /* If it doesn't end in a newline, try to buffer the current line */
+ if (!(lflags & LOG_NEWLINE)) {
+ if (cont_add(facility, level, lflags, text, text_len))
+ return text_len;
+ }
+
+ /* Store it in the record log */
+ return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len);
+}
+
asmlinkage int vprintk_emit(int facility, int level,
const char *dict, size_t dictlen,
const char *fmt, va_list args)
@@ -1819,10 +1865,9 @@ asmlinkage int vprintk_emit(int facility, int level,
/* strip kernel syslog prefix and extract log level or control flags */
if (facility == 0) {
- int kern_level = printk_get_level(text);
+ int kern_level;
- if (kern_level) {
- const char *end_of_header = printk_skip_level(text);
+ while ((kern_level = printk_get_level(text)) != 0) {
switch (kern_level) {
case '0' ... '7':
if (level == LOGLEVEL_DEFAULT)
@@ -1830,14 +1875,13 @@ asmlinkage int vprintk_emit(int facility, int level,
/* fallthrough */
case 'd': /* KERN_DEFAULT */
lflags |= LOG_PREFIX;
+ break;
+ case 'c': /* KERN_CONT */
+ lflags |= LOG_CONT;
}
- /*
- * No need to check length here because vscnprintf
- * put '\0' at the end of the string. Only valid and
- * newly printed level is detected.
- */
- text_len -= end_of_header - text;
- text = (char *)end_of_header;
+
+ text_len -= 2;
+ text += 2;
}
}
@@ -1847,45 +1891,7 @@ asmlinkage int vprintk_emit(int facility, int level,
if (dict)
lflags |= LOG_PREFIX|LOG_NEWLINE;
- if (!(lflags & LOG_NEWLINE)) {
- /*
- * Flush the conflicting buffer. An earlier newline was missing,
- * or another task also prints continuation lines.
- */
- if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
- cont_flush(LOG_NEWLINE);
-
- /* buffer line if possible, otherwise store it right away */
- if (cont_add(facility, level, text, text_len))
- printed_len += text_len;
- else
- printed_len += log_store(facility, level,
- lflags | LOG_CONT, 0,
- dict, dictlen, text, text_len);
- } else {
- bool stored = false;
-
- /*
- * If an earlier newline was missing and it was the same task,
- * either merge it with the current buffer and flush, or if
- * there was a race with interrupts (prefix == true) then just
- * flush it out and store this line separately.
- * If the preceding printk was from a different task and missed
- * a newline, flush and append the newline.
- */
- if (cont.len) {
- if (cont.owner == current && !(lflags & LOG_PREFIX))
- stored = cont_add(facility, level, text,
- text_len);
- cont_flush(LOG_NEWLINE);
- }
-
- if (stored)
- printed_len += text_len;
- else
- printed_len += log_store(facility, level, lflags, 0,
- dict, dictlen, text, text_len);
- }
+ printed_len += log_output(facility, level, lflags, dict, dictlen, text, text_len);
logbuf_cpu = UINT_MAX;
raw_spin_unlock(&logbuf_lock);
@@ -2647,7 +2653,7 @@ void register_console(struct console *newcon)
* didn't select a console we take the first one
* that registers here.
*/
- if (preferred_console < 0) {
+ if (preferred_console < 0 && !of_specified_console) {
if (newcon->index < 0)
newcon->index = 0;
if (newcon->setup == NULL ||
@@ -3029,6 +3035,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
dumper->active = true;
raw_spin_lock_irqsave(&logbuf_lock, flags);
+ cont_flush();
dumper->cur_seq = clear_seq;
dumper->cur_idx = clear_idx;
dumper->next_seq = log_next_seq;
@@ -3119,6 +3126,7 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
bool ret;
raw_spin_lock_irqsave(&logbuf_lock, flags);
+ cont_flush();
ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
@@ -3161,6 +3169,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
goto out;
raw_spin_lock_irqsave(&logbuf_lock, flags);
+ cont_flush();
if (dumper->cur_seq < log_first_seq) {
/* messages are gone, move to first available one */
dumper->cur_seq = log_first_seq;
diff --git a/kernel/relay.c b/kernel/relay.c
index fc9b4a4af463..9988f5cc2d46 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -1108,51 +1108,23 @@ static size_t relay_file_read_end_pos(struct rchan_buf *buf,
return end_pos;
}
-/*
- * subbuf_read_actor - read up to one subbuf's worth of data
- */
-static int subbuf_read_actor(size_t read_start,
- struct rchan_buf *buf,
- size_t avail,
- read_descriptor_t *desc)
-{
- void *from;
- int ret = 0;
-
- from = buf->start + read_start;
- ret = avail;
- if (copy_to_user(desc->arg.buf, from, avail)) {
- desc->error = -EFAULT;
- ret = 0;
- }
- desc->arg.data += ret;
- desc->written += ret;
- desc->count -= ret;
-
- return ret;
-}
-
-typedef int (*subbuf_actor_t) (size_t read_start,
- struct rchan_buf *buf,
- size_t avail,
- read_descriptor_t *desc);
-
-/*
- * relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
- */
-static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
- subbuf_actor_t subbuf_actor,
- read_descriptor_t *desc)
+static ssize_t relay_file_read(struct file *filp,
+ char __user *buffer,
+ size_t count,
+ loff_t *ppos)
{
struct rchan_buf *buf = filp->private_data;
size_t read_start, avail;
+ size_t written = 0;
int ret;
- if (!desc->count)
+ if (!count)
return 0;
inode_lock(file_inode(filp));
do {
+ void *from;
+
if (!relay_file_read_avail(buf, *ppos))
break;
@@ -1161,32 +1133,22 @@ static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
if (!avail)
break;
- avail = min(desc->count, avail);
- ret = subbuf_actor(read_start, buf, avail, desc);
- if (desc->error < 0)
+ avail = min(count, avail);
+ from = buf->start + read_start;
+ ret = avail;
+ if (copy_to_user(buffer, from, avail))
break;
- if (ret) {
- relay_file_read_consume(buf, read_start, ret);
- *ppos = relay_file_read_end_pos(buf, read_start, ret);
- }
- } while (desc->count && ret);
- inode_unlock(file_inode(filp));
+ buffer += ret;
+ written += ret;
+ count -= ret;
- return desc->written;
-}
+ relay_file_read_consume(buf, read_start, ret);
+ *ppos = relay_file_read_end_pos(buf, read_start, ret);
+ } while (count);
+ inode_unlock(file_inode(filp));
-static ssize_t relay_file_read(struct file *filp,
- char __user *buffer,
- size_t count,
- loff_t *ppos)
-{
- read_descriptor_t desc;
- desc.written = 0;
- desc.count = count;
- desc.arg.buf = buffer;
- desc.error = 0;
- return relay_file_read_subbufs(filp, ppos, subbuf_read_actor, &desc);
+ return written;
}
static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 9fb873cfc75c..1d8718d5300d 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -16,6 +16,9 @@
#include "sched.h"
+/* Linker adds these: start and end of __cpuidle functions */
+extern char __cpuidle_text_start[], __cpuidle_text_end[];
+
/**
* sched_idle_set_state - Record idle state for the current CPU.
* @idle_state: State to record.
@@ -53,7 +56,7 @@ static int __init cpu_idle_nopoll_setup(char *__unused)
__setup("hlt", cpu_idle_nopoll_setup);
#endif
-static inline int cpu_idle_poll(void)
+static noinline int __cpuidle cpu_idle_poll(void)
{
rcu_idle_enter();
trace_cpu_idle_rcuidle(0, smp_processor_id());
@@ -84,7 +87,7 @@ void __weak arch_cpu_idle(void)
*
* To use when the cpuidle framework cannot be used.
*/
-void default_idle_call(void)
+void __cpuidle default_idle_call(void)
{
if (current_clr_polling_and_test()) {
local_irq_enable();
@@ -271,6 +274,12 @@ static void cpu_idle_loop(void)
}
}
+bool cpu_in_idle(unsigned long pc)
+{
+ return pc >= (unsigned long)__cpuidle_text_start &&
+ pc < (unsigned long)__cpuidle_text_end;
+}
+
void cpu_startup_entry(enum cpuhp_state state)
{
/*
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index fc0d8270f69e..13bc43d1fb22 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -122,12 +122,12 @@ static int smpboot_thread_fn(void *data)
if (kthread_should_park()) {
__set_current_state(TASK_RUNNING);
+ preempt_enable();
if (ht->park && td->status == HP_THREAD_ACTIVE) {
BUG_ON(td->cpu != smp_processor_id());
ht->park(td->cpu);
td->status = HP_THREAD_PARKED;
}
- preempt_enable();
kthread_parkme();
/* We might have been woken for stop */
continue;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 2c5e3a8e00d7..635482e60ca3 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -250,3 +250,8 @@ cond_syscall(sys_execveat);
/* membarrier */
cond_syscall(sys_membarrier);
+
+/* memory protection keys */
+cond_syscall(sys_pkey_mprotect);
+cond_syscall(sys_pkey_alloc);
+cond_syscall(sys_pkey_free);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index a43775c6646c..706309f9ed84 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -107,9 +107,8 @@ extern unsigned int core_pipe_limit;
extern int pid_max;
extern int pid_max_min, pid_max_max;
extern int percpu_pagelist_fraction;
-extern int compat_log;
extern int latencytop_enabled;
-extern int sysctl_nr_open_min, sysctl_nr_open_max;
+extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
#ifndef CONFIG_MMU
extern int sysctl_nr_trim_pages;
#endif
@@ -1085,15 +1084,6 @@ static struct ctl_table kern_table[] = {
.extra1 = &neg_one,
},
#endif
-#ifdef CONFIG_COMPAT
- {
- .procname = "compat-log",
- .data = &compat_log,
- .maxlen = sizeof (int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
-#endif
#ifdef CONFIG_RT_MUTEXES
{
.procname = "max_lock_depth",
@@ -1693,7 +1683,7 @@ static struct ctl_table fs_table[] = {
{
.procname = "nr_open",
.data = &sysctl_nr_open,
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &sysctl_nr_open_min,
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e07fb093f819..37dec7e3db43 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -403,8 +403,11 @@ static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
tkr = tkf->base + (seq & 0x01);
now = ktime_to_ns(tkr->base);
- now += clocksource_delta(tkr->read(tkr->clock),
- tkr->cycle_last, tkr->mask);
+ now += timekeeping_delta_to_ns(tkr,
+ clocksource_delta(
+ tkr->read(tkr->clock),
+ tkr->cycle_last,
+ tkr->mask));
} while (read_seqcount_retry(&tkf->seq, seq));
return now;
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index b2b6efc083a4..5e10395da88e 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -610,8 +610,7 @@ static int perf_sysenter_enable(struct trace_event_call *call)
if (!sys_perf_refcount_enter)
ret = register_trace_sys_enter(perf_syscall_enter, NULL);
if (ret) {
- pr_info("event trace: Could not activate"
- "syscall entry trace point");
+ pr_info("event trace: Could not activate syscall entry trace point");
} else {
set_bit(num, enabled_perf_enter_syscalls);
sys_perf_refcount_enter++;
@@ -682,8 +681,7 @@ static int perf_sysexit_enable(struct trace_event_call *call)
if (!sys_perf_refcount_exit)
ret = register_trace_sys_exit(perf_syscall_exit, NULL);
if (ret) {
- pr_info("event trace: Could not activate"
- "syscall exit trace point");
+ pr_info("event trace: Could not activate syscall exit trace point");
} else {
set_bit(num, enabled_perf_exit_syscalls);
sys_perf_refcount_exit++;
diff --git a/kernel/uid16.c b/kernel/uid16.c
index d58cc4d8f0d1..cc40793464e3 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -117,7 +117,7 @@ static int groups16_to_user(old_gid_t __user *grouplist,
kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
- kgid = GROUP_AT(group_info, i);
+ kgid = group_info->gid[i];
group = high2lowgid(from_kgid_munged(user_ns, kgid));
if (put_user(group, grouplist+i))
return -EFAULT;
@@ -142,7 +142,7 @@ static int groups16_from_user(struct group_info *group_info,
if (!gid_valid(kgid))
return -EINVAL;
- GROUP_AT(group_info, i) = kgid;
+ group_info->gid[i] = kgid;
}
return 0;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index ef071ca73fc3..bd81f0390277 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2974,6 +2974,31 @@ bool flush_delayed_work(struct delayed_work *dwork)
}
EXPORT_SYMBOL(flush_delayed_work);
+static bool __cancel_work(struct work_struct *work, bool is_dwork)
+{
+ unsigned long flags;
+ int ret;
+
+ do {
+ ret = try_to_grab_pending(work, is_dwork, &flags);
+ } while (unlikely(ret == -EAGAIN));
+
+ if (unlikely(ret < 0))
+ return false;
+
+ set_work_pool_and_clear_pending(work, get_work_pool_id(work));
+ local_irq_restore(flags);
+ return ret;
+}
+
+/*
+ * See cancel_delayed_work()
+ */
+bool cancel_work(struct work_struct *work)
+{
+ return __cancel_work(work, false);
+}
+
/**
* cancel_delayed_work - cancel a delayed work
* @dwork: delayed_work to cancel
@@ -2992,20 +3017,7 @@ EXPORT_SYMBOL(flush_delayed_work);
*/
bool cancel_delayed_work(struct delayed_work *dwork)
{
- unsigned long flags;
- int ret;
-
- do {
- ret = try_to_grab_pending(&dwork->work, true, &flags);
- } while (unlikely(ret == -EAGAIN));
-
- if (unlikely(ret < 0))
- return false;
-
- set_work_pool_and_clear_pending(&dwork->work,
- get_work_pool_id(&dwork->work));
- local_irq_restore(flags);
- return ret;
+ return __cancel_work(&dwork->work, true);
}
EXPORT_SYMBOL(cancel_delayed_work);
diff --git a/lib/Kconfig b/lib/Kconfig
index d79909dc01ec..260a80e313b9 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -457,9 +457,6 @@ config NLATTR
config GENERIC_ATOMIC64
bool
-config ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
- def_bool y if GENERIC_ATOMIC64
-
config LRU_CACHE
tristate
@@ -550,4 +547,7 @@ config STACKDEPOT
bool
select STACKTRACE
+config SBITMAP
+ bool
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index cab7405f48d2..39d07e754822 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -305,7 +305,7 @@ config DEBUG_SECTION_MISMATCH
a larger kernel).
- Run the section mismatch analysis for each module/built-in.o file.
When we run the section mismatch analysis on vmlinux.o, we
- lose valueble information about where the mismatch was
+ lose valuable information about where the mismatch was
introduced.
Running the analysis for each module/built-in.o file
tells where the mismatch happens much closer to the
diff --git a/lib/Makefile b/lib/Makefile
index df747e5eeb7a..f3ca8c0ab634 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -227,3 +227,5 @@ obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
obj-$(CONFIG_UBSAN) += ubsan.o
UBSAN_SANITIZE_ubsan.o := n
+
+obj-$(CONFIG_SBITMAP) += sbitmap.o
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c
index dbb369145dda..46042901130f 100644
--- a/lib/atomic64_test.c
+++ b/lib/atomic64_test.c
@@ -213,7 +213,6 @@ static __init void test_atomic64(void)
r += one;
BUG_ON(v.counter != r);
-#ifdef CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
INIT(onestwos);
BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
r -= one;
@@ -226,9 +225,6 @@ static __init void test_atomic64(void)
INIT(-one);
BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
BUG_ON(v.counter != r);
-#else
-#warning Please implement atomic64_dec_if_positive for your architecture and select the above Kconfig symbol
-#endif
INIT(onestwos);
BUG_ON(!atomic64_inc_not_zero(&v));
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 06f02f6aecd2..8971370bfb16 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -44,6 +44,7 @@ enum {
dma_debug_page,
dma_debug_sg,
dma_debug_coherent,
+ dma_debug_resource,
};
enum map_err_types {
@@ -151,8 +152,9 @@ static const char *const maperr2str[] = {
[MAP_ERR_CHECKED] = "dma map error checked",
};
-static const char *type2name[4] = { "single", "page",
- "scather-gather", "coherent" };
+static const char *type2name[5] = { "single", "page",
+ "scather-gather", "coherent",
+ "resource" };
static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
"DMA_FROM_DEVICE", "DMA_NONE" };
@@ -400,6 +402,9 @@ static void hash_bucket_del(struct dma_debug_entry *entry)
static unsigned long long phys_addr(struct dma_debug_entry *entry)
{
+ if (entry->type == dma_debug_resource)
+ return __pfn_to_phys(entry->pfn) + entry->offset;
+
return page_to_phys(pfn_to_page(entry->pfn)) + entry->offset;
}
@@ -1519,6 +1524,49 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
}
EXPORT_SYMBOL(debug_dma_free_coherent);
+void debug_dma_map_resource(struct device *dev, phys_addr_t addr, size_t size,
+ int direction, dma_addr_t dma_addr)
+{
+ struct dma_debug_entry *entry;
+
+ if (unlikely(dma_debug_disabled()))
+ return;
+
+ entry = dma_entry_alloc();
+ if (!entry)
+ return;
+
+ entry->type = dma_debug_resource;
+ entry->dev = dev;
+ entry->pfn = PHYS_PFN(addr);
+ entry->offset = offset_in_page(addr);
+ entry->size = size;
+ entry->dev_addr = dma_addr;
+ entry->direction = direction;
+ entry->map_err_type = MAP_ERR_NOT_CHECKED;
+
+ add_dma_entry(entry);
+}
+EXPORT_SYMBOL(debug_dma_map_resource);
+
+void debug_dma_unmap_resource(struct device *dev, dma_addr_t dma_addr,
+ size_t size, int direction)
+{
+ struct dma_debug_entry ref = {
+ .type = dma_debug_resource,
+ .dev = dev,
+ .dev_addr = dma_addr,
+ .size = size,
+ .direction = direction,
+ };
+
+ if (unlikely(dma_debug_disabled()))
+ return;
+
+ check_unmap(&ref);
+}
+EXPORT_SYMBOL(debug_dma_unmap_resource);
+
void debug_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
size_t size, int direction)
{
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 7e3138cfc8c9..0ce341125195 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -3,8 +3,11 @@
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/splice.h>
#include <net/checksum.h>
+#define PIPE_PARANOIA /* for now */
+
#define iterate_iovec(i, n, __v, __p, skip, STEP) { \
size_t left; \
size_t wanted = n; \
@@ -290,6 +293,93 @@ done:
return wanted - bytes;
}
+#ifdef PIPE_PARANOIA
+static bool sanity(const struct iov_iter *i)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ int idx = i->idx;
+ int next = pipe->curbuf + pipe->nrbufs;
+ if (i->iov_offset) {
+ struct pipe_buffer *p;
+ if (unlikely(!pipe->nrbufs))
+ goto Bad; // pipe must be non-empty
+ if (unlikely(idx != ((next - 1) & (pipe->buffers - 1))))
+ goto Bad; // must be at the last buffer...
+
+ p = &pipe->bufs[idx];
+ if (unlikely(p->offset + p->len != i->iov_offset))
+ goto Bad; // ... at the end of segment
+ } else {
+ if (idx != (next & (pipe->buffers - 1)))
+ goto Bad; // must be right after the last buffer
+ }
+ return true;
+Bad:
+ printk(KERN_ERR "idx = %d, offset = %zd\n", i->idx, i->iov_offset);
+ printk(KERN_ERR "curbuf = %d, nrbufs = %d, buffers = %d\n",
+ pipe->curbuf, pipe->nrbufs, pipe->buffers);
+ for (idx = 0; idx < pipe->buffers; idx++)
+ printk(KERN_ERR "[%p %p %d %d]\n",
+ pipe->bufs[idx].ops,
+ pipe->bufs[idx].page,
+ pipe->bufs[idx].offset,
+ pipe->bufs[idx].len);
+ WARN_ON(1);
+ return false;
+}
+#else
+#define sanity(i) true
+#endif
+
+static inline int next_idx(int idx, struct pipe_inode_info *pipe)
+{
+ return (idx + 1) & (pipe->buffers - 1);
+}
+
+static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t bytes,
+ struct iov_iter *i)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ struct pipe_buffer *buf;
+ size_t off;
+ int idx;
+
+ if (unlikely(bytes > i->count))
+ bytes = i->count;
+
+ if (unlikely(!bytes))
+ return 0;
+
+ if (!sanity(i))
+ return 0;
+
+ off = i->iov_offset;
+ idx = i->idx;
+ buf = &pipe->bufs[idx];
+ if (off) {
+ if (offset == off && buf->page == page) {
+ /* merge with the last one */
+ buf->len += bytes;
+ i->iov_offset += bytes;
+ goto out;
+ }
+ idx = next_idx(idx, pipe);
+ buf = &pipe->bufs[idx];
+ }
+ if (idx == pipe->curbuf && pipe->nrbufs)
+ return 0;
+ pipe->nrbufs++;
+ buf->ops = &page_cache_pipe_buf_ops;
+ get_page(buf->page = page);
+ buf->offset = offset;
+ buf->len = bytes;
+ i->iov_offset = offset + bytes;
+ i->idx = idx;
+out:
+ i->count -= bytes;
+ return bytes;
+}
+
/*
* Fault in one or more iovecs of the given iov_iter, to a maximum length of
* bytes. For each iovec, fault in each page that constitutes the iovec.
@@ -306,8 +396,7 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
iterate_iovec(i, bytes, v, iov, skip, ({
- err = fault_in_multipages_readable(v.iov_base,
- v.iov_len);
+ err = fault_in_pages_readable(v.iov_base, v.iov_len);
if (unlikely(err))
return err;
0;}))
@@ -356,9 +445,98 @@ static void memzero_page(struct page *page, size_t offset, size_t len)
kunmap_atomic(addr);
}
+static inline bool allocated(struct pipe_buffer *buf)
+{
+ return buf->ops == &default_pipe_buf_ops;
+}
+
+static inline void data_start(const struct iov_iter *i, int *idxp, size_t *offp)
+{
+ size_t off = i->iov_offset;
+ int idx = i->idx;
+ if (off && (!allocated(&i->pipe->bufs[idx]) || off == PAGE_SIZE)) {
+ idx = next_idx(idx, i->pipe);
+ off = 0;
+ }
+ *idxp = idx;
+ *offp = off;
+}
+
+static size_t push_pipe(struct iov_iter *i, size_t size,
+ int *idxp, size_t *offp)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ size_t off;
+ int idx;
+ ssize_t left;
+
+ if (unlikely(size > i->count))
+ size = i->count;
+ if (unlikely(!size))
+ return 0;
+
+ left = size;
+ data_start(i, &idx, &off);
+ *idxp = idx;
+ *offp = off;
+ if (off) {
+ left -= PAGE_SIZE - off;
+ if (left <= 0) {
+ pipe->bufs[idx].len += size;
+ return size;
+ }
+ pipe->bufs[idx].len = PAGE_SIZE;
+ idx = next_idx(idx, pipe);
+ }
+ while (idx != pipe->curbuf || !pipe->nrbufs) {
+ struct page *page = alloc_page(GFP_USER);
+ if (!page)
+ break;
+ pipe->nrbufs++;
+ pipe->bufs[idx].ops = &default_pipe_buf_ops;
+ pipe->bufs[idx].page = page;
+ pipe->bufs[idx].offset = 0;
+ if (left <= PAGE_SIZE) {
+ pipe->bufs[idx].len = left;
+ return size;
+ }
+ pipe->bufs[idx].len = PAGE_SIZE;
+ left -= PAGE_SIZE;
+ idx = next_idx(idx, pipe);
+ }
+ return size - left;
+}
+
+static size_t copy_pipe_to_iter(const void *addr, size_t bytes,
+ struct iov_iter *i)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ size_t n, off;
+ int idx;
+
+ if (!sanity(i))
+ return 0;
+
+ bytes = n = push_pipe(i, bytes, &idx, &off);
+ if (unlikely(!n))
+ return 0;
+ for ( ; n; idx = next_idx(idx, pipe), off = 0) {
+ size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
+ memcpy_to_page(pipe->bufs[idx].page, off, addr, chunk);
+ i->idx = idx;
+ i->iov_offset = off + chunk;
+ n -= chunk;
+ addr += chunk;
+ }
+ i->count -= bytes;
+ return bytes;
+}
+
size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
{
const char *from = addr;
+ if (unlikely(i->type & ITER_PIPE))
+ return copy_pipe_to_iter(addr, bytes, i);
iterate_and_advance(i, bytes, v,
__copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
v.iov_len),
@@ -374,6 +552,10 @@ EXPORT_SYMBOL(copy_to_iter);
size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
{
char *to = addr;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return 0;
+ }
iterate_and_advance(i, bytes, v,
__copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
v.iov_len),
@@ -389,6 +571,10 @@ EXPORT_SYMBOL(copy_from_iter);
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
{
char *to = addr;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return 0;
+ }
iterate_and_advance(i, bytes, v,
__copy_from_user_nocache((to += v.iov_len) - v.iov_len,
v.iov_base, v.iov_len),
@@ -409,14 +595,20 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
kunmap_atomic(kaddr);
return wanted;
- } else
+ } else if (likely(!(i->type & ITER_PIPE)))
return copy_page_to_iter_iovec(page, offset, bytes, i);
+ else
+ return copy_page_to_iter_pipe(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 (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return 0;
+ }
if (i->type & (ITER_BVEC|ITER_KVEC)) {
void *kaddr = kmap_atomic(page);
size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
@@ -427,8 +619,34 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
}
EXPORT_SYMBOL(copy_page_from_iter);
+static size_t pipe_zero(size_t bytes, struct iov_iter *i)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ size_t n, off;
+ int idx;
+
+ if (!sanity(i))
+ return 0;
+
+ bytes = n = push_pipe(i, bytes, &idx, &off);
+ if (unlikely(!n))
+ return 0;
+
+ for ( ; n; idx = next_idx(idx, pipe), off = 0) {
+ size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
+ memzero_page(pipe->bufs[idx].page, off, chunk);
+ i->idx = idx;
+ i->iov_offset = off + chunk;
+ n -= chunk;
+ }
+ i->count -= bytes;
+ return bytes;
+}
+
size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
{
+ if (unlikely(i->type & ITER_PIPE))
+ return pipe_zero(bytes, i);
iterate_and_advance(i, bytes, v,
__clear_user(v.iov_base, v.iov_len),
memzero_page(v.bv_page, v.bv_offset, v.bv_len),
@@ -443,6 +661,11 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
struct iov_iter *i, unsigned long offset, size_t bytes)
{
char *kaddr = kmap_atomic(page), *p = kaddr + offset;
+ if (unlikely(i->type & ITER_PIPE)) {
+ kunmap_atomic(kaddr);
+ WARN_ON(1);
+ return 0;
+ }
iterate_all_kinds(i, bytes, v,
__copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
v.iov_base, v.iov_len),
@@ -455,8 +678,49 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
}
EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
+static void pipe_advance(struct iov_iter *i, size_t size)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ struct pipe_buffer *buf;
+ int idx = i->idx;
+ size_t off = i->iov_offset;
+
+ if (unlikely(i->count < size))
+ size = i->count;
+
+ if (size) {
+ if (off) /* make it relative to the beginning of buffer */
+ size += off - pipe->bufs[idx].offset;
+ while (1) {
+ buf = &pipe->bufs[idx];
+ if (size <= buf->len)
+ break;
+ size -= buf->len;
+ idx = next_idx(idx, pipe);
+ }
+ buf->len = size;
+ i->idx = idx;
+ off = i->iov_offset = buf->offset + size;
+ }
+ if (off)
+ idx = next_idx(idx, pipe);
+ if (pipe->nrbufs) {
+ int unused = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
+ /* [curbuf,unused) is in use. Free [idx,unused) */
+ while (idx != unused) {
+ pipe_buf_release(pipe, &pipe->bufs[idx]);
+ idx = next_idx(idx, pipe);
+ pipe->nrbufs--;
+ }
+ }
+}
+
void iov_iter_advance(struct iov_iter *i, size_t size)
{
+ if (unlikely(i->type & ITER_PIPE)) {
+ pipe_advance(i, size);
+ return;
+ }
iterate_and_advance(i, size, v, 0, 0, 0)
}
EXPORT_SYMBOL(iov_iter_advance);
@@ -466,6 +730,8 @@ EXPORT_SYMBOL(iov_iter_advance);
*/
size_t iov_iter_single_seg_count(const struct iov_iter *i)
{
+ if (unlikely(i->type & ITER_PIPE))
+ return i->count; // it is a silly place, anyway
if (i->nr_segs == 1)
return i->count;
else if (i->type & ITER_BVEC)
@@ -501,6 +767,19 @@ void iov_iter_bvec(struct iov_iter *i, int direction,
}
EXPORT_SYMBOL(iov_iter_bvec);
+void iov_iter_pipe(struct iov_iter *i, int direction,
+ struct pipe_inode_info *pipe,
+ size_t count)
+{
+ BUG_ON(direction != ITER_PIPE);
+ i->type = direction;
+ i->pipe = pipe;
+ i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
+ i->iov_offset = 0;
+ i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_pipe);
+
unsigned long iov_iter_alignment(const struct iov_iter *i)
{
unsigned long res = 0;
@@ -509,6 +788,11 @@ unsigned long iov_iter_alignment(const struct iov_iter *i)
if (!size)
return 0;
+ if (unlikely(i->type & ITER_PIPE)) {
+ if (i->iov_offset && allocated(&i->pipe->bufs[i->idx]))
+ return size | i->iov_offset;
+ return size;
+ }
iterate_all_kinds(i, size, v,
(res |= (unsigned long)v.iov_base | v.iov_len, 0),
res |= v.bv_offset | v.bv_len,
@@ -525,6 +809,11 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
if (!size)
return 0;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return ~0U;
+ }
+
iterate_all_kinds(i, size, v,
(res |= (!res ? 0 : (unsigned long)v.iov_base) |
(size != v.iov_len ? size : 0), 0),
@@ -537,6 +826,47 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
}
EXPORT_SYMBOL(iov_iter_gap_alignment);
+static inline size_t __pipe_get_pages(struct iov_iter *i,
+ size_t maxsize,
+ struct page **pages,
+ int idx,
+ size_t *start)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ size_t n = push_pipe(i, maxsize, &idx, start);
+ if (!n)
+ return -EFAULT;
+
+ maxsize = n;
+ n += *start;
+ while (n >= PAGE_SIZE) {
+ get_page(*pages++ = pipe->bufs[idx].page);
+ idx = next_idx(idx, pipe);
+ n -= PAGE_SIZE;
+ }
+
+ return maxsize;
+}
+
+static ssize_t pipe_get_pages(struct iov_iter *i,
+ struct page **pages, size_t maxsize, unsigned maxpages,
+ size_t *start)
+{
+ unsigned npages;
+ size_t capacity;
+ int idx;
+
+ if (!sanity(i))
+ return -EFAULT;
+
+ data_start(i, &idx, start);
+ /* some of this one + all after this one */
+ npages = ((i->pipe->curbuf - idx - 1) & (i->pipe->buffers - 1)) + 1;
+ capacity = min(npages,maxpages) * PAGE_SIZE - *start;
+
+ return __pipe_get_pages(i, min(maxsize, capacity), pages, idx, start);
+}
+
ssize_t iov_iter_get_pages(struct iov_iter *i,
struct page **pages, size_t maxsize, unsigned maxpages,
size_t *start)
@@ -547,6 +877,8 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
if (!maxsize)
return 0;
+ if (unlikely(i->type & ITER_PIPE))
+ return pipe_get_pages(i, pages, maxsize, maxpages, start);
iterate_all_kinds(i, maxsize, v, ({
unsigned long addr = (unsigned long)v.iov_base;
size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
@@ -582,6 +914,37 @@ static struct page **get_pages_array(size_t n)
return p;
}
+static ssize_t pipe_get_pages_alloc(struct iov_iter *i,
+ struct page ***pages, size_t maxsize,
+ size_t *start)
+{
+ struct page **p;
+ size_t n;
+ int idx;
+ int npages;
+
+ if (!sanity(i))
+ return -EFAULT;
+
+ data_start(i, &idx, start);
+ /* some of this one + all after this one */
+ npages = ((i->pipe->curbuf - idx - 1) & (i->pipe->buffers - 1)) + 1;
+ n = npages * PAGE_SIZE - *start;
+ if (maxsize > n)
+ maxsize = n;
+ else
+ npages = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE);
+ p = get_pages_array(npages);
+ if (!p)
+ return -ENOMEM;
+ n = __pipe_get_pages(i, maxsize, p, idx, start);
+ if (n > 0)
+ *pages = p;
+ else
+ kvfree(p);
+ return n;
+}
+
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
struct page ***pages, size_t maxsize,
size_t *start)
@@ -594,6 +957,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
if (!maxsize)
return 0;
+ if (unlikely(i->type & ITER_PIPE))
+ return pipe_get_pages_alloc(i, pages, maxsize, start);
iterate_all_kinds(i, maxsize, v, ({
unsigned long addr = (unsigned long)v.iov_base;
size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
@@ -635,6 +1000,10 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
__wsum sum, next;
size_t off = 0;
sum = *csum;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return 0;
+ }
iterate_and_advance(i, bytes, v, ({
int err = 0;
next = csum_and_copy_from_user(v.iov_base,
@@ -673,6 +1042,10 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum,
__wsum sum, next;
size_t off = 0;
sum = *csum;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1); /* for now */
+ return 0;
+ }
iterate_and_advance(i, bytes, v, ({
int err = 0;
next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
@@ -712,7 +1085,20 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)
if (!size)
return 0;
- iterate_all_kinds(i, size, v, ({
+ if (unlikely(i->type & ITER_PIPE)) {
+ struct pipe_inode_info *pipe = i->pipe;
+ size_t off;
+ int idx;
+
+ if (!sanity(i))
+ return 0;
+
+ data_start(i, &idx, &off);
+ /* some of this one + all after this one */
+ npages = ((pipe->curbuf - idx - 1) & (pipe->buffers - 1)) + 1;
+ if (npages >= maxpages)
+ return maxpages;
+ } else iterate_all_kinds(i, size, v, ({
unsigned long p = (unsigned long)v.iov_base;
npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
- p / PAGE_SIZE;
@@ -737,6 +1123,10 @@ EXPORT_SYMBOL(iov_iter_npages);
const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
{
*new = *old;
+ if (unlikely(new->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return NULL;
+ }
if (new->type & ITER_BVEC)
return new->bvec = kmemdup(new->bvec,
new->nr_segs * sizeof(struct bio_vec),
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
index 26caf51cc238..75554754eadf 100644
--- a/lib/nmi_backtrace.c
+++ b/lib/nmi_backtrace.c
@@ -16,21 +16,23 @@
#include <linux/delay.h>
#include <linux/kprobes.h>
#include <linux/nmi.h>
+#include <linux/cpu.h>
-#ifdef arch_trigger_all_cpu_backtrace
+#ifdef arch_trigger_cpumask_backtrace
/* For reliability, we're prepared to waste bits here. */
static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
-/* "in progress" flag of arch_trigger_all_cpu_backtrace */
+/* "in progress" flag of arch_trigger_cpumask_backtrace */
static unsigned long backtrace_flag;
/*
- * When raise() is called it will be is passed a pointer to the
+ * When raise() is called it will be passed a pointer to the
* backtrace_mask. Architectures that call nmi_cpu_backtrace()
* directly from their raise() functions may rely on the mask
* they are passed being updated as a side effect of this call.
*/
-void nmi_trigger_all_cpu_backtrace(bool include_self,
+void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
+ bool exclude_self,
void (*raise)(cpumask_t *mask))
{
int i, this_cpu = get_cpu();
@@ -44,13 +46,22 @@ void nmi_trigger_all_cpu_backtrace(bool include_self,
return;
}
- cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
- if (!include_self)
+ cpumask_copy(to_cpumask(backtrace_mask), mask);
+ if (exclude_self)
cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask));
+ /*
+ * Don't try to send an NMI to this cpu; it may work on some
+ * architectures, but on others it may not, and we'll get
+ * information at least as useful just by doing a dump_stack() here.
+ * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit.
+ */
+ if (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask)))
+ nmi_cpu_backtrace(NULL);
+
if (!cpumask_empty(to_cpumask(backtrace_mask))) {
- pr_info("Sending NMI to %s CPUs:\n",
- (include_self ? "all" : "other"));
+ pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n",
+ this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask));
raise(to_cpumask(backtrace_mask));
}
@@ -77,11 +88,16 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
int cpu = smp_processor_id();
if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
- pr_warn("NMI backtrace for cpu %d\n", cpu);
- if (regs)
- show_regs(regs);
- else
- dump_stack();
+ if (regs && cpu_in_idle(instruction_pointer(regs))) {
+ pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n",
+ cpu, instruction_pointer(regs));
+ } else {
+ pr_warn("NMI backtrace for cpu %d\n", cpu);
+ if (regs)
+ show_regs(regs);
+ else
+ dump_stack();
+ }
cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
return true;
}
diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile
index 29f503ebfd60..3057011f5599 100644
--- a/lib/raid6/Makefile
+++ b/lib/raid6/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_RAID6_PQ) += raid6_pq.o
raid6_pq-y += algos.o recov.o tables.o int1.o int2.o int4.o \
int8.o int16.o int32.o
-raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o
+raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o avx512.o recov_avx512.o
raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o
raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o
raid6_pq-$(CONFIG_TILEGX) += tilegx8.o
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 592ff49df47d..7857049fd7d3 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -49,6 +49,10 @@ const struct raid6_calls * const raid6_algos[] = {
&raid6_avx2x1,
&raid6_avx2x2,
#endif
+#ifdef CONFIG_AS_AVX512
+ &raid6_avx512x1,
+ &raid6_avx512x2,
+#endif
#endif
#if defined(__x86_64__) && !defined(__arch_um__)
&raid6_sse2x1,
@@ -59,6 +63,11 @@ const struct raid6_calls * const raid6_algos[] = {
&raid6_avx2x2,
&raid6_avx2x4,
#endif
+#ifdef CONFIG_AS_AVX512
+ &raid6_avx512x1,
+ &raid6_avx512x2,
+ &raid6_avx512x4,
+#endif
#endif
#ifdef CONFIG_ALTIVEC
&raid6_altivec1,
@@ -92,6 +101,9 @@ void (*raid6_datap_recov)(int, size_t, int, void **);
EXPORT_SYMBOL_GPL(raid6_datap_recov);
const struct raid6_recov_calls *const raid6_recov_algos[] = {
+#ifdef CONFIG_AS_AVX512
+ &raid6_recov_avx512,
+#endif
#ifdef CONFIG_AS_AVX2
&raid6_recov_avx2,
#endif
diff --git a/lib/raid6/avx512.c b/lib/raid6/avx512.c
new file mode 100644
index 000000000000..f524a7972006
--- /dev/null
+++ b/lib/raid6/avx512.c
@@ -0,0 +1,569 @@
+/* -*- linux-c -*- --------------------------------------------------------
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Gayatri Kammela <gayatri.kammela@intel.com>
+ * Author: Megha Dey <megha.dey@linux.intel.com>
+ *
+ * Based on avx2.c: Copyright 2012 Yuanhan Liu All Rights Reserved
+ * Based on sse2.c: Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * AVX512 implementation of RAID-6 syndrome functions
+ *
+ */
+
+#ifdef CONFIG_AS_AVX512
+
+#include <linux/raid/pq.h>
+#include "x86.h"
+
+static const struct raid6_avx512_constants {
+ u64 x1d[8];
+} raid6_avx512_constants __aligned(512) = {
+ { 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,
+ 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,
+ 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,
+ 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,},
+};
+
+static int raid6_have_avx512(void)
+{
+ return boot_cpu_has(X86_FEATURE_AVX2) &&
+ boot_cpu_has(X86_FEATURE_AVX) &&
+ boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512BW) &&
+ boot_cpu_has(X86_FEATURE_AVX512VL) &&
+ boot_cpu_has(X86_FEATURE_AVX512DQ);
+}
+
+static void raid6_avx5121_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+ u8 **dptr = (u8 **)ptrs;
+ u8 *p, *q;
+ int d, z, z0;
+
+ z0 = disks - 3; /* Highest data disk */
+ p = dptr[z0+1]; /* XOR parity */
+ q = dptr[z0+2]; /* RS syndrome */
+
+ kernel_fpu_begin();
+
+ asm volatile("vmovdqa64 %0,%%zmm0\n\t"
+ "vpxorq %%zmm1,%%zmm1,%%zmm1" /* Zero temp */
+ :
+ : "m" (raid6_avx512_constants.x1d[0]));
+
+ for (d = 0; d < bytes; d += 64) {
+ asm volatile("prefetchnta %0\n\t"
+ "vmovdqa64 %0,%%zmm2\n\t" /* P[0] */
+ "prefetchnta %1\n\t"
+ "vmovdqa64 %%zmm2,%%zmm4\n\t" /* Q[0] */
+ "vmovdqa64 %1,%%zmm6"
+ :
+ : "m" (dptr[z0][d]), "m" (dptr[z0-1][d]));
+ for (z = z0-2; z >= 0; z--) {
+ asm volatile("prefetchnta %0\n\t"
+ "vpcmpgtb %%zmm4,%%zmm1,%%k1\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm6,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm6,%%zmm4,%%zmm4\n\t"
+ "vmovdqa64 %0,%%zmm6"
+ :
+ : "m" (dptr[z][d]));
+ }
+ asm volatile("vpcmpgtb %%zmm4,%%zmm1,%%k1\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm6,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm6,%%zmm4,%%zmm4\n\t"
+ "vmovntdq %%zmm2,%0\n\t"
+ "vpxorq %%zmm2,%%zmm2,%%zmm2\n\t"
+ "vmovntdq %%zmm4,%1\n\t"
+ "vpxorq %%zmm4,%%zmm4,%%zmm4"
+ :
+ : "m" (p[d]), "m" (q[d]));
+ }
+
+ asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
+}
+
+static void raid6_avx5121_xor_syndrome(int disks, int start, int stop,
+ size_t bytes, void **ptrs)
+{
+ u8 **dptr = (u8 **)ptrs;
+ u8 *p, *q;
+ int d, z, z0;
+
+ z0 = stop; /* P/Q right side optimization */
+ p = dptr[disks-2]; /* XOR parity */
+ q = dptr[disks-1]; /* RS syndrome */
+
+ kernel_fpu_begin();
+
+ asm volatile("vmovdqa64 %0,%%zmm0"
+ : : "m" (raid6_avx512_constants.x1d[0]));
+
+ for (d = 0 ; d < bytes ; d += 64) {
+ asm volatile("vmovdqa64 %0,%%zmm4\n\t"
+ "vmovdqa64 %1,%%zmm2\n\t"
+ "vpxorq %%zmm4,%%zmm2,%%zmm2"
+ :
+ : "m" (dptr[z0][d]), "m" (p[d]));
+ /* P/Q data pages */
+ for (z = z0-1 ; z >= start ; z--) {
+ asm volatile("vpxorq %%zmm5,%%zmm5,%%zmm5\n\t"
+ "vpcmpgtb %%zmm4,%%zmm5,%%k1\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vmovdqa64 %0,%%zmm5\n\t"
+ "vpxorq %%zmm5,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4"
+ :
+ : "m" (dptr[z][d]));
+ }
+ /* P/Q left side optimization */
+ for (z = start-1 ; z >= 0 ; z--) {
+ asm volatile("vpxorq %%zmm5,%%zmm5,%%zmm5\n\t"
+ "vpcmpgtb %%zmm4,%%zmm5,%%k1\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4"
+ :
+ : );
+ }
+ asm volatile("vpxorq %0,%%zmm4,%%zmm4\n\t"
+ /* Don't use movntdq for r/w memory area < cache line */
+ "vmovdqa64 %%zmm4,%0\n\t"
+ "vmovdqa64 %%zmm2,%1"
+ :
+ : "m" (q[d]), "m" (p[d]));
+ }
+
+ asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
+}
+
+const struct raid6_calls raid6_avx512x1 = {
+ raid6_avx5121_gen_syndrome,
+ raid6_avx5121_xor_syndrome,
+ raid6_have_avx512,
+ "avx512x1",
+ 1 /* Has cache hints */
+};
+
+/*
+ * Unrolled-by-2 AVX512 implementation
+ */
+static void raid6_avx5122_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+ u8 **dptr = (u8 **)ptrs;
+ u8 *p, *q;
+ int d, z, z0;
+
+ z0 = disks - 3; /* Highest data disk */
+ p = dptr[z0+1]; /* XOR parity */
+ q = dptr[z0+2]; /* RS syndrome */
+
+ kernel_fpu_begin();
+
+ asm volatile("vmovdqa64 %0,%%zmm0\n\t"
+ "vpxorq %%zmm1,%%zmm1,%%zmm1" /* Zero temp */
+ :
+ : "m" (raid6_avx512_constants.x1d[0]));
+
+ /* We uniformly assume a single prefetch covers at least 64 bytes */
+ for (d = 0; d < bytes; d += 128) {
+ asm volatile("prefetchnta %0\n\t"
+ "prefetchnta %1\n\t"
+ "vmovdqa64 %0,%%zmm2\n\t" /* P[0] */
+ "vmovdqa64 %1,%%zmm3\n\t" /* P[1] */
+ "vmovdqa64 %%zmm2,%%zmm4\n\t" /* Q[0] */
+ "vmovdqa64 %%zmm3,%%zmm6" /* Q[1] */
+ :
+ : "m" (dptr[z0][d]), "m" (dptr[z0][d+64]));
+ for (z = z0-1; z >= 0; z--) {
+ asm volatile("prefetchnta %0\n\t"
+ "prefetchnta %1\n\t"
+ "vpcmpgtb %%zmm4,%%zmm1,%%k1\n\t"
+ "vpcmpgtb %%zmm6,%%zmm1,%%k2\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpmovm2b %%k2,%%zmm7\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpaddb %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpandq %%zmm0,%%zmm7,%%zmm7\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vmovdqa64 %0,%%zmm5\n\t"
+ "vmovdqa64 %1,%%zmm7\n\t"
+ "vpxorq %%zmm5,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm7,%%zmm3,%%zmm3\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6"
+ :
+ : "m" (dptr[z][d]), "m" (dptr[z][d+64]));
+ }
+ asm volatile("vmovntdq %%zmm2,%0\n\t"
+ "vmovntdq %%zmm3,%1\n\t"
+ "vmovntdq %%zmm4,%2\n\t"
+ "vmovntdq %%zmm6,%3"
+ :
+ : "m" (p[d]), "m" (p[d+64]), "m" (q[d]),
+ "m" (q[d+64]));
+ }
+
+ asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
+}
+
+static void raid6_avx5122_xor_syndrome(int disks, int start, int stop,
+ size_t bytes, void **ptrs)
+{
+ u8 **dptr = (u8 **)ptrs;
+ u8 *p, *q;
+ int d, z, z0;
+
+ z0 = stop; /* P/Q right side optimization */
+ p = dptr[disks-2]; /* XOR parity */
+ q = dptr[disks-1]; /* RS syndrome */
+
+ kernel_fpu_begin();
+
+ asm volatile("vmovdqa64 %0,%%zmm0"
+ : : "m" (raid6_avx512_constants.x1d[0]));
+
+ for (d = 0 ; d < bytes ; d += 128) {
+ asm volatile("vmovdqa64 %0,%%zmm4\n\t"
+ "vmovdqa64 %1,%%zmm6\n\t"
+ "vmovdqa64 %2,%%zmm2\n\t"
+ "vmovdqa64 %3,%%zmm3\n\t"
+ "vpxorq %%zmm4,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm6,%%zmm3,%%zmm3"
+ :
+ : "m" (dptr[z0][d]), "m" (dptr[z0][d+64]),
+ "m" (p[d]), "m" (p[d+64]));
+ /* P/Q data pages */
+ for (z = z0-1 ; z >= start ; z--) {
+ asm volatile("vpxorq %%zmm5,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm7,%%zmm7,%%zmm7\n\t"
+ "vpcmpgtb %%zmm4,%%zmm5,%%k1\n\t"
+ "vpcmpgtb %%zmm6,%%zmm7,%%k2\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpmovm2b %%k2,%%zmm7\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpaddb %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpandq %%zmm0,%%zmm7,%%zmm7\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vmovdqa64 %0,%%zmm5\n\t"
+ "vmovdqa64 %1,%%zmm7\n\t"
+ "vpxorq %%zmm5,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm7,%%zmm3,%%zmm3\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6"
+ :
+ : "m" (dptr[z][d]), "m" (dptr[z][d+64]));
+ }
+ /* P/Q left side optimization */
+ for (z = start-1 ; z >= 0 ; z--) {
+ asm volatile("vpxorq %%zmm5,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm7,%%zmm7,%%zmm7\n\t"
+ "vpcmpgtb %%zmm4,%%zmm5,%%k1\n\t"
+ "vpcmpgtb %%zmm6,%%zmm7,%%k2\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpmovm2b %%k2,%%zmm7\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpaddb %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpandq %%zmm0,%%zmm7,%%zmm7\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6"
+ :
+ : );
+ }
+ asm volatile("vpxorq %0,%%zmm4,%%zmm4\n\t"
+ "vpxorq %1,%%zmm6,%%zmm6\n\t"
+ /* Don't use movntdq for r/w
+ * memory area < cache line
+ */
+ "vmovdqa64 %%zmm4,%0\n\t"
+ "vmovdqa64 %%zmm6,%1\n\t"
+ "vmovdqa64 %%zmm2,%2\n\t"
+ "vmovdqa64 %%zmm3,%3"
+ :
+ : "m" (q[d]), "m" (q[d+64]), "m" (p[d]),
+ "m" (p[d+64]));
+ }
+
+ asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
+}
+
+const struct raid6_calls raid6_avx512x2 = {
+ raid6_avx5122_gen_syndrome,
+ raid6_avx5122_xor_syndrome,
+ raid6_have_avx512,
+ "avx512x2",
+ 1 /* Has cache hints */
+};
+
+#ifdef CONFIG_X86_64
+
+/*
+ * Unrolled-by-4 AVX2 implementation
+ */
+static void raid6_avx5124_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+ u8 **dptr = (u8 **)ptrs;
+ u8 *p, *q;
+ int d, z, z0;
+
+ z0 = disks - 3; /* Highest data disk */
+ p = dptr[z0+1]; /* XOR parity */
+ q = dptr[z0+2]; /* RS syndrome */
+
+ kernel_fpu_begin();
+
+ asm volatile("vmovdqa64 %0,%%zmm0\n\t"
+ "vpxorq %%zmm1,%%zmm1,%%zmm1\n\t" /* Zero temp */
+ "vpxorq %%zmm2,%%zmm2,%%zmm2\n\t" /* P[0] */
+ "vpxorq %%zmm3,%%zmm3,%%zmm3\n\t" /* P[1] */
+ "vpxorq %%zmm4,%%zmm4,%%zmm4\n\t" /* Q[0] */
+ "vpxorq %%zmm6,%%zmm6,%%zmm6\n\t" /* Q[1] */
+ "vpxorq %%zmm10,%%zmm10,%%zmm10\n\t" /* P[2] */
+ "vpxorq %%zmm11,%%zmm11,%%zmm11\n\t" /* P[3] */
+ "vpxorq %%zmm12,%%zmm12,%%zmm12\n\t" /* Q[2] */
+ "vpxorq %%zmm14,%%zmm14,%%zmm14" /* Q[3] */
+ :
+ : "m" (raid6_avx512_constants.x1d[0]));
+
+ for (d = 0; d < bytes; d += 256) {
+ for (z = z0; z >= 0; z--) {
+ asm volatile("prefetchnta %0\n\t"
+ "prefetchnta %1\n\t"
+ "prefetchnta %2\n\t"
+ "prefetchnta %3\n\t"
+ "vpcmpgtb %%zmm4,%%zmm1,%%k1\n\t"
+ "vpcmpgtb %%zmm6,%%zmm1,%%k2\n\t"
+ "vpcmpgtb %%zmm12,%%zmm1,%%k3\n\t"
+ "vpcmpgtb %%zmm14,%%zmm1,%%k4\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpmovm2b %%k2,%%zmm7\n\t"
+ "vpmovm2b %%k3,%%zmm13\n\t"
+ "vpmovm2b %%k4,%%zmm15\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpaddb %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vpaddb %%zmm12,%%zmm12,%%zmm12\n\t"
+ "vpaddb %%zmm14,%%zmm14,%%zmm14\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpandq %%zmm0,%%zmm7,%%zmm7\n\t"
+ "vpandq %%zmm0,%%zmm13,%%zmm13\n\t"
+ "vpandq %%zmm0,%%zmm15,%%zmm15\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vpxorq %%zmm13,%%zmm12,%%zmm12\n\t"
+ "vpxorq %%zmm15,%%zmm14,%%zmm14\n\t"
+ "vmovdqa64 %0,%%zmm5\n\t"
+ "vmovdqa64 %1,%%zmm7\n\t"
+ "vmovdqa64 %2,%%zmm13\n\t"
+ "vmovdqa64 %3,%%zmm15\n\t"
+ "vpxorq %%zmm5,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm7,%%zmm3,%%zmm3\n\t"
+ "vpxorq %%zmm13,%%zmm10,%%zmm10\n\t"
+ "vpxorq %%zmm15,%%zmm11,%%zmm11\n"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vpxorq %%zmm13,%%zmm12,%%zmm12\n\t"
+ "vpxorq %%zmm15,%%zmm14,%%zmm14"
+ :
+ : "m" (dptr[z][d]), "m" (dptr[z][d+64]),
+ "m" (dptr[z][d+128]), "m" (dptr[z][d+192]));
+ }
+ asm volatile("vmovntdq %%zmm2,%0\n\t"
+ "vpxorq %%zmm2,%%zmm2,%%zmm2\n\t"
+ "vmovntdq %%zmm3,%1\n\t"
+ "vpxorq %%zmm3,%%zmm3,%%zmm3\n\t"
+ "vmovntdq %%zmm10,%2\n\t"
+ "vpxorq %%zmm10,%%zmm10,%%zmm10\n\t"
+ "vmovntdq %%zmm11,%3\n\t"
+ "vpxorq %%zmm11,%%zmm11,%%zmm11\n\t"
+ "vmovntdq %%zmm4,%4\n\t"
+ "vpxorq %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vmovntdq %%zmm6,%5\n\t"
+ "vpxorq %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vmovntdq %%zmm12,%6\n\t"
+ "vpxorq %%zmm12,%%zmm12,%%zmm12\n\t"
+ "vmovntdq %%zmm14,%7\n\t"
+ "vpxorq %%zmm14,%%zmm14,%%zmm14"
+ :
+ : "m" (p[d]), "m" (p[d+64]), "m" (p[d+128]),
+ "m" (p[d+192]), "m" (q[d]), "m" (q[d+64]),
+ "m" (q[d+128]), "m" (q[d+192]));
+ }
+
+ asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
+}
+
+static void raid6_avx5124_xor_syndrome(int disks, int start, int stop,
+ size_t bytes, void **ptrs)
+{
+ u8 **dptr = (u8 **)ptrs;
+ u8 *p, *q;
+ int d, z, z0;
+
+ z0 = stop; /* P/Q right side optimization */
+ p = dptr[disks-2]; /* XOR parity */
+ q = dptr[disks-1]; /* RS syndrome */
+
+ kernel_fpu_begin();
+
+ asm volatile("vmovdqa64 %0,%%zmm0"
+ :: "m" (raid6_avx512_constants.x1d[0]));
+
+ for (d = 0 ; d < bytes ; d += 256) {
+ asm volatile("vmovdqa64 %0,%%zmm4\n\t"
+ "vmovdqa64 %1,%%zmm6\n\t"
+ "vmovdqa64 %2,%%zmm12\n\t"
+ "vmovdqa64 %3,%%zmm14\n\t"
+ "vmovdqa64 %4,%%zmm2\n\t"
+ "vmovdqa64 %5,%%zmm3\n\t"
+ "vmovdqa64 %6,%%zmm10\n\t"
+ "vmovdqa64 %7,%%zmm11\n\t"
+ "vpxorq %%zmm4,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm6,%%zmm3,%%zmm3\n\t"
+ "vpxorq %%zmm12,%%zmm10,%%zmm10\n\t"
+ "vpxorq %%zmm14,%%zmm11,%%zmm11"
+ :
+ : "m" (dptr[z0][d]), "m" (dptr[z0][d+64]),
+ "m" (dptr[z0][d+128]), "m" (dptr[z0][d+192]),
+ "m" (p[d]), "m" (p[d+64]), "m" (p[d+128]),
+ "m" (p[d+192]));
+ /* P/Q data pages */
+ for (z = z0-1 ; z >= start ; z--) {
+ asm volatile("vpxorq %%zmm5,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm7,%%zmm7,%%zmm7\n\t"
+ "vpxorq %%zmm13,%%zmm13,%%zmm13\n\t"
+ "vpxorq %%zmm15,%%zmm15,%%zmm15\n\t"
+ "prefetchnta %0\n\t"
+ "prefetchnta %2\n\t"
+ "vpcmpgtb %%zmm4,%%zmm5,%%k1\n\t"
+ "vpcmpgtb %%zmm6,%%zmm7,%%k2\n\t"
+ "vpcmpgtb %%zmm12,%%zmm13,%%k3\n\t"
+ "vpcmpgtb %%zmm14,%%zmm15,%%k4\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpmovm2b %%k2,%%zmm7\n\t"
+ "vpmovm2b %%k3,%%zmm13\n\t"
+ "vpmovm2b %%k4,%%zmm15\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpaddb %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vpaddb %%zmm12,%%zmm12,%%zmm12\n\t"
+ "vpaddb %%Zmm14,%%zmm14,%%zmm14\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpandq %%zmm0,%%zmm7,%%zmm7\n\t"
+ "vpandq %%zmm0,%%zmm13,%%zmm13\n\t"
+ "vpandq %%zmm0,%%zmm15,%%zmm15\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vpxorq %%zmm13,%%zmm12,%%zmm12\n\t"
+ "vpxorq %%zmm15,%%zmm14,%%zmm14\n\t"
+ "vmovdqa64 %0,%%zmm5\n\t"
+ "vmovdqa64 %1,%%zmm7\n\t"
+ "vmovdqa64 %2,%%zmm13\n\t"
+ "vmovdqa64 %3,%%zmm15\n\t"
+ "vpxorq %%zmm5,%%zmm2,%%zmm2\n\t"
+ "vpxorq %%zmm7,%%zmm3,%%zmm3\n\t"
+ "vpxorq %%zmm13,%%zmm10,%%zmm10\n\t"
+ "vpxorq %%zmm15,%%zmm11,%%zmm11\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vpxorq %%zmm13,%%zmm12,%%zmm12\n\t"
+ "vpxorq %%zmm15,%%zmm14,%%zmm14"
+ :
+ : "m" (dptr[z][d]), "m" (dptr[z][d+64]),
+ "m" (dptr[z][d+128]),
+ "m" (dptr[z][d+192]));
+ }
+ asm volatile("prefetchnta %0\n\t"
+ "prefetchnta %1\n\t"
+ :
+ : "m" (q[d]), "m" (q[d+128]));
+ /* P/Q left side optimization */
+ for (z = start-1 ; z >= 0 ; z--) {
+ asm volatile("vpxorq %%zmm5,%%zmm5,%%zmm5\n\t"
+ "vpxorq %%zmm7,%%zmm7,%%zmm7\n\t"
+ "vpxorq %%zmm13,%%zmm13,%%zmm13\n\t"
+ "vpxorq %%zmm15,%%zmm15,%%zmm15\n\t"
+ "vpcmpgtb %%zmm4,%%zmm5,%%k1\n\t"
+ "vpcmpgtb %%zmm6,%%zmm7,%%k2\n\t"
+ "vpcmpgtb %%zmm12,%%zmm13,%%k3\n\t"
+ "vpcmpgtb %%zmm14,%%zmm15,%%k4\n\t"
+ "vpmovm2b %%k1,%%zmm5\n\t"
+ "vpmovm2b %%k2,%%zmm7\n\t"
+ "vpmovm2b %%k3,%%zmm13\n\t"
+ "vpmovm2b %%k4,%%zmm15\n\t"
+ "vpaddb %%zmm4,%%zmm4,%%zmm4\n\t"
+ "vpaddb %%zmm6,%%zmm6,%%zmm6\n\t"
+ "vpaddb %%zmm12,%%zmm12,%%zmm12\n\t"
+ "vpaddb %%zmm14,%%zmm14,%%zmm14\n\t"
+ "vpandq %%zmm0,%%zmm5,%%zmm5\n\t"
+ "vpandq %%zmm0,%%zmm7,%%zmm7\n\t"
+ "vpandq %%zmm0,%%zmm13,%%zmm13\n\t"
+ "vpandq %%zmm0,%%zmm15,%%zmm15\n\t"
+ "vpxorq %%zmm5,%%zmm4,%%zmm4\n\t"
+ "vpxorq %%zmm7,%%zmm6,%%zmm6\n\t"
+ "vpxorq %%zmm13,%%zmm12,%%zmm12\n\t"
+ "vpxorq %%zmm15,%%zmm14,%%zmm14"
+ :
+ : );
+ }
+ asm volatile("vmovntdq %%zmm2,%0\n\t"
+ "vmovntdq %%zmm3,%1\n\t"
+ "vmovntdq %%zmm10,%2\n\t"
+ "vmovntdq %%zmm11,%3\n\t"
+ "vpxorq %4,%%zmm4,%%zmm4\n\t"
+ "vpxorq %5,%%zmm6,%%zmm6\n\t"
+ "vpxorq %6,%%zmm12,%%zmm12\n\t"
+ "vpxorq %7,%%zmm14,%%zmm14\n\t"
+ "vmovntdq %%zmm4,%4\n\t"
+ "vmovntdq %%zmm6,%5\n\t"
+ "vmovntdq %%zmm12,%6\n\t"
+ "vmovntdq %%zmm14,%7"
+ :
+ : "m" (p[d]), "m" (p[d+64]), "m" (p[d+128]),
+ "m" (p[d+192]), "m" (q[d]), "m" (q[d+64]),
+ "m" (q[d+128]), "m" (q[d+192]));
+ }
+ asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
+}
+const struct raid6_calls raid6_avx512x4 = {
+ raid6_avx5124_gen_syndrome,
+ raid6_avx5124_xor_syndrome,
+ raid6_have_avx512,
+ "avx512x4",
+ 1 /* Has cache hints */
+};
+#endif
+
+#endif /* CONFIG_AS_AVX512 */
diff --git a/lib/raid6/recov_avx512.c b/lib/raid6/recov_avx512.c
new file mode 100644
index 000000000000..625aafa33b61
--- /dev/null
+++ b/lib/raid6/recov_avx512.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Gayatri Kammela <gayatri.kammela@intel.com>
+ * Author: Megha Dey <megha.dey@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ */
+
+#ifdef CONFIG_AS_AVX512
+
+#include <linux/raid/pq.h>
+#include "x86.h"
+
+static int raid6_has_avx512(void)
+{
+ return boot_cpu_has(X86_FEATURE_AVX2) &&
+ boot_cpu_has(X86_FEATURE_AVX) &&
+ boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512BW) &&
+ boot_cpu_has(X86_FEATURE_AVX512VL) &&
+ boot_cpu_has(X86_FEATURE_AVX512DQ);
+}
+
+static void raid6_2data_recov_avx512(int disks, size_t bytes, int faila,
+ int failb, void **ptrs)
+{
+ u8 *p, *q, *dp, *dq;
+ const u8 *pbmul; /* P multiplier table for B data */
+ const u8 *qmul; /* Q multiplier table (for both) */
+ const u8 x0f = 0x0f;
+
+ p = (u8 *)ptrs[disks-2];
+ q = (u8 *)ptrs[disks-1];
+
+ /*
+ * Compute syndrome with zero for the missing data pages
+ * Use the dead data pages as temporary storage for
+ * delta p and delta q
+ */
+
+ dp = (u8 *)ptrs[faila];
+ ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[disks-2] = dp;
+ dq = (u8 *)ptrs[failb];
+ ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[disks-1] = dq;
+
+ raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+ /* Restore pointer table */
+ ptrs[faila] = dp;
+ ptrs[failb] = dq;
+ ptrs[disks-2] = p;
+ ptrs[disks-1] = q;
+
+ /* Now, pick the proper data tables */
+ pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]];
+ qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^
+ raid6_gfexp[failb]]];
+
+ kernel_fpu_begin();
+
+ /* zmm0 = x0f[16] */
+ asm volatile("vpbroadcastb %0, %%zmm7" : : "m" (x0f));
+
+ while (bytes) {
+#ifdef CONFIG_X86_64
+ asm volatile("vmovdqa64 %0, %%zmm1\n\t"
+ "vmovdqa64 %1, %%zmm9\n\t"
+ "vmovdqa64 %2, %%zmm0\n\t"
+ "vmovdqa64 %3, %%zmm8\n\t"
+ "vpxorq %4, %%zmm1, %%zmm1\n\t"
+ "vpxorq %5, %%zmm9, %%zmm9\n\t"
+ "vpxorq %6, %%zmm0, %%zmm0\n\t"
+ "vpxorq %7, %%zmm8, %%zmm8"
+ :
+ : "m" (q[0]), "m" (q[64]), "m" (p[0]),
+ "m" (p[64]), "m" (dq[0]), "m" (dq[64]),
+ "m" (dp[0]), "m" (dp[64]));
+
+ /*
+ * 1 = dq[0] ^ q[0]
+ * 9 = dq[64] ^ q[64]
+ * 0 = dp[0] ^ p[0]
+ * 8 = dp[64] ^ p[64]
+ */
+
+ asm volatile("vbroadcasti64x2 %0, %%zmm4\n\t"
+ "vbroadcasti64x2 %1, %%zmm5"
+ :
+ : "m" (qmul[0]), "m" (qmul[16]));
+
+ asm volatile("vpsraw $4, %%zmm1, %%zmm3\n\t"
+ "vpsraw $4, %%zmm9, %%zmm12\n\t"
+ "vpandq %%zmm7, %%zmm1, %%zmm1\n\t"
+ "vpandq %%zmm7, %%zmm9, %%zmm9\n\t"
+ "vpandq %%zmm7, %%zmm3, %%zmm3\n\t"
+ "vpandq %%zmm7, %%zmm12, %%zmm12\n\t"
+ "vpshufb %%zmm9, %%zmm4, %%zmm14\n\t"
+ "vpshufb %%zmm1, %%zmm4, %%zmm4\n\t"
+ "vpshufb %%zmm12, %%zmm5, %%zmm15\n\t"
+ "vpshufb %%zmm3, %%zmm5, %%zmm5\n\t"
+ "vpxorq %%zmm14, %%zmm15, %%zmm15\n\t"
+ "vpxorq %%zmm4, %%zmm5, %%zmm5"
+ :
+ : );
+
+ /*
+ * 5 = qx[0]
+ * 15 = qx[64]
+ */
+
+ asm volatile("vbroadcasti64x2 %0, %%zmm4\n\t"
+ "vbroadcasti64x2 %1, %%zmm1\n\t"
+ "vpsraw $4, %%zmm0, %%zmm2\n\t"
+ "vpsraw $4, %%zmm8, %%zmm6\n\t"
+ "vpandq %%zmm7, %%zmm0, %%zmm3\n\t"
+ "vpandq %%zmm7, %%zmm8, %%zmm14\n\t"
+ "vpandq %%zmm7, %%zmm2, %%zmm2\n\t"
+ "vpandq %%zmm7, %%zmm6, %%zmm6\n\t"
+ "vpshufb %%zmm14, %%zmm4, %%zmm12\n\t"
+ "vpshufb %%zmm3, %%zmm4, %%zmm4\n\t"
+ "vpshufb %%zmm6, %%zmm1, %%zmm13\n\t"
+ "vpshufb %%zmm2, %%zmm1, %%zmm1\n\t"
+ "vpxorq %%zmm4, %%zmm1, %%zmm1\n\t"
+ "vpxorq %%zmm12, %%zmm13, %%zmm13"
+ :
+ : "m" (pbmul[0]), "m" (pbmul[16]));
+
+ /*
+ * 1 = pbmul[px[0]]
+ * 13 = pbmul[px[64]]
+ */
+ asm volatile("vpxorq %%zmm5, %%zmm1, %%zmm1\n\t"
+ "vpxorq %%zmm15, %%zmm13, %%zmm13"
+ :
+ : );
+
+ /*
+ * 1 = db = DQ
+ * 13 = db[64] = DQ[64]
+ */
+ asm volatile("vmovdqa64 %%zmm1, %0\n\t"
+ "vmovdqa64 %%zmm13,%1\n\t"
+ "vpxorq %%zmm1, %%zmm0, %%zmm0\n\t"
+ "vpxorq %%zmm13, %%zmm8, %%zmm8"
+ :
+ : "m" (dq[0]), "m" (dq[64]));
+
+ asm volatile("vmovdqa64 %%zmm0, %0\n\t"
+ "vmovdqa64 %%zmm8, %1"
+ :
+ : "m" (dp[0]), "m" (dp[64]));
+
+ bytes -= 128;
+ p += 128;
+ q += 128;
+ dp += 128;
+ dq += 128;
+#else
+ asm volatile("vmovdqa64 %0, %%zmm1\n\t"
+ "vmovdqa64 %1, %%zmm0\n\t"
+ "vpxorq %2, %%zmm1, %%zmm1\n\t"
+ "vpxorq %3, %%zmm0, %%zmm0"
+ :
+ : "m" (*q), "m" (*p), "m"(*dq), "m" (*dp));
+
+ /* 1 = dq ^ q; 0 = dp ^ p */
+
+ asm volatile("vbroadcasti64x2 %0, %%zmm4\n\t"
+ "vbroadcasti64x2 %1, %%zmm5"
+ :
+ : "m" (qmul[0]), "m" (qmul[16]));
+
+ /*
+ * 1 = dq ^ q
+ * 3 = dq ^ p >> 4
+ */
+ asm volatile("vpsraw $4, %%zmm1, %%zmm3\n\t"
+ "vpandq %%zmm7, %%zmm1, %%zmm1\n\t"
+ "vpandq %%zmm7, %%zmm3, %%zmm3\n\t"
+ "vpshufb %%zmm1, %%zmm4, %%zmm4\n\t"
+ "vpshufb %%zmm3, %%zmm5, %%zmm5\n\t"
+ "vpxorq %%zmm4, %%zmm5, %%zmm5"
+ :
+ : );
+
+ /* 5 = qx */
+
+ asm volatile("vbroadcasti64x2 %0, %%zmm4\n\t"
+ "vbroadcasti64x2 %1, %%zmm1"
+ :
+ : "m" (pbmul[0]), "m" (pbmul[16]));
+
+ asm volatile("vpsraw $4, %%zmm0, %%zmm2\n\t"
+ "vpandq %%zmm7, %%zmm0, %%zmm3\n\t"
+ "vpandq %%zmm7, %%zmm2, %%zmm2\n\t"
+ "vpshufb %%zmm3, %%zmm4, %%zmm4\n\t"
+ "vpshufb %%zmm2, %%zmm1, %%zmm1\n\t"
+ "vpxorq %%zmm4, %%zmm1, %%zmm1"
+ :
+ : );
+
+ /* 1 = pbmul[px] */
+ asm volatile("vpxorq %%zmm5, %%zmm1, %%zmm1\n\t"
+ /* 1 = db = DQ */
+ "vmovdqa64 %%zmm1, %0\n\t"
+ :
+ : "m" (dq[0]));
+
+ asm volatile("vpxorq %%zmm1, %%zmm0, %%zmm0\n\t"
+ "vmovdqa64 %%zmm0, %0"
+ :
+ : "m" (dp[0]));
+
+ bytes -= 64;
+ p += 64;
+ q += 64;
+ dp += 64;
+ dq += 64;
+#endif
+ }
+
+ kernel_fpu_end();
+}
+
+static void raid6_datap_recov_avx512(int disks, size_t bytes, int faila,
+ void **ptrs)
+{
+ u8 *p, *q, *dq;
+ const u8 *qmul; /* Q multiplier table */
+ const u8 x0f = 0x0f;
+
+ p = (u8 *)ptrs[disks-2];
+ q = (u8 *)ptrs[disks-1];
+
+ /*
+ * Compute syndrome with zero for the missing data page
+ * Use the dead data page as temporary storage for delta q
+ */
+
+ dq = (u8 *)ptrs[faila];
+ ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[disks-1] = dq;
+
+ raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+ /* Restore pointer table */
+ ptrs[faila] = dq;
+ ptrs[disks-1] = q;
+
+ /* Now, pick the proper data tables */
+ qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
+
+ kernel_fpu_begin();
+
+ asm volatile("vpbroadcastb %0, %%zmm7" : : "m" (x0f));
+
+ while (bytes) {
+#ifdef CONFIG_X86_64
+ asm volatile("vmovdqa64 %0, %%zmm3\n\t"
+ "vmovdqa64 %1, %%zmm8\n\t"
+ "vpxorq %2, %%zmm3, %%zmm3\n\t"
+ "vpxorq %3, %%zmm8, %%zmm8"
+ :
+ : "m" (dq[0]), "m" (dq[64]), "m" (q[0]),
+ "m" (q[64]));
+
+ /*
+ * 3 = q[0] ^ dq[0]
+ * 8 = q[64] ^ dq[64]
+ */
+ asm volatile("vbroadcasti64x2 %0, %%zmm0\n\t"
+ "vmovapd %%zmm0, %%zmm13\n\t"
+ "vbroadcasti64x2 %1, %%zmm1\n\t"
+ "vmovapd %%zmm1, %%zmm14"
+ :
+ : "m" (qmul[0]), "m" (qmul[16]));
+
+ asm volatile("vpsraw $4, %%zmm3, %%zmm6\n\t"
+ "vpsraw $4, %%zmm8, %%zmm12\n\t"
+ "vpandq %%zmm7, %%zmm3, %%zmm3\n\t"
+ "vpandq %%zmm7, %%zmm8, %%zmm8\n\t"
+ "vpandq %%zmm7, %%zmm6, %%zmm6\n\t"
+ "vpandq %%zmm7, %%zmm12, %%zmm12\n\t"
+ "vpshufb %%zmm3, %%zmm0, %%zmm0\n\t"
+ "vpshufb %%zmm8, %%zmm13, %%zmm13\n\t"
+ "vpshufb %%zmm6, %%zmm1, %%zmm1\n\t"
+ "vpshufb %%zmm12, %%zmm14, %%zmm14\n\t"
+ "vpxorq %%zmm0, %%zmm1, %%zmm1\n\t"
+ "vpxorq %%zmm13, %%zmm14, %%zmm14"
+ :
+ : );
+
+ /*
+ * 1 = qmul[q[0] ^ dq[0]]
+ * 14 = qmul[q[64] ^ dq[64]]
+ */
+ asm volatile("vmovdqa64 %0, %%zmm2\n\t"
+ "vmovdqa64 %1, %%zmm12\n\t"
+ "vpxorq %%zmm1, %%zmm2, %%zmm2\n\t"
+ "vpxorq %%zmm14, %%zmm12, %%zmm12"
+ :
+ : "m" (p[0]), "m" (p[64]));
+
+ /*
+ * 2 = p[0] ^ qmul[q[0] ^ dq[0]]
+ * 12 = p[64] ^ qmul[q[64] ^ dq[64]]
+ */
+
+ asm volatile("vmovdqa64 %%zmm1, %0\n\t"
+ "vmovdqa64 %%zmm14, %1\n\t"
+ "vmovdqa64 %%zmm2, %2\n\t"
+ "vmovdqa64 %%zmm12,%3"
+ :
+ : "m" (dq[0]), "m" (dq[64]), "m" (p[0]),
+ "m" (p[64]));
+
+ bytes -= 128;
+ p += 128;
+ q += 128;
+ dq += 128;
+#else
+ asm volatile("vmovdqa64 %0, %%zmm3\n\t"
+ "vpxorq %1, %%zmm3, %%zmm3"
+ :
+ : "m" (dq[0]), "m" (q[0]));
+
+ /* 3 = q ^ dq */
+
+ asm volatile("vbroadcasti64x2 %0, %%zmm0\n\t"
+ "vbroadcasti64x2 %1, %%zmm1"
+ :
+ : "m" (qmul[0]), "m" (qmul[16]));
+
+ asm volatile("vpsraw $4, %%zmm3, %%zmm6\n\t"
+ "vpandq %%zmm7, %%zmm3, %%zmm3\n\t"
+ "vpandq %%zmm7, %%zmm6, %%zmm6\n\t"
+ "vpshufb %%zmm3, %%zmm0, %%zmm0\n\t"
+ "vpshufb %%zmm6, %%zmm1, %%zmm1\n\t"
+ "vpxorq %%zmm0, %%zmm1, %%zmm1"
+ :
+ : );
+
+ /* 1 = qmul[q ^ dq] */
+
+ asm volatile("vmovdqa64 %0, %%zmm2\n\t"
+ "vpxorq %%zmm1, %%zmm2, %%zmm2"
+ :
+ : "m" (p[0]));
+
+ /* 2 = p ^ qmul[q ^ dq] */
+
+ asm volatile("vmovdqa64 %%zmm1, %0\n\t"
+ "vmovdqa64 %%zmm2, %1"
+ :
+ : "m" (dq[0]), "m" (p[0]));
+
+ bytes -= 64;
+ p += 64;
+ q += 64;
+ dq += 64;
+#endif
+ }
+
+ kernel_fpu_end();
+}
+
+const struct raid6_recov_calls raid6_recov_avx512 = {
+ .data2 = raid6_2data_recov_avx512,
+ .datap = raid6_datap_recov_avx512,
+ .valid = raid6_has_avx512,
+#ifdef CONFIG_X86_64
+ .name = "avx512x2",
+#else
+ .name = "avx512x1",
+#endif
+ .priority = 3,
+};
+
+#else
+#warning "your version of binutils lacks AVX512 support"
+#endif
diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile
index 29090f3db677..2c7b60edea04 100644
--- a/lib/raid6/test/Makefile
+++ b/lib/raid6/test/Makefile
@@ -32,10 +32,13 @@ ifeq ($(ARCH),arm64)
endif
ifeq ($(IS_X86),yes)
- OBJS += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o
+ OBJS += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o avx512.o recov_avx512.o
CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" | \
gcc -c -x assembler - >&/dev/null && \
rm ./-.o && echo -DCONFIG_AS_AVX2=1)
+ CFLAGS += $(shell echo "vpmovm2b %k1, %zmm5" | \
+ gcc -c -x assembler - >&/dev/null && \
+ rm ./-.o && echo -DCONFIG_AS_AVX512=1)
else ifeq ($(HAS_NEON),yes)
OBJS += neon.o neon1.o neon2.o neon4.o neon8.o
CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1
diff --git a/lib/raid6/test/test.c b/lib/raid6/test/test.c
index 3bebbabdb510..b07f4d8e6b03 100644
--- a/lib/raid6/test/test.c
+++ b/lib/raid6/test/test.c
@@ -21,12 +21,13 @@
#define NDISKS 16 /* Including P and Q */
-const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
+const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
struct raid6_calls raid6_call;
char *dataptrs[NDISKS];
-char data[NDISKS][PAGE_SIZE];
-char recovi[PAGE_SIZE], recovj[PAGE_SIZE];
+char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+char recovi[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+char recovj[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
static void makedata(int start, int stop)
{
diff --git a/lib/raid6/x86.h b/lib/raid6/x86.h
index 8fe9d9662abb..834d268a4b05 100644
--- a/lib/raid6/x86.h
+++ b/lib/raid6/x86.h
@@ -46,6 +46,16 @@ static inline void kernel_fpu_end(void)
#define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental SSE-3 */
#define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */
#define X86_FEATURE_AVX2 (9*32+ 5) /* AVX2 instructions */
+#define X86_FEATURE_AVX512F (9*32+16) /* AVX-512 Foundation */
+#define X86_FEATURE_AVX512DQ (9*32+17) /* AVX-512 DQ (Double/Quad granular)
+ * Instructions
+ */
+#define X86_FEATURE_AVX512BW (9*32+30) /* AVX-512 BW (Byte/Word granular)
+ * Instructions
+ */
+#define X86_FEATURE_AVX512VL (9*32+31) /* AVX-512 VL (128/256 Vector Length)
+ * Extensions
+ */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
/* Should work well enough on modern CPUs for testing */
diff --git a/lib/sbitmap.c b/lib/sbitmap.c
new file mode 100644
index 000000000000..2cecf05c82fd
--- /dev/null
+++ b/lib/sbitmap.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2016 Facebook
+ * Copyright (C) 2013-2014 Jens Axboe
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <linux/random.h>
+#include <linux/sbitmap.h>
+
+int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
+ gfp_t flags, int node)
+{
+ unsigned int bits_per_word;
+ unsigned int i;
+
+ if (shift < 0) {
+ shift = ilog2(BITS_PER_LONG);
+ /*
+ * If the bitmap is small, shrink the number of bits per word so
+ * we spread over a few cachelines, at least. If less than 4
+ * bits, just forget about it, it's not going to work optimally
+ * anyway.
+ */
+ if (depth >= 4) {
+ while ((4U << shift) > depth)
+ shift--;
+ }
+ }
+ bits_per_word = 1U << shift;
+ if (bits_per_word > BITS_PER_LONG)
+ return -EINVAL;
+
+ sb->shift = shift;
+ sb->depth = depth;
+ sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
+
+ if (depth == 0) {
+ sb->map = NULL;
+ return 0;
+ }
+
+ sb->map = kzalloc_node(sb->map_nr * sizeof(*sb->map), flags, node);
+ if (!sb->map)
+ return -ENOMEM;
+
+ for (i = 0; i < sb->map_nr; i++) {
+ sb->map[i].depth = min(depth, bits_per_word);
+ depth -= sb->map[i].depth;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sbitmap_init_node);
+
+void sbitmap_resize(struct sbitmap *sb, unsigned int depth)
+{
+ unsigned int bits_per_word = 1U << sb->shift;
+ unsigned int i;
+
+ sb->depth = depth;
+ sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
+
+ for (i = 0; i < sb->map_nr; i++) {
+ sb->map[i].depth = min(depth, bits_per_word);
+ depth -= sb->map[i].depth;
+ }
+}
+EXPORT_SYMBOL_GPL(sbitmap_resize);
+
+static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint,
+ bool wrap)
+{
+ unsigned int orig_hint = hint;
+ int nr;
+
+ while (1) {
+ nr = find_next_zero_bit(&word->word, word->depth, hint);
+ if (unlikely(nr >= word->depth)) {
+ /*
+ * We started with an offset, and we didn't reset the
+ * offset to 0 in a failure case, so start from 0 to
+ * exhaust the map.
+ */
+ if (orig_hint && hint && wrap) {
+ hint = orig_hint = 0;
+ continue;
+ }
+ return -1;
+ }
+
+ if (!test_and_set_bit(nr, &word->word))
+ break;
+
+ hint = nr + 1;
+ if (hint >= word->depth - 1)
+ hint = 0;
+ }
+
+ return nr;
+}
+
+int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin)
+{
+ unsigned int i, index;
+ int nr = -1;
+
+ index = SB_NR_TO_INDEX(sb, alloc_hint);
+
+ for (i = 0; i < sb->map_nr; i++) {
+ nr = __sbitmap_get_word(&sb->map[index],
+ SB_NR_TO_BIT(sb, alloc_hint),
+ !round_robin);
+ if (nr != -1) {
+ nr += index << sb->shift;
+ break;
+ }
+
+ /* Jump to next index. */
+ index++;
+ alloc_hint = index << sb->shift;
+
+ if (index >= sb->map_nr) {
+ index = 0;
+ alloc_hint = 0;
+ }
+ }
+
+ return nr;
+}
+EXPORT_SYMBOL_GPL(sbitmap_get);
+
+bool sbitmap_any_bit_set(const struct sbitmap *sb)
+{
+ unsigned int i;
+
+ for (i = 0; i < sb->map_nr; i++) {
+ if (sb->map[i].word)
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(sbitmap_any_bit_set);
+
+bool sbitmap_any_bit_clear(const struct sbitmap *sb)
+{
+ unsigned int i;
+
+ for (i = 0; i < sb->map_nr; i++) {
+ const struct sbitmap_word *word = &sb->map[i];
+ unsigned long ret;
+
+ ret = find_first_zero_bit(&word->word, word->depth);
+ if (ret < word->depth)
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(sbitmap_any_bit_clear);
+
+unsigned int sbitmap_weight(const struct sbitmap *sb)
+{
+ unsigned int i, weight = 0;
+
+ for (i = 0; i < sb->map_nr; i++) {
+ const struct sbitmap_word *word = &sb->map[i];
+
+ weight += bitmap_weight(&word->word, word->depth);
+ }
+ return weight;
+}
+EXPORT_SYMBOL_GPL(sbitmap_weight);
+
+static unsigned int sbq_calc_wake_batch(unsigned int depth)
+{
+ unsigned int wake_batch;
+
+ /*
+ * For each batch, we wake up one queue. We need to make sure that our
+ * batch size is small enough that the full depth of the bitmap is
+ * enough to wake up all of the queues.
+ */
+ wake_batch = SBQ_WAKE_BATCH;
+ if (wake_batch > depth / SBQ_WAIT_QUEUES)
+ wake_batch = max(1U, depth / SBQ_WAIT_QUEUES);
+
+ return wake_batch;
+}
+
+int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth,
+ int shift, bool round_robin, gfp_t flags, int node)
+{
+ int ret;
+ int i;
+
+ ret = sbitmap_init_node(&sbq->sb, depth, shift, flags, node);
+ if (ret)
+ return ret;
+
+ sbq->alloc_hint = alloc_percpu_gfp(unsigned int, flags);
+ if (!sbq->alloc_hint) {
+ sbitmap_free(&sbq->sb);
+ return -ENOMEM;
+ }
+
+ if (depth && !round_robin) {
+ for_each_possible_cpu(i)
+ *per_cpu_ptr(sbq->alloc_hint, i) = prandom_u32() % depth;
+ }
+
+ sbq->wake_batch = sbq_calc_wake_batch(depth);
+ atomic_set(&sbq->wake_index, 0);
+
+ sbq->ws = kzalloc_node(SBQ_WAIT_QUEUES * sizeof(*sbq->ws), flags, node);
+ if (!sbq->ws) {
+ free_percpu(sbq->alloc_hint);
+ sbitmap_free(&sbq->sb);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
+ init_waitqueue_head(&sbq->ws[i].wait);
+ atomic_set(&sbq->ws[i].wait_cnt, sbq->wake_batch);
+ }
+
+ sbq->round_robin = round_robin;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sbitmap_queue_init_node);
+
+void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth)
+{
+ sbq->wake_batch = sbq_calc_wake_batch(depth);
+ sbitmap_resize(&sbq->sb, depth);
+}
+EXPORT_SYMBOL_GPL(sbitmap_queue_resize);
+
+int __sbitmap_queue_get(struct sbitmap_queue *sbq)
+{
+ unsigned int hint, depth;
+ int nr;
+
+ hint = this_cpu_read(*sbq->alloc_hint);
+ depth = READ_ONCE(sbq->sb.depth);
+ if (unlikely(hint >= depth)) {
+ hint = depth ? prandom_u32() % depth : 0;
+ this_cpu_write(*sbq->alloc_hint, hint);
+ }
+ nr = sbitmap_get(&sbq->sb, hint, sbq->round_robin);
+
+ if (nr == -1) {
+ /* If the map is full, a hint won't do us much good. */
+ this_cpu_write(*sbq->alloc_hint, 0);
+ } else if (nr == hint || unlikely(sbq->round_robin)) {
+ /* Only update the hint if we used it. */
+ hint = nr + 1;
+ if (hint >= depth - 1)
+ hint = 0;
+ this_cpu_write(*sbq->alloc_hint, hint);
+ }
+
+ return nr;
+}
+EXPORT_SYMBOL_GPL(__sbitmap_queue_get);
+
+static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
+{
+ int i, wake_index;
+
+ wake_index = atomic_read(&sbq->wake_index);
+ for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
+ struct sbq_wait_state *ws = &sbq->ws[wake_index];
+
+ if (waitqueue_active(&ws->wait)) {
+ int o = atomic_read(&sbq->wake_index);
+
+ if (wake_index != o)
+ atomic_cmpxchg(&sbq->wake_index, o, wake_index);
+ return ws;
+ }
+
+ wake_index = sbq_index_inc(wake_index);
+ }
+
+ return NULL;
+}
+
+static void sbq_wake_up(struct sbitmap_queue *sbq)
+{
+ struct sbq_wait_state *ws;
+ int wait_cnt;
+
+ /* Ensure that the wait list checks occur after clear_bit(). */
+ smp_mb();
+
+ ws = sbq_wake_ptr(sbq);
+ if (!ws)
+ return;
+
+ wait_cnt = atomic_dec_return(&ws->wait_cnt);
+ if (unlikely(wait_cnt < 0))
+ wait_cnt = atomic_inc_return(&ws->wait_cnt);
+ if (wait_cnt == 0) {
+ atomic_add(sbq->wake_batch, &ws->wait_cnt);
+ sbq_index_atomic_inc(&sbq->wake_index);
+ wake_up(&ws->wait);
+ }
+}
+
+void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr,
+ unsigned int cpu)
+{
+ sbitmap_clear_bit(&sbq->sb, nr);
+ sbq_wake_up(sbq);
+ if (likely(!sbq->round_robin && nr < sbq->sb.depth))
+ *per_cpu_ptr(sbq->alloc_hint, cpu) = nr;
+}
+EXPORT_SYMBOL_GPL(sbitmap_queue_clear);
+
+void sbitmap_queue_wake_all(struct sbitmap_queue *sbq)
+{
+ int i, wake_index;
+
+ /*
+ * Make sure all changes prior to this are visible from other CPUs.
+ */
+ smp_mb();
+ wake_index = atomic_read(&sbq->wake_index);
+ for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
+ struct sbq_wait_state *ws = &sbq->ws[wake_index];
+
+ if (waitqueue_active(&ws->wait))
+ wake_up(&ws->wait);
+
+ wake_index = sbq_index_inc(wake_index);
+ }
+}
+EXPORT_SYMBOL_GPL(sbitmap_queue_wake_all);
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 0aa7dda52402..a869f84f44d3 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -11,15 +11,12 @@
#include <linux/init.h>
#include <linux/pfn.h>
#include <linux/slab.h>
-#include <linux/bootmem.h>
#include <linux/export.h>
#include <linux/kmemleak.h>
#include <linux/range.h>
-#include <linux/memblock.h>
#include <linux/bug.h>
#include <linux/io.h>
-
-#include <asm/processor.h>
+#include <linux/bootmem.h>
#include "internal.h"
@@ -712,7 +709,7 @@ void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
void *ptr;
if (WARN_ON_ONCE(slab_is_available()))
- return kzalloc(size, GFP_NOWAIT);
+ return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
again:
/* do not panic in alloc_bootmem_bdata() */
@@ -738,9 +735,6 @@ again:
void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
unsigned long align, unsigned long goal)
{
- if (WARN_ON_ONCE(slab_is_available()))
- return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
-
return ___alloc_bootmem_node_nopanic(pgdat, size, align, goal, 0);
}
@@ -812,10 +806,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
}
-#ifndef ARCH_LOW_ADDRESS_LIMIT
-#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
-#endif
-
/**
* __alloc_bootmem_low - allocate low boot memory
* @size: size of the request in bytes
diff --git a/mm/compaction.c b/mm/compaction.c
index 9affb2908304..0409a4ad6ea1 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -997,8 +997,12 @@ isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,
#ifdef CONFIG_COMPACTION
/* Returns true if the page is within a block suitable for migration to */
-static bool suitable_migration_target(struct page *page)
+static bool suitable_migration_target(struct compact_control *cc,
+ struct page *page)
{
+ if (cc->ignore_block_suitable)
+ return true;
+
/* If the page is a large free page, then disallow migration */
if (PageBuddy(page)) {
/*
@@ -1083,7 +1087,7 @@ static void isolate_freepages(struct compact_control *cc)
continue;
/* Check the block is suitable for migration */
- if (!suitable_migration_target(page))
+ if (!suitable_migration_target(cc, page))
continue;
/* If isolation recently failed, do not retry */
@@ -1316,7 +1320,7 @@ static enum compact_result __compact_finished(struct zone *zone, struct compact_
return COMPACT_CONTINUE;
/* Compaction run is not finished if the watermark is not met */
- watermark = low_wmark_pages(zone);
+ watermark = zone->watermark[cc->alloc_flags & ALLOC_WMARK_MASK];
if (!zone_watermark_ok(zone, cc->order, watermark, cc->classzone_idx,
cc->alloc_flags))
@@ -1329,13 +1333,13 @@ static enum compact_result __compact_finished(struct zone *zone, struct compact_
/* Job done if page is free of the right migratetype */
if (!list_empty(&area->free_list[migratetype]))
- return COMPACT_PARTIAL;
+ return COMPACT_SUCCESS;
#ifdef CONFIG_CMA
/* MIGRATE_MOVABLE can fallback on MIGRATE_CMA */
if (migratetype == MIGRATE_MOVABLE &&
!list_empty(&area->free_list[MIGRATE_CMA]))
- return COMPACT_PARTIAL;
+ return COMPACT_SUCCESS;
#endif
/*
* Job done if allocation would steal freepages from
@@ -1343,7 +1347,7 @@ static enum compact_result __compact_finished(struct zone *zone, struct compact_
*/
if (find_suitable_fallback(area, order, migratetype,
true, &can_steal) != -1)
- return COMPACT_PARTIAL;
+ return COMPACT_SUCCESS;
}
return COMPACT_NO_SUITABLE_PAGE;
@@ -1367,7 +1371,7 @@ static enum compact_result compact_finished(struct zone *zone,
* compaction_suitable: Is this suitable to run compaction on this zone now?
* Returns
* COMPACT_SKIPPED - If there are too few free pages for compaction
- * COMPACT_PARTIAL - If the allocation would succeed without compaction
+ * COMPACT_SUCCESS - If the allocation would succeed without compaction
* COMPACT_CONTINUE - If compaction should run now
*/
static enum compact_result __compaction_suitable(struct zone *zone, int order,
@@ -1375,46 +1379,41 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
int classzone_idx,
unsigned long wmark_target)
{
- int fragindex;
unsigned long watermark;
if (is_via_compact_memory(order))
return COMPACT_CONTINUE;
- watermark = low_wmark_pages(zone);
+ watermark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
/*
* If watermarks for high-order allocation are already met, there
* should be no need for compaction at all.
*/
if (zone_watermark_ok(zone, order, watermark, classzone_idx,
alloc_flags))
- return COMPACT_PARTIAL;
+ return COMPACT_SUCCESS;
/*
- * Watermarks for order-0 must be met for compaction. Note the 2UL.
- * This is because during migration, copies of pages need to be
- * allocated and for a short time, the footprint is higher
+ * Watermarks for order-0 must be met for compaction to be able to
+ * isolate free pages for migration targets. This means that the
+ * watermark and alloc_flags have to match, or be more pessimistic than
+ * the check in __isolate_free_page(). We don't use the direct
+ * compactor's alloc_flags, as they are not relevant for freepage
+ * isolation. We however do use the direct compactor's classzone_idx to
+ * skip over zones where lowmem reserves would prevent allocation even
+ * if compaction succeeds.
+ * For costly orders, we require low watermark instead of min for
+ * compaction to proceed to increase its chances.
+ * ALLOC_CMA is used, as pages in CMA pageblocks are considered
+ * suitable migration targets
*/
- watermark += (2UL << order);
+ watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?
+ low_wmark_pages(zone) : min_wmark_pages(zone);
+ watermark += compact_gap(order);
if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,
- alloc_flags, wmark_target))
+ ALLOC_CMA, wmark_target))
return COMPACT_SKIPPED;
- /*
- * fragmentation index determines if allocation failures are due to
- * low memory or external fragmentation
- *
- * index of -1000 would imply allocations might succeed depending on
- * watermarks, but we already failed the high-order watermark check
- * index towards 0 implies failure is due to lack of memory
- * index towards 1000 implies failure is due to fragmentation
- *
- * Only compact if a failure would be due to fragmentation.
- */
- fragindex = fragmentation_index(zone, order);
- if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
- return COMPACT_NOT_SUITABLE_ZONE;
-
return COMPACT_CONTINUE;
}
@@ -1423,9 +1422,32 @@ enum compact_result compaction_suitable(struct zone *zone, int order,
int classzone_idx)
{
enum compact_result ret;
+ int fragindex;
ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx,
zone_page_state(zone, NR_FREE_PAGES));
+ /*
+ * fragmentation index determines if allocation failures are due to
+ * low memory or external fragmentation
+ *
+ * index of -1000 would imply allocations might succeed depending on
+ * watermarks, but we already failed the high-order watermark check
+ * index towards 0 implies failure is due to lack of memory
+ * index towards 1000 implies failure is due to fragmentation
+ *
+ * Only compact if a failure would be due to fragmentation. Also
+ * ignore fragindex for non-costly orders where the alternative to
+ * a successful reclaim/compaction is OOM. Fragindex and the
+ * vm.extfrag_threshold sysctl is meant as a heuristic to prevent
+ * excessive compaction for costly orders, but it should not be at the
+ * expense of system stability.
+ */
+ if (ret == COMPACT_CONTINUE && (order > PAGE_ALLOC_COSTLY_ORDER)) {
+ fragindex = fragmentation_index(zone, order);
+ if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
+ ret = COMPACT_NOT_SUITABLE_ZONE;
+ }
+
trace_mm_compaction_suitable(zone, order, ret);
if (ret == COMPACT_NOT_SUITABLE_ZONE)
ret = COMPACT_SKIPPED;
@@ -1458,8 +1480,7 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
compact_result = __compaction_suitable(zone, order, alloc_flags,
ac_classzone_idx(ac), available);
- if (compact_result != COMPACT_SKIPPED &&
- compact_result != COMPACT_NOT_SUITABLE_ZONE)
+ if (compact_result != COMPACT_SKIPPED)
return true;
}
@@ -1477,7 +1498,7 @@ static enum compact_result compact_zone(struct zone *zone, struct compact_contro
ret = compaction_suitable(zone, cc->order, cc->alloc_flags,
cc->classzone_idx);
/* Compaction is likely to fail */
- if (ret == COMPACT_PARTIAL || ret == COMPACT_SKIPPED)
+ if (ret == COMPACT_SUCCESS || ret == COMPACT_SKIPPED)
return ret;
/* huh, compaction_suitable is returning something unexpected */
@@ -1492,23 +1513,29 @@ static enum compact_result compact_zone(struct zone *zone, struct compact_contro
/*
* Setup to move all movable pages to the end of the zone. Used cached
- * information on where the scanners should start but check that it
- * is initialised by ensuring the values are within zone boundaries.
+ * information on where the scanners should start (unless we explicitly
+ * want to compact the whole zone), but check that it is initialised
+ * by ensuring the values are within zone boundaries.
*/
- cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync];
- cc->free_pfn = zone->compact_cached_free_pfn;
- if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) {
- cc->free_pfn = pageblock_start_pfn(end_pfn - 1);
- zone->compact_cached_free_pfn = cc->free_pfn;
- }
- if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) {
+ if (cc->whole_zone) {
cc->migrate_pfn = start_pfn;
- zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn;
- zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn;
- }
+ cc->free_pfn = pageblock_start_pfn(end_pfn - 1);
+ } else {
+ cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync];
+ cc->free_pfn = zone->compact_cached_free_pfn;
+ if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) {
+ cc->free_pfn = pageblock_start_pfn(end_pfn - 1);
+ zone->compact_cached_free_pfn = cc->free_pfn;
+ }
+ if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) {
+ cc->migrate_pfn = start_pfn;
+ zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn;
+ zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn;
+ }
- if (cc->migrate_pfn == start_pfn)
- cc->whole_zone = true;
+ if (cc->migrate_pfn == start_pfn)
+ cc->whole_zone = true;
+ }
cc->last_migrated_pfn = 0;
@@ -1638,6 +1665,9 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
.alloc_flags = alloc_flags,
.classzone_idx = classzone_idx,
.direct_compaction = true,
+ .whole_zone = (prio == MIN_COMPACT_PRIORITY),
+ .ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY),
+ .ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY)
};
INIT_LIST_HEAD(&cc.freepages);
INIT_LIST_HEAD(&cc.migratepages);
@@ -1683,7 +1713,8 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
ac->nodemask) {
enum compact_result status;
- if (compaction_deferred(zone, order)) {
+ if (prio > MIN_COMPACT_PRIORITY
+ && compaction_deferred(zone, order)) {
rc = max_t(enum compact_result, COMPACT_DEFERRED, rc);
continue;
}
@@ -1692,9 +1723,8 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
alloc_flags, ac_classzone_idx(ac));
rc = max(status, rc);
- /* If a normal allocation would succeed, stop compacting */
- if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
- ac_classzone_idx(ac), alloc_flags)) {
+ /* The allocation should succeed, stop compacting */
+ if (status == COMPACT_SUCCESS) {
/*
* We think the allocation will succeed in this zone,
* but it is not certain, hence the false. The caller
@@ -1730,10 +1760,18 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
/* Compact all zones within a node */
-static void __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
+static void compact_node(int nid)
{
+ pg_data_t *pgdat = NODE_DATA(nid);
int zoneid;
struct zone *zone;
+ struct compact_control cc = {
+ .order = -1,
+ .mode = MIGRATE_SYNC,
+ .ignore_skip_hint = true,
+ .whole_zone = true,
+ };
+
for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
@@ -1741,60 +1779,19 @@ static void __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
if (!populated_zone(zone))
continue;
- cc->nr_freepages = 0;
- cc->nr_migratepages = 0;
- cc->zone = zone;
- INIT_LIST_HEAD(&cc->freepages);
- INIT_LIST_HEAD(&cc->migratepages);
-
- /*
- * When called via /proc/sys/vm/compact_memory
- * this makes sure we compact the whole zone regardless of
- * cached scanner positions.
- */
- if (is_via_compact_memory(cc->order))
- __reset_isolation_suitable(zone);
-
- if (is_via_compact_memory(cc->order) ||
- !compaction_deferred(zone, cc->order))
- compact_zone(zone, cc);
-
- VM_BUG_ON(!list_empty(&cc->freepages));
- VM_BUG_ON(!list_empty(&cc->migratepages));
+ cc.nr_freepages = 0;
+ cc.nr_migratepages = 0;
+ cc.zone = zone;
+ INIT_LIST_HEAD(&cc.freepages);
+ INIT_LIST_HEAD(&cc.migratepages);
- if (is_via_compact_memory(cc->order))
- continue;
+ compact_zone(zone, &cc);
- if (zone_watermark_ok(zone, cc->order,
- low_wmark_pages(zone), 0, 0))
- compaction_defer_reset(zone, cc->order, false);
+ VM_BUG_ON(!list_empty(&cc.freepages));
+ VM_BUG_ON(!list_empty(&cc.migratepages));
}
}
-void compact_pgdat(pg_data_t *pgdat, int order)
-{
- struct compact_control cc = {
- .order = order,
- .mode = MIGRATE_ASYNC,
- };
-
- if (!order)
- return;
-
- __compact_pgdat(pgdat, &cc);
-}
-
-static void compact_node(int nid)
-{
- struct compact_control cc = {
- .order = -1,
- .mode = MIGRATE_SYNC,
- .ignore_skip_hint = true,
- };
-
- __compact_pgdat(NODE_DATA(nid), &cc);
-}
-
/* Compact all nodes in the system */
static void compact_nodes(void)
{
@@ -1900,8 +1897,6 @@ static void kcompactd_do_work(pg_data_t *pgdat)
.ignore_skip_hint = true,
};
- bool success = false;
-
trace_mm_compaction_kcompactd_wake(pgdat->node_id, cc.order,
cc.classzone_idx);
count_vm_event(KCOMPACTD_WAKE);
@@ -1930,9 +1925,7 @@ static void kcompactd_do_work(pg_data_t *pgdat)
return;
status = compact_zone(zone, &cc);
- if (zone_watermark_ok(zone, cc.order, low_wmark_pages(zone),
- cc.classzone_idx, 0)) {
- success = true;
+ if (status == COMPACT_SUCCESS) {
compaction_defer_reset(zone, cc.order, false);
} else if (status == COMPACT_PARTIAL_SKIPPED || status == COMPACT_COMPLETE) {
/*
diff --git a/mm/debug.c b/mm/debug.c
index 74c7cae4f683..9feb699c5d25 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -42,6 +42,11 @@ const struct trace_print_flags vmaflag_names[] = {
void __dump_page(struct page *page, const char *reason)
{
+ /*
+ * Avoid VM_BUG_ON() in page_mapcount().
+ * page->_mapcount space in struct page is used by sl[aou]b pages to
+ * encode own info.
+ */
int mapcount = PageSlab(page) ? 0 : page_mapcount(page);
pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
diff --git a/mm/filemap.c b/mm/filemap.c
index 68f1813fbdc3..849f459ad078 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1687,6 +1687,10 @@ static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos,
unsigned int prev_offset;
int error = 0;
+ if (unlikely(*ppos >= inode->i_sb->s_maxbytes))
+ return -EINVAL;
+ iov_iter_truncate(iter, inode->i_sb->s_maxbytes);
+
index = *ppos >> PAGE_SHIFT;
prev_index = ra->prev_pos >> PAGE_SHIFT;
prev_offset = ra->prev_pos & (PAGE_SIZE-1);
@@ -1721,7 +1725,9 @@ find_page:
* wait_on_page_locked is used to avoid unnecessarily
* serialisations and why it's safe.
*/
- wait_on_page_locked_killable(page);
+ error = wait_on_page_locked_killable(page);
+ if (unlikely(error))
+ goto readpage_error;
if (PageUptodate(page))
goto page_ok;
@@ -1935,7 +1941,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
file_accessed(file);
retval = mapping->a_ops->direct_IO(iocb, &data);
- if (retval > 0) {
+ if (retval >= 0) {
iocb->ki_pos += retval;
iov_iter_advance(iter, retval);
}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 283583fcb1e7..cdcd25cb30fe 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -59,7 +59,7 @@ static struct shrinker deferred_split_shrinker;
static atomic_t huge_zero_refcount;
struct page *huge_zero_page __read_mostly;
-struct page *get_huge_zero_page(void)
+static struct page *get_huge_zero_page(void)
{
struct page *zero_page;
retry:
@@ -86,7 +86,7 @@ retry:
return READ_ONCE(huge_zero_page);
}
-void put_huge_zero_page(void)
+static void put_huge_zero_page(void)
{
/*
* Counter should never go to zero here. Only shrinker can put
@@ -95,6 +95,26 @@ void put_huge_zero_page(void)
BUG_ON(atomic_dec_and_test(&huge_zero_refcount));
}
+struct page *mm_get_huge_zero_page(struct mm_struct *mm)
+{
+ if (test_bit(MMF_HUGE_ZERO_PAGE, &mm->flags))
+ return READ_ONCE(huge_zero_page);
+
+ if (!get_huge_zero_page())
+ return NULL;
+
+ if (test_and_set_bit(MMF_HUGE_ZERO_PAGE, &mm->flags))
+ put_huge_zero_page();
+
+ return READ_ONCE(huge_zero_page);
+}
+
+void mm_put_huge_zero_page(struct mm_struct *mm)
+{
+ if (test_bit(MMF_HUGE_ZERO_PAGE, &mm->flags))
+ put_huge_zero_page();
+}
+
static unsigned long shrink_huge_zero_page_count(struct shrinker *shrink,
struct shrink_control *sc)
{
@@ -469,6 +489,49 @@ void prep_transhuge_page(struct page *page)
set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR);
}
+unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len,
+ loff_t off, unsigned long flags, unsigned long size)
+{
+ unsigned long addr;
+ loff_t off_end = off + len;
+ loff_t off_align = round_up(off, size);
+ unsigned long len_pad;
+
+ if (off_end <= off_align || (off_end - off_align) < size)
+ return 0;
+
+ len_pad = len + size;
+ if (len_pad < len || (off + len_pad) < off)
+ return 0;
+
+ addr = current->mm->get_unmapped_area(filp, 0, len_pad,
+ off >> PAGE_SHIFT, flags);
+ if (IS_ERR_VALUE(addr))
+ return 0;
+
+ addr += (off - addr) & (size - 1);
+ return addr;
+}
+
+unsigned long thp_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ loff_t off = (loff_t)pgoff << PAGE_SHIFT;
+
+ if (addr)
+ goto out;
+ if (!IS_DAX(filp->f_mapping->host) || !IS_ENABLED(CONFIG_FS_DAX_PMD))
+ goto out;
+
+ addr = __thp_get_unmapped_area(filp, len, off, flags, PMD_SIZE);
+ if (addr)
+ return addr;
+
+ out:
+ return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+EXPORT_SYMBOL_GPL(thp_get_unmapped_area);
+
static int __do_huge_pmd_anonymous_page(struct fault_env *fe, struct page *page,
gfp_t gfp)
{
@@ -601,7 +664,7 @@ int do_huge_pmd_anonymous_page(struct fault_env *fe)
pgtable = pte_alloc_one(vma->vm_mm, haddr);
if (unlikely(!pgtable))
return VM_FAULT_OOM;
- zero_page = get_huge_zero_page();
+ zero_page = mm_get_huge_zero_page(vma->vm_mm);
if (unlikely(!zero_page)) {
pte_free(vma->vm_mm, pgtable);
count_vm_event(THP_FAULT_FALLBACK);
@@ -623,10 +686,8 @@ int do_huge_pmd_anonymous_page(struct fault_env *fe)
}
} else
spin_unlock(fe->ptl);
- if (!set) {
+ if (!set)
pte_free(vma->vm_mm, pgtable);
- put_huge_zero_page();
- }
return ret;
}
gfp = alloc_hugepage_direct_gfpmask(vma);
@@ -780,7 +841,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
* since we already have a zero page to copy. It just takes a
* reference.
*/
- zero_page = get_huge_zero_page();
+ zero_page = mm_get_huge_zero_page(dst_mm);
set_huge_zero_page(pgtable, dst_mm, vma, addr, dst_pmd,
zero_page);
ret = 0;
@@ -1038,7 +1099,6 @@ alloc:
update_mmu_cache_pmd(vma, fe->address, fe->pmd);
if (!page) {
add_mm_counter(vma->vm_mm, MM_ANONPAGES, HPAGE_PMD_NR);
- put_huge_zero_page();
} else {
VM_BUG_ON_PAGE(!PageHead(page), page);
page_remove_rmap(page, true);
@@ -1499,7 +1559,6 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
}
smp_wmb(); /* make pte visible before pmd */
pmd_populate(mm, pmd, pgtable);
- put_huge_zero_page();
}
static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
@@ -1522,8 +1581,6 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (!vma_is_anonymous(vma)) {
_pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd);
- if (is_huge_zero_pmd(_pmd))
- put_huge_zero_page();
if (vma_is_dax(vma))
return;
page = pmd_page(_pmd);
@@ -1563,7 +1620,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (soft_dirty)
entry = pte_swp_mksoft_dirty(entry);
} else {
- entry = mk_pte(page + i, vma->vm_page_prot);
+ entry = mk_pte(page + i, READ_ONCE(vma->vm_page_prot));
entry = maybe_mkwrite(entry, vma);
if (!write)
entry = pte_wrprotect(entry);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 87e11d8ad536..ec49d9ef1eef 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -567,13 +567,13 @@ retry:
* appear as a "reserved" entry instead of simply dangling with incorrect
* counts.
*/
-void hugetlb_fix_reserve_counts(struct inode *inode, bool restore_reserve)
+void hugetlb_fix_reserve_counts(struct inode *inode)
{
struct hugepage_subpool *spool = subpool_inode(inode);
long rsv_adjust;
rsv_adjust = hugepage_subpool_get_pages(spool, 1);
- if (restore_reserve && rsv_adjust) {
+ if (rsv_adjust) {
struct hstate *h = hstate_inode(inode);
hugetlb_acct_memory(h, 1);
@@ -1022,7 +1022,7 @@ static int hstate_next_node_to_free(struct hstate *h, nodemask_t *nodes_allowed)
((node = hstate_next_node_to_free(hs, mask)) || 1); \
nr_nodes--)
-#if (defined(CONFIG_X86_64) || defined(CONFIG_S390)) && \
+#if defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) && \
((defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || \
defined(CONFIG_CMA))
static void destroy_compound_gigantic_page(struct page *page,
@@ -1437,38 +1437,61 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
/*
* Dissolve a given free hugepage into free buddy pages. This function does
- * nothing for in-use (including surplus) hugepages.
+ * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the
+ * number of free hugepages would be reduced below the number of reserved
+ * hugepages.
*/
-static void dissolve_free_huge_page(struct page *page)
+static int dissolve_free_huge_page(struct page *page)
{
+ int rc = 0;
+
spin_lock(&hugetlb_lock);
if (PageHuge(page) && !page_count(page)) {
- struct hstate *h = page_hstate(page);
- int nid = page_to_nid(page);
- list_del(&page->lru);
+ struct page *head = compound_head(page);
+ struct hstate *h = page_hstate(head);
+ int nid = page_to_nid(head);
+ if (h->free_huge_pages - h->resv_huge_pages == 0) {
+ rc = -EBUSY;
+ goto out;
+ }
+ list_del(&head->lru);
h->free_huge_pages--;
h->free_huge_pages_node[nid]--;
h->max_huge_pages--;
- update_and_free_page(h, page);
+ update_and_free_page(h, head);
}
+out:
spin_unlock(&hugetlb_lock);
+ return rc;
}
/*
* Dissolve free hugepages in a given pfn range. Used by memory hotplug to
* make specified memory blocks removable from the system.
- * Note that start_pfn should aligned with (minimum) hugepage size.
+ * Note that this will dissolve a free gigantic hugepage completely, if any
+ * part of it lies within the given range.
+ * Also note that if dissolve_free_huge_page() returns with an error, all
+ * free hugepages that were dissolved before that error are lost.
*/
-void dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
+int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
{
unsigned long pfn;
+ struct page *page;
+ int rc = 0;
if (!hugepages_supported())
- return;
+ return rc;
+
+ for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order) {
+ page = pfn_to_page(pfn);
+ if (PageHuge(page) && !page_count(page)) {
+ rc = dissolve_free_huge_page(page);
+ if (rc)
+ break;
+ }
+ }
- VM_BUG_ON(!IS_ALIGNED(start_pfn, 1 << minimum_order));
- for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order)
- dissolve_free_huge_page(pfn_to_page(pfn));
+ return rc;
}
/*
diff --git a/mm/internal.h b/mm/internal.h
index 1501304f87a4..537ac9951f5f 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -178,8 +178,9 @@ struct compact_control {
unsigned long last_migrated_pfn;/* Not yet flushed page being freed */
enum migrate_mode mode; /* Async or sync migration mode */
bool ignore_skip_hint; /* Scan blocks even if marked skip */
+ bool ignore_block_suitable; /* Scan blocks considered unsuitable */
bool direct_compaction; /* False from kcompactd or /proc/... */
- bool whole_zone; /* Whole zone has been scanned */
+ bool whole_zone; /* Whole zone should/has been scanned */
int order; /* order a direct compactor needs */
const gfp_t gfp_mask; /* gfp mask of a direct compactor */
const unsigned int alloc_flags; /* alloc flags of a direct compactor */
diff --git a/mm/ksm.c b/mm/ksm.c
index 5048083b60f2..9ae6011a41f8 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -299,7 +299,12 @@ static inline void free_rmap_item(struct rmap_item *rmap_item)
static inline struct stable_node *alloc_stable_node(void)
{
- return kmem_cache_alloc(stable_node_cache, GFP_KERNEL);
+ /*
+ * The allocation can take too long with GFP_KERNEL when memory is under
+ * pressure, which may lead to hung task warnings. Adding __GFP_HIGH
+ * grants access to memory reserves, helping to avoid this problem.
+ */
+ return kmem_cache_alloc(stable_node_cache, GFP_KERNEL | __GFP_HIGH);
}
static inline void free_stable_node(struct stable_node *stable_node)
diff --git a/mm/memblock.c b/mm/memblock.c
index 483197ef613f..c8dfa430342b 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1438,6 +1438,11 @@ phys_addr_t __init_memblock memblock_phys_mem_size(void)
return memblock.memory.total_size;
}
+phys_addr_t __init_memblock memblock_reserved_size(void)
+{
+ return memblock.reserved.total_size;
+}
+
phys_addr_t __init memblock_mem_size(unsigned long limit_pfn)
{
unsigned long pages = 0;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 4be518d4e68a..ae052b5e3315 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -921,6 +921,43 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
iter = mem_cgroup_iter(NULL, iter, NULL))
/**
+ * mem_cgroup_scan_tasks - iterate over tasks of a memory cgroup hierarchy
+ * @memcg: hierarchy root
+ * @fn: function to call for each task
+ * @arg: argument passed to @fn
+ *
+ * This function iterates over tasks attached to @memcg or to any of its
+ * descendants and calls @fn for each task. If @fn returns a non-zero
+ * value, the function breaks the iteration loop and returns the value.
+ * Otherwise, it will iterate over all tasks and return 0.
+ *
+ * This function must not be called for the root memory cgroup.
+ */
+int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
+ int (*fn)(struct task_struct *, void *), void *arg)
+{
+ struct mem_cgroup *iter;
+ int ret = 0;
+
+ BUG_ON(memcg == root_mem_cgroup);
+
+ for_each_mem_cgroup_tree(iter, memcg) {
+ struct css_task_iter it;
+ struct task_struct *task;
+
+ css_task_iter_start(&iter->css, &it);
+ while (!ret && (task = css_task_iter_next(&it)))
+ ret = fn(task, arg);
+ css_task_iter_end(&it);
+ if (ret) {
+ mem_cgroup_iter_break(memcg, iter);
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
* mem_cgroup_page_lruvec - return lruvec for isolating/putting an LRU page
* @page: the page
* @zone: zone of the page
@@ -1178,7 +1215,7 @@ static int mem_cgroup_count_children(struct mem_cgroup *memcg)
/*
* Return the memory (and swap, if configured) limit for a memcg.
*/
-static unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg)
+unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg)
{
unsigned long limit;
@@ -1205,79 +1242,12 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
.gfp_mask = gfp_mask,
.order = order,
};
- struct mem_cgroup *iter;
- unsigned long chosen_points = 0;
- unsigned long totalpages;
- unsigned int points = 0;
- struct task_struct *chosen = NULL;
+ bool ret;
mutex_lock(&oom_lock);
-
- /*
- * If current has a pending SIGKILL or is exiting, then automatically
- * select it. The goal is to allow it to allocate so that it may
- * quickly exit and free its memory.
- */
- if (task_will_free_mem(current)) {
- mark_oom_victim(current);
- wake_oom_reaper(current);
- goto unlock;
- }
-
- check_panic_on_oom(&oc, CONSTRAINT_MEMCG);
- totalpages = mem_cgroup_get_limit(memcg) ? : 1;
- for_each_mem_cgroup_tree(iter, memcg) {
- struct css_task_iter it;
- struct task_struct *task;
-
- css_task_iter_start(&iter->css, &it);
- while ((task = css_task_iter_next(&it))) {
- switch (oom_scan_process_thread(&oc, task)) {
- case OOM_SCAN_SELECT:
- if (chosen)
- put_task_struct(chosen);
- chosen = task;
- chosen_points = ULONG_MAX;
- get_task_struct(chosen);
- /* fall through */
- case OOM_SCAN_CONTINUE:
- continue;
- case OOM_SCAN_ABORT:
- css_task_iter_end(&it);
- mem_cgroup_iter_break(memcg, iter);
- if (chosen)
- put_task_struct(chosen);
- /* Set a dummy value to return "true". */
- chosen = (void *) 1;
- goto unlock;
- case OOM_SCAN_OK:
- break;
- };
- points = oom_badness(task, memcg, NULL, totalpages);
- if (!points || points < chosen_points)
- continue;
- /* Prefer thread group leaders for display purposes */
- if (points == chosen_points &&
- thread_group_leader(chosen))
- continue;
-
- if (chosen)
- put_task_struct(chosen);
- chosen = task;
- chosen_points = points;
- get_task_struct(chosen);
- }
- css_task_iter_end(&it);
- }
-
- if (chosen) {
- points = chosen_points * 1000 / totalpages;
- oom_kill_process(&oc, chosen, points, totalpages,
- "Memory cgroup out of memory");
- }
-unlock:
+ ret = out_of_memory(&oc);
mutex_unlock(&oom_lock);
- return chosen;
+ return ret;
}
#if MAX_NUMNODES > 1
@@ -1600,7 +1570,7 @@ bool mem_cgroup_oom_synchronize(bool handle)
if (!memcg)
return false;
- if (!handle || oom_killer_disabled)
+ if (!handle)
goto cleanup;
owait.memcg = memcg;
@@ -2969,16 +2939,16 @@ static int memcg_update_tcp_limit(struct mem_cgroup *memcg, unsigned long limit)
/*
* The active flag needs to be written after the static_key
* update. This is what guarantees that the socket activation
- * function is the last one to run. See sock_update_memcg() for
- * details, and note that we don't mark any socket as belonging
- * to this memcg until that flag is up.
+ * function is the last one to run. See mem_cgroup_sk_alloc()
+ * for details, and note that we don't mark any socket as
+ * belonging to this memcg until that flag is up.
*
* We need to do this, because static_keys will span multiple
* sites, but we can't control their order. If we mark a socket
* as accounted, but the accounting functions are not patched in
* yet, we'll lose accounting.
*
- * We never race with the readers in sock_update_memcg(),
+ * We never race with the readers in mem_cgroup_sk_alloc(),
* because when this value change, the code to process it is not
* patched in yet.
*/
@@ -4092,11 +4062,13 @@ static DEFINE_IDR(mem_cgroup_idr);
static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
{
+ VM_BUG_ON(atomic_read(&memcg->id.ref) <= 0);
atomic_add(n, &memcg->id.ref);
}
static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
{
+ VM_BUG_ON(atomic_read(&memcg->id.ref) < n);
if (atomic_sub_and_test(n, &memcg->id.ref)) {
idr_remove(&mem_cgroup_idr, memcg->id.id);
memcg->id.id = 0;
@@ -4285,8 +4257,10 @@ fail:
static int mem_cgroup_css_online(struct cgroup_subsys_state *css)
{
+ struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+
/* Online state pins memcg ID, memcg ID pins CSS */
- mem_cgroup_id_get(mem_cgroup_from_css(css));
+ atomic_set(&memcg->id.ref, 1);
css_get(css);
return 0;
}
@@ -4434,7 +4408,7 @@ static struct page *mc_handle_swap_pte(struct vm_area_struct *vma,
* Because lookup_swap_cache() updates some statistics counter,
* we call find_get_page() with swapper_space directly.
*/
- page = find_get_page(swap_address_space(ent), ent.val);
+ page = find_get_page(swap_address_space(ent), swp_offset(ent));
if (do_memsw_account())
entry->val = ent.val;
@@ -4472,7 +4446,8 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
swp_entry_t swp = radix_to_swp_entry(page);
if (do_memsw_account())
*entry = swp;
- page = find_get_page(swap_address_space(swp), swp.val);
+ page = find_get_page(swap_address_space(swp),
+ swp_offset(swp));
}
} else
page = find_get_page(mapping, pgoff);
@@ -4707,7 +4682,8 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
.mm = mm,
};
down_read(&mm->mmap_sem);
- walk_page_range(0, ~0UL, &mem_cgroup_count_precharge_walk);
+ walk_page_range(0, mm->highest_vm_end,
+ &mem_cgroup_count_precharge_walk);
up_read(&mm->mmap_sem);
precharge = mc.precharge;
@@ -4995,7 +4971,8 @@ retry:
* When we have consumed all precharges and failed in doing
* additional charge, the page walk just aborts.
*/
- walk_page_range(0, ~0UL, &mem_cgroup_move_charge_walk);
+ walk_page_range(0, mc.mm->highest_vm_end, &mem_cgroup_move_charge_walk);
+
up_read(&mc.mm->mmap_sem);
atomic_dec(&mc.from->moving_account);
}
@@ -5674,11 +5651,15 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage)
DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);
EXPORT_SYMBOL(memcg_sockets_enabled_key);
-void sock_update_memcg(struct sock *sk)
+void mem_cgroup_sk_alloc(struct sock *sk)
{
struct mem_cgroup *memcg;
- /* Socket cloning can throw us here with sk_cgrp already
+ if (!mem_cgroup_sockets_enabled)
+ return;
+
+ /*
+ * Socket cloning can throw us here with sk_memcg already
* filled. It won't however, necessarily happen from
* process context. So the test for root memcg given
* the current task's memcg won't help us in this case.
@@ -5703,12 +5684,11 @@ void sock_update_memcg(struct sock *sk)
out:
rcu_read_unlock();
}
-EXPORT_SYMBOL(sock_update_memcg);
-void sock_release_memcg(struct sock *sk)
+void mem_cgroup_sk_free(struct sock *sk)
{
- WARN_ON(!sk->sk_memcg);
- css_put(&sk->sk_memcg->css);
+ if (sk->sk_memcg)
+ css_put(&sk->sk_memcg->css);
}
/**
diff --git a/mm/memory.c b/mm/memory.c
index f1a68049edff..fc1987dfd8cc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1649,10 +1649,14 @@ EXPORT_SYMBOL(vm_insert_pfn_prot);
int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
pfn_t pfn)
{
+ pgprot_t pgprot = vma->vm_page_prot;
+
BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
if (addr < vma->vm_start || addr >= vma->vm_end)
return -EFAULT;
+ if (track_pfn_insert(vma, &pgprot, pfn))
+ return -EINVAL;
/*
* If we don't have pte special, then we have to use the pfn_valid()
@@ -1670,9 +1674,9 @@ int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
* result in pfn_t_has_page() == false.
*/
page = pfn_to_page(pfn_t_to_pfn(pfn));
- return insert_page(vma, addr, page, vma->vm_page_prot);
+ return insert_page(vma, addr, page, pgprot);
}
- return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+ return insert_pfn(vma, addr, pfn, pgprot);
}
EXPORT_SYMBOL(vm_insert_mixed);
@@ -3658,6 +3662,19 @@ int handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
mem_cgroup_oom_synchronize(false);
}
+ /*
+ * This mm has been already reaped by the oom reaper and so the
+ * refault cannot be trusted in general. Anonymous refaults would
+ * lose data and give a zero page instead e.g. This is especially
+ * problem for use_mm() because regular tasks will just die and
+ * the corrupted data will not be visible anywhere while kthread
+ * will outlive the oom victim and potentially propagate the date
+ * further.
+ */
+ if (unlikely((current->flags & PF_KTHREAD) && !(ret & VM_FAULT_ERROR)
+ && test_bit(MMF_UNSTABLE, &vma->vm_mm->flags)))
+ ret = VM_FAULT_SIGBUS;
+
return ret;
}
EXPORT_SYMBOL_GPL(handle_mm_fault);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 9d29ba0f7192..962927309b6e 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1945,7 +1945,9 @@ repeat:
* dissolve free hugepages in the memory block before doing offlining
* actually in order to make hugetlbfs's object counting consistent.
*/
- dissolve_free_huge_pages(start_pfn, end_pfn);
+ ret = dissolve_free_huge_pages(start_pfn, end_pfn);
+ if (ret)
+ goto failed_removal;
/* check again */
offlined_pages = check_pages_isolated(start_pfn, end_pfn);
if (offlined_pages < 0) {
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 2da72a5b6ecc..ad1c96ac313c 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1749,7 +1749,7 @@ unsigned int mempolicy_slab_node(void)
*/
struct zonelist *zonelist;
enum zone_type highest_zoneidx = gfp_zone(GFP_KERNEL);
- zonelist = &NODE_DATA(node)->node_zonelists[0];
+ zonelist = &NODE_DATA(node)->node_zonelists[ZONELIST_FALLBACK];
z = first_zones_zonelist(zonelist, highest_zoneidx,
&policy->v.nodes);
return z->zone ? z->zone->node : node;
diff --git a/mm/migrate.c b/mm/migrate.c
index f7ee04a5ae27..99250aee1ac1 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -234,7 +234,7 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
goto unlock;
get_page(new);
- pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
+ pte = pte_mkold(mk_pte(new, READ_ONCE(vma->vm_page_prot)));
if (pte_swp_soft_dirty(*ptep))
pte = pte_mksoft_dirty(pte);
diff --git a/mm/mincore.c b/mm/mincore.c
index c0b5ba965200..bfb866435478 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -66,7 +66,8 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
*/
if (radix_tree_exceptional_entry(page)) {
swp_entry_t swp = radix_to_swp_entry(page);
- page = find_get_page(swap_address_space(swp), swp.val);
+ page = find_get_page(swap_address_space(swp),
+ swp_offset(swp));
}
} else
page = find_get_page(mapping, pgoff);
@@ -150,7 +151,7 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
} else {
#ifdef CONFIG_SWAP
*vec = mincore_page(swap_address_space(entry),
- entry.val);
+ swp_offset(entry));
#else
WARN_ON(1);
*vec = 1;
diff --git a/mm/mlock.c b/mm/mlock.c
index 14645be06e30..145a4258ddbc 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -516,6 +516,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
int nr_pages;
int ret = 0;
int lock = !!(newflags & VM_LOCKED);
+ vm_flags_t old_flags = vma->vm_flags;
if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
@@ -550,6 +551,8 @@ success:
nr_pages = (end - start) >> PAGE_SHIFT;
if (!lock)
nr_pages = -nr_pages;
+ else if (old_flags & VM_LOCKED)
+ nr_pages = 0;
mm->locked_vm += nr_pages;
/*
@@ -617,6 +620,45 @@ static int apply_vma_lock_flags(unsigned long start, size_t len,
return error;
}
+/*
+ * Go through vma areas and sum size of mlocked
+ * vma pages, as return value.
+ * Note deferred memory locking case(mlock2(,,MLOCK_ONFAULT)
+ * is also counted.
+ * Return value: previously mlocked page counts
+ */
+static int count_mm_mlocked_page_nr(struct mm_struct *mm,
+ unsigned long start, size_t len)
+{
+ struct vm_area_struct *vma;
+ int count = 0;
+
+ if (mm == NULL)
+ mm = current->mm;
+
+ vma = find_vma(mm, start);
+ if (vma == NULL)
+ vma = mm->mmap;
+
+ for (; vma ; vma = vma->vm_next) {
+ if (start >= vma->vm_end)
+ continue;
+ if (start + len <= vma->vm_start)
+ break;
+ if (vma->vm_flags & VM_LOCKED) {
+ if (start > vma->vm_start)
+ count -= (start - vma->vm_start);
+ if (start + len < vma->vm_end) {
+ count += start + len - vma->vm_start;
+ break;
+ }
+ count += vma->vm_end - vma->vm_start;
+ }
+ }
+
+ return count >> PAGE_SHIFT;
+}
+
static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t flags)
{
unsigned long locked;
@@ -639,6 +681,16 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla
return -EINTR;
locked += current->mm->locked_vm;
+ if ((locked > lock_limit) && (!capable(CAP_IPC_LOCK))) {
+ /*
+ * It is possible that the regions requested intersect with
+ * previously mlocked areas, that part area in "mm->locked_vm"
+ * should not be counted to new mlock increment count. So check
+ * and adjust locked count if necessary.
+ */
+ locked -= count_mm_mlocked_page_nr(current->mm,
+ start, len);
+ }
/* check against resource limits */
if ((locked <= lock_limit) || capable(CAP_IPC_LOCK))
diff --git a/mm/mmap.c b/mm/mmap.c
index 7a0707a48047..1af87c14183d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -116,13 +116,15 @@ static pgprot_t vm_pgprot_modify(pgprot_t oldprot, unsigned long vm_flags)
void vma_set_page_prot(struct vm_area_struct *vma)
{
unsigned long vm_flags = vma->vm_flags;
+ pgprot_t vm_page_prot;
- vma->vm_page_prot = vm_pgprot_modify(vma->vm_page_prot, vm_flags);
- if (vma_wants_writenotify(vma)) {
+ vm_page_prot = vm_pgprot_modify(vma->vm_page_prot, vm_flags);
+ if (vma_wants_writenotify(vma, vm_page_prot)) {
vm_flags &= ~VM_SHARED;
- vma->vm_page_prot = vm_pgprot_modify(vma->vm_page_prot,
- vm_flags);
+ vm_page_prot = vm_pgprot_modify(vm_page_prot, vm_flags);
}
+ /* remove_protection_ptes reads vma->vm_page_prot without mmap_sem */
+ WRITE_ONCE(vma->vm_page_prot, vm_page_prot);
}
/*
@@ -400,15 +402,9 @@ static inline void vma_rb_insert(struct vm_area_struct *vma,
rb_insert_augmented(&vma->vm_rb, root, &vma_gap_callbacks);
}
-static void vma_rb_erase(struct vm_area_struct *vma, struct rb_root *root)
+static void __vma_rb_erase(struct vm_area_struct *vma, struct rb_root *root)
{
/*
- * All rb_subtree_gap values must be consistent prior to erase,
- * with the possible exception of the vma being erased.
- */
- validate_mm_rb(root, vma);
-
- /*
* Note rb_erase_augmented is a fairly large inline function,
* so make sure we instantiate it only once with our desired
* augmented rbtree callbacks.
@@ -416,6 +412,32 @@ static void vma_rb_erase(struct vm_area_struct *vma, struct rb_root *root)
rb_erase_augmented(&vma->vm_rb, root, &vma_gap_callbacks);
}
+static __always_inline void vma_rb_erase_ignore(struct vm_area_struct *vma,
+ struct rb_root *root,
+ struct vm_area_struct *ignore)
+{
+ /*
+ * All rb_subtree_gap values must be consistent prior to erase,
+ * with the possible exception of the "next" vma being erased if
+ * next->vm_start was reduced.
+ */
+ validate_mm_rb(root, ignore);
+
+ __vma_rb_erase(vma, root);
+}
+
+static __always_inline void vma_rb_erase(struct vm_area_struct *vma,
+ struct rb_root *root)
+{
+ /*
+ * All rb_subtree_gap values must be consistent prior to erase,
+ * with the possible exception of the vma being erased.
+ */
+ validate_mm_rb(root, vma);
+
+ __vma_rb_erase(vma, root);
+}
+
/*
* vma has some anon_vma assigned, and is already inserted on that
* anon_vma's interval trees.
@@ -599,14 +621,25 @@ static void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
mm->map_count++;
}
-static inline void
-__vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma,
- struct vm_area_struct *prev)
+static __always_inline void __vma_unlink_common(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ struct vm_area_struct *prev,
+ bool has_prev,
+ struct vm_area_struct *ignore)
{
struct vm_area_struct *next;
- vma_rb_erase(vma, &mm->mm_rb);
- prev->vm_next = next = vma->vm_next;
+ vma_rb_erase_ignore(vma, &mm->mm_rb, ignore);
+ next = vma->vm_next;
+ if (has_prev)
+ prev->vm_next = next;
+ else {
+ prev = vma->vm_prev;
+ if (prev)
+ prev->vm_next = next;
+ else
+ mm->mmap = next;
+ }
if (next)
next->vm_prev = prev;
@@ -614,6 +647,13 @@ __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma,
vmacache_invalidate(mm);
}
+static inline void __vma_unlink_prev(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ struct vm_area_struct *prev)
+{
+ __vma_unlink_common(mm, vma, prev, true, vma);
+}
+
/*
* We cannot adjust vm_start, vm_end, vm_pgoff fields of a vma that
* is already present in an i_mmap tree without adjusting the tree.
@@ -621,11 +661,12 @@ __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma,
* are necessary. The "insert" vma (if any) is to be inserted
* before we drop the necessary locks.
*/
-int vma_adjust(struct vm_area_struct *vma, unsigned long start,
- unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert)
+int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert,
+ struct vm_area_struct *expand)
{
struct mm_struct *mm = vma->vm_mm;
- struct vm_area_struct *next = vma->vm_next;
+ struct vm_area_struct *next = vma->vm_next, *orig_vma = vma;
struct address_space *mapping = NULL;
struct rb_root *root = NULL;
struct anon_vma *anon_vma = NULL;
@@ -641,9 +682,38 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
/*
* vma expands, overlapping all the next, and
* perhaps the one after too (mprotect case 6).
+ * The only other cases that gets here are
+ * case 1, case 7 and case 8.
*/
- remove_next = 1 + (end > next->vm_end);
- end = next->vm_end;
+ if (next == expand) {
+ /*
+ * The only case where we don't expand "vma"
+ * and we expand "next" instead is case 8.
+ */
+ VM_WARN_ON(end != next->vm_end);
+ /*
+ * remove_next == 3 means we're
+ * removing "vma" and that to do so we
+ * swapped "vma" and "next".
+ */
+ remove_next = 3;
+ VM_WARN_ON(file != next->vm_file);
+ swap(vma, next);
+ } else {
+ VM_WARN_ON(expand != vma);
+ /*
+ * case 1, 6, 7, remove_next == 2 is case 6,
+ * remove_next == 1 is case 1 or 7.
+ */
+ remove_next = 1 + (end > next->vm_end);
+ VM_WARN_ON(remove_next == 2 &&
+ end != next->vm_next->vm_end);
+ VM_WARN_ON(remove_next == 1 &&
+ end != next->vm_end);
+ /* trim end to next, for case 6 first pass */
+ end = next->vm_end;
+ }
+
exporter = next;
importer = vma;
@@ -651,7 +721,7 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
* If next doesn't have anon_vma, import from vma after
* next, if the vma overlaps with it.
*/
- if (remove_next == 2 && next && !next->anon_vma)
+ if (remove_next == 2 && !next->anon_vma)
exporter = next->vm_next;
} else if (end > next->vm_start) {
@@ -662,6 +732,7 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
adjust_next = (end - next->vm_start) >> PAGE_SHIFT;
exporter = next;
importer = vma;
+ VM_WARN_ON(expand != importer);
} else if (end < vma->vm_end) {
/*
* vma shrinks, and !insert tells it's not
@@ -671,6 +742,7 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
adjust_next = -((vma->vm_end - end) >> PAGE_SHIFT);
exporter = vma;
importer = next;
+ VM_WARN_ON(expand != importer);
}
/*
@@ -688,7 +760,7 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
}
}
again:
- vma_adjust_trans_huge(vma, start, end, adjust_next);
+ vma_adjust_trans_huge(orig_vma, start, end, adjust_next);
if (file) {
mapping = file->f_mapping;
@@ -714,8 +786,8 @@ again:
if (!anon_vma && adjust_next)
anon_vma = next->anon_vma;
if (anon_vma) {
- VM_BUG_ON_VMA(adjust_next && next->anon_vma &&
- anon_vma != next->anon_vma, next);
+ VM_WARN_ON(adjust_next && next->anon_vma &&
+ anon_vma != next->anon_vma);
anon_vma_lock_write(anon_vma);
anon_vma_interval_tree_pre_update_vma(vma);
if (adjust_next)
@@ -755,7 +827,19 @@ again:
* vma_merge has merged next into vma, and needs
* us to remove next before dropping the locks.
*/
- __vma_unlink(mm, next, vma);
+ if (remove_next != 3)
+ __vma_unlink_prev(mm, next, vma);
+ else
+ /*
+ * vma is not before next if they've been
+ * swapped.
+ *
+ * pre-swap() next->vm_start was reduced so
+ * tell validate_mm_rb to ignore pre-swap()
+ * "next" (which is stored in post-swap()
+ * "vma").
+ */
+ __vma_unlink_common(mm, next, NULL, false, vma);
if (file)
__remove_shared_vm_struct(next, file, mapping);
} else if (insert) {
@@ -807,7 +891,27 @@ again:
* we must remove another next too. It would clutter
* up the code too much to do both in one go.
*/
- next = vma->vm_next;
+ if (remove_next != 3) {
+ /*
+ * If "next" was removed and vma->vm_end was
+ * expanded (up) over it, in turn
+ * "next->vm_prev->vm_end" changed and the
+ * "vma->vm_next" gap must be updated.
+ */
+ next = vma->vm_next;
+ } else {
+ /*
+ * For the scope of the comment "next" and
+ * "vma" considered pre-swap(): if "vma" was
+ * removed, next->vm_start was expanded (down)
+ * over it and the "next" gap must be updated.
+ * Because of the swap() the post-swap() "vma"
+ * actually points to pre-swap() "next"
+ * (post-swap() "next" as opposed is now a
+ * dangling pointer).
+ */
+ next = vma;
+ }
if (remove_next == 2) {
remove_next = 1;
end = next->vm_end;
@@ -815,8 +919,28 @@ again:
}
else if (next)
vma_gap_update(next);
- else
- mm->highest_vm_end = end;
+ else {
+ /*
+ * If remove_next == 2 we obviously can't
+ * reach this path.
+ *
+ * If remove_next == 3 we can't reach this
+ * path because pre-swap() next is always not
+ * NULL. pre-swap() "next" is not being
+ * removed and its next->vm_end is not altered
+ * (and furthermore "end" already matches
+ * next->vm_end in remove_next == 3).
+ *
+ * We reach this only in the remove_next == 1
+ * case if the "next" vma that was removed was
+ * the highest vma of the mm. However in such
+ * case next->vm_end == "end" and the extended
+ * "vma" has vma->vm_end == next->vm_end so
+ * mm->highest_vm_end doesn't need any update
+ * in remove_next == 1 case.
+ */
+ VM_WARN_ON(mm->highest_vm_end != end);
+ }
}
if (insert && file)
uprobe_mmap(insert);
@@ -936,13 +1060,24 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
* cannot merge might become might become might become
* PPNNNNNNNNNN PPPPPPPPPPNN PPPPPPPPPPPP 6 or
* mmap, brk or case 4 below case 5 below PPPPPPPPXXXX 7 or
- * mremap move: PPPPNNNNNNNN 8
+ * mremap move: PPPPXXXXXXXX 8
* AAAA
* PPPP NNNN PPPPPPPPPPPP PPPPPPPPNNNN PPPPNNNNNNNN
* might become case 1 below case 2 below case 3 below
*
- * Odd one out? Case 8, because it extends NNNN but needs flags of XXXX:
- * mprotect_fixup updates vm_flags & vm_page_prot on successful return.
+ * It is important for case 8 that the the vma NNNN overlapping the
+ * region AAAA is never going to extended over XXXX. Instead XXXX must
+ * be extended in region AAAA and NNNN must be removed. This way in
+ * all cases where vma_merge succeeds, the moment vma_adjust drops the
+ * rmap_locks, the properties of the merged vma will be already
+ * correct for the whole merged range. Some of those properties like
+ * vm_page_prot/vm_flags may be accessed by rmap_walks and they must
+ * be correct for the whole merged range immediately after the
+ * rmap_locks are released. Otherwise if XXXX would be removed and
+ * NNNN would be extended over the XXXX range, remove_migration_ptes
+ * or other rmap walkers (if working on addresses beyond the "end"
+ * parameter) may establish ptes with the wrong permissions of NNNN
+ * instead of the right permissions of XXXX.
*/
struct vm_area_struct *vma_merge(struct mm_struct *mm,
struct vm_area_struct *prev, unsigned long addr,
@@ -967,9 +1102,14 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
else
next = mm->mmap;
area = next;
- if (next && next->vm_end == end) /* cases 6, 7, 8 */
+ if (area && area->vm_end == end) /* cases 6, 7, 8 */
next = next->vm_next;
+ /* verify some invariant that must be enforced by the caller */
+ VM_WARN_ON(prev && addr <= prev->vm_start);
+ VM_WARN_ON(area && end > area->vm_end);
+ VM_WARN_ON(addr >= end);
+
/*
* Can it merge with the predecessor?
*/
@@ -990,11 +1130,12 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
is_mergeable_anon_vma(prev->anon_vma,
next->anon_vma, NULL)) {
/* cases 1, 6 */
- err = vma_adjust(prev, prev->vm_start,
- next->vm_end, prev->vm_pgoff, NULL);
+ err = __vma_adjust(prev, prev->vm_start,
+ next->vm_end, prev->vm_pgoff, NULL,
+ prev);
} else /* cases 2, 5, 7 */
- err = vma_adjust(prev, prev->vm_start,
- end, prev->vm_pgoff, NULL);
+ err = __vma_adjust(prev, prev->vm_start,
+ end, prev->vm_pgoff, NULL, prev);
if (err)
return NULL;
khugepaged_enter_vma_merge(prev, vm_flags);
@@ -1010,11 +1151,18 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
anon_vma, file, pgoff+pglen,
vm_userfaultfd_ctx)) {
if (prev && addr < prev->vm_end) /* case 4 */
- err = vma_adjust(prev, prev->vm_start,
- addr, prev->vm_pgoff, NULL);
- else /* cases 3, 8 */
- err = vma_adjust(area, addr, next->vm_end,
- next->vm_pgoff - pglen, NULL);
+ err = __vma_adjust(prev, prev->vm_start,
+ addr, prev->vm_pgoff, NULL, next);
+ else { /* cases 3, 8 */
+ err = __vma_adjust(area, addr, next->vm_end,
+ next->vm_pgoff - pglen, NULL, next);
+ /*
+ * In case 3 area is already equal to next and
+ * this is a noop, but in case 8 "area" has
+ * been removed and next was expanded over it.
+ */
+ area = next;
+ }
if (err)
return NULL;
khugepaged_enter_vma_merge(area, vm_flags);
@@ -1386,7 +1534,7 @@ SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg)
* to the private version (using protection_map[] without the
* VM_SHARED bit).
*/
-int vma_wants_writenotify(struct vm_area_struct *vma)
+int vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot)
{
vm_flags_t vm_flags = vma->vm_flags;
const struct vm_operations_struct *vm_ops = vma->vm_ops;
@@ -1401,8 +1549,8 @@ int vma_wants_writenotify(struct vm_area_struct *vma)
/* The open routine did something to the protections that pgprot_modify
* won't preserve? */
- if (pgprot_val(vma->vm_page_prot) !=
- pgprot_val(vm_pgprot_modify(vma->vm_page_prot, vm_flags)))
+ if (pgprot_val(vm_page_prot) !=
+ pgprot_val(vm_pgprot_modify(vm_page_prot, vm_flags)))
return 0;
/* Do we need to track softdirty? */
diff --git a/mm/mprotect.c b/mm/mprotect.c
index a4830f0325fe..bcdbe62f3e6d 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -23,11 +23,13 @@
#include <linux/mmu_notifier.h>
#include <linux/migrate.h>
#include <linux/perf_event.h>
+#include <linux/pkeys.h>
#include <linux/ksm.h>
#include <linux/pkeys.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include "internal.h"
@@ -304,6 +306,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
vma->vm_userfaultfd_ctx);
if (*pprev) {
vma = *pprev;
+ VM_WARN_ON((vma->vm_flags ^ newflags) & ~VM_SOFTDIRTY);
goto success;
}
@@ -327,7 +330,7 @@ success:
* held in write mode.
*/
vma->vm_flags = newflags;
- dirty_accountable = vma_wants_writenotify(vma);
+ dirty_accountable = vma_wants_writenotify(vma, vma->vm_page_prot);
vma_set_page_prot(vma);
change_protection(vma, start, end, vma->vm_page_prot,
@@ -352,8 +355,11 @@ fail:
return error;
}
-SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
- unsigned long, prot)
+/*
+ * pkey==-1 when doing a legacy mprotect()
+ */
+static int do_mprotect_pkey(unsigned long start, size_t len,
+ unsigned long prot, int pkey)
{
unsigned long nstart, end, tmp, reqprot;
struct vm_area_struct *vma, *prev;
@@ -382,6 +388,14 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
if (down_write_killable(&current->mm->mmap_sem))
return -EINTR;
+ /*
+ * If userspace did not allocate the pkey, do not let
+ * them use it here.
+ */
+ error = -EINVAL;
+ if ((pkey != -1) && !mm_pkey_is_allocated(current->mm, pkey))
+ goto out;
+
vma = find_vma(current->mm, start);
error = -ENOMEM;
if (!vma)
@@ -408,8 +422,9 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
prev = vma;
for (nstart = start ; ; ) {
+ unsigned long mask_off_old_flags;
unsigned long newflags;
- int pkey = arch_override_mprotect_pkey(vma, prot, -1);
+ int new_vma_pkey;
/* Here we know that vma->vm_start <= nstart < vma->vm_end. */
@@ -417,8 +432,17 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
if (rier && (vma->vm_flags & VM_MAYEXEC))
prot |= PROT_EXEC;
- newflags = calc_vm_prot_bits(prot, pkey);
- newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
+ /*
+ * Each mprotect() call explicitly passes r/w/x permissions.
+ * If a permission is not passed to mprotect(), it must be
+ * cleared from the VMA.
+ */
+ mask_off_old_flags = VM_READ | VM_WRITE | VM_EXEC |
+ ARCH_VM_PKEY_FLAGS;
+
+ new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey);
+ newflags = calc_vm_prot_bits(prot, new_vma_pkey);
+ newflags |= (vma->vm_flags & ~mask_off_old_flags);
/* newflags >> 4 shift VM_MAY% in place of VM_% */
if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
@@ -454,3 +478,60 @@ out:
up_write(&current->mm->mmap_sem);
return error;
}
+
+SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
+ unsigned long, prot)
+{
+ return do_mprotect_pkey(start, len, prot, -1);
+}
+
+SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len,
+ unsigned long, prot, int, pkey)
+{
+ return do_mprotect_pkey(start, len, prot, pkey);
+}
+
+SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val)
+{
+ int pkey;
+ int ret;
+
+ /* No flags supported yet. */
+ if (flags)
+ return -EINVAL;
+ /* check for unsupported init values */
+ if (init_val & ~PKEY_ACCESS_MASK)
+ return -EINVAL;
+
+ down_write(&current->mm->mmap_sem);
+ pkey = mm_pkey_alloc(current->mm);
+
+ ret = -ENOSPC;
+ if (pkey == -1)
+ goto out;
+
+ ret = arch_set_user_pkey_access(current, pkey, init_val);
+ if (ret) {
+ mm_pkey_free(current->mm, pkey);
+ goto out;
+ }
+ ret = pkey;
+out:
+ up_write(&current->mm->mmap_sem);
+ return ret;
+}
+
+SYSCALL_DEFINE1(pkey_free, int, pkey)
+{
+ int ret;
+
+ down_write(&current->mm->mmap_sem);
+ ret = mm_pkey_free(current->mm, pkey);
+ up_write(&current->mm->mmap_sem);
+
+ /*
+ * We could provie warnings or errors if any VMA still
+ * has the pkey set here.
+ */
+ return ret;
+}
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index bd05a70f44b9..ba609b684d7a 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -11,18 +11,21 @@
#include <linux/init.h>
#include <linux/pfn.h>
#include <linux/slab.h>
-#include <linux/bootmem.h>
#include <linux/export.h>
#include <linux/kmemleak.h>
#include <linux/range.h>
#include <linux/memblock.h>
+#include <linux/bootmem.h>
#include <asm/bug.h>
#include <asm/io.h>
-#include <asm/processor.h>
#include "internal.h"
+#ifndef CONFIG_HAVE_MEMBLOCK
+#error CONFIG_HAVE_MEMBLOCK not defined
+#endif
+
#ifndef CONFIG_NEED_MULTIPLE_NODES
struct pglist_data __refdata contig_page_data;
EXPORT_SYMBOL(contig_page_data);
@@ -134,6 +137,11 @@ static unsigned long __init free_low_memory_core_early(void)
for_each_reserved_mem_region(i, &start, &end)
reserve_bootmem_region(start, end);
+ /*
+ * We need to use NUMA_NO_NODE instead of NODE_DATA(0)->node_id
+ * because in some case like Node0 doesn't have RAM installed
+ * low ram will be on Node1
+ */
for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end,
NULL)
count += __free_memory_core(start, end);
@@ -191,11 +199,6 @@ unsigned long __init free_all_bootmem(void)
reset_all_zones_managed_pages();
- /*
- * We need to use NUMA_NO_NODE instead of NODE_DATA(0)->node_id
- * because in some case like Node0 doesn't have RAM installed
- * low ram will be on Node1
- */
pages = free_low_memory_core_early();
totalram_pages += pages;
@@ -395,9 +398,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
return __alloc_bootmem_node(pgdat, size, align, goal);
}
-#ifndef ARCH_LOW_ADDRESS_LIMIT
-#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
-#endif
/**
* __alloc_bootmem_low - allocate low boot memory
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index d53a9aa00977..ec9f11d4f094 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -132,6 +132,11 @@ static inline bool is_sysrq_oom(struct oom_control *oc)
return oc->order == -1;
}
+static inline bool is_memcg_oom(struct oom_control *oc)
+{
+ return oc->memcg != NULL;
+}
+
/* return true if the task is not adequate as candidate victim task. */
static bool oom_unkillable_task(struct task_struct *p,
struct mem_cgroup *memcg, const nodemask_t *nodemask)
@@ -181,7 +186,7 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
*/
adj = (long)p->signal->oom_score_adj;
if (adj == OOM_SCORE_ADJ_MIN ||
- test_bit(MMF_OOM_REAPED, &p->mm->flags) ||
+ test_bit(MMF_OOM_SKIP, &p->mm->flags) ||
in_vfork(p)) {
task_unlock(p);
return 0;
@@ -213,12 +218,17 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
return points > 0 ? points : 1;
}
+enum oom_constraint {
+ CONSTRAINT_NONE,
+ CONSTRAINT_CPUSET,
+ CONSTRAINT_MEMORY_POLICY,
+ CONSTRAINT_MEMCG,
+};
+
/*
* Determine the type of allocation constraint.
*/
-#ifdef CONFIG_NUMA
-static enum oom_constraint constrained_alloc(struct oom_control *oc,
- unsigned long *totalpages)
+static enum oom_constraint constrained_alloc(struct oom_control *oc)
{
struct zone *zone;
struct zoneref *z;
@@ -226,8 +236,16 @@ static enum oom_constraint constrained_alloc(struct oom_control *oc,
bool cpuset_limited = false;
int nid;
+ if (is_memcg_oom(oc)) {
+ oc->totalpages = mem_cgroup_get_limit(oc->memcg) ?: 1;
+ return CONSTRAINT_MEMCG;
+ }
+
/* Default to all available memory */
- *totalpages = totalram_pages + total_swap_pages;
+ oc->totalpages = totalram_pages + total_swap_pages;
+
+ if (!IS_ENABLED(CONFIG_NUMA))
+ return CONSTRAINT_NONE;
if (!oc->zonelist)
return CONSTRAINT_NONE;
@@ -246,9 +264,9 @@ static enum oom_constraint constrained_alloc(struct oom_control *oc,
*/
if (oc->nodemask &&
!nodes_subset(node_states[N_MEMORY], *oc->nodemask)) {
- *totalpages = total_swap_pages;
+ oc->totalpages = total_swap_pages;
for_each_node_mask(nid, *oc->nodemask)
- *totalpages += node_spanned_pages(nid);
+ oc->totalpages += node_spanned_pages(nid);
return CONSTRAINT_MEMORY_POLICY;
}
@@ -259,98 +277,84 @@ static enum oom_constraint constrained_alloc(struct oom_control *oc,
cpuset_limited = true;
if (cpuset_limited) {
- *totalpages = total_swap_pages;
+ oc->totalpages = total_swap_pages;
for_each_node_mask(nid, cpuset_current_mems_allowed)
- *totalpages += node_spanned_pages(nid);
+ oc->totalpages += node_spanned_pages(nid);
return CONSTRAINT_CPUSET;
}
return CONSTRAINT_NONE;
}
-#else
-static enum oom_constraint constrained_alloc(struct oom_control *oc,
- unsigned long *totalpages)
-{
- *totalpages = totalram_pages + total_swap_pages;
- return CONSTRAINT_NONE;
-}
-#endif
-enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
- struct task_struct *task)
+static int oom_evaluate_task(struct task_struct *task, void *arg)
{
+ struct oom_control *oc = arg;
+ unsigned long points;
+
if (oom_unkillable_task(task, NULL, oc->nodemask))
- return OOM_SCAN_CONTINUE;
+ goto next;
/*
* This task already has access to memory reserves and is being killed.
* Don't allow any other task to have access to the reserves unless
- * the task has MMF_OOM_REAPED because chances that it would release
+ * the task has MMF_OOM_SKIP because chances that it would release
* any memory is quite low.
*/
- if (!is_sysrq_oom(oc) && atomic_read(&task->signal->oom_victims)) {
- struct task_struct *p = find_lock_task_mm(task);
- enum oom_scan_t ret = OOM_SCAN_ABORT;
-
- if (p) {
- if (test_bit(MMF_OOM_REAPED, &p->mm->flags))
- ret = OOM_SCAN_CONTINUE;
- task_unlock(p);
- }
-
- return ret;
+ if (!is_sysrq_oom(oc) && tsk_is_oom_victim(task)) {
+ if (test_bit(MMF_OOM_SKIP, &task->signal->oom_mm->flags))
+ goto next;
+ goto abort;
}
/*
* If task is allocating a lot of memory and has been marked to be
* killed first if it triggers an oom, then select it.
*/
- if (oom_task_origin(task))
- return OOM_SCAN_SELECT;
+ if (oom_task_origin(task)) {
+ points = ULONG_MAX;
+ goto select;
+ }
- return OOM_SCAN_OK;
+ points = oom_badness(task, NULL, oc->nodemask, oc->totalpages);
+ if (!points || points < oc->chosen_points)
+ goto next;
+
+ /* Prefer thread group leaders for display purposes */
+ if (points == oc->chosen_points && thread_group_leader(oc->chosen))
+ goto next;
+select:
+ if (oc->chosen)
+ put_task_struct(oc->chosen);
+ get_task_struct(task);
+ oc->chosen = task;
+ oc->chosen_points = points;
+next:
+ return 0;
+abort:
+ if (oc->chosen)
+ put_task_struct(oc->chosen);
+ oc->chosen = (void *)-1UL;
+ return 1;
}
/*
- * Simple selection loop. We chose the process with the highest
- * number of 'points'. Returns -1 on scan abort.
+ * Simple selection loop. We choose the process with the highest number of
+ * 'points'. In case scan was aborted, oc->chosen is set to -1.
*/
-static struct task_struct *select_bad_process(struct oom_control *oc,
- unsigned int *ppoints, unsigned long totalpages)
+static void select_bad_process(struct oom_control *oc)
{
- struct task_struct *p;
- struct task_struct *chosen = NULL;
- unsigned long chosen_points = 0;
-
- rcu_read_lock();
- for_each_process(p) {
- unsigned int points;
-
- switch (oom_scan_process_thread(oc, p)) {
- case OOM_SCAN_SELECT:
- chosen = p;
- chosen_points = ULONG_MAX;
- /* fall through */
- case OOM_SCAN_CONTINUE:
- continue;
- case OOM_SCAN_ABORT:
- rcu_read_unlock();
- return (struct task_struct *)(-1UL);
- case OOM_SCAN_OK:
- break;
- };
- points = oom_badness(p, NULL, oc->nodemask, totalpages);
- if (!points || points < chosen_points)
- continue;
+ if (is_memcg_oom(oc))
+ mem_cgroup_scan_tasks(oc->memcg, oom_evaluate_task, oc);
+ else {
+ struct task_struct *p;
- chosen = p;
- chosen_points = points;
+ rcu_read_lock();
+ for_each_process(p)
+ if (oom_evaluate_task(p, oc))
+ break;
+ rcu_read_unlock();
}
- if (chosen)
- get_task_struct(chosen);
- rcu_read_unlock();
- *ppoints = chosen_points * 1000 / totalpages;
- return chosen;
+ oc->chosen_points = oc->chosen_points * 1000 / oc->totalpages;
}
/**
@@ -399,9 +403,14 @@ static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
static void dump_header(struct oom_control *oc, struct task_struct *p)
{
- pr_warn("%s invoked oom-killer: gfp_mask=%#x(%pGg), order=%d, oom_score_adj=%hd\n",
- current->comm, oc->gfp_mask, &oc->gfp_mask, oc->order,
+ nodemask_t *nm = (oc->nodemask) ? oc->nodemask : &cpuset_current_mems_allowed;
+
+ pr_warn("%s invoked oom-killer: gfp_mask=%#x(%pGg), nodemask=%*pbl, order=%d, oom_score_adj=%hd\n",
+ current->comm, oc->gfp_mask, &oc->gfp_mask,
+ nodemask_pr_args(nm), oc->order,
current->signal->oom_score_adj);
+ if (!IS_ENABLED(CONFIG_COMPACTION) && oc->order)
+ pr_warn("COMPACTION is disabled!!!\n");
cpuset_print_current_mems_allowed();
dump_stack();
@@ -419,7 +428,7 @@ static void dump_header(struct oom_control *oc, struct task_struct *p)
static atomic_t oom_victims = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(oom_victims_wait);
-bool oom_killer_disabled __read_mostly;
+static bool oom_killer_disabled __read_mostly;
#define K(x) ((x) << (PAGE_SHIFT-10))
@@ -452,12 +461,10 @@ static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait);
static struct task_struct *oom_reaper_list;
static DEFINE_SPINLOCK(oom_reaper_lock);
-static bool __oom_reap_task(struct task_struct *tsk)
+static bool __oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm)
{
struct mmu_gather tlb;
struct vm_area_struct *vma;
- struct mm_struct *mm = NULL;
- struct task_struct *p;
struct zap_details details = {.check_swap_entries = true,
.ignore_dirty = true};
bool ret = true;
@@ -465,7 +472,7 @@ static bool __oom_reap_task(struct task_struct *tsk)
/*
* We have to make sure to not race with the victim exit path
* and cause premature new oom victim selection:
- * __oom_reap_task exit_mm
+ * __oom_reap_task_mm exit_mm
* mmget_not_zero
* mmput
* atomic_dec_and_test
@@ -478,22 +485,9 @@ static bool __oom_reap_task(struct task_struct *tsk)
*/
mutex_lock(&oom_lock);
- /*
- * Make sure we find the associated mm_struct even when the particular
- * thread has already terminated and cleared its mm.
- * We might have race with exit path so consider our work done if there
- * is no mm.
- */
- p = find_lock_task_mm(tsk);
- if (!p)
- goto unlock_oom;
- mm = p->mm;
- atomic_inc(&mm->mm_count);
- task_unlock(p);
-
if (!down_read_trylock(&mm->mmap_sem)) {
ret = false;
- goto mm_drop;
+ goto unlock_oom;
}
/*
@@ -503,9 +497,17 @@ static bool __oom_reap_task(struct task_struct *tsk)
*/
if (!mmget_not_zero(mm)) {
up_read(&mm->mmap_sem);
- goto mm_drop;
+ goto unlock_oom;
}
+ /*
+ * Tell all users of get_user/copy_from_user etc... that the content
+ * is no longer stable. No barriers really needed because unmapping
+ * should imply barriers already and the reader would hit a page fault
+ * if it stumbled over a reaped memory.
+ */
+ set_bit(MMF_UNSTABLE, &mm->flags);
+
tlb_gather_mmu(&tlb, mm, 0, -1);
for (vma = mm->mmap ; vma; vma = vma->vm_next) {
if (is_vm_hugetlb_page(vma))
@@ -541,18 +543,11 @@ static bool __oom_reap_task(struct task_struct *tsk)
up_read(&mm->mmap_sem);
/*
- * This task can be safely ignored because we cannot do much more
- * to release its memory.
- */
- set_bit(MMF_OOM_REAPED, &mm->flags);
- /*
* Drop our reference but make sure the mmput slow path is called from a
* different context because we shouldn't risk we get stuck there and
* put the oom_reaper out of the way.
*/
mmput_async(mm);
-mm_drop:
- mmdrop(mm);
unlock_oom:
mutex_unlock(&oom_lock);
return ret;
@@ -562,44 +557,28 @@ unlock_oom:
static void oom_reap_task(struct task_struct *tsk)
{
int attempts = 0;
+ struct mm_struct *mm = tsk->signal->oom_mm;
/* Retry the down_read_trylock(mmap_sem) a few times */
- while (attempts++ < MAX_OOM_REAP_RETRIES && !__oom_reap_task(tsk))
+ while (attempts++ < MAX_OOM_REAP_RETRIES && !__oom_reap_task_mm(tsk, mm))
schedule_timeout_idle(HZ/10);
- if (attempts > MAX_OOM_REAP_RETRIES) {
- struct task_struct *p;
+ if (attempts <= MAX_OOM_REAP_RETRIES)
+ goto done;
- pr_info("oom_reaper: unable to reap pid:%d (%s)\n",
- task_pid_nr(tsk), tsk->comm);
- /*
- * If we've already tried to reap this task in the past and
- * failed it probably doesn't make much sense to try yet again
- * so hide the mm from the oom killer so that it can move on
- * to another task with a different mm struct.
- */
- p = find_lock_task_mm(tsk);
- if (p) {
- if (test_and_set_bit(MMF_OOM_NOT_REAPABLE, &p->mm->flags)) {
- pr_info("oom_reaper: giving up pid:%d (%s)\n",
- task_pid_nr(tsk), tsk->comm);
- set_bit(MMF_OOM_REAPED, &p->mm->flags);
- }
- task_unlock(p);
- }
+ pr_info("oom_reaper: unable to reap pid:%d (%s)\n",
+ task_pid_nr(tsk), tsk->comm);
+ debug_show_all_locks();
- debug_show_all_locks();
- }
+done:
+ tsk->oom_reaper_list = NULL;
/*
- * Clear TIF_MEMDIE because the task shouldn't be sitting on a
- * reasonably reclaimable memory anymore or it is not a good candidate
- * for the oom victim right now because it cannot release its memory
- * itself nor by the oom reaper.
+ * Hide this mm from OOM killer because it has been either reaped or
+ * somebody can't call up_write(mmap_sem).
*/
- tsk->oom_reaper_list = NULL;
- exit_oom_victim(tsk);
+ set_bit(MMF_OOM_SKIP, &mm->flags);
/* Drop a reference taken by wake_oom_reaper */
put_task_struct(tsk);
@@ -607,8 +586,6 @@ static void oom_reap_task(struct task_struct *tsk)
static int oom_reaper(void *unused)
{
- set_freezable();
-
while (true) {
struct task_struct *tsk = NULL;
@@ -627,7 +604,7 @@ static int oom_reaper(void *unused)
return 0;
}
-void wake_oom_reaper(struct task_struct *tsk)
+static void wake_oom_reaper(struct task_struct *tsk)
{
if (!oom_reaper_th)
return;
@@ -656,7 +633,11 @@ static int __init oom_init(void)
return 0;
}
subsys_initcall(oom_init)
-#endif
+#else
+static inline void wake_oom_reaper(struct task_struct *tsk)
+{
+}
+#endif /* CONFIG_MMU */
/**
* mark_oom_victim - mark the given task as OOM victim
@@ -664,14 +645,23 @@ subsys_initcall(oom_init)
*
* Has to be called with oom_lock held and never after
* oom has been disabled already.
+ *
+ * tsk->mm has to be non NULL and caller has to guarantee it is stable (either
+ * under task_lock or operate on the current).
*/
-void mark_oom_victim(struct task_struct *tsk)
+static void mark_oom_victim(struct task_struct *tsk)
{
+ struct mm_struct *mm = tsk->mm;
+
WARN_ON(oom_killer_disabled);
/* OOM killer might race with memcg OOM */
if (test_and_set_tsk_thread_flag(tsk, TIF_MEMDIE))
return;
- atomic_inc(&tsk->signal->oom_victims);
+
+ /* oom_mm is bound to the signal struct life time. */
+ if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm))
+ atomic_inc(&tsk->signal->oom_mm->mm_count);
+
/*
* Make sure that the task is woken up from uninterruptible sleep
* if it is frozen because OOM killer wouldn't be able to free
@@ -685,21 +675,29 @@ void mark_oom_victim(struct task_struct *tsk)
/**
* exit_oom_victim - note the exit of an OOM victim
*/
-void exit_oom_victim(struct task_struct *tsk)
+void exit_oom_victim(void)
{
- if (!test_and_clear_tsk_thread_flag(tsk, TIF_MEMDIE))
- return;
- atomic_dec(&tsk->signal->oom_victims);
+ clear_thread_flag(TIF_MEMDIE);
if (!atomic_dec_return(&oom_victims))
wake_up_all(&oom_victims_wait);
}
/**
+ * oom_killer_enable - enable OOM killer
+ */
+void oom_killer_enable(void)
+{
+ oom_killer_disabled = false;
+}
+
+/**
* oom_killer_disable - disable OOM killer
+ * @timeout: maximum timeout to wait for oom victims in jiffies
*
* Forces all page allocations to fail rather than trigger OOM killer.
- * Will block and wait until all OOM victims are killed.
+ * Will block and wait until all OOM victims are killed or the given
+ * timeout expires.
*
* The function cannot be called when there are runnable user tasks because
* the userspace would see unexpected allocation failures as a result. Any
@@ -708,8 +706,10 @@ void exit_oom_victim(struct task_struct *tsk)
* Returns true if successful and false if the OOM killer cannot be
* disabled.
*/
-bool oom_killer_disable(void)
+bool oom_killer_disable(signed long timeout)
{
+ signed long ret;
+
/*
* Make sure to not race with an ongoing OOM killer. Check that the
* current is not killed (possibly due to sharing the victim's memory).
@@ -719,19 +719,16 @@ bool oom_killer_disable(void)
oom_killer_disabled = true;
mutex_unlock(&oom_lock);
- wait_event(oom_victims_wait, !atomic_read(&oom_victims));
+ ret = wait_event_interruptible_timeout(oom_victims_wait,
+ !atomic_read(&oom_victims), timeout);
+ if (ret <= 0) {
+ oom_killer_enable();
+ return false;
+ }
return true;
}
-/**
- * oom_killer_enable - enable OOM killer
- */
-void oom_killer_enable(void)
-{
- oom_killer_disabled = false;
-}
-
static inline bool __task_will_free_mem(struct task_struct *task)
{
struct signal_struct *sig = task->signal;
@@ -760,7 +757,7 @@ static inline bool __task_will_free_mem(struct task_struct *task)
* Caller has to make sure that task->mm is stable (hold task_lock or
* it operates on the current).
*/
-bool task_will_free_mem(struct task_struct *task)
+static bool task_will_free_mem(struct task_struct *task)
{
struct mm_struct *mm = task->mm;
struct task_struct *p;
@@ -781,15 +778,16 @@ bool task_will_free_mem(struct task_struct *task)
* This task has already been drained by the oom reaper so there are
* only small chances it will free some more
*/
- if (test_bit(MMF_OOM_REAPED, &mm->flags))
+ if (test_bit(MMF_OOM_SKIP, &mm->flags))
return false;
if (atomic_read(&mm->mm_users) <= 1)
return true;
/*
- * This is really pessimistic but we do not have any reliable way
- * to check that external processes share with our mm
+ * Make sure that all tasks which share the mm with the given tasks
+ * are dying as well to make sure that a) nobody pins its mm and
+ * b) the task is also reapable by the oom reaper.
*/
rcu_read_lock();
for_each_process(p) {
@@ -806,14 +804,10 @@ bool task_will_free_mem(struct task_struct *task)
return ret;
}
-/*
- * Must be called while holding a reference to p, which will be released upon
- * returning.
- */
-void oom_kill_process(struct oom_control *oc, struct task_struct *p,
- unsigned int points, unsigned long totalpages,
- const char *message)
+static void oom_kill_process(struct oom_control *oc, const char *message)
{
+ struct task_struct *p = oc->chosen;
+ unsigned int points = oc->chosen_points;
struct task_struct *victim = p;
struct task_struct *child;
struct task_struct *t;
@@ -860,7 +854,7 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
* oom_badness() returns 0 if the thread is unkillable
*/
child_points = oom_badness(child,
- oc->memcg, oc->nodemask, totalpages);
+ oc->memcg, oc->nodemask, oc->totalpages);
if (child_points > victim_points) {
put_task_struct(victim);
victim = child;
@@ -913,20 +907,20 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
continue;
if (same_thread_group(p, victim))
continue;
- if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p)) {
- /*
- * We cannot use oom_reaper for the mm shared by this
- * process because it wouldn't get killed and so the
- * memory might be still used. Hide the mm from the oom
- * killer to guarantee OOM forward progress.
- */
+ if (is_global_init(p)) {
can_oom_reap = false;
- set_bit(MMF_OOM_REAPED, &mm->flags);
+ set_bit(MMF_OOM_SKIP, &mm->flags);
pr_info("oom killer %d (%s) has mm pinned by %d (%s)\n",
task_pid_nr(victim), victim->comm,
task_pid_nr(p), p->comm);
continue;
}
+ /*
+ * No use_mm() user needs to read from the userspace so we are
+ * ok to reap it.
+ */
+ if (unlikely(p->flags & PF_KTHREAD))
+ continue;
do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
}
rcu_read_unlock();
@@ -942,7 +936,8 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
/*
* Determines whether the kernel must panic because of the panic_on_oom sysctl.
*/
-void check_panic_on_oom(struct oom_control *oc, enum oom_constraint constraint)
+static void check_panic_on_oom(struct oom_control *oc,
+ enum oom_constraint constraint)
{
if (likely(!sysctl_panic_on_oom))
return;
@@ -988,19 +983,18 @@ EXPORT_SYMBOL_GPL(unregister_oom_notifier);
*/
bool out_of_memory(struct oom_control *oc)
{
- struct task_struct *p;
- unsigned long totalpages;
unsigned long freed = 0;
- unsigned int uninitialized_var(points);
enum oom_constraint constraint = CONSTRAINT_NONE;
if (oom_killer_disabled)
return false;
- blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
- if (freed > 0)
- /* Got some memory back in the last second. */
- return true;
+ if (!is_memcg_oom(oc)) {
+ blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
+ if (freed > 0)
+ /* Got some memory back in the last second. */
+ return true;
+ }
/*
* If current has a pending SIGKILL or is exiting, then automatically
@@ -1024,37 +1018,38 @@ bool out_of_memory(struct oom_control *oc)
/*
* Check if there were limitations on the allocation (only relevant for
- * NUMA) that may require different handling.
+ * NUMA and memcg) that may require different handling.
*/
- constraint = constrained_alloc(oc, &totalpages);
+ constraint = constrained_alloc(oc);
if (constraint != CONSTRAINT_MEMORY_POLICY)
oc->nodemask = NULL;
check_panic_on_oom(oc, constraint);
- if (sysctl_oom_kill_allocating_task && current->mm &&
- !oom_unkillable_task(current, NULL, oc->nodemask) &&
+ if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task &&
+ current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) &&
current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) {
get_task_struct(current);
- oom_kill_process(oc, current, 0, totalpages,
- "Out of memory (oom_kill_allocating_task)");
+ oc->chosen = current;
+ oom_kill_process(oc, "Out of memory (oom_kill_allocating_task)");
return true;
}
- p = select_bad_process(oc, &points, totalpages);
+ select_bad_process(oc);
/* Found nothing?!?! Either we hang forever, or we panic. */
- if (!p && !is_sysrq_oom(oc)) {
+ if (!oc->chosen && !is_sysrq_oom(oc) && !is_memcg_oom(oc)) {
dump_header(oc, NULL);
panic("Out of memory and no killable processes...\n");
}
- if (p && p != (void *)-1UL) {
- oom_kill_process(oc, p, points, totalpages, "Out of memory");
+ if (oc->chosen && oc->chosen != (void *)-1UL) {
+ oom_kill_process(oc, !is_memcg_oom(oc) ? "Out of memory" :
+ "Memory cgroup out of memory");
/*
* Give the killed process a good chance to exit before trying
* to allocate memory again.
*/
schedule_timeout_killable(1);
}
- return true;
+ return !!oc->chosen;
}
/*
@@ -1077,16 +1072,6 @@ void pagefault_out_of_memory(void)
if (!mutex_trylock(&oom_lock))
return;
-
- if (!out_of_memory(&oc)) {
- /*
- * There shouldn't be any user tasks runnable while the
- * OOM killer is disabled, so the current task has to
- * be a racing OOM victim for which oom_killer_disable()
- * is waiting for.
- */
- WARN_ON(test_thread_flag(TIF_MEMDIE));
- }
-
+ out_of_memory(&oc);
mutex_unlock(&oom_lock);
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 28d6f36a2d79..439cc63ad903 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -1965,36 +1965,6 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb)
return false;
}
-void throttle_vm_writeout(gfp_t gfp_mask)
-{
- unsigned long background_thresh;
- unsigned long dirty_thresh;
-
- for ( ; ; ) {
- global_dirty_limits(&background_thresh, &dirty_thresh);
- dirty_thresh = hard_dirty_limit(&global_wb_domain, dirty_thresh);
-
- /*
- * Boost the allowable dirty threshold a bit for page
- * allocators so they don't get DoS'ed by heavy writers
- */
- dirty_thresh += dirty_thresh / 10; /* wheeee... */
-
- if (global_node_page_state(NR_UNSTABLE_NFS) +
- global_node_page_state(NR_WRITEBACK) <= dirty_thresh)
- break;
- congestion_wait(BLK_RW_ASYNC, HZ/10);
-
- /*
- * The caller might hold locks which can prevent IO completion
- * or progress in the filesystem. So we cannot just sit here
- * waiting for IO to complete.
- */
- if ((gfp_mask & (__GFP_FS|__GFP_IO)) != (__GFP_FS|__GFP_IO))
- break;
- }
-}
-
/*
* sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
*/
@@ -2746,7 +2716,7 @@ int test_clear_page_writeback(struct page *page)
int ret;
lock_page_memcg(page);
- if (mapping) {
+ if (mapping && mapping_use_writeback_tags(mapping)) {
struct inode *inode = mapping->host;
struct backing_dev_info *bdi = inode_to_bdi(inode);
unsigned long flags;
@@ -2789,7 +2759,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
int ret;
lock_page_memcg(page);
- if (mapping) {
+ if (mapping && mapping_use_writeback_tags(mapping)) {
struct inode *inode = mapping->host;
struct backing_dev_info *bdi = inode_to_bdi(inode);
unsigned long flags;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a2214c64ed3c..ca423cc20b59 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -607,6 +607,9 @@ static bool need_debug_guardpage(void)
if (!debug_pagealloc_enabled())
return false;
+ if (!debug_guardpage_minorder())
+ return false;
+
return true;
}
@@ -615,6 +618,9 @@ static void init_debug_guardpage(void)
if (!debug_pagealloc_enabled())
return;
+ if (!debug_guardpage_minorder())
+ return;
+
_debug_guardpage_enabled = true;
}
@@ -635,19 +641,22 @@ static int __init debug_guardpage_minorder_setup(char *buf)
pr_info("Setting debug_guardpage_minorder to %lu\n", res);
return 0;
}
-__setup("debug_guardpage_minorder=", debug_guardpage_minorder_setup);
+early_param("debug_guardpage_minorder", debug_guardpage_minorder_setup);
-static inline void set_page_guard(struct zone *zone, struct page *page,
+static inline bool set_page_guard(struct zone *zone, struct page *page,
unsigned int order, int migratetype)
{
struct page_ext *page_ext;
if (!debug_guardpage_enabled())
- return;
+ return false;
+
+ if (order >= debug_guardpage_minorder())
+ return false;
page_ext = lookup_page_ext(page);
if (unlikely(!page_ext))
- return;
+ return false;
__set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags);
@@ -655,6 +664,8 @@ static inline void set_page_guard(struct zone *zone, struct page *page,
set_page_private(page, order);
/* Guard pages are not available for any usage */
__mod_zone_freepage_state(zone, -(1 << order), migratetype);
+
+ return true;
}
static inline void clear_page_guard(struct zone *zone, struct page *page,
@@ -676,9 +687,9 @@ static inline void clear_page_guard(struct zone *zone, struct page *page,
__mod_zone_freepage_state(zone, (1 << order), migratetype);
}
#else
-struct page_ext_operations debug_guardpage_ops = { NULL, };
-static inline void set_page_guard(struct zone *zone, struct page *page,
- unsigned int order, int migratetype) {}
+struct page_ext_operations debug_guardpage_ops;
+static inline bool set_page_guard(struct zone *zone, struct page *page,
+ unsigned int order, int migratetype) { return false; }
static inline void clear_page_guard(struct zone *zone, struct page *page,
unsigned int order, int migratetype) {}
#endif
@@ -1393,15 +1404,18 @@ static void __init deferred_free_range(struct page *page,
return;
/* Free a large naturally-aligned chunk if possible */
- if (nr_pages == MAX_ORDER_NR_PAGES &&
- (pfn & (MAX_ORDER_NR_PAGES-1)) == 0) {
+ if (nr_pages == pageblock_nr_pages &&
+ (pfn & (pageblock_nr_pages - 1)) == 0) {
set_pageblock_migratetype(page, MIGRATE_MOVABLE);
- __free_pages_boot_core(page, MAX_ORDER-1);
+ __free_pages_boot_core(page, pageblock_order);
return;
}
- for (i = 0; i < nr_pages; i++, page++)
+ for (i = 0; i < nr_pages; i++, page++, pfn++) {
+ if ((pfn & (pageblock_nr_pages - 1)) == 0)
+ set_pageblock_migratetype(page, MIGRATE_MOVABLE);
__free_pages_boot_core(page, 0);
+ }
}
/* Completion tracking for deferred_init_memmap() threads */
@@ -1469,9 +1483,9 @@ static int __init deferred_init_memmap(void *data)
/*
* Ensure pfn_valid is checked every
- * MAX_ORDER_NR_PAGES for memory holes
+ * pageblock_nr_pages for memory holes
*/
- if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) {
+ if ((pfn & (pageblock_nr_pages - 1)) == 0) {
if (!pfn_valid(pfn)) {
page = NULL;
goto free_range;
@@ -1484,7 +1498,7 @@ static int __init deferred_init_memmap(void *data)
}
/* Minimise pfn page lookups and scheduler checks */
- if (page && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0) {
+ if (page && (pfn & (pageblock_nr_pages - 1)) != 0) {
page++;
} else {
nr_pages += nr_to_free;
@@ -1520,6 +1534,9 @@ free_range:
free_base_page = NULL;
free_base_pfn = nr_to_free = 0;
}
+ /* Free the last block of pages to allocator */
+ nr_pages += nr_to_free;
+ deferred_free_range(free_base_page, free_base_pfn, nr_to_free);
first_init_pfn = max(end_pfn, first_init_pfn);
}
@@ -1616,18 +1633,15 @@ static inline void expand(struct zone *zone, struct page *page,
size >>= 1;
VM_BUG_ON_PAGE(bad_range(zone, &page[size]), &page[size]);
- if (IS_ENABLED(CONFIG_DEBUG_PAGEALLOC) &&
- debug_guardpage_enabled() &&
- high < debug_guardpage_minorder()) {
- /*
- * Mark as guard pages (or page), that will allow to
- * merge back to allocator when buddy will be freed.
- * Corresponding page table entries will not be touched,
- * pages will stay not present in virtual address space
- */
- set_page_guard(zone, &page[size], high, migratetype);
+ /*
+ * Mark as guard pages (or page), that will allow to
+ * merge back to allocator when buddy will be freed.
+ * Corresponding page table entries will not be touched,
+ * pages will stay not present in virtual address space
+ */
+ if (set_page_guard(zone, &page[size], high, migratetype))
continue;
- }
+
list_add(&page[size].lru, &area->free_list[migratetype]);
area->nr_free++;
set_page_order(&page[size], high);
@@ -2489,9 +2503,14 @@ int __isolate_free_page(struct page *page, unsigned int order)
mt = get_pageblock_migratetype(page);
if (!is_migrate_isolate(mt)) {
- /* Obey watermarks as if the page was being allocated */
- watermark = low_wmark_pages(zone) + (1 << order);
- if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+ /*
+ * Obey watermarks as if the page was being allocated. We can
+ * emulate a high-order watermark check with a raised order-0
+ * watermark, because we already know our high-order page
+ * exists.
+ */
+ watermark = min_wmark_pages(zone) + (1UL << order);
+ if (!zone_watermark_ok(zone, 0, watermark, 0, ALLOC_CMA))
return 0;
__mod_zone_freepage_state(zone, -(1UL << order), mt);
@@ -2960,9 +2979,11 @@ static DEFINE_RATELIMIT_STATE(nopage_rs,
DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
-void warn_alloc_failed(gfp_t gfp_mask, unsigned int order, const char *fmt, ...)
+void warn_alloc(gfp_t gfp_mask, const char *fmt, ...)
{
unsigned int filter = SHOW_MEM_FILTER_NODES;
+ struct va_format vaf;
+ va_list args;
if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
debug_guardpage_minorder() > 0)
@@ -2980,22 +3001,16 @@ void warn_alloc_failed(gfp_t gfp_mask, unsigned int order, const char *fmt, ...)
if (in_interrupt() || !(gfp_mask & __GFP_DIRECT_RECLAIM))
filter &= ~SHOW_MEM_FILTER_NODES;
- if (fmt) {
- struct va_format vaf;
- va_list args;
+ pr_warn("%s: ", current->comm);
- va_start(args, fmt);
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ pr_cont("%pV", &vaf);
+ va_end(args);
- vaf.fmt = fmt;
- vaf.va = &args;
+ pr_cont(", mode:%#x(%pGg)\n", gfp_mask, &gfp_mask);
- pr_warn("%pV", &vaf);
-
- va_end(args);
- }
-
- pr_warn("%s: page allocation failure: order:%u, mode:%#x(%pGg)\n",
- current->comm, order, gfp_mask, &gfp_mask);
dump_stack();
if (!should_suppress_show_mem())
show_mem(filter);
@@ -3137,6 +3152,65 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
return NULL;
}
+static inline bool
+should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
+ enum compact_result compact_result,
+ enum compact_priority *compact_priority,
+ int *compaction_retries)
+{
+ int max_retries = MAX_COMPACT_RETRIES;
+ int min_priority;
+
+ if (!order)
+ return false;
+
+ if (compaction_made_progress(compact_result))
+ (*compaction_retries)++;
+
+ /*
+ * compaction considers all the zone as desperately out of memory
+ * so it doesn't really make much sense to retry except when the
+ * failure could be caused by insufficient priority
+ */
+ if (compaction_failed(compact_result))
+ goto check_priority;
+
+ /*
+ * make sure the compaction wasn't deferred or didn't bail out early
+ * due to locks contention before we declare that we should give up.
+ * But do not retry if the given zonelist is not suitable for
+ * compaction.
+ */
+ if (compaction_withdrawn(compact_result))
+ return compaction_zonelist_suitable(ac, order, alloc_flags);
+
+ /*
+ * !costly requests are much more important than __GFP_REPEAT
+ * costly ones because they are de facto nofail and invoke OOM
+ * killer to move on while costly can fail and users are ready
+ * to cope with that. 1/4 retries is rather arbitrary but we
+ * would need much more detailed feedback from compaction to
+ * make a better decision.
+ */
+ if (order > PAGE_ALLOC_COSTLY_ORDER)
+ max_retries /= 4;
+ if (*compaction_retries <= max_retries)
+ return true;
+
+ /*
+ * Make sure there are attempts at the highest priority if we exhausted
+ * all retries or failed at the lower priorities.
+ */
+check_priority:
+ min_priority = (order > PAGE_ALLOC_COSTLY_ORDER) ?
+ MIN_COMPACT_COSTLY_PRIORITY : MIN_COMPACT_PRIORITY;
+ if (*compact_priority > min_priority) {
+ (*compact_priority)--;
+ *compaction_retries = 0;
+ return true;
+ }
+ return false;
+}
#else
static inline struct page *
__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
@@ -3147,13 +3221,11 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
return NULL;
}
-#endif /* CONFIG_COMPACTION */
-
static inline bool
should_compact_retry(struct alloc_context *ac, unsigned int order, int alloc_flags,
enum compact_result compact_result,
enum compact_priority *compact_priority,
- int compaction_retries)
+ int *compaction_retries)
{
struct zone *zone;
struct zoneref *z;
@@ -3175,6 +3247,7 @@ should_compact_retry(struct alloc_context *ac, unsigned int order, int alloc_fla
}
return false;
}
+#endif /* CONFIG_COMPACTION */
/* Perform direct synchronous page reclaim */
static int
@@ -3325,16 +3398,26 @@ bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
static inline bool
should_reclaim_retry(gfp_t gfp_mask, unsigned order,
struct alloc_context *ac, int alloc_flags,
- bool did_some_progress, int no_progress_loops)
+ bool did_some_progress, int *no_progress_loops)
{
struct zone *zone;
struct zoneref *z;
/*
+ * Costly allocations might have made a progress but this doesn't mean
+ * their order will become available due to high fragmentation so
+ * always increment the no progress counter for them
+ */
+ if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+ *no_progress_loops = 0;
+ else
+ (*no_progress_loops)++;
+
+ /*
* Make sure we converge to OOM if we cannot make any progress
* several times in the row.
*/
- if (no_progress_loops > MAX_RECLAIM_RETRIES)
+ if (*no_progress_loops > MAX_RECLAIM_RETRIES)
return false;
/*
@@ -3349,7 +3432,7 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
unsigned long reclaimable;
available = reclaimable = zone_reclaimable_pages(zone);
- available -= DIV_ROUND_UP(no_progress_loops * available,
+ available -= DIV_ROUND_UP((*no_progress_loops) * available,
MAX_RECLAIM_RETRIES);
available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
@@ -3410,6 +3493,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
enum compact_result compact_result;
int compaction_retries = 0;
int no_progress_loops = 0;
+ unsigned long alloc_start = jiffies;
+ unsigned int stall_timeout = 10 * HZ;
/*
* In the slowpath, we sanity check order to avoid ever trying to
@@ -3554,9 +3639,6 @@ retry:
if (page)
goto got_pg;
- if (order && compaction_made_progress(compact_result))
- compaction_retries++;
-
/* Do not loop if specifically requested */
if (gfp_mask & __GFP_NORETRY)
goto nopage;
@@ -3568,18 +3650,16 @@ retry:
if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_REPEAT))
goto nopage;
- /*
- * Costly allocations might have made a progress but this doesn't mean
- * their order will become available due to high fragmentation so
- * always increment the no progress counter for them
- */
- if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
- no_progress_loops = 0;
- else
- no_progress_loops++;
+ /* Make sure we know about allocations which stall for too long */
+ if (time_after(jiffies, alloc_start + stall_timeout)) {
+ warn_alloc(gfp_mask,
+ "page alloction stalls for %ums, order:%u\n",
+ jiffies_to_msecs(jiffies-alloc_start), order);
+ stall_timeout += 10 * HZ;
+ }
if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags,
- did_some_progress > 0, no_progress_loops))
+ did_some_progress > 0, &no_progress_loops))
goto retry;
/*
@@ -3591,7 +3671,7 @@ retry:
if (did_some_progress > 0 &&
should_compact_retry(ac, order, alloc_flags,
compact_result, &compact_priority,
- compaction_retries))
+ &compaction_retries))
goto retry;
/* Reclaim has failed us, start killing things */
@@ -3606,7 +3686,8 @@ retry:
}
nopage:
- warn_alloc_failed(gfp_mask, order, NULL);
+ warn_alloc(gfp_mask,
+ "page allocation failure: order:%u", order);
got_pg:
return page;
}
@@ -4555,7 +4636,7 @@ static void build_zonelists_in_node_order(pg_data_t *pgdat, int node)
int j;
struct zonelist *zonelist;
- zonelist = &pgdat->node_zonelists[0];
+ zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK];
for (j = 0; zonelist->_zonerefs[j].zone != NULL; j++)
;
j = build_zonelists_node(NODE_DATA(node), zonelist, j);
@@ -4571,7 +4652,7 @@ static void build_thisnode_zonelists(pg_data_t *pgdat)
int j;
struct zonelist *zonelist;
- zonelist = &pgdat->node_zonelists[1];
+ zonelist = &pgdat->node_zonelists[ZONELIST_NOFALLBACK];
j = build_zonelists_node(pgdat, zonelist, 0);
zonelist->_zonerefs[j].zone = NULL;
zonelist->_zonerefs[j].zone_idx = 0;
@@ -4592,7 +4673,7 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes)
struct zone *z;
struct zonelist *zonelist;
- zonelist = &pgdat->node_zonelists[0];
+ zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK];
pos = 0;
for (zone_type = MAX_NR_ZONES - 1; zone_type >= 0; zone_type--) {
for (j = 0; j < nr_nodes; j++) {
@@ -4727,7 +4808,7 @@ static void build_zonelists(pg_data_t *pgdat)
local_node = pgdat->node_id;
- zonelist = &pgdat->node_zonelists[0];
+ zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK];
j = build_zonelists_node(pgdat, zonelist, 0);
/*
@@ -5000,15 +5081,6 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
/*
- * If not mirrored_kernelcore and ZONE_MOVABLE exists, range
- * from zone_movable_pfn[nid] to end of each node should be
- * ZONE_MOVABLE not ZONE_NORMAL. skip it.
- */
- if (!mirrored_kernelcore && zone_movable_pfn[nid])
- if (zone == ZONE_NORMAL && pfn >= zone_movable_pfn[nid])
- continue;
-
- /*
* Check given memblock attribute by firmware which can affect
* kernel memory layout. If zone==ZONE_MOVABLE but memory is
* mirrored, it's an overlapped memmap init. skip it.
@@ -5451,6 +5523,12 @@ static void __meminit adjust_zone_range_for_zone_movable(int nid,
*zone_end_pfn = min(node_end_pfn,
arch_zone_highest_possible_pfn[movable_zone]);
+ /* Adjust for ZONE_MOVABLE starting within this range */
+ } else if (!mirrored_kernelcore &&
+ *zone_start_pfn < zone_movable_pfn[nid] &&
+ *zone_end_pfn > zone_movable_pfn[nid]) {
+ *zone_end_pfn = zone_movable_pfn[nid];
+
/* Check if this whole range is within ZONE_MOVABLE */
} else if (*zone_start_pfn >= zone_movable_pfn[nid])
*zone_start_pfn = *zone_end_pfn;
@@ -5554,28 +5632,23 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
* Treat pages to be ZONE_MOVABLE in ZONE_NORMAL as absent pages
* and vice versa.
*/
- if (zone_movable_pfn[nid]) {
- if (mirrored_kernelcore) {
- unsigned long start_pfn, end_pfn;
- struct memblock_region *r;
-
- for_each_memblock(memory, r) {
- start_pfn = clamp(memblock_region_memory_base_pfn(r),
- zone_start_pfn, zone_end_pfn);
- end_pfn = clamp(memblock_region_memory_end_pfn(r),
- zone_start_pfn, zone_end_pfn);
-
- if (zone_type == ZONE_MOVABLE &&
- memblock_is_mirror(r))
- nr_absent += end_pfn - start_pfn;
-
- if (zone_type == ZONE_NORMAL &&
- !memblock_is_mirror(r))
- nr_absent += end_pfn - start_pfn;
- }
- } else {
- if (zone_type == ZONE_NORMAL)
- nr_absent += node_end_pfn - zone_movable_pfn[nid];
+ if (mirrored_kernelcore && zone_movable_pfn[nid]) {
+ unsigned long start_pfn, end_pfn;
+ struct memblock_region *r;
+
+ for_each_memblock(memory, r) {
+ start_pfn = clamp(memblock_region_memory_base_pfn(r),
+ zone_start_pfn, zone_end_pfn);
+ end_pfn = clamp(memblock_region_memory_end_pfn(r),
+ zone_start_pfn, zone_end_pfn);
+
+ if (zone_type == ZONE_MOVABLE &&
+ memblock_is_mirror(r))
+ nr_absent += end_pfn - start_pfn;
+
+ if (zone_type == ZONE_NORMAL &&
+ !memblock_is_mirror(r))
+ nr_absent += end_pfn - start_pfn;
}
}
@@ -6929,6 +7002,17 @@ static int __init set_hashdist(char *str)
__setup("hashdist=", set_hashdist);
#endif
+#ifndef __HAVE_ARCH_RESERVED_KERNEL_PAGES
+/*
+ * Returns the number of pages that arch has reserved but
+ * is not known to alloc_large_system_hash().
+ */
+static unsigned long __init arch_reserved_kernel_pages(void)
+{
+ return 0;
+}
+#endif
+
/*
* allocate a large system hash table from bootmem
* - it is assumed that the hash table must contain an exact power-of-2
@@ -6953,6 +7037,7 @@ void *__init alloc_large_system_hash(const char *tablename,
if (!numentries) {
/* round applicable memory size up to nearest megabyte */
numentries = nr_kernel_pages;
+ numentries -= arch_reserved_kernel_pages();
/* It isn't necessary when PAGE_SIZE >= 1MB */
if (PAGE_SHIFT < 20)
diff --git a/mm/page_ext.c b/mm/page_ext.c
index 44a4c029c8e7..121dcffc4ec1 100644
--- a/mm/page_ext.c
+++ b/mm/page_ext.c
@@ -42,6 +42,11 @@
* and page extension core can skip to allocate memory. As result,
* none of memory is wasted.
*
+ * When need callback returns true, page_ext checks if there is a request for
+ * extra memory through size in struct page_ext_operations. If it is non-zero,
+ * extra space is allocated for each page_ext entry and offset is returned to
+ * user through offset in struct page_ext_operations.
+ *
* The init callback is used to do proper initialization after page extension
* is completely initialized. In sparse memory system, extra memory is
* allocated some time later than memmap is allocated. In other words, lifetime
@@ -66,18 +71,24 @@ static struct page_ext_operations *page_ext_ops[] = {
};
static unsigned long total_usage;
+static unsigned long extra_mem;
static bool __init invoke_need_callbacks(void)
{
int i;
int entries = ARRAY_SIZE(page_ext_ops);
+ bool need = false;
for (i = 0; i < entries; i++) {
- if (page_ext_ops[i]->need && page_ext_ops[i]->need())
- return true;
+ if (page_ext_ops[i]->need && page_ext_ops[i]->need()) {
+ page_ext_ops[i]->offset = sizeof(struct page_ext) +
+ extra_mem;
+ extra_mem += page_ext_ops[i]->size;
+ need = true;
+ }
}
- return false;
+ return need;
}
static void __init invoke_init_callbacks(void)
@@ -91,6 +102,16 @@ static void __init invoke_init_callbacks(void)
}
}
+static unsigned long get_entry_size(void)
+{
+ return sizeof(struct page_ext) + extra_mem;
+}
+
+static inline struct page_ext *get_entry(void *base, unsigned long index)
+{
+ return base + get_entry_size() * index;
+}
+
#if !defined(CONFIG_SPARSEMEM)
@@ -102,7 +123,7 @@ void __meminit pgdat_page_ext_init(struct pglist_data *pgdat)
struct page_ext *lookup_page_ext(struct page *page)
{
unsigned long pfn = page_to_pfn(page);
- unsigned long offset;
+ unsigned long index;
struct page_ext *base;
base = NODE_DATA(page_to_nid(page))->node_page_ext;
@@ -119,9 +140,9 @@ struct page_ext *lookup_page_ext(struct page *page)
if (unlikely(!base))
return NULL;
#endif
- offset = pfn - round_down(node_start_pfn(page_to_nid(page)),
+ index = pfn - round_down(node_start_pfn(page_to_nid(page)),
MAX_ORDER_NR_PAGES);
- return base + offset;
+ return get_entry(base, index);
}
static int __init alloc_node_page_ext(int nid)
@@ -143,7 +164,7 @@ static int __init alloc_node_page_ext(int nid)
!IS_ALIGNED(node_end_pfn(nid), MAX_ORDER_NR_PAGES))
nr_pages += MAX_ORDER_NR_PAGES;
- table_size = sizeof(struct page_ext) * nr_pages;
+ table_size = get_entry_size() * nr_pages;
base = memblock_virt_alloc_try_nid_nopanic(
table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS),
@@ -196,7 +217,7 @@ struct page_ext *lookup_page_ext(struct page *page)
if (!section->page_ext)
return NULL;
#endif
- return section->page_ext + pfn;
+ return get_entry(section->page_ext, pfn);
}
static void *__meminit alloc_page_ext(size_t size, int nid)
@@ -229,7 +250,7 @@ static int __meminit init_section_page_ext(unsigned long pfn, int nid)
if (section->page_ext)
return 0;
- table_size = sizeof(struct page_ext) * PAGES_PER_SECTION;
+ table_size = get_entry_size() * PAGES_PER_SECTION;
base = alloc_page_ext(table_size, nid);
/*
@@ -249,7 +270,7 @@ static int __meminit init_section_page_ext(unsigned long pfn, int nid)
* we need to apply a mask.
*/
pfn &= PAGE_SECTION_MASK;
- section->page_ext = base - pfn;
+ section->page_ext = (void *)base - get_entry_size() * pfn;
total_usage += table_size;
return 0;
}
@@ -262,7 +283,7 @@ static void free_page_ext(void *addr)
struct page *page = virt_to_page(addr);
size_t table_size;
- table_size = sizeof(struct page_ext) * PAGES_PER_SECTION;
+ table_size = get_entry_size() * PAGES_PER_SECTION;
BUG_ON(PageReserved(page));
free_pages_exact(addr, table_size);
@@ -277,7 +298,7 @@ static void __free_page_ext(unsigned long pfn)
ms = __pfn_to_section(pfn);
if (!ms || !ms->page_ext)
return;
- base = ms->page_ext + pfn;
+ base = get_entry(ms->page_ext, pfn);
free_page_ext(base);
ms->page_ext = NULL;
}
diff --git a/mm/page_io.c b/mm/page_io.c
index eafe5ddc2b54..a2651f58c86a 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -264,7 +264,7 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
int ret;
struct swap_info_struct *sis = page_swap_info(page);
- BUG_ON(!PageSwapCache(page));
+ VM_BUG_ON_PAGE(!PageSwapCache(page), page);
if (sis->flags & SWP_FILE) {
struct kiocb kiocb;
struct file *swap_file = sis->swap_file;
@@ -338,7 +338,7 @@ int swap_readpage(struct page *page)
int ret = 0;
struct swap_info_struct *sis = page_swap_info(page);
- BUG_ON(!PageSwapCache(page));
+ VM_BUG_ON_PAGE(!PageSwapCache(page), page);
VM_BUG_ON_PAGE(!PageLocked(page), page);
VM_BUG_ON_PAGE(PageUptodate(page), page);
if (frontswap_load(page) == 0) {
@@ -388,7 +388,8 @@ int swap_set_page_dirty(struct page *page)
if (sis->flags & SWP_FILE) {
struct address_space *mapping = sis->swap_file->f_mapping;
- BUG_ON(!PageSwapCache(page));
+
+ VM_BUG_ON_PAGE(!PageSwapCache(page), page);
return mapping->a_ops->set_page_dirty(page);
} else {
return __set_page_dirty_no_writeback(page);
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 064b7fb6e0b5..a5594bfcc5ed 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -55,7 +55,7 @@ static int set_migratetype_isolate(struct page *page,
ret = 0;
/*
- * immobile means "not-on-lru" paes. If immobile is larger than
+ * immobile means "not-on-lru" pages. If immobile is larger than
* removable-by-driver pages reported by notifier, we'll fail.
*/
diff --git a/mm/page_owner.c b/mm/page_owner.c
index ec6dc1886f71..60634dc53a88 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -8,6 +8,7 @@
#include <linux/jump_label.h>
#include <linux/migrate.h>
#include <linux/stackdepot.h>
+#include <linux/seq_file.h>
#include "internal.h"
@@ -17,6 +18,13 @@
*/
#define PAGE_OWNER_STACK_DEPTH (16)
+struct page_owner {
+ unsigned int order;
+ gfp_t gfp_mask;
+ int last_migrate_reason;
+ depot_stack_handle_t handle;
+};
+
static bool page_owner_disabled = true;
DEFINE_STATIC_KEY_FALSE(page_owner_inited);
@@ -85,10 +93,16 @@ static void init_page_owner(void)
}
struct page_ext_operations page_owner_ops = {
+ .size = sizeof(struct page_owner),
.need = need_page_owner,
.init = init_page_owner,
};
+static inline struct page_owner *get_page_owner(struct page_ext *page_ext)
+{
+ return (void *)page_ext + page_owner_ops.offset;
+}
+
void __reset_page_owner(struct page *page, unsigned int order)
{
int i;
@@ -155,14 +169,16 @@ noinline void __set_page_owner(struct page *page, unsigned int order,
gfp_t gfp_mask)
{
struct page_ext *page_ext = lookup_page_ext(page);
+ struct page_owner *page_owner;
if (unlikely(!page_ext))
return;
- page_ext->handle = save_stack(gfp_mask);
- page_ext->order = order;
- page_ext->gfp_mask = gfp_mask;
- page_ext->last_migrate_reason = -1;
+ page_owner = get_page_owner(page_ext);
+ page_owner->handle = save_stack(gfp_mask);
+ page_owner->order = order;
+ page_owner->gfp_mask = gfp_mask;
+ page_owner->last_migrate_reason = -1;
__set_bit(PAGE_EXT_OWNER, &page_ext->flags);
}
@@ -170,21 +186,26 @@ noinline void __set_page_owner(struct page *page, unsigned int order,
void __set_page_owner_migrate_reason(struct page *page, int reason)
{
struct page_ext *page_ext = lookup_page_ext(page);
+ struct page_owner *page_owner;
+
if (unlikely(!page_ext))
return;
- page_ext->last_migrate_reason = reason;
+ page_owner = get_page_owner(page_ext);
+ page_owner->last_migrate_reason = reason;
}
void __split_page_owner(struct page *page, unsigned int order)
{
int i;
struct page_ext *page_ext = lookup_page_ext(page);
+ struct page_owner *page_owner;
if (unlikely(!page_ext))
return;
- page_ext->order = 0;
+ page_owner = get_page_owner(page_ext);
+ page_owner->order = 0;
for (i = 1; i < (1 << order); i++)
__copy_page_owner(page, page + i);
}
@@ -193,14 +214,18 @@ void __copy_page_owner(struct page *oldpage, struct page *newpage)
{
struct page_ext *old_ext = lookup_page_ext(oldpage);
struct page_ext *new_ext = lookup_page_ext(newpage);
+ struct page_owner *old_page_owner, *new_page_owner;
if (unlikely(!old_ext || !new_ext))
return;
- new_ext->order = old_ext->order;
- new_ext->gfp_mask = old_ext->gfp_mask;
- new_ext->last_migrate_reason = old_ext->last_migrate_reason;
- new_ext->handle = old_ext->handle;
+ old_page_owner = get_page_owner(old_ext);
+ new_page_owner = get_page_owner(new_ext);
+ new_page_owner->order = old_page_owner->order;
+ new_page_owner->gfp_mask = old_page_owner->gfp_mask;
+ new_page_owner->last_migrate_reason =
+ old_page_owner->last_migrate_reason;
+ new_page_owner->handle = old_page_owner->handle;
/*
* We don't clear the bit on the oldpage as it's going to be freed
@@ -214,9 +239,88 @@ void __copy_page_owner(struct page *oldpage, struct page *newpage)
__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
}
+void pagetypeinfo_showmixedcount_print(struct seq_file *m,
+ pg_data_t *pgdat, struct zone *zone)
+{
+ struct page *page;
+ struct page_ext *page_ext;
+ struct page_owner *page_owner;
+ unsigned long pfn = zone->zone_start_pfn, block_end_pfn;
+ unsigned long end_pfn = pfn + zone->spanned_pages;
+ unsigned long count[MIGRATE_TYPES] = { 0, };
+ int pageblock_mt, page_mt;
+ int i;
+
+ /* Scan block by block. First and last block may be incomplete */
+ pfn = zone->zone_start_pfn;
+
+ /*
+ * Walk the zone in pageblock_nr_pages steps. If a page block spans
+ * a zone boundary, it will be double counted between zones. This does
+ * not matter as the mixed block count will still be correct
+ */
+ for (; pfn < end_pfn; ) {
+ if (!pfn_valid(pfn)) {
+ pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
+ continue;
+ }
+
+ block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
+ block_end_pfn = min(block_end_pfn, end_pfn);
+
+ page = pfn_to_page(pfn);
+ pageblock_mt = get_pageblock_migratetype(page);
+
+ for (; pfn < block_end_pfn; pfn++) {
+ if (!pfn_valid_within(pfn))
+ continue;
+
+ page = pfn_to_page(pfn);
+
+ if (page_zone(page) != zone)
+ continue;
+
+ if (PageBuddy(page)) {
+ pfn += (1UL << page_order(page)) - 1;
+ continue;
+ }
+
+ if (PageReserved(page))
+ continue;
+
+ page_ext = lookup_page_ext(page);
+ if (unlikely(!page_ext))
+ continue;
+
+ if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
+ continue;
+
+ page_owner = get_page_owner(page_ext);
+ page_mt = gfpflags_to_migratetype(
+ page_owner->gfp_mask);
+ if (pageblock_mt != page_mt) {
+ if (is_migrate_cma(pageblock_mt))
+ count[MIGRATE_MOVABLE]++;
+ else
+ count[pageblock_mt]++;
+
+ pfn = block_end_pfn;
+ break;
+ }
+ pfn += (1UL << page_owner->order) - 1;
+ }
+ }
+
+ /* Print counts */
+ seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
+ for (i = 0; i < MIGRATE_TYPES; i++)
+ seq_printf(m, "%12lu ", count[i]);
+ seq_putc(m, '\n');
+}
+
static ssize_t
print_page_owner(char __user *buf, size_t count, unsigned long pfn,
- struct page *page, struct page_ext *page_ext,
+ struct page *page, struct page_owner *page_owner,
depot_stack_handle_t handle)
{
int ret;
@@ -236,15 +340,15 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
ret = snprintf(kbuf, count,
"Page allocated via order %u, mask %#x(%pGg)\n",
- page_ext->order, page_ext->gfp_mask,
- &page_ext->gfp_mask);
+ page_owner->order, page_owner->gfp_mask,
+ &page_owner->gfp_mask);
if (ret >= count)
goto err;
/* Print information relevant to grouping pages by mobility */
pageblock_mt = get_pageblock_migratetype(page);
- page_mt = gfpflags_to_migratetype(page_ext->gfp_mask);
+ page_mt = gfpflags_to_migratetype(page_owner->gfp_mask);
ret += snprintf(kbuf + ret, count - ret,
"PFN %lu type %s Block %lu type %s Flags %#lx(%pGp)\n",
pfn,
@@ -261,10 +365,10 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
if (ret >= count)
goto err;
- if (page_ext->last_migrate_reason != -1) {
+ if (page_owner->last_migrate_reason != -1) {
ret += snprintf(kbuf + ret, count - ret,
"Page has been migrated, last migrate reason: %s\n",
- migrate_reason_names[page_ext->last_migrate_reason]);
+ migrate_reason_names[page_owner->last_migrate_reason]);
if (ret >= count)
goto err;
}
@@ -287,6 +391,7 @@ err:
void __dump_page_owner(struct page *page)
{
struct page_ext *page_ext = lookup_page_ext(page);
+ struct page_owner *page_owner;
unsigned long entries[PAGE_OWNER_STACK_DEPTH];
struct stack_trace trace = {
.nr_entries = 0,
@@ -302,7 +407,9 @@ void __dump_page_owner(struct page *page)
pr_alert("There is not page extension available.\n");
return;
}
- gfp_mask = page_ext->gfp_mask;
+
+ page_owner = get_page_owner(page_ext);
+ gfp_mask = page_owner->gfp_mask;
mt = gfpflags_to_migratetype(gfp_mask);
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) {
@@ -310,7 +417,7 @@ void __dump_page_owner(struct page *page)
return;
}
- handle = READ_ONCE(page_ext->handle);
+ handle = READ_ONCE(page_owner->handle);
if (!handle) {
pr_alert("page_owner info is not active (free page?)\n");
return;
@@ -318,12 +425,12 @@ void __dump_page_owner(struct page *page)
depot_fetch_stack(handle, &trace);
pr_alert("page allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
- page_ext->order, migratetype_names[mt], gfp_mask, &gfp_mask);
+ page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask);
print_stack_trace(&trace, 0);
- if (page_ext->last_migrate_reason != -1)
+ if (page_owner->last_migrate_reason != -1)
pr_alert("page has been migrated, last migrate reason: %s\n",
- migrate_reason_names[page_ext->last_migrate_reason]);
+ migrate_reason_names[page_owner->last_migrate_reason]);
}
static ssize_t
@@ -332,6 +439,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
unsigned long pfn;
struct page *page;
struct page_ext *page_ext;
+ struct page_owner *page_owner;
depot_stack_handle_t handle;
if (!static_branch_unlikely(&page_owner_inited))
@@ -381,11 +489,13 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
continue;
+ page_owner = get_page_owner(page_ext);
+
/*
* Access to page_ext->handle isn't synchronous so we should
* be careful to access it.
*/
- handle = READ_ONCE(page_ext->handle);
+ handle = READ_ONCE(page_owner->handle);
if (!handle)
continue;
@@ -393,7 +503,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
*ppos = (pfn - min_low_pfn) + 1;
return print_page_owner(buf, count, pfn, page,
- page_ext, handle);
+ page_owner, handle);
}
return 0;
diff --git a/mm/shmem.c b/mm/shmem.c
index 971fc83e6402..ad7813d73ea7 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -934,7 +934,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend)
{
shmem_undo_range(inode, lstart, lend, false);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
}
EXPORT_SYMBOL_GPL(shmem_truncate_range);
@@ -960,7 +960,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
@@ -979,7 +979,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
if (error)
return error;
i_size_write(inode, newsize);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = current_time(inode);
}
if (newsize <= oldsize) {
loff_t holebegin = round_up(newsize, PAGE_SIZE);
@@ -2083,7 +2083,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
inode->i_ino = get_next_ino();
inode_init_owner(inode, dir, mode);
inode->i_blocks = 0;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_generation = get_seconds();
info = SHMEM_I(inode);
memset(info, 0, (char *)inode - (char *)info);
@@ -2311,119 +2311,6 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
return retval ? retval : error;
}
-static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags)
-{
- struct address_space *mapping = in->f_mapping;
- struct inode *inode = mapping->host;
- unsigned int loff, nr_pages, req_pages;
- struct page *pages[PIPE_DEF_BUFFERS];
- struct partial_page partial[PIPE_DEF_BUFFERS];
- struct page *page;
- pgoff_t index, end_index;
- loff_t isize, left;
- int error, page_nr;
- struct splice_pipe_desc spd = {
- .pages = pages,
- .partial = partial,
- .nr_pages_max = PIPE_DEF_BUFFERS,
- .flags = flags,
- .ops = &page_cache_pipe_buf_ops,
- .spd_release = spd_release_page,
- };
-
- isize = i_size_read(inode);
- if (unlikely(*ppos >= isize))
- return 0;
-
- left = isize - *ppos;
- if (unlikely(left < len))
- len = left;
-
- if (splice_grow_spd(pipe, &spd))
- return -ENOMEM;
-
- index = *ppos >> PAGE_SHIFT;
- loff = *ppos & ~PAGE_MASK;
- req_pages = (len + loff + PAGE_SIZE - 1) >> PAGE_SHIFT;
- nr_pages = min(req_pages, spd.nr_pages_max);
-
- spd.nr_pages = find_get_pages_contig(mapping, index,
- nr_pages, spd.pages);
- index += spd.nr_pages;
- error = 0;
-
- while (spd.nr_pages < nr_pages) {
- error = shmem_getpage(inode, index, &page, SGP_CACHE);
- if (error)
- break;
- unlock_page(page);
- spd.pages[spd.nr_pages++] = page;
- index++;
- }
-
- index = *ppos >> PAGE_SHIFT;
- nr_pages = spd.nr_pages;
- spd.nr_pages = 0;
-
- for (page_nr = 0; page_nr < nr_pages; page_nr++) {
- unsigned int this_len;
-
- if (!len)
- break;
-
- this_len = min_t(unsigned long, len, PAGE_SIZE - loff);
- page = spd.pages[page_nr];
-
- if (!PageUptodate(page) || page->mapping != mapping) {
- error = shmem_getpage(inode, index, &page, SGP_CACHE);
- if (error)
- break;
- unlock_page(page);
- put_page(spd.pages[page_nr]);
- spd.pages[page_nr] = page;
- }
-
- isize = i_size_read(inode);
- end_index = (isize - 1) >> PAGE_SHIFT;
- if (unlikely(!isize || index > end_index))
- break;
-
- if (end_index == index) {
- unsigned int plen;
-
- plen = ((isize - 1) & ~PAGE_MASK) + 1;
- if (plen <= loff)
- break;
-
- this_len = min(this_len, plen - loff);
- len = this_len;
- }
-
- spd.partial[page_nr].offset = loff;
- spd.partial[page_nr].len = this_len;
- len -= this_len;
- loff = 0;
- spd.nr_pages++;
- index++;
- }
-
- while (page_nr < nr_pages)
- put_page(spd.pages[page_nr++]);
-
- if (spd.nr_pages)
- error = splice_to_pipe(pipe, &spd);
-
- splice_shrink_spd(&spd);
-
- if (error > 0) {
- *ppos += error;
- file_accessed(in);
- }
- return error;
-}
-
/*
* llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
*/
@@ -2854,7 +2741,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size)
i_size_write(inode, offset + len);
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(inode);
undone:
spin_lock(&inode->i_lock);
inode->i_private = NULL;
@@ -2907,7 +2794,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
error = 0;
dir->i_size += BOGO_DIRENT_SIZE;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
d_instantiate(dentry, inode);
dget(dentry); /* Extra count - pin the dentry in core */
}
@@ -2975,7 +2862,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr
goto out;
dir->i_size += BOGO_DIRENT_SIZE;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
inc_nlink(inode);
ihold(inode); /* New dentry reference */
dget(dentry); /* Extra pinning count for the created dentry */
@@ -2992,7 +2879,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
shmem_free_inode(inode->i_sb);
dir->i_size -= BOGO_DIRENT_SIZE;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
drop_nlink(inode);
dput(dentry); /* Undo the count from "create" - this does all the work */
return 0;
@@ -3025,7 +2912,7 @@ static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, stru
old_dir->i_ctime = old_dir->i_mtime =
new_dir->i_ctime = new_dir->i_mtime =
d_inode(old_dentry)->i_ctime =
- d_inode(new_dentry)->i_ctime = CURRENT_TIME;
+ d_inode(new_dentry)->i_ctime = current_time(old_dir);
return 0;
}
@@ -3099,7 +2986,7 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc
new_dir->i_size += BOGO_DIRENT_SIZE;
old_dir->i_ctime = old_dir->i_mtime =
new_dir->i_ctime = new_dir->i_mtime =
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = current_time(old_dir);
return 0;
}
@@ -3154,7 +3041,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
put_page(page);
}
dir->i_size += BOGO_DIRENT_SIZE;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_ctime = dir->i_mtime = current_time(dir);
d_instantiate(dentry, inode);
dget(dentry);
return 0;
@@ -3288,10 +3175,7 @@ static const struct inode_operations shmem_short_symlink_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link,
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -3299,10 +3183,7 @@ static const struct inode_operations shmem_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = shmem_get_link,
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = generic_removexattr,
#endif
};
@@ -3786,7 +3667,7 @@ static const struct file_operations shmem_file_operations = {
.read_iter = shmem_file_read_iter,
.write_iter = generic_file_write_iter,
.fsync = noop_fsync,
- .splice_read = shmem_file_splice_read,
+ .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = shmem_fallocate,
#endif
@@ -3796,10 +3677,7 @@ static const struct inode_operations shmem_inode_operations = {
.getattr = shmem_getattr,
.setattr = shmem_setattr,
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = generic_removexattr,
.set_acl = simple_set_acl,
#endif
};
@@ -3814,14 +3692,11 @@ static const struct inode_operations shmem_dir_inode_operations = {
.mkdir = shmem_mkdir,
.rmdir = shmem_rmdir,
.mknod = shmem_mknod,
- .rename2 = shmem_rename2,
+ .rename = shmem_rename2,
.tmpfile = shmem_tmpfile,
#endif
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = generic_removexattr,
#endif
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_setattr,
@@ -3831,10 +3706,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
static const struct inode_operations shmem_special_inode_operations = {
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = generic_setxattr,
- .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = generic_removexattr,
#endif
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_setattr,
@@ -4078,7 +3950,7 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range);
/* common code */
-static struct dentry_operations anon_ops = {
+static const struct dentry_operations anon_ops = {
.d_dname = simple_dname
};
diff --git a/mm/swap.c b/mm/swap.c
index 75c63bb2a1da..4dcf852e1e6d 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -748,10 +748,8 @@ void release_pages(struct page **pages, int nr, bool cold)
locked_pgdat = NULL;
}
- if (is_huge_zero_page(page)) {
- put_huge_zero_page();
+ if (is_huge_zero_page(page))
continue;
- }
page = compound_head(page);
if (!put_page_testzero(page))
diff --git a/mm/swap_state.c b/mm/swap_state.c
index c8310a37be3a..35d7e0ee1c77 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -37,6 +37,8 @@ struct address_space swapper_spaces[MAX_SWAPFILES] = {
.page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN),
.i_mmap_writable = ATOMIC_INIT(0),
.a_ops = &swap_aops,
+ /* swap cache doesn't use writeback related tags */
+ .flags = 1 << AS_NO_WRITEBACK_TAGS,
}
};
@@ -92,7 +94,7 @@ int __add_to_swap_cache(struct page *page, swp_entry_t entry)
address_space = swap_address_space(entry);
spin_lock_irq(&address_space->tree_lock);
error = radix_tree_insert(&address_space->page_tree,
- entry.val, page);
+ swp_offset(entry), page);
if (likely(!error)) {
address_space->nrpages++;
__inc_node_page_state(page, NR_FILE_PAGES);
@@ -143,7 +145,7 @@ void __delete_from_swap_cache(struct page *page)
entry.val = page_private(page);
address_space = swap_address_space(entry);
- radix_tree_delete(&address_space->page_tree, page_private(page));
+ radix_tree_delete(&address_space->page_tree, swp_offset(entry));
set_page_private(page, 0);
ClearPageSwapCache(page);
address_space->nrpages--;
@@ -252,9 +254,7 @@ static inline void free_swap_cache(struct page *page)
void free_page_and_swap_cache(struct page *page)
{
free_swap_cache(page);
- if (is_huge_zero_page(page))
- put_huge_zero_page();
- else
+ if (!is_huge_zero_page(page))
put_page(page);
}
@@ -283,7 +283,7 @@ struct page * lookup_swap_cache(swp_entry_t entry)
{
struct page *page;
- page = find_get_page(swap_address_space(entry), entry.val);
+ page = find_get_page(swap_address_space(entry), swp_offset(entry));
if (page) {
INC_CACHE_INFO(find_success);
@@ -310,7 +310,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
* called after lookup_swap_cache() failed, re-calling
* that would confuse statistics.
*/
- found_page = find_get_page(swapper_space, entry.val);
+ found_page = find_get_page(swapper_space, swp_offset(entry));
if (found_page)
break;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 2657accc6e2b..2210de290b54 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -105,7 +105,7 @@ __try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset)
struct page *page;
int ret = 0;
- page = find_get_page(swap_address_space(entry), entry.val);
+ page = find_get_page(swap_address_space(entry), swp_offset(entry));
if (!page)
return 0;
/*
@@ -257,6 +257,53 @@ static inline void cluster_set_null(struct swap_cluster_info *info)
info->data = 0;
}
+static inline bool cluster_list_empty(struct swap_cluster_list *list)
+{
+ return cluster_is_null(&list->head);
+}
+
+static inline unsigned int cluster_list_first(struct swap_cluster_list *list)
+{
+ return cluster_next(&list->head);
+}
+
+static void cluster_list_init(struct swap_cluster_list *list)
+{
+ cluster_set_null(&list->head);
+ cluster_set_null(&list->tail);
+}
+
+static void cluster_list_add_tail(struct swap_cluster_list *list,
+ struct swap_cluster_info *ci,
+ unsigned int idx)
+{
+ if (cluster_list_empty(list)) {
+ cluster_set_next_flag(&list->head, idx, 0);
+ cluster_set_next_flag(&list->tail, idx, 0);
+ } else {
+ unsigned int tail = cluster_next(&list->tail);
+
+ cluster_set_next(&ci[tail], idx);
+ cluster_set_next_flag(&list->tail, idx, 0);
+ }
+}
+
+static unsigned int cluster_list_del_first(struct swap_cluster_list *list,
+ struct swap_cluster_info *ci)
+{
+ unsigned int idx;
+
+ idx = cluster_next(&list->head);
+ if (cluster_next(&list->tail) == idx) {
+ cluster_set_null(&list->head);
+ cluster_set_null(&list->tail);
+ } else
+ cluster_set_next_flag(&list->head,
+ cluster_next(&ci[idx]), 0);
+
+ return idx;
+}
+
/* Add a cluster to discard list and schedule it to do discard */
static void swap_cluster_schedule_discard(struct swap_info_struct *si,
unsigned int idx)
@@ -270,17 +317,7 @@ static void swap_cluster_schedule_discard(struct swap_info_struct *si,
memset(si->swap_map + idx * SWAPFILE_CLUSTER,
SWAP_MAP_BAD, SWAPFILE_CLUSTER);
- if (cluster_is_null(&si->discard_cluster_head)) {
- cluster_set_next_flag(&si->discard_cluster_head,
- idx, 0);
- cluster_set_next_flag(&si->discard_cluster_tail,
- idx, 0);
- } else {
- unsigned int tail = cluster_next(&si->discard_cluster_tail);
- cluster_set_next(&si->cluster_info[tail], idx);
- cluster_set_next_flag(&si->discard_cluster_tail,
- idx, 0);
- }
+ cluster_list_add_tail(&si->discard_clusters, si->cluster_info, idx);
schedule_work(&si->discard_work);
}
@@ -296,15 +333,8 @@ static void swap_do_scheduled_discard(struct swap_info_struct *si)
info = si->cluster_info;
- while (!cluster_is_null(&si->discard_cluster_head)) {
- idx = cluster_next(&si->discard_cluster_head);
-
- cluster_set_next_flag(&si->discard_cluster_head,
- cluster_next(&info[idx]), 0);
- if (cluster_next(&si->discard_cluster_tail) == idx) {
- cluster_set_null(&si->discard_cluster_head);
- cluster_set_null(&si->discard_cluster_tail);
- }
+ while (!cluster_list_empty(&si->discard_clusters)) {
+ idx = cluster_list_del_first(&si->discard_clusters, info);
spin_unlock(&si->lock);
discard_swap_cluster(si, idx * SWAPFILE_CLUSTER,
@@ -312,19 +342,7 @@ static void swap_do_scheduled_discard(struct swap_info_struct *si)
spin_lock(&si->lock);
cluster_set_flag(&info[idx], CLUSTER_FLAG_FREE);
- if (cluster_is_null(&si->free_cluster_head)) {
- cluster_set_next_flag(&si->free_cluster_head,
- idx, 0);
- cluster_set_next_flag(&si->free_cluster_tail,
- idx, 0);
- } else {
- unsigned int tail;
-
- tail = cluster_next(&si->free_cluster_tail);
- cluster_set_next(&info[tail], idx);
- cluster_set_next_flag(&si->free_cluster_tail,
- idx, 0);
- }
+ cluster_list_add_tail(&si->free_clusters, info, idx);
memset(si->swap_map + idx * SWAPFILE_CLUSTER,
0, SWAPFILE_CLUSTER);
}
@@ -353,13 +371,8 @@ static void inc_cluster_info_page(struct swap_info_struct *p,
if (!cluster_info)
return;
if (cluster_is_free(&cluster_info[idx])) {
- VM_BUG_ON(cluster_next(&p->free_cluster_head) != idx);
- cluster_set_next_flag(&p->free_cluster_head,
- cluster_next(&cluster_info[idx]), 0);
- if (cluster_next(&p->free_cluster_tail) == idx) {
- cluster_set_null(&p->free_cluster_tail);
- cluster_set_null(&p->free_cluster_head);
- }
+ VM_BUG_ON(cluster_list_first(&p->free_clusters) != idx);
+ cluster_list_del_first(&p->free_clusters, cluster_info);
cluster_set_count_flag(&cluster_info[idx], 0, 0);
}
@@ -398,14 +411,7 @@ static void dec_cluster_info_page(struct swap_info_struct *p,
}
cluster_set_flag(&cluster_info[idx], CLUSTER_FLAG_FREE);
- if (cluster_is_null(&p->free_cluster_head)) {
- cluster_set_next_flag(&p->free_cluster_head, idx, 0);
- cluster_set_next_flag(&p->free_cluster_tail, idx, 0);
- } else {
- unsigned int tail = cluster_next(&p->free_cluster_tail);
- cluster_set_next(&cluster_info[tail], idx);
- cluster_set_next_flag(&p->free_cluster_tail, idx, 0);
- }
+ cluster_list_add_tail(&p->free_clusters, cluster_info, idx);
}
}
@@ -421,8 +427,8 @@ scan_swap_map_ssd_cluster_conflict(struct swap_info_struct *si,
bool conflict;
offset /= SWAPFILE_CLUSTER;
- conflict = !cluster_is_null(&si->free_cluster_head) &&
- offset != cluster_next(&si->free_cluster_head) &&
+ conflict = !cluster_list_empty(&si->free_clusters) &&
+ offset != cluster_list_first(&si->free_clusters) &&
cluster_is_free(&si->cluster_info[offset]);
if (!conflict)
@@ -447,11 +453,11 @@ static void scan_swap_map_try_ssd_cluster(struct swap_info_struct *si,
new_cluster:
cluster = this_cpu_ptr(si->percpu_cluster);
if (cluster_is_null(&cluster->index)) {
- if (!cluster_is_null(&si->free_cluster_head)) {
- cluster->index = si->free_cluster_head;
+ if (!cluster_list_empty(&si->free_clusters)) {
+ cluster->index = si->free_clusters.head;
cluster->next = cluster_next(&cluster->index) *
SWAPFILE_CLUSTER;
- } else if (!cluster_is_null(&si->discard_cluster_head)) {
+ } else if (!cluster_list_empty(&si->discard_clusters)) {
/*
* we don't have free cluster but have some clusters in
* discarding, do discard now and reclaim them
@@ -999,7 +1005,7 @@ int free_swap_and_cache(swp_entry_t entry)
if (p) {
if (swap_entry_free(p, entry, 1) == SWAP_HAS_CACHE) {
page = find_get_page(swap_address_space(entry),
- entry.val);
+ swp_offset(entry));
if (page && !trylock_page(page)) {
put_page(page);
page = NULL;
@@ -2292,10 +2298,8 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
nr_good_pages = maxpages - 1; /* omit header page */
- cluster_set_null(&p->free_cluster_head);
- cluster_set_null(&p->free_cluster_tail);
- cluster_set_null(&p->discard_cluster_head);
- cluster_set_null(&p->discard_cluster_tail);
+ cluster_list_init(&p->free_clusters);
+ cluster_list_init(&p->discard_clusters);
for (i = 0; i < swap_header->info.nr_badpages; i++) {
unsigned int page_nr = swap_header->info.badpages[i];
@@ -2341,19 +2345,8 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
for (i = 0; i < nr_clusters; i++) {
if (!cluster_count(&cluster_info[idx])) {
cluster_set_flag(&cluster_info[idx], CLUSTER_FLAG_FREE);
- if (cluster_is_null(&p->free_cluster_head)) {
- cluster_set_next_flag(&p->free_cluster_head,
- idx, 0);
- cluster_set_next_flag(&p->free_cluster_tail,
- idx, 0);
- } else {
- unsigned int tail;
-
- tail = cluster_next(&p->free_cluster_tail);
- cluster_set_next(&cluster_info[tail], idx);
- cluster_set_next_flag(&p->free_cluster_tail,
- idx, 0);
- }
+ cluster_list_add_tail(&p->free_clusters, cluster_info,
+ idx);
}
idx++;
if (idx == nr_clusters)
diff --git a/mm/vmacache.c b/mm/vmacache.c
index fd09dc9c6812..035fdeb35b43 100644
--- a/mm/vmacache.c
+++ b/mm/vmacache.c
@@ -87,11 +87,11 @@ struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr)
{
int i;
+ count_vm_vmacache_event(VMACACHE_FIND_CALLS);
+
if (!vmacache_valid(mm))
return NULL;
- count_vm_vmacache_event(VMACACHE_FIND_CALLS);
-
for (i = 0; i < VMACACHE_SIZE; i++) {
struct vm_area_struct *vma = current->vmacache[i];
@@ -115,11 +115,11 @@ struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm,
{
int i;
+ count_vm_vmacache_event(VMACACHE_FIND_CALLS);
+
if (!vmacache_valid(mm))
return NULL;
- count_vm_vmacache_event(VMACACHE_FIND_CALLS);
-
for (i = 0; i < VMACACHE_SIZE; i++) {
struct vm_area_struct *vma = current->vmacache[i];
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 91f44e78c516..f2481cb4e6b2 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1359,14 +1359,14 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
struct vm_struct *area;
BUG_ON(in_interrupt());
- if (flags & VM_IOREMAP)
- align = 1ul << clamp_t(int, fls_long(size),
- PAGE_SHIFT, IOREMAP_MAX_ORDER);
-
size = PAGE_ALIGN(size);
if (unlikely(!size))
return NULL;
+ if (flags & VM_IOREMAP)
+ align = 1ul << clamp_t(int, get_count_order_long(size),
+ PAGE_SHIFT, IOREMAP_MAX_ORDER);
+
area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!area))
return NULL;
@@ -1601,7 +1601,6 @@ static void *__vmalloc_node(unsigned long size, unsigned long align,
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot, int node)
{
- const int order = 0;
struct page **pages;
unsigned int nr_pages, array_size, i;
const gfp_t nested_gfp = (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO;
@@ -1629,9 +1628,9 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
struct page *page;
if (node == NUMA_NO_NODE)
- page = alloc_pages(alloc_mask, order);
+ page = alloc_page(alloc_mask);
else
- page = alloc_pages_node(node, alloc_mask, order);
+ page = alloc_pages_node(node, alloc_mask, 0);
if (unlikely(!page)) {
/* Successfully allocated i pages, free them in __vunmap() */
@@ -1648,8 +1647,8 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
return area->addr;
fail:
- warn_alloc_failed(gfp_mask, order,
- "vmalloc: allocation failure, allocated %ld of %ld bytes\n",
+ warn_alloc(gfp_mask,
+ "vmalloc: allocation failure, allocated %ld of %ld bytes",
(area->nr_pages*PAGE_SIZE), area->size);
vfree(area->addr);
return NULL;
@@ -1710,9 +1709,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
return addr;
fail:
- warn_alloc_failed(gfp_mask, 0,
- "vmalloc: allocation failure: %lu bytes\n",
- real_size);
+ warn_alloc(gfp_mask,
+ "vmalloc: allocation failure: %lu bytes", real_size);
return NULL;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 0fe8b7113868..744f926af442 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2418,8 +2418,6 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
if (inactive_list_is_low(lruvec, false, sc))
shrink_active_list(SWAP_CLUSTER_MAX, lruvec,
sc, LRU_ACTIVE_ANON);
-
- throttle_vm_writeout(sc->gfp_mask);
}
/* Use reclaim/compaction for costly allocs or under memory pressure */
@@ -2480,7 +2478,7 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
* If we have not reclaimed enough pages for compaction and the
* inactive lists are large enough, continue reclaiming
*/
- pages_for_compaction = (2UL << sc->order);
+ pages_for_compaction = compact_gap(sc->order);
inactive_lru_pages = node_page_state(pgdat, NR_INACTIVE_FILE);
if (get_nr_swap_pages() > 0)
inactive_lru_pages += node_page_state(pgdat, NR_INACTIVE_ANON);
@@ -2495,7 +2493,7 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
continue;
switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) {
- case COMPACT_PARTIAL:
+ case COMPACT_SUCCESS:
case COMPACT_CONTINUE:
return false;
default:
@@ -2598,38 +2596,35 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc)
}
/*
- * Returns true if compaction should go ahead for a high-order request, or
- * the high-order allocation would succeed without compaction.
+ * Returns true if compaction should go ahead for a costly-order request, or
+ * the allocation would already succeed without compaction. Return false if we
+ * should reclaim first.
*/
static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
{
unsigned long watermark;
- bool watermark_ok;
+ enum compact_result suitable;
- /*
- * Compaction takes time to run and there are potentially other
- * callers using the pages just freed. Continue reclaiming until
- * there is a buffer of free pages available to give compaction
- * a reasonable chance of completing and allocating the page
- */
- watermark = high_wmark_pages(zone) + (2UL << sc->order);
- watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, sc->reclaim_idx);
-
- /*
- * If compaction is deferred, reclaim up to a point where
- * compaction will have a chance of success when re-enabled
- */
- if (compaction_deferred(zone, sc->order))
- return watermark_ok;
+ suitable = compaction_suitable(zone, sc->order, 0, sc->reclaim_idx);
+ if (suitable == COMPACT_SUCCESS)
+ /* Allocation should succeed already. Don't reclaim. */
+ return true;
+ if (suitable == COMPACT_SKIPPED)
+ /* Compaction cannot yet proceed. Do reclaim. */
+ return false;
/*
- * If compaction is not ready to start and allocation is not likely
- * to succeed without it, then keep reclaiming.
+ * Compaction is already possible, but it takes time to run and there
+ * are potentially other callers using the pages just freed. So proceed
+ * with reclaim to make a buffer of free pages available to give
+ * compaction a reasonable chance of completing and allocating the page.
+ * Note that we won't actually reclaim the whole buffer in one attempt
+ * as the target watermark in should_continue_reclaim() is lower. But if
+ * we are already above the high+gap watermark, don't reclaim at all.
*/
- if (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx) == COMPACT_SKIPPED)
- return false;
+ watermark = high_wmark_pages(zone) + compact_gap(sc->order);
- return watermark_ok;
+ return zone_watermark_ok_safe(zone, 0, watermark, sc->reclaim_idx);
}
/*
@@ -3041,7 +3036,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
*/
nid = mem_cgroup_select_victim_node(memcg);
- zonelist = NODE_DATA(nid)->node_zonelists;
+ zonelist = &NODE_DATA(nid)->node_zonelists[ZONELIST_FALLBACK];
trace_mm_vmscan_memcg_reclaim_begin(0,
sc.may_writepage,
@@ -3169,7 +3164,7 @@ static bool kswapd_shrink_node(pg_data_t *pgdat,
* excessive reclaim. Assume that a process requested a high-order
* can direct reclaim/compact.
*/
- if (sc->order && sc->nr_reclaimed >= 2UL << sc->order)
+ if (sc->order && sc->nr_reclaimed >= compact_gap(sc->order))
sc->order = 0;
return sc->nr_scanned >= sc->nr_to_reclaim;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 89cec42d19ff..604f26a4f696 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1254,85 +1254,6 @@ static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
return 0;
}
-#ifdef CONFIG_PAGE_OWNER
-static void pagetypeinfo_showmixedcount_print(struct seq_file *m,
- pg_data_t *pgdat,
- struct zone *zone)
-{
- struct page *page;
- struct page_ext *page_ext;
- unsigned long pfn = zone->zone_start_pfn, block_end_pfn;
- unsigned long end_pfn = pfn + zone->spanned_pages;
- unsigned long count[MIGRATE_TYPES] = { 0, };
- int pageblock_mt, page_mt;
- int i;
-
- /* Scan block by block. First and last block may be incomplete */
- pfn = zone->zone_start_pfn;
-
- /*
- * Walk the zone in pageblock_nr_pages steps. If a page block spans
- * a zone boundary, it will be double counted between zones. This does
- * not matter as the mixed block count will still be correct
- */
- for (; pfn < end_pfn; ) {
- if (!pfn_valid(pfn)) {
- pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
- continue;
- }
-
- block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
- block_end_pfn = min(block_end_pfn, end_pfn);
-
- page = pfn_to_page(pfn);
- pageblock_mt = get_pageblock_migratetype(page);
-
- for (; pfn < block_end_pfn; pfn++) {
- if (!pfn_valid_within(pfn))
- continue;
-
- page = pfn_to_page(pfn);
-
- if (page_zone(page) != zone)
- continue;
-
- if (PageBuddy(page)) {
- pfn += (1UL << page_order(page)) - 1;
- continue;
- }
-
- if (PageReserved(page))
- continue;
-
- page_ext = lookup_page_ext(page);
- if (unlikely(!page_ext))
- continue;
-
- if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
- continue;
-
- page_mt = gfpflags_to_migratetype(page_ext->gfp_mask);
- if (pageblock_mt != page_mt) {
- if (is_migrate_cma(pageblock_mt))
- count[MIGRATE_MOVABLE]++;
- else
- count[pageblock_mt]++;
-
- pfn = block_end_pfn;
- break;
- }
- pfn += (1UL << page_ext->order) - 1;
- }
- }
-
- /* Print counts */
- seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
- for (i = 0; i < MIGRATE_TYPES; i++)
- seq_printf(m, "%12lu ", count[i]);
- seq_putc(m, '\n');
-}
-#endif /* CONFIG_PAGE_OWNER */
-
/*
* Print out the number of pageblocks for each migratetype that contain pages
* of other types. This gives an indication of how well fallbacks are being
@@ -1592,7 +1513,10 @@ static int vmstat_show(struct seq_file *m, void *arg)
{
unsigned long *l = arg;
unsigned long off = l - (unsigned long *)m->private;
- seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
+
+ seq_puts(m, vmstat_text[off]);
+ seq_put_decimal_ull(m, " ", *l);
+ seq_putc(m, '\n');
return 0;
}
@@ -1794,6 +1718,16 @@ static void __init start_shepherd_timer(void)
round_jiffies_relative(sysctl_stat_interval));
}
+static void __init init_cpu_node_state(void)
+{
+ int cpu;
+
+ get_online_cpus();
+ for_each_online_cpu(cpu)
+ node_set_state(cpu_to_node(cpu), N_CPU);
+ put_online_cpus();
+}
+
static void vmstat_cpu_dead(int node)
{
int cpu;
@@ -1851,6 +1785,7 @@ static int __init setup_vmstat(void)
#ifdef CONFIG_SMP
cpu_notifier_register_begin();
__register_cpu_notifier(&vmstat_notifier);
+ init_cpu_node_state();
start_shepherd_timer();
cpu_notifier_register_done();
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index 1852e383afd6..553ed4ecb6a0 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -680,7 +680,7 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args)
goto error;
/* Create the Protection Domain */
- rdma->pd = ib_alloc_pd(rdma->cm_id->device);
+ rdma->pd = ib_alloc_pd(rdma->cm_id->device, 0);
if (IS_ERR(rdma->pd))
goto error;
diff --git a/net/ceph/Makefile b/net/ceph/Makefile
index 84cbed630c4b..6a5180903e7b 100644
--- a/net/ceph/Makefile
+++ b/net/ceph/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_CEPH_LIB) += libceph.o
libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
mon_client.o \
+ cls_lock_client.o \
osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
debugfs.o \
auth.o auth_none.o \
diff --git a/net/ceph/auth.c b/net/ceph/auth.c
index 2bc5965fdd1e..c822b3ae1bd3 100644
--- a/net/ceph/auth.c
+++ b/net/ceph/auth.c
@@ -82,7 +82,10 @@ void ceph_auth_reset(struct ceph_auth_client *ac)
mutex_unlock(&ac->mutex);
}
-int ceph_entity_name_encode(const char *name, void **p, void *end)
+/*
+ * EntityName, not to be confused with entity_name_t
+ */
+int ceph_auth_entity_name_encode(const char *name, void **p, void *end)
{
int len = strlen(name);
@@ -111,7 +114,7 @@ int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
monhdr->session_mon = cpu_to_le16(-1);
monhdr->session_mon_tid = 0;
- ceph_encode_32(&p, 0); /* no protocol, yet */
+ ceph_encode_32(&p, CEPH_AUTH_UNKNOWN); /* no protocol, yet */
lenp = p;
p += sizeof(u32);
@@ -124,7 +127,7 @@ int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
for (i = 0; i < num; i++)
ceph_encode_32(&p, supported_protocols[i]);
- ret = ceph_entity_name_encode(ac->name, &p, end);
+ ret = ceph_auth_entity_name_encode(ac->name, &p, end);
if (ret < 0)
goto out;
ceph_decode_need(&p, end, sizeof(u64), bad);
@@ -259,9 +262,7 @@ int ceph_build_auth(struct ceph_auth_client *ac,
int ret = 0;
mutex_lock(&ac->mutex);
- if (!ac->protocol)
- ret = ceph_auth_build_hello(ac, msg_buf, msg_len);
- else if (ac->ops->should_authenticate(ac))
+ if (ac->ops->should_authenticate(ac))
ret = ceph_build_auth_request(ac, msg_buf, msg_len);
mutex_unlock(&ac->mutex);
return ret;
diff --git a/net/ceph/auth_none.c b/net/ceph/auth_none.c
index 5f836f02ae36..df45e467c81f 100644
--- a/net/ceph/auth_none.c
+++ b/net/ceph/auth_none.c
@@ -46,7 +46,7 @@ static int ceph_auth_none_build_authorizer(struct ceph_auth_client *ac,
int ret;
ceph_encode_8_safe(&p, end, 1, e_range);
- ret = ceph_entity_name_encode(ac->name, &p, end);
+ ret = ceph_auth_entity_name_encode(ac->name, &p, end);
if (ret < 0)
return ret;
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index bddfcf6f09c2..464e88599b9d 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -566,11 +566,17 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client)
}
EXPORT_SYMBOL(ceph_print_client_options);
-u64 ceph_client_id(struct ceph_client *client)
+struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client)
+{
+ return &client->msgr.inst.addr;
+}
+EXPORT_SYMBOL(ceph_client_addr);
+
+u64 ceph_client_gid(struct ceph_client *client)
{
return client->monc.auth->global_id;
}
-EXPORT_SYMBOL(ceph_client_id);
+EXPORT_SYMBOL(ceph_client_gid);
/*
* create a fresh client instance
@@ -685,7 +691,8 @@ int __ceph_open_session(struct ceph_client *client, unsigned long started)
return client->auth_err;
}
- pr_info("client%llu fsid %pU\n", ceph_client_id(client), &client->fsid);
+ pr_info("client%llu fsid %pU\n", ceph_client_gid(client),
+ &client->fsid);
ceph_debugfs_client_init(client);
return 0;
diff --git a/net/ceph/ceph_strings.c b/net/ceph/ceph_strings.c
index 3773a4fa11e3..19b7d8aa915c 100644
--- a/net/ceph/ceph_strings.c
+++ b/net/ceph/ceph_strings.c
@@ -15,6 +15,7 @@ const char *ceph_entity_type_name(int type)
default: return "unknown";
}
}
+EXPORT_SYMBOL(ceph_entity_type_name);
const char *ceph_osd_op_name(int op)
{
diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c
new file mode 100644
index 000000000000..50f040fdb2a9
--- /dev/null
+++ b/net/ceph/cls_lock_client.c
@@ -0,0 +1,325 @@
+#include <linux/ceph/ceph_debug.h>
+
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <linux/ceph/cls_lock_client.h>
+#include <linux/ceph/decode.h>
+
+/**
+ * ceph_cls_lock - grab rados lock for object
+ * @oid, @oloc: object to lock
+ * @lock_name: the name of the lock
+ * @type: lock type (CEPH_CLS_LOCK_EXCLUSIVE or CEPH_CLS_LOCK_SHARED)
+ * @cookie: user-defined identifier for this instance of the lock
+ * @tag: user-defined tag
+ * @desc: user-defined lock description
+ * @flags: lock flags
+ *
+ * All operations on the same lock should use the same tag.
+ */
+int ceph_cls_lock(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, u8 type, char *cookie,
+ char *tag, char *desc, u8 flags)
+{
+ int lock_op_buf_size;
+ int name_len = strlen(lock_name);
+ int cookie_len = strlen(cookie);
+ int tag_len = strlen(tag);
+ int desc_len = strlen(desc);
+ void *p, *end;
+ struct page *lock_op_page;
+ struct timespec mtime;
+ int ret;
+
+ lock_op_buf_size = name_len + sizeof(__le32) +
+ cookie_len + sizeof(__le32) +
+ tag_len + sizeof(__le32) +
+ desc_len + sizeof(__le32) +
+ sizeof(struct ceph_timespec) +
+ /* flag and type */
+ sizeof(u8) + sizeof(u8) +
+ CEPH_ENCODING_START_BLK_LEN;
+ if (lock_op_buf_size > PAGE_SIZE)
+ return -E2BIG;
+
+ lock_op_page = alloc_page(GFP_NOIO);
+ if (!lock_op_page)
+ return -ENOMEM;
+
+ p = page_address(lock_op_page);
+ end = p + lock_op_buf_size;
+
+ /* encode cls_lock_lock_op struct */
+ ceph_start_encoding(&p, 1, 1,
+ lock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
+ ceph_encode_string(&p, end, lock_name, name_len);
+ ceph_encode_8(&p, type);
+ ceph_encode_string(&p, end, cookie, cookie_len);
+ ceph_encode_string(&p, end, tag, tag_len);
+ ceph_encode_string(&p, end, desc, desc_len);
+ /* only support infinite duration */
+ memset(&mtime, 0, sizeof(mtime));
+ ceph_encode_timespec(p, &mtime);
+ p += sizeof(struct ceph_timespec);
+ ceph_encode_8(&p, flags);
+
+ dout("%s lock_name %s type %d cookie %s tag %s desc %s flags 0x%x\n",
+ __func__, lock_name, type, cookie, tag, desc, flags);
+ ret = ceph_osdc_call(osdc, oid, oloc, "lock", "lock",
+ CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+ lock_op_page, lock_op_buf_size, NULL, NULL);
+
+ dout("%s: status %d\n", __func__, ret);
+ __free_page(lock_op_page);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_cls_lock);
+
+/**
+ * ceph_cls_unlock - release rados lock for object
+ * @oid, @oloc: object to lock
+ * @lock_name: the name of the lock
+ * @cookie: user-defined identifier for this instance of the lock
+ */
+int ceph_cls_unlock(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, char *cookie)
+{
+ int unlock_op_buf_size;
+ int name_len = strlen(lock_name);
+ int cookie_len = strlen(cookie);
+ void *p, *end;
+ struct page *unlock_op_page;
+ int ret;
+
+ unlock_op_buf_size = name_len + sizeof(__le32) +
+ cookie_len + sizeof(__le32) +
+ CEPH_ENCODING_START_BLK_LEN;
+ if (unlock_op_buf_size > PAGE_SIZE)
+ return -E2BIG;
+
+ unlock_op_page = alloc_page(GFP_NOIO);
+ if (!unlock_op_page)
+ return -ENOMEM;
+
+ p = page_address(unlock_op_page);
+ end = p + unlock_op_buf_size;
+
+ /* encode cls_lock_unlock_op struct */
+ ceph_start_encoding(&p, 1, 1,
+ unlock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
+ ceph_encode_string(&p, end, lock_name, name_len);
+ ceph_encode_string(&p, end, cookie, cookie_len);
+
+ dout("%s lock_name %s cookie %s\n", __func__, lock_name, cookie);
+ ret = ceph_osdc_call(osdc, oid, oloc, "lock", "unlock",
+ CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+ unlock_op_page, unlock_op_buf_size, NULL, NULL);
+
+ dout("%s: status %d\n", __func__, ret);
+ __free_page(unlock_op_page);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_cls_unlock);
+
+/**
+ * ceph_cls_break_lock - release rados lock for object for specified client
+ * @oid, @oloc: object to lock
+ * @lock_name: the name of the lock
+ * @cookie: user-defined identifier for this instance of the lock
+ * @locker: current lock owner
+ */
+int ceph_cls_break_lock(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, char *cookie,
+ struct ceph_entity_name *locker)
+{
+ int break_op_buf_size;
+ int name_len = strlen(lock_name);
+ int cookie_len = strlen(cookie);
+ struct page *break_op_page;
+ void *p, *end;
+ int ret;
+
+ break_op_buf_size = name_len + sizeof(__le32) +
+ cookie_len + sizeof(__le32) +
+ sizeof(u8) + sizeof(__le64) +
+ CEPH_ENCODING_START_BLK_LEN;
+ if (break_op_buf_size > PAGE_SIZE)
+ return -E2BIG;
+
+ break_op_page = alloc_page(GFP_NOIO);
+ if (!break_op_page)
+ return -ENOMEM;
+
+ p = page_address(break_op_page);
+ end = p + break_op_buf_size;
+
+ /* encode cls_lock_break_op struct */
+ ceph_start_encoding(&p, 1, 1,
+ break_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
+ ceph_encode_string(&p, end, lock_name, name_len);
+ ceph_encode_copy(&p, locker, sizeof(*locker));
+ ceph_encode_string(&p, end, cookie, cookie_len);
+
+ dout("%s lock_name %s cookie %s locker %s%llu\n", __func__, lock_name,
+ cookie, ENTITY_NAME(*locker));
+ ret = ceph_osdc_call(osdc, oid, oloc, "lock", "break_lock",
+ CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+ break_op_page, break_op_buf_size, NULL, NULL);
+
+ dout("%s: status %d\n", __func__, ret);
+ __free_page(break_op_page);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_cls_break_lock);
+
+void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers)
+{
+ int i;
+
+ for (i = 0; i < num_lockers; i++)
+ kfree(lockers[i].id.cookie);
+ kfree(lockers);
+}
+EXPORT_SYMBOL(ceph_free_lockers);
+
+static int decode_locker(void **p, void *end, struct ceph_locker *locker)
+{
+ u8 struct_v;
+ u32 len;
+ char *s;
+ int ret;
+
+ ret = ceph_start_decoding(p, end, 1, "locker_id_t", &struct_v, &len);
+ if (ret)
+ return ret;
+
+ ceph_decode_copy(p, &locker->id.name, sizeof(locker->id.name));
+ s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
+ if (IS_ERR(s))
+ return PTR_ERR(s);
+
+ locker->id.cookie = s;
+
+ ret = ceph_start_decoding(p, end, 1, "locker_info_t", &struct_v, &len);
+ if (ret)
+ return ret;
+
+ *p += sizeof(struct ceph_timespec); /* skip expiration */
+ ceph_decode_copy(p, &locker->info.addr, sizeof(locker->info.addr));
+ ceph_decode_addr(&locker->info.addr);
+ len = ceph_decode_32(p);
+ *p += len; /* skip description */
+
+ dout("%s %s%llu cookie %s addr %s\n", __func__,
+ ENTITY_NAME(locker->id.name), locker->id.cookie,
+ ceph_pr_addr(&locker->info.addr.in_addr));
+ return 0;
+}
+
+static int decode_lockers(void **p, void *end, u8 *type, char **tag,
+ struct ceph_locker **lockers, u32 *num_lockers)
+{
+ u8 struct_v;
+ u32 struct_len;
+ char *s;
+ int i;
+ int ret;
+
+ ret = ceph_start_decoding(p, end, 1, "cls_lock_get_info_reply",
+ &struct_v, &struct_len);
+ if (ret)
+ return ret;
+
+ *num_lockers = ceph_decode_32(p);
+ *lockers = kcalloc(*num_lockers, sizeof(**lockers), GFP_NOIO);
+ if (!*lockers)
+ return -ENOMEM;
+
+ for (i = 0; i < *num_lockers; i++) {
+ ret = decode_locker(p, end, *lockers + i);
+ if (ret)
+ goto err_free_lockers;
+ }
+
+ *type = ceph_decode_8(p);
+ s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
+ if (IS_ERR(s)) {
+ ret = PTR_ERR(s);
+ goto err_free_lockers;
+ }
+
+ *tag = s;
+ return 0;
+
+err_free_lockers:
+ ceph_free_lockers(*lockers, *num_lockers);
+ return ret;
+}
+
+/*
+ * On success, the caller is responsible for:
+ *
+ * kfree(tag);
+ * ceph_free_lockers(lockers, num_lockers);
+ */
+int ceph_cls_lock_info(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ char *lock_name, u8 *type, char **tag,
+ struct ceph_locker **lockers, u32 *num_lockers)
+{
+ int get_info_op_buf_size;
+ int name_len = strlen(lock_name);
+ struct page *get_info_op_page, *reply_page;
+ size_t reply_len;
+ void *p, *end;
+ int ret;
+
+ get_info_op_buf_size = name_len + sizeof(__le32) +
+ CEPH_ENCODING_START_BLK_LEN;
+ if (get_info_op_buf_size > PAGE_SIZE)
+ return -E2BIG;
+
+ get_info_op_page = alloc_page(GFP_NOIO);
+ if (!get_info_op_page)
+ return -ENOMEM;
+
+ reply_page = alloc_page(GFP_NOIO);
+ if (!reply_page) {
+ __free_page(get_info_op_page);
+ return -ENOMEM;
+ }
+
+ p = page_address(get_info_op_page);
+ end = p + get_info_op_buf_size;
+
+ /* encode cls_lock_get_info_op struct */
+ ceph_start_encoding(&p, 1, 1,
+ get_info_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
+ ceph_encode_string(&p, end, lock_name, name_len);
+
+ dout("%s lock_name %s\n", __func__, lock_name);
+ ret = ceph_osdc_call(osdc, oid, oloc, "lock", "get_info",
+ CEPH_OSD_FLAG_READ, get_info_op_page,
+ get_info_op_buf_size, reply_page, &reply_len);
+
+ dout("%s: status %d\n", __func__, ret);
+ if (ret >= 0) {
+ p = page_address(reply_page);
+ end = p + reply_len;
+
+ ret = decode_lockers(&p, end, type, tag, lockers, num_lockers);
+ }
+
+ __free_page(get_info_op_page);
+ __free_page(reply_page);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_cls_lock_info);
diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c
index 5fcfb98f309e..a421e905331a 100644
--- a/net/ceph/crush/mapper.c
+++ b/net/ceph/crush/mapper.c
@@ -245,7 +245,7 @@ static int bucket_straw_choose(struct crush_bucket_straw *bucket,
/* compute 2^44*log2(input+1) */
static __u64 crush_ln(unsigned int xin)
{
- unsigned int x = xin, x1;
+ unsigned int x = xin;
int iexpon, index1, index2;
__u64 RH, LH, LL, xl64, result;
@@ -253,9 +253,15 @@ static __u64 crush_ln(unsigned int xin)
/* normalize input */
iexpon = 15;
- while (!(x & 0x18000)) {
- x <<= 1;
- iexpon--;
+
+ /*
+ * figure out number of bits we need to shift and
+ * do it in one step instead of iteratively
+ */
+ if (!(x & 0x18000)) {
+ int bits = __builtin_clz(x & 0x1FFFF) - 16;
+ x <<= bits;
+ iexpon = 15 - bits;
}
index1 = (x >> 8) << 1;
@@ -267,12 +273,11 @@ static __u64 crush_ln(unsigned int xin)
/* RH*x ~ 2^48 * (2^15 + xf), xf<2^8 */
xl64 = (__s64)x * RH;
xl64 >>= 48;
- x1 = xl64;
result = iexpon;
result <<= (12 + 32);
- index2 = x1 & 0xff;
+ index2 = xl64 & 0xff;
/* LL ~ 2^48*log2(1.0+index2/2^15) */
LL = __LL_tbl[index2];
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index ef34a02719d7..a8effc8b7280 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -835,6 +835,83 @@ int ceph_monc_get_version_async(struct ceph_mon_client *monc, const char *what,
}
EXPORT_SYMBOL(ceph_monc_get_version_async);
+static void handle_command_ack(struct ceph_mon_client *monc,
+ struct ceph_msg *msg)
+{
+ struct ceph_mon_generic_request *req;
+ void *p = msg->front.iov_base;
+ void *const end = p + msg->front_alloc_len;
+ u64 tid = le64_to_cpu(msg->hdr.tid);
+
+ dout("%s msg %p tid %llu\n", __func__, msg, tid);
+
+ ceph_decode_need(&p, end, sizeof(struct ceph_mon_request_header) +
+ sizeof(u32), bad);
+ p += sizeof(struct ceph_mon_request_header);
+
+ mutex_lock(&monc->mutex);
+ req = lookup_generic_request(&monc->generic_request_tree, tid);
+ if (!req) {
+ mutex_unlock(&monc->mutex);
+ return;
+ }
+
+ req->result = ceph_decode_32(&p);
+ __finish_generic_request(req);
+ mutex_unlock(&monc->mutex);
+
+ complete_generic_request(req);
+ return;
+
+bad:
+ pr_err("corrupt mon_command ack, tid %llu\n", tid);
+ ceph_msg_dump(msg);
+}
+
+int ceph_monc_blacklist_add(struct ceph_mon_client *monc,
+ struct ceph_entity_addr *client_addr)
+{
+ struct ceph_mon_generic_request *req;
+ struct ceph_mon_command *h;
+ int ret = -ENOMEM;
+ int len;
+
+ req = alloc_generic_request(monc, GFP_NOIO);
+ if (!req)
+ goto out;
+
+ req->request = ceph_msg_new(CEPH_MSG_MON_COMMAND, 256, GFP_NOIO, true);
+ if (!req->request)
+ goto out;
+
+ req->reply = ceph_msg_new(CEPH_MSG_MON_COMMAND_ACK, 512, GFP_NOIO,
+ true);
+ if (!req->reply)
+ goto out;
+
+ mutex_lock(&monc->mutex);
+ register_generic_request(req);
+ h = req->request->front.iov_base;
+ h->monhdr.have_version = 0;
+ h->monhdr.session_mon = cpu_to_le16(-1);
+ h->monhdr.session_mon_tid = 0;
+ h->fsid = monc->monmap->fsid;
+ h->num_strs = cpu_to_le32(1);
+ len = sprintf(h->str, "{ \"prefix\": \"osd blacklist\", \
+ \"blacklistop\": \"add\", \
+ \"addr\": \"%pISpc/%u\" }",
+ &client_addr->in_addr, le32_to_cpu(client_addr->nonce));
+ h->str_len = cpu_to_le32(len);
+ send_generic_request(monc, req);
+ mutex_unlock(&monc->mutex);
+
+ ret = wait_generic_request(req);
+out:
+ put_generic_request(req);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_monc_blacklist_add);
+
/*
* Resend pending generic requests.
*/
@@ -1139,6 +1216,10 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
handle_get_version_reply(monc, msg);
break;
+ case CEPH_MSG_MON_COMMAND_ACK:
+ handle_command_ack(monc, msg);
+ break;
+
case CEPH_MSG_MON_MAP:
ceph_monc_handle_map(monc, msg);
break;
@@ -1178,6 +1259,7 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
m = ceph_msg_get(monc->m_subscribe_ack);
break;
case CEPH_MSG_STATFS_REPLY:
+ case CEPH_MSG_MON_COMMAND_ACK:
return get_generic_reply(con, hdr, skip);
case CEPH_MSG_AUTH_REPLY:
m = ceph_msg_get(monc->m_auth_reply);
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index a97e7b506612..d9bf7a1d0a58 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -338,6 +338,9 @@ static void osd_req_op_data_release(struct ceph_osd_request *osd_req,
ceph_osd_data_release(&op->notify.request_data);
ceph_osd_data_release(&op->notify.response_data);
break;
+ case CEPH_OSD_OP_LIST_WATCHERS:
+ ceph_osd_data_release(&op->list_watchers.response_data);
+ break;
default:
break;
}
@@ -863,6 +866,8 @@ static u32 osd_req_encode_op(struct ceph_osd_op *dst,
case CEPH_OSD_OP_NOTIFY:
dst->notify.cookie = cpu_to_le64(src->notify.cookie);
break;
+ case CEPH_OSD_OP_LIST_WATCHERS:
+ break;
case CEPH_OSD_OP_SETALLOCHINT:
dst->alloc_hint.expected_object_size =
cpu_to_le64(src->alloc_hint.expected_object_size);
@@ -1445,6 +1450,10 @@ static void setup_request_data(struct ceph_osd_request *req,
ceph_osdc_msg_data_add(req->r_reply,
&op->extent.osd_data);
break;
+ case CEPH_OSD_OP_LIST_WATCHERS:
+ ceph_osdc_msg_data_add(req->r_reply,
+ &op->list_watchers.response_data);
+ break;
/* both */
case CEPH_OSD_OP_CALL:
@@ -3891,12 +3900,121 @@ int ceph_osdc_watch_check(struct ceph_osd_client *osdc,
return ret;
}
+static int decode_watcher(void **p, void *end, struct ceph_watch_item *item)
+{
+ u8 struct_v;
+ u32 struct_len;
+ int ret;
+
+ ret = ceph_start_decoding(p, end, 2, "watch_item_t",
+ &struct_v, &struct_len);
+ if (ret)
+ return ret;
+
+ ceph_decode_copy(p, &item->name, sizeof(item->name));
+ item->cookie = ceph_decode_64(p);
+ *p += 4; /* skip timeout_seconds */
+ if (struct_v >= 2) {
+ ceph_decode_copy(p, &item->addr, sizeof(item->addr));
+ ceph_decode_addr(&item->addr);
+ }
+
+ dout("%s %s%llu cookie %llu addr %s\n", __func__,
+ ENTITY_NAME(item->name), item->cookie,
+ ceph_pr_addr(&item->addr.in_addr));
+ return 0;
+}
+
+static int decode_watchers(void **p, void *end,
+ struct ceph_watch_item **watchers,
+ u32 *num_watchers)
+{
+ u8 struct_v;
+ u32 struct_len;
+ int i;
+ int ret;
+
+ ret = ceph_start_decoding(p, end, 1, "obj_list_watch_response_t",
+ &struct_v, &struct_len);
+ if (ret)
+ return ret;
+
+ *num_watchers = ceph_decode_32(p);
+ *watchers = kcalloc(*num_watchers, sizeof(**watchers), GFP_NOIO);
+ if (!*watchers)
+ return -ENOMEM;
+
+ for (i = 0; i < *num_watchers; i++) {
+ ret = decode_watcher(p, end, *watchers + i);
+ if (ret) {
+ kfree(*watchers);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * On success, the caller is responsible for:
+ *
+ * kfree(watchers);
+ */
+int ceph_osdc_list_watchers(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ struct ceph_watch_item **watchers,
+ u32 *num_watchers)
+{
+ struct ceph_osd_request *req;
+ struct page **pages;
+ int ret;
+
+ req = ceph_osdc_alloc_request(osdc, NULL, 1, false, GFP_NOIO);
+ if (!req)
+ return -ENOMEM;
+
+ ceph_oid_copy(&req->r_base_oid, oid);
+ ceph_oloc_copy(&req->r_base_oloc, oloc);
+ req->r_flags = CEPH_OSD_FLAG_READ;
+
+ ret = ceph_osdc_alloc_messages(req, GFP_NOIO);
+ if (ret)
+ goto out_put_req;
+
+ pages = ceph_alloc_page_vector(1, GFP_NOIO);
+ if (IS_ERR(pages)) {
+ ret = PTR_ERR(pages);
+ goto out_put_req;
+ }
+
+ osd_req_op_init(req, 0, CEPH_OSD_OP_LIST_WATCHERS, 0);
+ ceph_osd_data_pages_init(osd_req_op_data(req, 0, list_watchers,
+ response_data),
+ pages, PAGE_SIZE, 0, false, true);
+
+ ceph_osdc_start_request(osdc, req, false);
+ ret = ceph_osdc_wait_request(osdc, req);
+ if (ret >= 0) {
+ void *p = page_address(pages[0]);
+ void *const end = p + req->r_ops[0].outdata_len;
+
+ ret = decode_watchers(&p, end, watchers, num_watchers);
+ }
+
+out_put_req:
+ ceph_osdc_put_request(req);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_osdc_list_watchers);
+
/*
* Call all pending notify callbacks - for use after a watch is
* unregistered, to make sure no more callbacks for it will be invoked
*/
void ceph_osdc_flush_notifies(struct ceph_osd_client *osdc)
{
+ dout("%s osdc %p\n", __func__, osdc);
flush_workqueue(osdc->notify_wq);
}
EXPORT_SYMBOL(ceph_osdc_flush_notifies);
@@ -3910,6 +4028,57 @@ void ceph_osdc_maybe_request_map(struct ceph_osd_client *osdc)
EXPORT_SYMBOL(ceph_osdc_maybe_request_map);
/*
+ * Execute an OSD class method on an object.
+ *
+ * @flags: CEPH_OSD_FLAG_*
+ * @resp_len: out param for reply length
+ */
+int ceph_osdc_call(struct ceph_osd_client *osdc,
+ struct ceph_object_id *oid,
+ struct ceph_object_locator *oloc,
+ const char *class, const char *method,
+ unsigned int flags,
+ struct page *req_page, size_t req_len,
+ struct page *resp_page, size_t *resp_len)
+{
+ struct ceph_osd_request *req;
+ int ret;
+
+ req = ceph_osdc_alloc_request(osdc, NULL, 1, false, GFP_NOIO);
+ if (!req)
+ return -ENOMEM;
+
+ ceph_oid_copy(&req->r_base_oid, oid);
+ ceph_oloc_copy(&req->r_base_oloc, oloc);
+ req->r_flags = flags;
+
+ ret = ceph_osdc_alloc_messages(req, GFP_NOIO);
+ if (ret)
+ goto out_put_req;
+
+ osd_req_op_cls_init(req, 0, CEPH_OSD_OP_CALL, class, method);
+ if (req_page)
+ osd_req_op_cls_request_data_pages(req, 0, &req_page, req_len,
+ 0, false, false);
+ if (resp_page)
+ osd_req_op_cls_response_data_pages(req, 0, &resp_page,
+ PAGE_SIZE, 0, false, false);
+
+ ceph_osdc_start_request(osdc, req, false);
+ ret = ceph_osdc_wait_request(osdc, req);
+ if (ret >= 0) {
+ ret = req->r_ops[0].rval;
+ if (resp_page)
+ *resp_len = req->r_ops[0].outdata_len;
+ }
+
+out_put_req:
+ ceph_osdc_put_request(req);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_osdc_call);
+
+/*
* init, shutdown
*/
int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index cbd19d250947..1e3e0087245b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1962,37 +1962,13 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
return false;
}
-ssize_t skb_socket_splice(struct sock *sk,
- struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd)
-{
- int ret;
-
- /* Drop the socket lock, otherwise we have reverse
- * locking dependencies between sk_lock and i_mutex
- * here as compared to sendfile(). We enter here
- * with the socket lock held, and splice_to_pipe() will
- * grab the pipe inode lock. For sendfile() emulation,
- * we call into ->sendpage() with the i_mutex lock held
- * and networking will grab the socket lock.
- */
- release_sock(sk);
- ret = splice_to_pipe(pipe, spd);
- lock_sock(sk);
-
- return ret;
-}
-
/*
* Map data from the skb to a pipe. Should handle both the linear part,
* the fragments, and the frag list.
*/
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int tlen,
- unsigned int flags,
- ssize_t (*splice_cb)(struct sock *,
- struct pipe_inode_info *,
- struct splice_pipe_desc *))
+ unsigned int flags)
{
struct partial_page partial[MAX_SKB_FRAGS];
struct page *pages[MAX_SKB_FRAGS];
@@ -2009,7 +1985,7 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
__skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk);
if (spd.nr_pages)
- ret = splice_cb(sk, pipe, &spd);
+ ret = splice_to_pipe(pipe, &spd);
return ret;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 038e660ef844..c73e28fc9c2a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1363,6 +1363,7 @@ static void sk_prot_free(struct proto *prot, struct sock *sk)
slab = prot->slab;
cgroup_sk_free(&sk->sk_cgrp_data);
+ mem_cgroup_sk_free(sk);
security_sk_free(sk);
if (slab != NULL)
kmem_cache_free(slab, sk);
@@ -1399,6 +1400,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
sock_net_set(sk, net);
atomic_set(&sk->sk_wmem_alloc, 1);
+ mem_cgroup_sk_alloc(sk);
cgroup_sk_alloc(&sk->sk_cgrp_data);
sock_update_classid(&sk->sk_cgrp_data);
sock_update_netprioidx(&sk->sk_cgrp_data);
@@ -1545,6 +1547,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
newsk->sk_incoming_cpu = raw_smp_processor_id();
atomic64_set(&newsk->sk_cookie, 0);
+ mem_cgroup_sk_alloc(newsk);
cgroup_sk_alloc(&newsk->sk_cgrp_data);
/*
@@ -1569,9 +1572,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
sk_set_socket(newsk, NULL);
newsk->sk_wq = NULL;
- if (mem_cgroup_sockets_enabled && sk->sk_memcg)
- sock_update_memcg(newsk);
-
if (newsk->sk_prot->sockets_allocated)
sk_sockets_allocated_inc(newsk);
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 66ddcb60519a..7cf7d6e380c2 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -258,7 +258,7 @@ int ping_init_sock(struct sock *sk)
struct net *net = sock_net(sk);
kgid_t group = current_egid();
struct group_info *group_info;
- int i, j, count;
+ int i;
kgid_t low, high;
int ret = 0;
@@ -270,16 +270,11 @@ int ping_init_sock(struct sock *sk)
return 0;
group_info = get_current_groups();
- count = group_info->ngroups;
- for (i = 0; i < group_info->nblocks; i++) {
- int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
- for (j = 0; j < cp_count; j++) {
- kgid_t gid = group_info->blocks[i][j];
- if (gid_lte(low, gid) && gid_lte(gid, high))
- goto out_release_group;
- }
+ for (i = 0; i < group_info->ngroups; i++) {
+ kgid_t gid = group_info->gid[i];
- count -= cp_count;
+ if (gid_lte(low, gid) && gid_lte(gid, high))
+ goto out_release_group;
}
ret = -EACCES;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f253e5019d22..3251fe71f39f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -424,8 +424,6 @@ void tcp_init_sock(struct sock *sk)
sk->sk_rcvbuf = sysctl_tcp_rmem[1];
local_bh_disable();
- if (mem_cgroup_sockets_enabled)
- sock_update_memcg(sk);
sk_sockets_allocated_inc(sk);
local_bh_enable();
}
@@ -691,8 +689,7 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
int ret;
ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe,
- min(rd_desc->count, len), tss->flags,
- skb_socket_splice);
+ min(rd_desc->count, len), tss->flags);
if (ret > 0)
rd_desc->count -= ret;
return ret;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7ac37c314312..bd5e8d10893f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1871,9 +1871,6 @@ void tcp_v4_destroy_sock(struct sock *sk)
local_bh_disable();
sk_sockets_allocated_dec(sk);
local_bh_enable();
-
- if (mem_cgroup_sockets_enabled && sk->sk_memcg)
- sock_release_memcg(sk);
}
EXPORT_SYMBOL(tcp_v4_destroy_sock);
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index b7f869a85ab7..7e08a4d3d77d 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1160,19 +1160,6 @@ out:
return copied ? : err;
}
-static ssize_t kcm_sock_splice(struct sock *sk,
- struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd)
-{
- int ret;
-
- release_sock(sk);
- ret = splice_to_pipe(pipe, spd);
- lock_sock(sk);
-
- return ret;
-}
-
static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
@@ -1202,8 +1189,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
if (len > rxm->full_len)
len = rxm->full_len;
- copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags,
- kcm_sock_splice);
+ copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags);
if (copied < 0) {
err = copied;
goto err_out;
diff --git a/net/rds/ib.c b/net/rds/ib.c
index 7eaf887e46f8..5680d90b0b77 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -160,7 +160,7 @@ static void rds_ib_add_one(struct ib_device *device)
rds_ibdev->max_responder_resources = device->attrs.max_qp_rd_atom;
rds_ibdev->dev = device;
- rds_ibdev->pd = ib_alloc_pd(device);
+ rds_ibdev->pd = ib_alloc_pd(device, 0);
if (IS_ERR(rds_ibdev->pd)) {
rds_ibdev->pd = NULL;
goto put_dev;
diff --git a/net/socket.c b/net/socket.c
index a1bd16106625..5a9bf5ee2464 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -320,11 +320,38 @@ static const struct dentry_operations sockfs_dentry_operations = {
.d_dname = sockfs_dname,
};
+static int sockfs_xattr_get(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *suffix, void *value, size_t size)
+{
+ if (value) {
+ if (dentry->d_name.len + 1 > size)
+ return -ERANGE;
+ memcpy(value, dentry->d_name.name, dentry->d_name.len + 1);
+ }
+ return dentry->d_name.len + 1;
+}
+
+#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
+#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
+#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
+
+static const struct xattr_handler sockfs_xattr_handler = {
+ .name = XATTR_NAME_SOCKPROTONAME,
+ .get = sockfs_xattr_get,
+};
+
+static const struct xattr_handler *sockfs_xattr_handlers[] = {
+ &sockfs_xattr_handler,
+ NULL
+};
+
static struct dentry *sockfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
- return mount_pseudo(fs_type, "socket:", &sockfs_ops,
- &sockfs_dentry_operations, SOCKFS_MAGIC);
+ return mount_pseudo_xattr(fs_type, "socket:", &sockfs_ops,
+ sockfs_xattr_handlers,
+ &sockfs_dentry_operations, SOCKFS_MAGIC);
}
static struct vfsmount *sock_mnt __read_mostly;
@@ -463,35 +490,6 @@ static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
return NULL;
}
-#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
-#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
-#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
-static ssize_t sockfs_getxattr(struct dentry *dentry, struct inode *inode,
- const char *name, void *value, size_t size)
-{
- const char *proto_name;
- size_t proto_size;
- int error;
-
- error = -ENODATA;
- if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) {
- proto_name = dentry->d_name.name;
- proto_size = strlen(proto_name);
-
- if (value) {
- error = -ERANGE;
- if (proto_size + 1 > size)
- goto out;
-
- strncpy(value, proto_name, proto_size + 1);
- }
- error = proto_size + 1;
- }
-
-out:
- return error;
-}
-
static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
size_t size)
{
@@ -521,7 +519,6 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
}
static const struct inode_operations sockfs_inode_ops = {
- .getxattr = sockfs_getxattr,
.listxattr = sockfs_listxattr,
};
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 168219535a34..83dffeadf20a 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -176,8 +176,8 @@ generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
if (gcred->acred.group_info->ngroups != acred->group_info->ngroups)
goto out_nomatch;
for (i = 0; i < gcred->acred.group_info->ngroups; i++) {
- if (!gid_eq(GROUP_AT(gcred->acred.group_info, i),
- GROUP_AT(acred->group_info, i)))
+ if (!gid_eq(gcred->acred.group_info->gid[i],
+ acred->group_info->gid[i]))
goto out_nomatch;
}
out_match:
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c
index eeeba5adee6d..dc6fb79a361f 100644
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
@@ -229,7 +229,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
kgid = make_kgid(&init_user_ns, tmp);
if (!gid_valid(kgid))
goto out_free_groups;
- GROUP_AT(creds->cr_group_info, i) = kgid;
+ creds->cr_group_info->gid[i] = kgid;
}
return 0;
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index d8582028b346..d67f7e1bc82d 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -479,7 +479,7 @@ static int rsc_parse(struct cache_detail *cd,
kgid = make_kgid(&init_user_ns, id);
if (!gid_valid(kgid))
goto out;
- GROUP_AT(rsci.cred.cr_group_info, i) = kgid;
+ rsci.cred.cr_group_info->gid[i] = kgid;
}
/* mech name */
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index a99278c984e8..a1d768a973f5 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -79,7 +79,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t
cred->uc_gid = acred->gid;
for (i = 0; i < groups; i++)
- cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
+ cred->uc_gids[i] = acred->group_info->gid[i];
if (i < NFS_NGROUPS)
cred->uc_gids[i] = INVALID_GID;
@@ -127,7 +127,7 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
if (groups > NFS_NGROUPS)
groups = NFS_NGROUPS;
for (i = 0; i < groups ; i++)
- if (!gid_eq(cred->uc_gids[i], GROUP_AT(acred->group_info, i)))
+ if (!gid_eq(cred->uc_gids[i], acred->group_info->gid[i]))
return 0;
if (groups < NFS_NGROUPS && gid_valid(cred->uc_gids[groups]))
return 0;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 84f98cbe31c3..61a504fb1ae2 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -477,7 +477,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
return NULL;
inode->i_ino = get_next_ino();
inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
switch (mode & S_IFMT) {
case S_IFDIR:
inode->i_fop = &simple_dir_operations;
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index dfacdc95b3f5..64af4f034de6 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -517,7 +517,7 @@ static int unix_gid_parse(struct cache_detail *cd,
kgid = make_kgid(&init_user_ns, gid);
if (!gid_valid(kgid))
goto out;
- GROUP_AT(ug.gi, i) = kgid;
+ ug.gi->gid[i] = kgid;
}
ugp = unix_gid_lookup(cd, uid);
@@ -564,7 +564,7 @@ static int unix_gid_show(struct seq_file *m,
seq_printf(m, "%u %d:", from_kuid_munged(user_ns, ug->uid), glen);
for (i = 0; i < glen; i++)
- seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i)));
+ seq_printf(m, " %d", from_kgid_munged(user_ns, ug->gi->gid[i]));
seq_printf(m, "\n");
return 0;
}
@@ -817,7 +817,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
return SVC_CLOSE;
for (i = 0; i < slen; i++) {
kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv));
- GROUP_AT(cred->cr_group_info, i) = kgid;
+ cred->cr_group_info->gid[i] = kgid;
}
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index dd9440137834..eb2857f52b05 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -993,7 +993,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
newxprt->sc_ord = min_t(size_t, dev->attrs.max_qp_rd_atom, newxprt->sc_ord);
newxprt->sc_ord = min_t(size_t, svcrdma_ord, newxprt->sc_ord);
- newxprt->sc_pd = ib_alloc_pd(dev);
+ newxprt->sc_pd = ib_alloc_pd(dev, 0);
if (IS_ERR(newxprt->sc_pd)) {
dprintk("svcrdma: error creating PD for connect request\n");
goto errout;
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 799cce6cbe45..be3178e5e2d2 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -387,7 +387,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
}
ia->ri_device = ia->ri_id->device;
- ia->ri_pd = ib_alloc_pd(ia->ri_device);
+ ia->ri_pd = ib_alloc_pd(ia->ri_device, 0);
if (IS_ERR(ia->ri_pd)) {
rc = PTR_ERR(ia->ri_pd);
pr_err("rpcrdma: ib_alloc_pd() returned %d\n", rc);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 8309687a56b0..145082e2ba36 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2475,28 +2475,13 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg,
return unix_stream_read_generic(&state);
}
-static ssize_t skb_unix_socket_splice(struct sock *sk,
- struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd)
-{
- int ret;
- struct unix_sock *u = unix_sk(sk);
-
- mutex_unlock(&u->iolock);
- ret = splice_to_pipe(pipe, spd);
- mutex_lock(&u->iolock);
-
- return ret;
-}
-
static int unix_stream_splice_actor(struct sk_buff *skb,
int skip, int chunk,
struct unix_stream_read_state *state)
{
return skb_splice_bits(skb, state->socket->sk,
UNIXCB(skb).consumed + skip,
- state->pipe, chunk, state->splice_flags,
- skb_unix_socket_splice);
+ state->pipe, chunk, state->splice_flags);
}
static ssize_t unix_stream_splice_read(struct socket *sock, loff_t *ppos,
diff --git a/samples/rpmsg/rpmsg_client_sample.c b/samples/rpmsg/rpmsg_client_sample.c
index d0e249c90668..f161dfd3e70a 100644
--- a/samples/rpmsg/rpmsg_client_sample.c
+++ b/samples/rpmsg/rpmsg_client_sample.c
@@ -24,38 +24,52 @@
#define MSG "hello world!"
#define MSG_LIMIT 100
-static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+struct instance_data {
+ int rx_count;
+};
+
+static int rpmsg_sample_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
int ret;
- static int rx_count;
+ struct instance_data *idata = dev_get_drvdata(&rpdev->dev);
- dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", ++rx_count, src);
+ dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n",
+ ++idata->rx_count, src);
print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
data, len, true);
/* samples should not live forever */
- if (rx_count >= MSG_LIMIT) {
+ if (idata->rx_count >= MSG_LIMIT) {
dev_info(&rpdev->dev, "goodbye!\n");
- return;
+ return 0;
}
/* send a new message now */
- ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+ ret = rpmsg_send(rpdev->ept, MSG, strlen(MSG));
if (ret)
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+
+ return 0;
}
-static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+static int rpmsg_sample_probe(struct rpmsg_device *rpdev)
{
int ret;
+ struct instance_data *idata;
dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
rpdev->src, rpdev->dst);
+ idata = devm_kzalloc(&rpdev->dev, sizeof(*idata), GFP_KERNEL);
+ if (!idata)
+ return -ENOMEM;
+
+ dev_set_drvdata(&rpdev->dev, idata);
+
/* send a message to our remote processor */
- ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+ ret = rpmsg_send(rpdev->ept, MSG, strlen(MSG));
if (ret) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
return ret;
@@ -64,7 +78,7 @@ static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
return 0;
}
-static void rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+static void rpmsg_sample_remove(struct rpmsg_device *rpdev)
{
dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 48958d3cec9e..bd8349759095 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -888,7 +888,7 @@ static void check_section(const char *modname, struct elf_info *elf,
#define DATA_SECTIONS ".data", ".data.rel"
#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
- ".kprobes.text"
+ ".kprobes.text", ".cpuidle.text"
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
".fixup", ".entry.text", ".exception.text", ".text.*", \
".coldtext"
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index a68f03133df9..5423a58d1b06 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -365,6 +365,7 @@ is_mcounted_section_name(char const *const txtname)
strcmp(".irqentry.text", txtname) == 0 ||
strcmp(".softirqentry.text", txtname) == 0 ||
strcmp(".kprobes.text", txtname) == 0 ||
+ strcmp(".cpuidle.text", txtname) == 0 ||
strcmp(".text.unlikely", txtname) == 0;
}
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 2d48011bc362..faac4b10d8ea 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -136,6 +136,7 @@ my %text_sections = (
".irqentry.text" => 1,
".softirqentry.text" => 1,
".kprobes.text" => 1,
+ ".cpuidle.text" => 1,
".text.unlikely" => 1,
);
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
index fa79c6d2a5b8..163c720d3f2b 100644
--- a/scripts/spelling.txt
+++ b/scripts/spelling.txt
@@ -629,7 +629,6 @@ mispelt||misspelt
miximum||maximum
mmnemonic||mnemonic
mnay||many
-modeled||modelled
modulues||modules
monochorome||monochrome
monochromo||monochrome
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 729e595119ed..5923d5665209 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -381,7 +381,7 @@ void __aa_fs_profile_migrate_dents(struct aa_profile *old,
for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
new->dents[i] = old->dents[i];
if (new->dents[i])
- new->dents[i]->d_inode->i_mtime = CURRENT_TIME;
+ new->dents[i]->d_inode->i_mtime = current_time(new->dents[i]->d_inode);
old->dents[i] = NULL;
}
}
diff --git a/security/commoncap.c b/security/commoncap.c
index 14540bd78561..8df676fbd393 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -310,13 +310,8 @@ int cap_inode_need_killpriv(struct dentry *dentry)
struct inode *inode = d_backing_inode(dentry);
int error;
- if (!inode->i_op->getxattr)
- return 0;
-
- error = inode->i_op->getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
- if (error <= 0)
- return 0;
- return 1;
+ error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
+ return error > 0;
}
/**
@@ -329,12 +324,12 @@ int cap_inode_need_killpriv(struct dentry *dentry)
*/
int cap_inode_killpriv(struct dentry *dentry)
{
- struct inode *inode = d_backing_inode(dentry);
-
- if (!inode->i_op->removexattr)
- return 0;
+ int error;
- return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
+ error = __vfs_removexattr(dentry, XATTR_NAME_CAPS);
+ if (error == -EOPNOTSUPP)
+ error = 0;
+ return error;
}
/*
@@ -394,11 +389,11 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
- if (!inode || !inode->i_op->getxattr)
+ if (!inode)
return -ENODATA;
- size = inode->i_op->getxattr((struct dentry *)dentry, inode,
- XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ);
+ size = __vfs_getxattr((struct dentry *)dentry, inode,
+ XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ);
if (size == -ENODATA || size == -EOPNOTSUPP)
/* no data, that's ok */
return -ENODATA;
diff --git a/security/inode.c b/security/inode.c
index e3df905ab5b1..c83db05c15ab 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -117,7 +117,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
inode->i_ino = get_next_ino();
inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_private = data;
if (is_dir) {
inode->i_op = &simple_dir_inode_operations;
@@ -156,12 +156,11 @@ EXPORT_SYMBOL_GPL(securityfs_create_file);
* This function returns a pointer to a dentry if it succeeds. This
* pointer must be passed to the securityfs_remove() function when the file is
* to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here). If an error occurs, %NULL will be returned.
+ * you are responsible here). If an error occurs, the function will return
+ * the error value (via ERR_PTR).
*
* If securityfs is not enabled in the kernel, the value %-ENODEV is
- * returned. It is not wise to check for this value, but rather, check for
- * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
- * code.
+ * returned.
*/
struct dentry *securityfs_create_dir(const char *name, struct dentry *parent)
{
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 11c1d30bd705..bf663915412e 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -182,8 +182,9 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
int error;
int size;
- if (!inode->i_op->getxattr)
+ if (!(inode->i_opflags & IOP_XATTR))
return -EOPNOTSUPP;
+
desc = init_desc(type);
if (IS_ERR(desc))
return PTR_ERR(desc);
@@ -253,8 +254,8 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
&xattr_data,
sizeof(xattr_data), 0);
- } else if (rc == -ENODATA && inode->i_op->removexattr) {
- rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
+ } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
+ rc = __vfs_removexattr(dentry, XATTR_NAME_EVM);
}
return rc;
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index b9e26288d30c..ba8615576d4d 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -78,11 +78,11 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
int error;
int count = 0;
- if (!inode->i_op->getxattr)
+ if (!(inode->i_opflags & IOP_XATTR))
return -EOPNOTSUPP;
for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
- error = inode->i_op->getxattr(dentry, inode, *xattr, NULL, 0);
+ error = __vfs_getxattr(dentry, inode, *xattr, NULL, 0);
if (error < 0) {
if (error == -ENODATA)
continue;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 4b9b4a4e1b89..389325ac6067 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -165,13 +165,13 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
- struct inode *inode = d_backing_inode(dentry);
-
- if (!inode->i_op->getxattr)
- return 0;
+ ssize_t ret;
- return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
- 0, GFP_NOFS);
+ ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
+ 0, GFP_NOFS);
+ if (ret == -EOPNOTSUPP)
+ ret = 0;
+ return ret;
}
/*
@@ -190,12 +190,12 @@ int ima_appraise_measurement(enum ima_hooks func,
{
static const char op[] = "appraise_data";
char *cause = "unknown";
- struct dentry *dentry = file->f_path.dentry;
+ struct dentry *dentry = file_dentry(file);
struct inode *inode = d_backing_inode(dentry);
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;
- if (!inode->i_op->getxattr)
+ if (!(inode->i_opflags & IOP_XATTR))
return INTEGRITY_UNKNOWN;
if (rc <= 0) {
@@ -295,7 +295,7 @@ out:
*/
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
+ struct dentry *dentry = file_dentry(file);
int rc = 0;
/* do not collect and update hash for digital signatures */
@@ -322,10 +322,10 @@ void ima_inode_post_setattr(struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
struct integrity_iint_cache *iint;
- int must_appraise, rc;
+ int must_appraise;
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
- || !inode->i_op->removexattr)
+ || !(inode->i_opflags & IOP_XATTR))
return;
must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
@@ -338,8 +338,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
iint->flags |= IMA_APPRAISE;
}
if (!must_appraise)
- rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
- return;
+ __vfs_removexattr(dentry, XATTR_NAME_IMA);
}
/*
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 596ef616ac21..423d111b3b94 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -228,7 +228,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
/* read 'security.ima' */
- xattr_len = ima_read_xattr(file->f_path.dentry, &xattr_value);
+ xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2205ea27aa0a..085057936287 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -507,14 +507,14 @@ static int sb_finish_set_opts(struct super_block *sb)
the root directory. -ENODATA is ok, as this may be
the first boot of the SELinux kernel before we have
assigned xattr values to the filesystem. */
- if (!root_inode->i_op->getxattr) {
+ if (!(root_inode->i_opflags & IOP_XATTR)) {
printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
"xattr support\n", sb->s_id, sb->s_type->name);
rc = -EOPNOTSUPP;
goto out;
}
- rc = root_inode->i_op->getxattr(root, root_inode,
- XATTR_NAME_SELINUX, NULL, 0);
+
+ rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
if (rc < 0 && rc != -ENODATA) {
if (rc == -EOPNOTSUPP)
printk(KERN_WARNING "SELinux: (dev %s, type "
@@ -1410,11 +1410,10 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
case SECURITY_FS_USE_NATIVE:
break;
case SECURITY_FS_USE_XATTR:
- if (!inode->i_op->getxattr) {
+ if (!(inode->i_opflags & IOP_XATTR)) {
isec->sid = sbsec->def_sid;
break;
}
-
/* Need a dentry, since the xattr API requires one.
Life would be simpler if we could just pass the inode. */
if (opt_dentry) {
@@ -1445,14 +1444,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_unlock;
}
context[len] = '\0';
- rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX,
- context, len);
+ rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
if (rc == -ERANGE) {
kfree(context);
/* Need a larger buffer. Query for the right size. */
- rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX,
- NULL, 0);
+ rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
if (rc < 0) {
dput(dentry);
goto out_unlock;
@@ -1465,9 +1462,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_unlock;
}
context[len] = '\0';
- rc = inode->i_op->getxattr(dentry, inode,
- XATTR_NAME_SELINUX,
- context, len);
+ rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
}
dput(dentry);
if (rc < 0) {
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0765c5b053b5..72c145dd799f 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1089,7 +1089,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_mode = mode;
- ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
}
return ret;
}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index ace683838d80..d719db4219cd 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -527,9 +527,9 @@ static int policydb_index(struct policydb *p)
printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
if (p->mls_enabled)
- printk(", %d sens, %d cats", p->p_levels.nprim,
+ printk(KERN_CONT ", %d sens, %d cats", p->p_levels.nprim,
p->p_cats.nprim);
- printk("\n");
+ printk(KERN_CONT "\n");
printk(KERN_DEBUG "SELinux: %d classes, %d rules\n",
p->p_classes.nprim, p->te_avtab.nel);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index caec2256ab22..1cb060293505 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -265,14 +265,14 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
char *buffer;
struct smack_known *skp = NULL;
- if (ip->i_op->getxattr == NULL)
+ if (!(ip->i_opflags & IOP_XATTR))
return ERR_PTR(-EOPNOTSUPP);
buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL);
if (buffer == NULL)
return ERR_PTR(-ENOMEM);
- rc = ip->i_op->getxattr(dp, ip, name, buffer, SMK_LONGLABEL);
+ rc = __vfs_getxattr(dp, ip, name, buffer, SMK_LONGLABEL);
if (rc < 0)
skp = ERR_PTR(rc);
else if (rc == 0)
@@ -3520,8 +3520,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* It would be curious if the label of the task
* does not match that assigned.
*/
- if (inode->i_op->getxattr == NULL)
- break;
+ if (!(inode->i_opflags & IOP_XATTR))
+ break;
/*
* Get the dentry for xattr.
*/
@@ -3545,12 +3545,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
if (isp->smk_flags & SMK_INODE_CHANGED) {
isp->smk_flags &= ~SMK_INODE_CHANGED;
- rc = inode->i_op->setxattr(dp, inode,
+ rc = __vfs_setxattr(dp, inode,
XATTR_NAME_SMACKTRANSMUTE,
TRANS_TRUE, TRANS_TRUE_SIZE,
0);
} else {
- rc = inode->i_op->getxattr(dp, inode,
+ rc = __vfs_getxattr(dp, inode,
XATTR_NAME_SMACKTRANSMUTE, trattr,
TRANS_TRUE_SIZE);
if (rc >= 0 && strncmp(trattr, TRANS_TRUE,
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index 5077f1968841..a97b275ca3af 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -173,7 +173,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
* Use filesystem name if filesystem does not support rename()
* operation.
*/
- if (!inode->i_op->rename && !inode->i_op->rename2)
+ if (!inode->i_op->rename)
goto prepend_filesystem_name;
}
/* Prepend device name. */
@@ -283,7 +283,7 @@ char *tomoyo_realpath_from_path(const struct path *path)
* or dentry without vfsmount.
*/
if (!path->mnt ||
- (!inode->i_op->rename && !inode->i_op->rename2))
+ (!inode->i_op->rename))
pos = tomoyo_get_local_path(path->dentry, buf,
buf_len - 1);
/* Get absolute name for the rest. */
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index f34153962d07..71960089e207 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -118,7 +118,7 @@ static void get_irq(struct device_node * np, int *irqptr)
if (np)
*irqptr = irq_of_parse_and_map(np, 0);
else
- *irqptr = NO_IRQ;
+ *irqptr = 0;
}
/* 0x4 is outenable, 0x1 is out, thus 4 or 5 */
@@ -336,7 +336,7 @@ static int ftr_set_notify(struct gpio_runtime *rt,
return -EINVAL;
}
- if (irq == NO_IRQ)
+ if (!irq)
return -ENODEV;
mutex_lock(&notif->mutex);
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index c8fafba218a5..58ee8089bbf9 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1303,19 +1303,19 @@ static int tumbler_init(struct snd_pmac *chip)
&mix->line_mute, 1);
irq = tumbler_find_device("headphone-detect",
NULL, &mix->hp_detect, 0);
- if (irq <= NO_IRQ)
+ if (irq <= 0)
irq = tumbler_find_device("headphone-detect",
NULL, &mix->hp_detect, 1);
- if (irq <= NO_IRQ)
+ if (irq <= 0)
irq = tumbler_find_device("keywest-gpio15",
NULL, &mix->hp_detect, 1);
mix->headphone_irq = irq;
irq = tumbler_find_device("line-output-detect",
NULL, &mix->line_detect, 0);
- if (irq <= NO_IRQ)
+ if (irq <= 0)
irq = tumbler_find_device("line-output-detect",
NULL, &mix->line_detect, 1);
- if (IS_G4DA && irq <= NO_IRQ)
+ if (IS_G4DA && irq <= 0)
irq = tumbler_find_device("keywest-gpio16",
NULL, &mix->line_detect, 1);
mix->lineout_irq = irq;
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index 92a8308b96f6..1188bc849ee3 100644
--- a/tools/arch/x86/include/asm/cpufeatures.h
+++ b/tools/arch/x86/include/asm/cpufeatures.h
@@ -106,7 +106,6 @@
#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */
#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
-#define X86_FEATURE_MCE_RECOVERY ( 3*32+31) /* cpu has recoverable machine checks */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */
diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S
index 2ec0b0abbfaa..49e6ebac7e73 100644
--- a/tools/arch/x86/lib/memcpy_64.S
+++ b/tools/arch/x86/lib/memcpy_64.S
@@ -181,11 +181,11 @@ ENDPROC(memcpy_orig)
#ifndef CONFIG_UML
/*
- * memcpy_mcsafe - memory copy with machine check exception handling
+ * memcpy_mcsafe_unrolled - memory copy with machine check exception handling
* Note that we only catch machine checks when reading the source addresses.
* Writes to target are posted and don't generate machine checks.
*/
-ENTRY(memcpy_mcsafe)
+ENTRY(memcpy_mcsafe_unrolled)
cmpl $8, %edx
/* Less than 8 bytes? Go to byte copy loop */
jb .L_no_whole_words
@@ -273,7 +273,7 @@ ENTRY(memcpy_mcsafe)
.L_done_memcpy_trap:
xorq %rax, %rax
ret
-ENDPROC(memcpy_mcsafe)
+ENDPROC(memcpy_mcsafe_unrolled)
.section .fixup, "ax"
/* Return -EFAULT for any failure */
diff --git a/tools/build/Build b/tools/build/Build
index 63a6c34c0c88..76d1a4960973 100644
--- a/tools/build/Build
+++ b/tools/build/Build
@@ -1 +1,3 @@
+hostprogs := fixdep
+
fixdep-y := fixdep.o
diff --git a/tools/build/Build.include b/tools/build/Build.include
index 4d000bc959b4..1dcb95e76f70 100644
--- a/tools/build/Build.include
+++ b/tools/build/Build.include
@@ -90,3 +90,9 @@ if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
# - per object C flags
# - BUILD_STR macro to allow '-D"$(variable)"' constructs
c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj))
+cxx_flags = -Wp,-MD,$(depfile),-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj))
+
+###
+## HOSTCC C flags
+
+host_c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CHOSTFLAGS) -D"BUILD_STR(s)=\#s" $(CHOSTFLAGS_$(basetarget).o) $(CHOSTFLAGS_$(obj))
diff --git a/tools/build/Makefile b/tools/build/Makefile
index 0d5a0e3a8fa9..8332959fbca4 100644
--- a/tools/build/Makefile
+++ b/tools/build/Makefile
@@ -14,6 +14,12 @@ endef
$(call allow-override,CC,$(CROSS_COMPILE)gcc)
$(call allow-override,LD,$(CROSS_COMPILE)ld)
+HOSTCC ?= gcc
+HOSTLD ?= ld
+HOSTAR ?= ar
+
+export HOSTCC HOSTLD HOSTAR
+
ifeq ($(V),1)
Q =
else
@@ -36,7 +42,7 @@ $(OUTPUT)fixdep-in.o: FORCE
$(Q)$(MAKE) $(build)=fixdep
$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o
- $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $<
+ $(QUIET_LINK)$(HOSTCC) $(LDFLAGS) -o $@ $<
FORCE:
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
index 27f3583193e6..99c0ccd2f176 100644
--- a/tools/build/Makefile.build
+++ b/tools/build/Makefile.build
@@ -58,6 +58,12 @@ quiet_cmd_mkdir = MKDIR $(dir $@)
quiet_cmd_cc_o_c = CC $@
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+quiet_cmd_host_cc_o_c = HOSTCC $@
+ cmd_host_cc_o_c = $(HOSTCC) $(host_c_flags) -c -o $@ $<
+
+quiet_cmd_cxx_o_c = CXX $@
+ cmd_cxx_o_c = $(CXX) $(cxx_flags) -c -o $@ $<
+
quiet_cmd_cpp_i_c = CPP $@
cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $<
@@ -70,16 +76,28 @@ quiet_cmd_gen = GEN $@
# If there's nothing to link, create empty $@ object.
quiet_cmd_ld_multi = LD $@
cmd_ld_multi = $(if $(strip $(obj-y)),\
- $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@)
+ $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@)
+
+quiet_cmd_host_ld_multi = HOSTLD $@
+ cmd_host_ld_multi = $(if $(strip $(obj-y)),\
+ $(HOSTLD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(HOSTAR) rcs $@)
+
+ifneq ($(filter $(obj),$(hostprogs)),)
+ host = host_
+endif
# Build rules
$(OUTPUT)%.o: %.c FORCE
$(call rule_mkdir)
- $(call if_changed_dep,cc_o_c)
+ $(call if_changed_dep,$(host)cc_o_c)
+
+$(OUTPUT)%.o: %.cpp FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cxx_o_c)
$(OUTPUT)%.o: %.S FORCE
$(call rule_mkdir)
- $(call if_changed_dep,cc_o_c)
+ $(call if_changed_dep,$(host)cc_o_c)
$(OUTPUT)%.i: %.c FORCE
$(call rule_mkdir)
@@ -119,7 +137,7 @@ $(sort $(subdir-obj-y)): $(subdir-y) ;
$(in-target): $(obj-y) FORCE
$(call rule_mkdir)
- $(call if_changed,ld_multi)
+ $(call if_changed,$(host)ld_multi)
__build: $(in-target)
@:
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index a120c6b755a9..ae52e029dd22 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -7,7 +7,7 @@ endif
feature_check = $(eval $(feature_check_code))
define feature_check_code
- feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
+ feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
endef
feature_set = $(eval $(feature_set_code))
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include
index be630bed66d2..ad22e4e7bc59 100644
--- a/tools/build/Makefile.include
+++ b/tools/build/Makefile.include
@@ -1,10 +1,6 @@
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
-ifdef CROSS_COMPILE
-fixdep:
-else
fixdep:
$(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
-endif
.PHONY: fixdep
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index a0b29a311816..ac9c477a2a48 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -46,11 +46,13 @@ FILES= \
test-lzma.bin \
test-bpf.bin \
test-get_cpuid.bin \
- test-sdt.bin
+ test-sdt.bin \
+ test-cxx.bin
FILES := $(addprefix $(OUTPUT),$(FILES))
CC := $(CROSS_COMPILE)gcc -MD
+CXX := $(CROSS_COMPILE)g++ -MD
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
all: $(FILES)
@@ -58,6 +60,9 @@ all: $(FILES)
__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
+__BUILDXX = $(CXX) $(CXXFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
+ BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1
+
###############################
$(OUTPUT)test-all.bin:
@@ -217,6 +222,9 @@ $(OUTPUT)test-bpf.bin:
$(OUTPUT)test-sdt.bin:
$(BUILD)
+$(OUTPUT)test-cxx.bin:
+ $(BUILDXX) -std=gnu++11
+
-include $(OUTPUT)*.d
###############################
diff --git a/tools/build/feature/test-cxx.cpp b/tools/build/feature/test-cxx.cpp
new file mode 100644
index 000000000000..b1dee9a31d6c
--- /dev/null
+++ b/tools/build/feature/test-cxx.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <memory>
+
+static void print_str(std::string s)
+{
+ std::cout << s << std::endl;
+}
+
+int main()
+{
+ std::string s("Hello World!");
+ print_str(std::move(s));
+ std::cout << "|" << s << "|" << std::endl;
+ return 0;
+}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index da218fec6056..9e5fc168c8a3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -339,7 +339,7 @@ enum bpf_func_id {
BPF_FUNC_skb_change_type,
/**
- * bpf_skb_in_cgroup(skb, map, index) - Check cgroup2 membership of skb
+ * bpf_skb_under_cgroup(skb, map, index) - Check cgroup2 membership of skb
* @skb: pointer to skb
* @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
* @index: index of the cgroup in the bpf_map
@@ -348,7 +348,7 @@ enum bpf_func_id {
* == 1 skb succeeded the cgroup2 descendant test
* < 0 error
*/
- BPF_FUNC_skb_in_cgroup,
+ BPF_FUNC_skb_under_cgroup,
/**
* bpf_get_hash_recalc(skb)
diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c
index d50f3b58606b..6518bea926d6 100644
--- a/tools/lib/subcmd/pager.c
+++ b/tools/lib/subcmd/pager.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <signal.h>
+#include <sys/ioctl.h>
#include "pager.h"
#include "run-command.h"
#include "sigchain.h"
@@ -14,6 +15,7 @@
*/
static int spawned_pager;
+static int pager_columns;
void pager_init(const char *pager_env)
{
@@ -58,9 +60,12 @@ static void wait_for_pager_signal(int signo)
void setup_pager(void)
{
const char *pager = getenv(subcmd_config.pager_env);
+ struct winsize sz;
if (!isatty(1))
return;
+ if (ioctl(1, TIOCGWINSZ, &sz) == 0)
+ pager_columns = sz.ws_col;
if (!pager)
pager = getenv("PAGER");
if (!(pager || access("/usr/bin/pager", X_OK)))
@@ -98,3 +103,14 @@ int pager_in_use(void)
{
return spawned_pager;
}
+
+int pager_get_columns(void)
+{
+ char *s;
+
+ s = getenv("COLUMNS");
+ if (s)
+ return atoi(s);
+
+ return (pager_columns ? pager_columns : 80) - 2;
+}
diff --git a/tools/lib/subcmd/pager.h b/tools/lib/subcmd/pager.h
index 8b83714ecf73..623f5542d05d 100644
--- a/tools/lib/subcmd/pager.h
+++ b/tools/lib/subcmd/pager.h
@@ -5,5 +5,6 @@ extern void pager_init(const char *pager_env);
extern void setup_pager(void);
extern int pager_in_use(void);
+extern int pager_get_columns(void);
#endif /* __SUBCMD_PAGER_H */
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
index 3bcada3ae05a..65984f1c2974 100644
--- a/tools/lib/traceevent/kbuffer-parse.c
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -622,6 +622,7 @@ void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
/* Reset the buffer */
kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
+ data = kbuffer_read_event(kbuf, ts);
while (kbuf->curr < offset) {
data = kbuffer_next_event(kbuf, ts);
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index a126e97a8114..41857cce5e86 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,13 +8,23 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
-'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
+'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob]
DESCRIPTION
-----------
This command displays the symbolic event types which can be selected in the
various perf commands with the -e option.
+OPTIONS
+-------
+--no-desc::
+Don't print descriptions.
+
+-v::
+--long-desc::
+Print longer event descriptions.
+
+
[[EVENT_MODIFIERS]]
EVENT MODIFIERS
---------------
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index 5950b5a24efd..8a6479c0eac9 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -28,3 +28,7 @@ To change sampling frequency to 100 Hz: perf record -F 100
See assembly instructions with percentage: perf annotate <symbol>
If you prefer Intel style assembly, try: perf annotate -M intel
For hierarchical output, try: perf report --hierarchy
+Order by the overhead of source file name and line number: perf report -s srcline
+System-wide collection from all CPUs: perf record -a
+Show current config key-value pairs: perf config --list
+Show user configuration overrides: perf config --user --list
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index d710db16b963..982d6439bb07 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -144,6 +144,10 @@ $(call allow-override,LD,$(CROSS_COMPILE)ld)
LD += $(EXTRA_LDFLAGS)
+HOSTCC ?= gcc
+HOSTLD ?= ld
+HOSTAR ?= ar
+
PKG_CONFIG = $(CROSS_COMPILE)pkg-config
RM = rm -f
@@ -345,8 +349,18 @@ strip: $(PROGRAMS) $(OUTPUT)perf
PERF_IN := $(OUTPUT)perf-in.o
export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK
+export HOSTCC HOSTLD HOSTAR
include $(srctree)/tools/build/Makefile.include
+JEVENTS := $(OUTPUT)pmu-events/jevents
+JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o
+
+PMU_EVENTS_IN := $(OUTPUT)pmu-events/pmu-events-in.o
+
+export JEVENTS
+
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
+
$(PERF_IN): prepare FORCE
@(test -f ../../include/uapi/linux/perf_event.h && ( \
(diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \
@@ -443,9 +457,18 @@ $(PERF_IN): prepare FORCE
|| echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true
$(Q)$(MAKE) $(build)=perf
-$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
+$(JEVENTS_IN): FORCE
+ $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=jevents
+
+$(JEVENTS): $(JEVENTS_IN)
+ $(QUIET_LINK)$(HOSTCC) $(JEVENTS_IN) -o $@
+
+$(PMU_EVENTS_IN): $(JEVENTS) FORCE
+ $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=pmu-events
+
+$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \
- $(PERF_IN) $(LIBS) -o $@
+ $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@
$(GTK_IN): fixdep FORCE
$(Q)$(MAKE) $(build)=gtk
@@ -474,6 +497,8 @@ perf.spec $(SCRIPTS) \
ifneq ($(OUTPUT),)
%.o: $(OUTPUT)%.o
@echo " # Redirected target $@ => $(OUTPUT)$@"
+pmu-events/%.o: $(OUTPUT)pmu-events/%.o
+ @echo " # Redirected target $@ => $(OUTPUT)$@"
util/%.o: $(OUTPUT)util/%.o
@echo " # Redirected target $@ => $(OUTPUT)$@"
bench/%.o: $(OUTPUT)bench/%.o
@@ -729,10 +754,11 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
$(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) $(OUTPUT).config-detected
- $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
+ $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)pmu-events/jevents
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
$(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
- $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c
+ $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
+ $(OUTPUT)pmu-events/pmu-events.c
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
$(python-clean)
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index f8ccee132867..9aaa6f5a9347 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -32,3 +32,14 @@ get_cpuid(char *buffer, size_t sz)
}
return -1;
}
+
+char *
+get_cpuid_str(void)
+{
+ char *bufp;
+
+ if (asprintf(&bufp, "%.8lx", mfspr(SPRN_PVR)) < 0)
+ bufp = NULL;
+
+ return bufp;
+}
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index ed9d5d15d5b6..1030a6e504bb 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -82,7 +82,8 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
*
* In addition, we shouldn't specify an offset for kretprobes.
*/
- if (pev->point.offset || pev->point.retprobe || !map || !sym)
+ if (pev->point.offset || (!pev->uprobes && pev->point.retprobe) ||
+ !map || !sym)
return;
lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index 146d12a1cec0..a74a48db26f5 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -19,8 +19,8 @@ cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
: "a" (op));
}
-int
-get_cpuid(char *buffer, size_t sz)
+static int
+__get_cpuid(char *buffer, size_t sz, const char *fmt)
{
unsigned int a, b, c, d, lvl;
int family = -1, model = -1, step = -1;
@@ -48,7 +48,7 @@ get_cpuid(char *buffer, size_t sz)
if (family >= 0x6)
model += ((a >> 16) & 0xf) << 4;
}
- nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
+ nb = scnprintf(buffer, sz, fmt, vendor, family, model, step);
/* look for end marker to ensure the entire data fit */
if (strchr(buffer, '$')) {
@@ -57,3 +57,21 @@ get_cpuid(char *buffer, size_t sz)
}
return -1;
}
+
+int
+get_cpuid(char *buffer, size_t sz)
+{
+ return __get_cpuid(buffer, sz, "%s,%u,%u,%u$");
+}
+
+char *
+get_cpuid_str(void)
+{
+ char *buf = malloc(128);
+
+ if (__get_cpuid(buf, 128, "%s-%u-%X$") < 0) {
+ free(buf);
+ return NULL;
+ }
+ return buf;
+}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 88ee419e5189..ba9322ff858b 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -16,16 +16,23 @@
#include "util/pmu.h"
#include <subcmd/parse-options.h>
+static bool desc_flag = true;
+
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
{
int i;
bool raw_dump = false;
+ bool long_desc_flag = false;
struct option list_options[] = {
OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
+ OPT_BOOLEAN('d', "desc", &desc_flag,
+ "Print extra event descriptions. --no-desc to not print."),
+ OPT_BOOLEAN('v', "long-desc", &long_desc_flag,
+ "Print longer event descriptions."),
OPT_END()
};
const char * const list_usage[] = {
- "perf list [hw|sw|cache|tracepoint|pmu|sdt|event_glob]",
+ "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]",
NULL
};
@@ -40,7 +47,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
printf("\nList of pre-defined events (to be used in -e):\n\n");
if (argc == 0) {
- print_events(NULL, raw_dump);
+ print_events(NULL, raw_dump, !desc_flag, long_desc_flag);
return 0;
}
@@ -61,14 +68,16 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(NULL, raw_dump);
else if (strcmp(argv[i], "pmu") == 0)
- print_pmu_events(NULL, raw_dump);
+ print_pmu_events(NULL, raw_dump, !desc_flag,
+ long_desc_flag);
else if (strcmp(argv[i], "sdt") == 0)
print_sdt_events(NULL, NULL, raw_dump);
else if ((sep = strchr(argv[i], ':')) != NULL) {
int sep_idx;
if (sep == NULL) {
- print_events(argv[i], raw_dump);
+ print_events(argv[i], raw_dump, !desc_flag,
+ long_desc_flag);
continue;
}
sep_idx = sep - argv[i];
@@ -90,7 +99,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
print_symbol_events(s, PERF_TYPE_SOFTWARE,
event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump);
print_hwcache_events(s, raw_dump);
- print_pmu_events(s, raw_dump);
+ print_pmu_events(s, raw_dump, !desc_flag,
+ long_desc_flag);
print_tracepoint_events(NULL, s, raw_dump);
print_sdt_events(NULL, s, raw_dump);
free(s);
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
new file mode 100644
index 000000000000..9213a1273697
--- /dev/null
+++ b/tools/perf/pmu-events/Build
@@ -0,0 +1,13 @@
+hostprogs := jevents
+
+jevents-y += json.o jsmn.o jevents.o
+pmu-events-y += pmu-events.o
+JDIR = pmu-events/arch/$(ARCH)
+JSON = $(shell [ -d $(JDIR) ] && \
+ find $(JDIR) -name '*.json' -o -name 'mapfile.csv')
+#
+# Locate/process JSON files in pmu-events/arch/
+# directory and create tables in pmu-events.c.
+#
+$(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS)
+ $(Q)$(call echo-cmd,gen)$(JEVENTS) $(ARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
diff --git a/tools/perf/pmu-events/README b/tools/perf/pmu-events/README
new file mode 100644
index 000000000000..1408ade0d773
--- /dev/null
+++ b/tools/perf/pmu-events/README
@@ -0,0 +1,147 @@
+
+The contents of this directory allow users to specify PMU events in their
+CPUs by their symbolic names rather than raw event codes (see example below).
+
+The main program in this directory, is the 'jevents', which is built and
+executed _BEFORE_ the perf binary itself is built.
+
+The 'jevents' program tries to locate and process JSON files in the directory
+tree tools/perf/pmu-events/arch/foo.
+
+ - Regular files with '.json' extension in the name are assumed to be
+ JSON files, each of which describes a set of PMU events.
+
+ - Regular files with basename starting with 'mapfile.csv' are assumed
+ to be a CSV file that maps a specific CPU to its set of PMU events.
+ (see below for mapfile format)
+
+ - Directories are traversed, but all other files are ignored.
+
+The PMU events supported by a CPU model are expected to grouped into topics
+such as Pipelining, Cache, Memory, Floating-point etc. All events for a topic
+should be placed in a separate JSON file - where the file name identifies
+the topic. Eg: "Floating-point.json".
+
+All the topic JSON files for a CPU model/family should be in a separate
+sub directory. Thus for the Silvermont X86 CPU:
+
+ $ ls tools/perf/pmu-events/arch/x86/Silvermont_core
+ Cache.json Memory.json Virtual-Memory.json
+ Frontend.json Pipeline.json
+
+Using the JSON files and the mapfile, 'jevents' generates the C source file,
+'pmu-events.c', which encodes the two sets of tables:
+
+ - Set of 'PMU events tables' for all known CPUs in the architecture,
+ (one table like the following, per JSON file; table name 'pme_power8'
+ is derived from JSON file name, 'power8.json').
+
+ struct pmu_event pme_power8[] = {
+
+ ...
+
+ {
+ .name = "pm_1plus_ppc_cmpl",
+ .event = "event=0x100f2",
+ .desc = "1 or more ppc insts finished,",
+ },
+
+ ...
+ }
+
+ - A 'mapping table' that maps each CPU of the architecture, to its
+ 'PMU events table'
+
+ struct pmu_events_map pmu_events_map[] = {
+ {
+ .cpuid = "004b0000",
+ .version = "1",
+ .type = "core",
+ .table = pme_power8
+ },
+ ...
+
+ };
+
+After the 'pmu-events.c' is generated, it is compiled and the resulting
+'pmu-events.o' is added to 'libperf.a' which is then used to build perf.
+
+NOTES:
+ 1. Several CPUs can support same set of events and hence use a common
+ JSON file. Hence several entries in the pmu_events_map[] could map
+ to a single 'PMU events table'.
+
+ 2. The 'pmu-events.h' has an extern declaration for the mapping table
+ and the generated 'pmu-events.c' defines this table.
+
+ 3. _All_ known CPU tables for architecture are included in the perf
+ binary.
+
+At run time, perf determines the actual CPU it is running on, finds the
+matching events table and builds aliases for those events. This allows
+users to specify events by their name:
+
+ $ perf stat -e pm_1plus_ppc_cmpl sleep 1
+
+where 'pm_1plus_ppc_cmpl' is a Power8 PMU event.
+
+In case of errors when processing files in the tools/perf/pmu-events/arch
+directory, 'jevents' tries to create an empty mapping file to allow the perf
+build to succeed even if the PMU event aliases cannot be used.
+
+However some errors in processing may cause the perf build to fail.
+
+Mapfile format
+===============
+
+The mapfile enables multiple CPU models to share a single set of PMU events.
+It is required even if such mapping is 1:1.
+
+The mapfile.csv format is expected to be:
+
+ Header line
+ CPUID,Version,Dir/path/name,Type
+
+where:
+
+ Comma:
+ is the required field delimiter (i.e other fields cannot
+ have commas within them).
+
+ Comments:
+ Lines in which the first character is either '\n' or '#'
+ are ignored.
+
+ Header line
+ The header line is the first line in the file, which is
+ always _IGNORED_. It can empty.
+
+ CPUID:
+ CPUID is an arch-specific char string, that can be used
+ to identify CPU (and associate it with a set of PMU events
+ it supports). Multiple CPUIDS can point to the same
+ File/path/name.json.
+
+ Example:
+ CPUID == 'GenuineIntel-6-2E' (on x86).
+ CPUID == '004b0100' (PVR value in Powerpc)
+ Version:
+ is the Version of the mapfile.
+
+ Dir/path/name:
+ is the pathname to the directory containing the CPU's JSON
+ files, relative to the directory containing the mapfile.csv
+
+ Type:
+ indicates whether the events or "core" or "uncore" events.
+
+
+ Eg:
+
+ $ grep Silvermont tools/perf/pmu-events/arch/x86/mapfile.csv
+ GenuineIntel-6-37,V13,Silvermont_core,core
+ GenuineIntel-6-4D,V13,Silvermont_core,core
+ GenuineIntel-6-4C,V13,Silvermont_core,core
+
+ i.e the three CPU models use the JSON files (i.e PMU events) listed
+ in the directory 'tools/perf/pmu-events/arch/x86/Silvermont_core'.
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
new file mode 100644
index 000000000000..41611d7f9873
--- /dev/null
+++ b/tools/perf/pmu-events/jevents.c
@@ -0,0 +1,814 @@
+#define _XOPEN_SOURCE 500 /* needed for nftw() */
+#define _GNU_SOURCE /* needed for asprintf() */
+
+/* Parse event JSON files */
+
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * 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.
+ *
+ * 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 HOLDER 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <dirent.h>
+#include <sys/time.h> /* getrlimit */
+#include <sys/resource.h> /* getrlimit */
+#include <ftw.h>
+#include <sys/stat.h>
+#include "jsmn.h"
+#include "json.h"
+#include "jevents.h"
+
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((unused))
+#endif
+
+int verbose;
+char *prog;
+
+int eprintf(int level, int var, const char *fmt, ...)
+{
+
+ int ret;
+ va_list args;
+
+ if (var < level)
+ return 0;
+
+ va_start(args, fmt);
+
+ ret = vfprintf(stderr, fmt, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+__attribute__((weak)) char *get_cpu_str(void)
+{
+ return NULL;
+}
+
+static void addfield(char *map, char **dst, const char *sep,
+ const char *a, jsmntok_t *bt)
+{
+ unsigned int len = strlen(a) + 1 + strlen(sep);
+ int olen = *dst ? strlen(*dst) : 0;
+ int blen = bt ? json_len(bt) : 0;
+ char *out;
+
+ out = realloc(*dst, len + olen + blen);
+ if (!out) {
+ /* Don't add field in this case */
+ return;
+ }
+ *dst = out;
+
+ if (!olen)
+ *(*dst) = 0;
+ else
+ strcat(*dst, sep);
+ strcat(*dst, a);
+ if (bt)
+ strncat(*dst, map + bt->start, blen);
+}
+
+static void fixname(char *s)
+{
+ for (; *s; s++)
+ *s = tolower(*s);
+}
+
+static void fixdesc(char *s)
+{
+ char *e = s + strlen(s);
+
+ /* Remove trailing dots that look ugly in perf list */
+ --e;
+ while (e >= s && isspace(*e))
+ --e;
+ if (*e == '.')
+ *e = 0;
+}
+
+static struct msrmap {
+ const char *num;
+ const char *pname;
+} msrmap[] = {
+ { "0x3F6", "ldlat=" },
+ { "0x1A6", "offcore_rsp=" },
+ { "0x1A7", "offcore_rsp=" },
+ { "0x3F7", "frontend=" },
+ { NULL, NULL }
+};
+
+static struct field {
+ const char *field;
+ const char *kernel;
+} fields[] = {
+ { "EventCode", "event=" },
+ { "UMask", "umask=" },
+ { "CounterMask", "cmask=" },
+ { "Invert", "inv=" },
+ { "AnyThread", "any=" },
+ { "EdgeDetect", "edge=" },
+ { "SampleAfterValue", "period=" },
+ { NULL, NULL }
+};
+
+static void cut_comma(char *map, jsmntok_t *newval)
+{
+ int i;
+
+ /* Cut off everything after comma */
+ for (i = newval->start; i < newval->end; i++) {
+ if (map[i] == ',')
+ newval->end = i;
+ }
+}
+
+static int match_field(char *map, jsmntok_t *field, int nz,
+ char **event, jsmntok_t *val)
+{
+ struct field *f;
+ jsmntok_t newval = *val;
+
+ for (f = fields; f->field; f++)
+ if (json_streq(map, field, f->field) && nz) {
+ cut_comma(map, &newval);
+ addfield(map, event, ",", f->kernel, &newval);
+ return 1;
+ }
+ return 0;
+}
+
+static struct msrmap *lookup_msr(char *map, jsmntok_t *val)
+{
+ jsmntok_t newval = *val;
+ static bool warned;
+ int i;
+
+ cut_comma(map, &newval);
+ for (i = 0; msrmap[i].num; i++)
+ if (json_streq(map, &newval, msrmap[i].num))
+ return &msrmap[i];
+ if (!warned) {
+ warned = true;
+ pr_err("%s: Unknown MSR in event file %.*s\n", prog,
+ json_len(val), map + val->start);
+ }
+ return NULL;
+}
+
+#define EXPECT(e, t, m) do { if (!(e)) { \
+ jsmntok_t *loc = (t); \
+ if (!(t)->start && (t) > tokens) \
+ loc = (t) - 1; \
+ pr_err("%s:%d: " m ", got %s\n", fn, \
+ json_line(map, loc), \
+ json_name(t)); \
+ goto out_free; \
+} } while (0)
+
+#define TOPIC_DEPTH 256
+static char *topic_array[TOPIC_DEPTH];
+static int topic_level;
+
+static char *get_topic(void)
+{
+ char *tp_old, *tp = NULL;
+ int i;
+
+ for (i = 0; i < topic_level + 1; i++) {
+ int n;
+
+ tp_old = tp;
+ n = asprintf(&tp, "%s%s", tp ?: "", topic_array[i]);
+ if (n < 0) {
+ pr_info("%s: asprintf() error %s\n", prog);
+ return NULL;
+ }
+ free(tp_old);
+ }
+
+ for (i = 0; i < (int) strlen(tp); i++) {
+ char c = tp[i];
+
+ if (c == '-')
+ tp[i] = ' ';
+ else if (c == '.') {
+ tp[i] = '\0';
+ break;
+ }
+ }
+
+ return tp;
+}
+
+static int add_topic(int level, char *bname)
+{
+ char *topic;
+
+ level -= 2;
+
+ if (level >= TOPIC_DEPTH)
+ return -EINVAL;
+
+ topic = strdup(bname);
+ if (!topic) {
+ pr_info("%s: strdup() error %s for file %s\n", prog,
+ strerror(errno), bname);
+ return -ENOMEM;
+ }
+
+ free(topic_array[topic_level]);
+ topic_array[topic_level] = topic;
+ topic_level = level;
+ return 0;
+}
+
+struct perf_entry_data {
+ FILE *outfp;
+ char *topic;
+};
+
+static int close_table;
+
+static void print_events_table_prefix(FILE *fp, const char *tblname)
+{
+ fprintf(fp, "struct pmu_event %s[] = {\n", tblname);
+ close_table = 1;
+}
+
+static int print_events_table_entry(void *data, char *name, char *event,
+ char *desc, char *long_desc)
+{
+ struct perf_entry_data *pd = data;
+ FILE *outfp = pd->outfp;
+ char *topic = pd->topic;
+
+ /*
+ * TODO: Remove formatting chars after debugging to reduce
+ * string lengths.
+ */
+ fprintf(outfp, "{\n");
+
+ fprintf(outfp, "\t.name = \"%s\",\n", name);
+ fprintf(outfp, "\t.event = \"%s\",\n", event);
+ fprintf(outfp, "\t.desc = \"%s\",\n", desc);
+ fprintf(outfp, "\t.topic = \"%s\",\n", topic);
+ if (long_desc && long_desc[0])
+ fprintf(outfp, "\t.long_desc = \"%s\",\n", long_desc);
+
+ fprintf(outfp, "},\n");
+
+ return 0;
+}
+
+static void print_events_table_suffix(FILE *outfp)
+{
+ fprintf(outfp, "{\n");
+
+ fprintf(outfp, "\t.name = 0,\n");
+ fprintf(outfp, "\t.event = 0,\n");
+ fprintf(outfp, "\t.desc = 0,\n");
+
+ fprintf(outfp, "},\n");
+ fprintf(outfp, "};\n");
+ close_table = 0;
+}
+
+static struct fixed {
+ const char *name;
+ const char *event;
+} fixed[] = {
+ { "inst_retired.any", "event=0xc0" },
+ { "inst_retired.any_p", "event=0xc0" },
+ { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03" },
+ { "cpu_clk_unhalted.thread", "event=0x3c" },
+ { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1" },
+ { NULL, NULL},
+};
+
+/*
+ * Handle different fixed counter encodings between JSON and perf.
+ */
+static char *real_event(const char *name, char *event)
+{
+ int i;
+
+ for (i = 0; fixed[i].name; i++)
+ if (!strcasecmp(name, fixed[i].name))
+ return (char *)fixed[i].event;
+ return event;
+}
+
+/* Call func with each event in the json file */
+int json_events(const char *fn,
+ int (*func)(void *data, char *name, char *event, char *desc,
+ char *long_desc),
+ void *data)
+{
+ int err = -EIO;
+ size_t size;
+ jsmntok_t *tokens, *tok;
+ int i, j, len;
+ char *map;
+
+ if (!fn)
+ return -ENOENT;
+
+ tokens = parse_json(fn, &map, &size, &len);
+ if (!tokens)
+ return -EIO;
+ EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array");
+ tok = tokens + 1;
+ for (i = 0; i < tokens->size; i++) {
+ char *event = NULL, *desc = NULL, *name = NULL;
+ char *long_desc = NULL;
+ char *extra_desc = NULL;
+ struct msrmap *msr = NULL;
+ jsmntok_t *msrval = NULL;
+ jsmntok_t *precise = NULL;
+ jsmntok_t *obj = tok++;
+
+ EXPECT(obj->type == JSMN_OBJECT, obj, "expected object");
+ for (j = 0; j < obj->size; j += 2) {
+ jsmntok_t *field, *val;
+ int nz;
+
+ field = tok + j;
+ EXPECT(field->type == JSMN_STRING, tok + j,
+ "Expected field name");
+ val = tok + j + 1;
+ EXPECT(val->type == JSMN_STRING, tok + j + 1,
+ "Expected string value");
+
+ nz = !json_streq(map, val, "0");
+ if (match_field(map, field, nz, &event, val)) {
+ /* ok */
+ } else if (json_streq(map, field, "EventName")) {
+ addfield(map, &name, "", "", val);
+ } else if (json_streq(map, field, "BriefDescription")) {
+ addfield(map, &desc, "", "", val);
+ fixdesc(desc);
+ } else if (json_streq(map, field,
+ "PublicDescription")) {
+ addfield(map, &long_desc, "", "", val);
+ fixdesc(long_desc);
+ } else if (json_streq(map, field, "PEBS") && nz) {
+ precise = val;
+ } else if (json_streq(map, field, "MSRIndex") && nz) {
+ msr = lookup_msr(map, val);
+ } else if (json_streq(map, field, "MSRValue")) {
+ msrval = val;
+ } else if (json_streq(map, field, "Errata") &&
+ !json_streq(map, val, "null")) {
+ addfield(map, &extra_desc, ". ",
+ " Spec update: ", val);
+ } else if (json_streq(map, field, "Data_LA") && nz) {
+ addfield(map, &extra_desc, ". ",
+ " Supports address when precise",
+ NULL);
+ }
+ /* ignore unknown fields */
+ }
+ if (precise && desc && !strstr(desc, "(Precise Event)")) {
+ if (json_streq(map, precise, "2"))
+ addfield(map, &extra_desc, " ",
+ "(Must be precise)", NULL);
+ else
+ addfield(map, &extra_desc, " ",
+ "(Precise event)", NULL);
+ }
+ if (desc && extra_desc)
+ addfield(map, &desc, " ", extra_desc, NULL);
+ if (long_desc && extra_desc)
+ addfield(map, &long_desc, " ", extra_desc, NULL);
+ if (msr != NULL)
+ addfield(map, &event, ",", msr->pname, msrval);
+ fixname(name);
+
+ err = func(data, name, real_event(name, event), desc, long_desc);
+ free(event);
+ free(desc);
+ free(name);
+ free(long_desc);
+ free(extra_desc);
+ if (err)
+ break;
+ tok += j;
+ }
+ EXPECT(tok - tokens == len, tok, "unexpected objects at end");
+ err = 0;
+out_free:
+ free_json(map, size, tokens);
+ return err;
+}
+
+static char *file_name_to_table_name(char *fname)
+{
+ unsigned int i;
+ int n;
+ int c;
+ char *tblname;
+
+ /*
+ * Ensure tablename starts with alphabetic character.
+ * Derive rest of table name from basename of the JSON file,
+ * replacing hyphens and stripping out .json suffix.
+ */
+ n = asprintf(&tblname, "pme_%s", basename(fname));
+ if (n < 0) {
+ pr_info("%s: asprintf() error %s for file %s\n", prog,
+ strerror(errno), fname);
+ return NULL;
+ }
+
+ for (i = 0; i < strlen(tblname); i++) {
+ c = tblname[i];
+
+ if (c == '-')
+ tblname[i] = '_';
+ else if (c == '.') {
+ tblname[i] = '\0';
+ break;
+ } else if (!isalnum(c) && c != '_') {
+ pr_err("%s: Invalid character '%c' in file name %s\n",
+ prog, c, basename(fname));
+ free(tblname);
+ tblname = NULL;
+ break;
+ }
+ }
+
+ return tblname;
+}
+
+static void print_mapping_table_prefix(FILE *outfp)
+{
+ fprintf(outfp, "struct pmu_events_map pmu_events_map[] = {\n");
+}
+
+static void print_mapping_table_suffix(FILE *outfp)
+{
+ /*
+ * Print the terminating, NULL entry.
+ */
+ fprintf(outfp, "{\n");
+ fprintf(outfp, "\t.cpuid = 0,\n");
+ fprintf(outfp, "\t.version = 0,\n");
+ fprintf(outfp, "\t.type = 0,\n");
+ fprintf(outfp, "\t.table = 0,\n");
+ fprintf(outfp, "},\n");
+
+ /* and finally, the closing curly bracket for the struct */
+ fprintf(outfp, "};\n");
+}
+
+static int process_mapfile(FILE *outfp, char *fpath)
+{
+ int n = 16384;
+ FILE *mapfp;
+ char *save = NULL;
+ char *line, *p;
+ int line_num;
+ char *tblname;
+
+ pr_info("%s: Processing mapfile %s\n", prog, fpath);
+
+ line = malloc(n);
+ if (!line)
+ return -1;
+
+ mapfp = fopen(fpath, "r");
+ if (!mapfp) {
+ pr_info("%s: Error %s opening %s\n", prog, strerror(errno),
+ fpath);
+ return -1;
+ }
+
+ print_mapping_table_prefix(outfp);
+
+ /* Skip first line (header) */
+ p = fgets(line, n, mapfp);
+ if (!p)
+ goto out;
+
+ line_num = 1;
+ while (1) {
+ char *cpuid, *version, *type, *fname;
+
+ line_num++;
+ p = fgets(line, n, mapfp);
+ if (!p)
+ break;
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ if (line[strlen(line)-1] != '\n') {
+ /* TODO Deal with lines longer than 16K */
+ pr_info("%s: Mapfile %s: line %d too long, aborting\n",
+ prog, fpath, line_num);
+ return -1;
+ }
+ line[strlen(line)-1] = '\0';
+
+ cpuid = strtok_r(p, ",", &save);
+ version = strtok_r(NULL, ",", &save);
+ fname = strtok_r(NULL, ",", &save);
+ type = strtok_r(NULL, ",", &save);
+
+ tblname = file_name_to_table_name(fname);
+ fprintf(outfp, "{\n");
+ fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid);
+ fprintf(outfp, "\t.version = \"%s\",\n", version);
+ fprintf(outfp, "\t.type = \"%s\",\n", type);
+
+ /*
+ * CHECK: We can't use the type (eg "core") field in the
+ * table name. For us to do that, we need to somehow tweak
+ * the other caller of file_name_to_table(), process_json()
+ * to determine the type. process_json() file has no way
+ * of knowing these are "core" events unless file name has
+ * core in it. If filename has core in it, we can safely
+ * ignore the type field here also.
+ */
+ fprintf(outfp, "\t.table = %s\n", tblname);
+ fprintf(outfp, "},\n");
+ }
+
+out:
+ print_mapping_table_suffix(outfp);
+ return 0;
+}
+
+/*
+ * If we fail to locate/process JSON and map files, create a NULL mapping
+ * table. This would at least allow perf to build even if we can't find/use
+ * the aliases.
+ */
+static void create_empty_mapping(const char *output_file)
+{
+ FILE *outfp;
+
+ pr_info("%s: Creating empty pmu_events_map[] table\n", prog);
+
+ /* Truncate file to clear any partial writes to it */
+ outfp = fopen(output_file, "w");
+ if (!outfp) {
+ perror("fopen()");
+ _Exit(1);
+ }
+
+ fprintf(outfp, "#include \"../../pmu-events/pmu-events.h\"\n");
+ print_mapping_table_prefix(outfp);
+ print_mapping_table_suffix(outfp);
+ fclose(outfp);
+}
+
+static int get_maxfds(void)
+{
+ struct rlimit rlim;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
+ return min((int)rlim.rlim_max / 2, 512);
+
+ return 512;
+}
+
+/*
+ * nftw() doesn't let us pass an argument to the processing function,
+ * so use a global variables.
+ */
+static FILE *eventsfp;
+static char *mapfile;
+
+static int process_one_file(const char *fpath, const struct stat *sb,
+ int typeflag, struct FTW *ftwbuf)
+{
+ char *tblname, *bname = (char *) fpath + ftwbuf->base;
+ int is_dir = typeflag == FTW_D;
+ int is_file = typeflag == FTW_F;
+ int level = ftwbuf->level;
+ int err = 0;
+
+ pr_debug("%s %d %7jd %-20s %s\n",
+ is_file ? "f" : is_dir ? "d" : "x",
+ level, sb->st_size, bname, fpath);
+
+ /* base dir */
+ if (level == 0)
+ return 0;
+
+ /* model directory, reset topic */
+ if (level == 1 && is_dir) {
+ if (close_table)
+ print_events_table_suffix(eventsfp);
+
+ /*
+ * Drop file name suffix. Replace hyphens with underscores.
+ * Fail if file name contains any alphanum characters besides
+ * underscores.
+ */
+ tblname = file_name_to_table_name(bname);
+ if (!tblname) {
+ pr_info("%s: Error determining table name for %s\n", prog,
+ bname);
+ return -1;
+ }
+
+ print_events_table_prefix(eventsfp, tblname);
+ return 0;
+ }
+
+ /*
+ * Save the mapfile name for now. We will process mapfile
+ * after processing all JSON files (so we can write out the
+ * mapping table after all PMU events tables).
+ *
+ * TODO: Allow for multiple mapfiles? Punt for now.
+ */
+ if (level == 1 && is_file) {
+ if (!strncmp(bname, "mapfile.csv", 11)) {
+ if (mapfile) {
+ pr_info("%s: Many mapfiles? Using %s, ignoring %s\n",
+ prog, mapfile, fpath);
+ } else {
+ mapfile = strdup(fpath);
+ }
+ return 0;
+ }
+
+ pr_info("%s: Ignoring file %s\n", prog, fpath);
+ return 0;
+ }
+
+ /*
+ * If the file name does not have a .json extension,
+ * ignore it. It could be a readme.txt for instance.
+ */
+ if (is_file) {
+ char *suffix = bname + strlen(bname) - 5;
+
+ if (strncmp(suffix, ".json", 5)) {
+ pr_info("%s: Ignoring file without .json suffix %s\n", prog,
+ fpath);
+ return 0;
+ }
+ }
+
+ if (level > 1 && add_topic(level, bname))
+ return -ENOMEM;
+
+ /*
+ * Assume all other files are JSON files.
+ *
+ * If mapfile refers to 'power7_core.json', we create a table
+ * named 'power7_core'. Any inconsistencies between the mapfile
+ * and directory tree could result in build failure due to table
+ * names not being found.
+ *
+ * Atleast for now, be strict with processing JSON file names.
+ * i.e. if JSON file name cannot be mapped to C-style table name,
+ * fail.
+ */
+ if (is_file) {
+ struct perf_entry_data data = {
+ .topic = get_topic(),
+ .outfp = eventsfp,
+ };
+
+ err = json_events(fpath, print_events_table_entry, &data);
+
+ free(data.topic);
+ }
+
+ return err;
+}
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+/*
+ * Starting in directory 'start_dirname', find the "mapfile.csv" and
+ * the set of JSON files for the architecture 'arch'.
+ *
+ * From each JSON file, create a C-style "PMU events table" from the
+ * JSON file (see struct pmu_event).
+ *
+ * From the mapfile, create a mapping between the CPU revisions and
+ * PMU event tables (see struct pmu_events_map).
+ *
+ * Write out the PMU events tables and the mapping table to pmu-event.c.
+ *
+ * If unable to process the JSON or arch files, create an empty mapping
+ * table so we can continue to build/use perf even if we cannot use the
+ * PMU event aliases.
+ */
+int main(int argc, char *argv[])
+{
+ int rc;
+ int maxfds;
+ char ldirname[PATH_MAX];
+
+ const char *arch;
+ const char *output_file;
+ const char *start_dirname;
+
+ prog = basename(argv[0]);
+ if (argc < 4) {
+ pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog);
+ return 1;
+ }
+
+ arch = argv[1];
+ start_dirname = argv[2];
+ output_file = argv[3];
+
+ if (argc > 4)
+ verbose = atoi(argv[4]);
+
+ eventsfp = fopen(output_file, "w");
+ if (!eventsfp) {
+ pr_err("%s Unable to create required file %s (%s)\n",
+ prog, output_file, strerror(errno));
+ return 2;
+ }
+
+ /* Include pmu-events.h first */
+ fprintf(eventsfp, "#include \"../../pmu-events/pmu-events.h\"\n");
+
+ sprintf(ldirname, "%s/%s", start_dirname, arch);
+
+ /*
+ * The mapfile allows multiple CPUids to point to the same JSON file,
+ * so, not sure if there is a need for symlinks within the pmu-events
+ * directory.
+ *
+ * For now, treat symlinks of JSON files as regular files and create
+ * separate tables for each symlink (presumably, each symlink refers
+ * to specific version of the CPU).
+ */
+
+ maxfds = get_maxfds();
+ mapfile = NULL;
+ rc = nftw(ldirname, process_one_file, maxfds, 0);
+ if (rc && verbose) {
+ pr_info("%s: Error walking file tree %s\n", prog, ldirname);
+ goto empty_map;
+ } else if (rc) {
+ goto empty_map;
+ }
+
+ if (close_table)
+ print_events_table_suffix(eventsfp);
+
+ if (!mapfile) {
+ pr_info("%s: No CPU->JSON mapping?\n", prog);
+ goto empty_map;
+ }
+
+ if (process_mapfile(eventsfp, mapfile)) {
+ pr_info("%s: Error processing mapfile %s\n", prog, mapfile);
+ goto empty_map;
+ }
+
+ return 0;
+
+empty_map:
+ fclose(eventsfp);
+ create_empty_mapping(output_file);
+ return 0;
+}
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
new file mode 100644
index 000000000000..b0eb2744b498
--- /dev/null
+++ b/tools/perf/pmu-events/jevents.h
@@ -0,0 +1,18 @@
+#ifndef JEVENTS_H
+#define JEVENTS_H 1
+
+int json_events(const char *fn,
+ int (*func)(void *data, char *name, char *event, char *desc,
+ char *long_desc),
+ void *data);
+char *get_cpu_str(void);
+
+#ifndef min
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+#endif
+
+#endif
diff --git a/tools/perf/pmu-events/jsmn.c b/tools/perf/pmu-events/jsmn.c
new file mode 100644
index 000000000000..11d1fa18bfa5
--- /dev/null
+++ b/tools/perf/pmu-events/jsmn.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2010 Serge A. Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
+ * Slightly modified by AK to not assume 0 terminated input.
+ */
+
+#include <stdlib.h>
+#include "jsmn.h"
+
+/*
+ * Allocates a fresh unused token from the token pool.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
+ jsmntok_t *tokens, size_t num_tokens)
+{
+ jsmntok_t *tok;
+
+ if ((unsigned)parser->toknext >= num_tokens)
+ return NULL;
+ tok = &tokens[parser->toknext++];
+ tok->start = tok->end = -1;
+ tok->size = 0;
+ return tok;
+}
+
+/*
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
+ int start, int end)
+{
+ token->type = type;
+ token->start = start;
+ token->end = end;
+ token->size = 0;
+}
+
+/*
+ * Fills next available token with JSON primitive.
+ */
+static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+ size_t len,
+ jsmntok_t *tokens, size_t num_tokens)
+{
+ jsmntok_t *token;
+ int start;
+
+ start = parser->pos;
+
+ for (; parser->pos < len; parser->pos++) {
+ switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+ /*
+ * In strict mode primitive must be followed by ","
+ * or "}" or "]"
+ */
+ case ':':
+#endif
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ case ',':
+ case ']':
+ case '}':
+ goto found;
+ default:
+ break;
+ }
+ if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+#ifdef JSMN_STRICT
+ /*
+ * In strict mode primitive must be followed by a
+ * comma/object/array.
+ */
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+#endif
+
+found:
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+ parser->pos--; /* parent sees closing brackets */
+ return JSMN_SUCCESS;
+}
+
+/*
+ * Fills next token with JSON string.
+ */
+static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
+ size_t len,
+ jsmntok_t *tokens, size_t num_tokens)
+{
+ jsmntok_t *token;
+ int start = parser->pos;
+
+ /* Skip starting quote */
+ parser->pos++;
+
+ for (; parser->pos < len; parser->pos++) {
+ char c = js[parser->pos];
+
+ /* Quote: end of string */
+ if (c == '\"') {
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_STRING, start+1,
+ parser->pos);
+ return JSMN_SUCCESS;
+ }
+
+ /* Backslash: Quoted symbol expected */
+ if (c == '\\') {
+ parser->pos++;
+ switch (js[parser->pos]) {
+ /* Allowed escaped symbols */
+ case '\"':
+ case '/':
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'r':
+ case 'n':
+ case 't':
+ break;
+ /* Allows escaped symbol \uXXXX */
+ case 'u':
+ /* TODO */
+ break;
+ /* Unexpected symbol */
+ default:
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ }
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+}
+
+/*
+ * Parse JSON string and fill tokens.
+ */
+jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ jsmntok_t *tokens, unsigned int num_tokens)
+{
+ jsmnerr_t r;
+ int i;
+ jsmntok_t *token;
+
+ for (; parser->pos < len; parser->pos++) {
+ char c;
+ jsmntype_t type;
+
+ c = js[parser->pos];
+ switch (c) {
+ case '{':
+ case '[':
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL)
+ return JSMN_ERROR_NOMEM;
+ if (parser->toksuper != -1)
+ tokens[parser->toksuper].size++;
+ token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+ token->start = parser->pos;
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case '}':
+ case ']':
+ type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type)
+ return JSMN_ERROR_INVAL;
+ parser->toksuper = -1;
+ token->end = parser->pos + 1;
+ break;
+ }
+ }
+ /* Error if unmatched closing bracket */
+ if (i == -1)
+ return JSMN_ERROR_INVAL;
+ for (; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ parser->toksuper = i;
+ break;
+ }
+ }
+ break;
+ case '\"':
+ r = jsmn_parse_string(parser, js, len, tokens,
+ num_tokens);
+ if (r < 0)
+ return r;
+ if (parser->toksuper != -1)
+ tokens[parser->toksuper].size++;
+ break;
+ case '\t':
+ case '\r':
+ case '\n':
+ case ':':
+ case ',':
+ case ' ':
+ break;
+#ifdef JSMN_STRICT
+ /*
+ * In strict mode primitives are:
+ * numbers and booleans.
+ */
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 't':
+ case 'f':
+ case 'n':
+#else
+ /*
+ * In non-strict mode every unquoted value
+ * is a primitive.
+ */
+ /*FALL THROUGH */
+ default:
+#endif
+ r = jsmn_parse_primitive(parser, js, len, tokens,
+ num_tokens);
+ if (r < 0)
+ return r;
+ if (parser->toksuper != -1)
+ tokens[parser->toksuper].size++;
+ break;
+
+#ifdef JSMN_STRICT
+ /* Unexpected char in strict mode */
+ default:
+ return JSMN_ERROR_INVAL;
+#endif
+ }
+ }
+
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ /* Unmatched opened object or array */
+ if (tokens[i].start != -1 && tokens[i].end == -1)
+ return JSMN_ERROR_PART;
+ }
+
+ return JSMN_SUCCESS;
+}
+
+/*
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+void jsmn_init(jsmn_parser *parser)
+{
+ parser->pos = 0;
+ parser->toknext = 0;
+ parser->toksuper = -1;
+}
+
+const char *jsmn_strerror(jsmnerr_t err)
+{
+ switch (err) {
+ case JSMN_ERROR_NOMEM:
+ return "No enough tokens";
+ case JSMN_ERROR_INVAL:
+ return "Invalid character inside JSON string";
+ case JSMN_ERROR_PART:
+ return "The string is not a full JSON packet, more bytes expected";
+ case JSMN_SUCCESS:
+ return "Success";
+ default:
+ return "Unknown json error";
+ }
+}
diff --git a/tools/perf/pmu-events/jsmn.h b/tools/perf/pmu-events/jsmn.h
new file mode 100644
index 000000000000..d666b10cf25b
--- /dev/null
+++ b/tools/perf/pmu-events/jsmn.h
@@ -0,0 +1,67 @@
+#ifndef __JSMN_H_
+#define __JSMN_H_
+
+/*
+ * JSON type identifier. Basic types are:
+ * o Object
+ * o Array
+ * o String
+ * o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+ JSMN_PRIMITIVE = 0,
+ JSMN_OBJECT = 1,
+ JSMN_ARRAY = 2,
+ JSMN_STRING = 3
+} jsmntype_t;
+
+typedef enum {
+ /* Not enough tokens were provided */
+ JSMN_ERROR_NOMEM = -1,
+ /* Invalid character inside JSON string */
+ JSMN_ERROR_INVAL = -2,
+ /* The string is not a full JSON packet, more bytes expected */
+ JSMN_ERROR_PART = -3,
+ /* Everything was fine */
+ JSMN_SUCCESS = 0
+} jsmnerr_t;
+
+/*
+ * JSON token description.
+ * @param type type (object, array, string etc.)
+ * @param start start position in JSON data string
+ * @param end end position in JSON data string
+ */
+typedef struct {
+ jsmntype_t type;
+ int start;
+ int end;
+ int size;
+} jsmntok_t;
+
+/*
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string
+ */
+typedef struct {
+ unsigned int pos; /* offset in the JSON string */
+ int toknext; /* next token to allocate */
+ int toksuper; /* superior token node, e.g parent object or array */
+} jsmn_parser;
+
+/*
+ * Create JSON parser over an array of tokens
+ */
+void jsmn_init(jsmn_parser *parser);
+
+/*
+ * Run JSON parser. It parses a JSON data string into and array of tokens,
+ * each describing a single JSON object.
+ */
+jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
+ size_t len,
+ jsmntok_t *tokens, unsigned int num_tokens);
+
+const char *jsmn_strerror(jsmnerr_t err);
+
+#endif /* __JSMN_H_ */
diff --git a/tools/perf/pmu-events/json.c b/tools/perf/pmu-events/json.c
new file mode 100644
index 000000000000..f67bbb0aa36e
--- /dev/null
+++ b/tools/perf/pmu-events/json.c
@@ -0,0 +1,162 @@
+/* Parse JSON files using the JSMN parser. */
+
+/*
+ * Copyright (c) 2014, Intel Corporation
+ * 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.
+ *
+ * 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 HOLDER 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 <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include "jsmn.h"
+#include "json.h"
+#include <linux/kernel.h>
+
+
+static char *mapfile(const char *fn, size_t *size)
+{
+ unsigned ps = sysconf(_SC_PAGESIZE);
+ struct stat st;
+ char *map = NULL;
+ int err;
+ int fd = open(fn, O_RDONLY);
+
+ if (fd < 0 && verbose && fn) {
+ pr_err("Error opening events file '%s': %s\n", fn,
+ strerror(errno));
+ }
+
+ if (fd < 0)
+ return NULL;
+ err = fstat(fd, &st);
+ if (err < 0)
+ goto out;
+ *size = st.st_size;
+ map = mmap(NULL,
+ (st.st_size + ps - 1) & ~(ps - 1),
+ PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (map == MAP_FAILED)
+ map = NULL;
+out:
+ close(fd);
+ return map;
+}
+
+static void unmapfile(char *map, size_t size)
+{
+ unsigned ps = sysconf(_SC_PAGESIZE);
+ munmap(map, roundup(size, ps));
+}
+
+/*
+ * Parse json file using jsmn. Return array of tokens,
+ * and mapped file. Caller needs to free array.
+ */
+jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len)
+{
+ jsmn_parser parser;
+ jsmntok_t *tokens;
+ jsmnerr_t res;
+ unsigned sz;
+
+ *map = mapfile(fn, size);
+ if (!*map)
+ return NULL;
+ /* Heuristic */
+ sz = *size * 16;
+ tokens = malloc(sz);
+ if (!tokens)
+ goto error;
+ jsmn_init(&parser);
+ res = jsmn_parse(&parser, *map, *size, tokens,
+ sz / sizeof(jsmntok_t));
+ if (res != JSMN_SUCCESS) {
+ pr_err("%s: json error %s\n", fn, jsmn_strerror(res));
+ goto error_free;
+ }
+ if (len)
+ *len = parser.toknext;
+ return tokens;
+error_free:
+ free(tokens);
+error:
+ unmapfile(*map, *size);
+ return NULL;
+}
+
+void free_json(char *map, size_t size, jsmntok_t *tokens)
+{
+ free(tokens);
+ unmapfile(map, size);
+}
+
+static int countchar(char *map, char c, int end)
+{
+ int i;
+ int count = 0;
+ for (i = 0; i < end; i++)
+ if (map[i] == c)
+ count++;
+ return count;
+}
+
+/* Return line number of a jsmn token */
+int json_line(char *map, jsmntok_t *t)
+{
+ return countchar(map, '\n', t->start) + 1;
+}
+
+static const char * const jsmn_types[] = {
+ [JSMN_PRIMITIVE] = "primitive",
+ [JSMN_ARRAY] = "array",
+ [JSMN_OBJECT] = "object",
+ [JSMN_STRING] = "string"
+};
+
+#define LOOKUP(a, i) ((i) < (sizeof(a)/sizeof(*(a))) ? ((a)[i]) : "?")
+
+/* Return type name of a jsmn token */
+const char *json_name(jsmntok_t *t)
+{
+ return LOOKUP(jsmn_types, t->type);
+}
+
+int json_len(jsmntok_t *t)
+{
+ return t->end - t->start;
+}
+
+/* Is string t equal to s? */
+int json_streq(char *map, jsmntok_t *t, const char *s)
+{
+ unsigned len = json_len(t);
+ return len == strlen(s) && !strncasecmp(map + t->start, s, len);
+}
diff --git a/tools/perf/pmu-events/json.h b/tools/perf/pmu-events/json.h
new file mode 100644
index 000000000000..278ebd32cfb6
--- /dev/null
+++ b/tools/perf/pmu-events/json.h
@@ -0,0 +1,38 @@
+#ifndef JSON_H
+#define JSON_H 1
+
+#include "jsmn.h"
+
+jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len);
+void free_json(char *map, size_t size, jsmntok_t *tokens);
+int json_line(char *map, jsmntok_t *t);
+const char *json_name(jsmntok_t *t);
+int json_streq(char *map, jsmntok_t *t, const char *s);
+int json_len(jsmntok_t *t);
+
+extern int verbose;
+
+#include <stdbool.h>
+
+extern int eprintf(int level, int var, const char *fmt, ...);
+#define pr_fmt(fmt) fmt
+
+#define pr_err(fmt, ...) \
+ eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
+
+#define pr_info(fmt, ...) \
+ eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
+
+#define pr_debug(fmt, ...) \
+ eprintf(2, verbose, pr_fmt(fmt), ##__VA_ARGS__)
+
+#ifndef roundup
+#define roundup(x, y) ( \
+{ \
+ const typeof(y) __y = y; \
+ (((x) + (__y - 1)) / __y) * __y; \
+} \
+)
+#endif
+
+#endif
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
new file mode 100644
index 000000000000..2eaef595d8a0
--- /dev/null
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -0,0 +1,37 @@
+#ifndef PMU_EVENTS_H
+#define PMU_EVENTS_H
+
+/*
+ * Describe each PMU event. Each CPU has a table of PMU events.
+ */
+struct pmu_event {
+ const char *name;
+ const char *event;
+ const char *desc;
+ const char *topic;
+ const char *long_desc;
+};
+
+/*
+ *
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpustr() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+ const char *cpuid;
+ const char *version;
+ const char *type; /* core, uncore etc */
+ struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+extern struct pmu_events_map pmu_events_map[];
+
+#endif
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ea34c5a32c11..d92e02006fb8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -384,15 +384,14 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
struct perf_evsel *evsel, int cpu)
{
- int thread, err;
+ int thread;
int nr_threads = perf_evlist__nr_threads(evlist, evsel);
if (!evsel->fd)
return -EINVAL;
for (thread = 0; thread < nr_threads; thread++) {
- err = ioctl(FD(evsel, cpu, thread),
- PERF_EVENT_IOC_ENABLE, 0);
+ int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
if (err)
return err;
}
@@ -403,14 +402,14 @@ static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
struct perf_evsel *evsel,
int thread)
{
- int cpu, err;
+ int cpu;
int nr_cpus = cpu_map__nr(evlist->cpus);
if (!evsel->fd)
return -EINVAL;
for (cpu = 0; cpu < nr_cpus; cpu++) {
- err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
+ int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
if (err)
return err;
}
@@ -1606,10 +1605,9 @@ void perf_evlist__close(struct perf_evlist *evlist)
struct perf_evsel *evsel;
int ncpus = cpu_map__nr(evlist->cpus);
int nthreads = thread_map__nr(evlist->threads);
- int n;
evlist__for_each_entry_reverse(evlist, evsel) {
- n = evsel->cpus ? evsel->cpus->nr : ncpus;
+ int n = evsel->cpus ? evsel->cpus->nr : ncpus;
perf_evsel__close(evsel, n, nthreads);
}
}
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 380e84c3af3d..8bc271141d9d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -985,14 +985,13 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
{
- int cpu, thread;
-
if (evsel->system_wide)
nthreads = 1;
evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
if (evsel->fd) {
+ int cpu, thread;
for (cpu = 0; cpu < ncpus; cpu++) {
for (thread = 0; thread < nthreads; thread++) {
FD(evsel, cpu, thread) = -1;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d306ca118449..d30109b421ee 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -151,4 +151,5 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
*/
int get_cpuid(char *buffer, size_t sz);
+char *get_cpuid_str(void);
#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 7591a0c37473..16c06d3ae577 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -90,6 +90,7 @@ struct intel_pt_decoder {
bool pge;
bool have_tma;
bool have_cyc;
+ bool fixup_last_mtc;
uint64_t pos;
uint64_t last_ip;
uint64_t ip;
@@ -586,10 +587,31 @@ struct intel_pt_calc_cyc_to_tsc_info {
uint64_t tsc_timestamp;
uint64_t timestamp;
bool have_tma;
+ bool fixup_last_mtc;
bool from_mtc;
double cbr_cyc_to_tsc;
};
+/*
+ * MTC provides a 8-bit slice of CTC but the TMA packet only provides the lower
+ * 16 bits of CTC. If mtc_shift > 8 then some of the MTC bits are not in the CTC
+ * provided by the TMA packet. Fix-up the last_mtc calculated from the TMA
+ * packet by copying the missing bits from the current MTC assuming the least
+ * difference between the two, and that the current MTC comes after last_mtc.
+ */
+static void intel_pt_fixup_last_mtc(uint32_t mtc, int mtc_shift,
+ uint32_t *last_mtc)
+{
+ uint32_t first_missing_bit = 1U << (16 - mtc_shift);
+ uint32_t mask = ~(first_missing_bit - 1);
+
+ *last_mtc |= mtc & mask;
+ if (*last_mtc >= mtc) {
+ *last_mtc -= first_missing_bit;
+ *last_mtc &= 0xff;
+ }
+}
+
static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
{
struct intel_pt_decoder *decoder = pkt_info->decoder;
@@ -619,6 +641,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
return 0;
mtc = pkt_info->packet.payload;
+ if (decoder->mtc_shift > 8 && data->fixup_last_mtc) {
+ data->fixup_last_mtc = false;
+ intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
+ &data->last_mtc);
+ }
if (mtc > data->last_mtc)
mtc_delta = mtc - data->last_mtc;
else
@@ -687,6 +714,7 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
data->ctc_delta = 0;
data->have_tma = true;
+ data->fixup_last_mtc = true;
return 0;
@@ -753,6 +781,7 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder,
.tsc_timestamp = decoder->tsc_timestamp,
.timestamp = decoder->timestamp,
.have_tma = decoder->have_tma,
+ .fixup_last_mtc = decoder->fixup_last_mtc,
.from_mtc = from_mtc,
.cbr_cyc_to_tsc = 0,
};
@@ -1271,6 +1300,7 @@ static void intel_pt_calc_tma(struct intel_pt_decoder *decoder)
}
decoder->ctc_delta = 0;
decoder->have_tma = true;
+ decoder->fixup_last_mtc = true;
intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x CTC rem %#x\n",
decoder->ctc_timestamp, decoder->last_mtc, ctc_rem);
}
@@ -1285,6 +1315,12 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
mtc = decoder->packet.payload;
+ if (decoder->mtc_shift > 8 && decoder->fixup_last_mtc) {
+ decoder->fixup_last_mtc = false;
+ intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
+ &decoder->last_mtc);
+ }
+
if (mtc > decoder->last_mtc)
mtc_delta = mtc - decoder->last_mtc;
else
@@ -1353,6 +1389,8 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
timestamp, decoder->timestamp);
else
decoder->timestamp = timestamp;
+
+ decoder->timestamp_insn_cnt = 0;
}
/* Walk PSB+ packets when already in sync. */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 18e4519abef2..df85b9efd80f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1745,9 +1745,8 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
int max_stack)
{
struct ip_callchain *chain = sample->callchain;
- int chain_nr = min(max_stack, (int)chain->nr);
+ int chain_nr = min(max_stack, (int)chain->nr), i;
u8 cpumode = PERF_RECORD_MISC_USER;
- int i, j, err;
u64 ip;
for (i = 0; i < chain_nr; i++) {
@@ -1758,7 +1757,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
/* LBR only affects the user callchain */
if (i != chain_nr) {
struct branch_stack *lbr_stack = sample->branch_stack;
- int lbr_nr = lbr_stack->nr;
+ int lbr_nr = lbr_stack->nr, j;
/*
* LBR callstack can only get user call chain.
* The mix_chain_nr is kernel call chain
@@ -1772,6 +1771,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
int mix_chain_nr = i + 1 + lbr_nr + 1;
for (j = 0; j < mix_chain_nr; j++) {
+ int err;
if (callchain_param.order == ORDER_CALLEE) {
if (j < i + 1)
ip = chain->ips[j];
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 33546c3ac1fe..4e778eae1510 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -924,6 +924,7 @@ config_term_avail(int term_type, struct parse_events_error *err)
case PARSE_EVENTS__TERM_TYPE_CONFIG1:
case PARSE_EVENTS__TERM_TYPE_CONFIG2:
case PARSE_EVENTS__TERM_TYPE_NAME:
+ case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
return true;
default:
if (!err)
@@ -1458,7 +1459,7 @@ comp_pmu(const void *p1, const void *p2)
struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1;
struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2;
- return strcmp(pmu1->symbol, pmu2->symbol);
+ return strcasecmp(pmu1->symbol, pmu2->symbol);
}
static void perf_pmu__parse_cleanup(void)
@@ -2263,7 +2264,8 @@ out_enomem:
/*
* Print the help text for the event symbols:
*/
-void print_events(const char *event_glob, bool name_only)
+void print_events(const char *event_glob, bool name_only, bool quiet_flag,
+ bool long_desc)
{
print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
@@ -2273,7 +2275,7 @@ void print_events(const char *event_glob, bool name_only)
print_hwcache_events(event_glob, name_only);
- print_pmu_events(event_glob, name_only);
+ print_pmu_events(event_glob, name_only, quiet_flag, long_desc);
if (event_glob != NULL)
return;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8d09a976fca8..da246a3ddb69 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -172,7 +172,8 @@ void parse_events_update_lists(struct list_head *list_event,
void parse_events_evlist_error(struct parse_events_evlist *data,
int idx, const char *str);
-void print_events(const char *event_glob, bool name_only);
+void print_events(const char *event_glob, bool name_only, bool quiet,
+ bool long_desc);
struct event_symbol {
const char *symbol;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2babcdf62839..b1474dcadfa2 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -12,6 +12,9 @@
#include "pmu.h"
#include "parse-events.h"
#include "cpumap.h"
+#include "header.h"
+#include "pmu-events/pmu-events.h"
+#include "cache.h"
struct perf_pmu_format {
char *name;
@@ -220,7 +223,8 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
}
static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
- char *desc __maybe_unused, char *val)
+ char *desc, char *val, char *long_desc,
+ char *topic)
{
struct perf_pmu_alias *alias;
int ret;
@@ -253,6 +257,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
perf_pmu__parse_snapshot(alias, dir, name);
}
+ alias->desc = desc ? strdup(desc) : NULL;
+ alias->long_desc = long_desc ? strdup(long_desc) :
+ desc ? strdup(desc) : NULL;
+ alias->topic = topic ? strdup(topic) : NULL;
+
list_add_tail(&alias->list, list);
return 0;
@@ -269,7 +278,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
buf[ret] = 0;
- return __perf_pmu__new_alias(list, dir, name, NULL, buf);
+ return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL);
}
static inline bool pmu_alias_info_file(char *name)
@@ -473,6 +482,68 @@ static struct cpu_map *pmu_cpumask(const char *name)
return cpus;
}
+/*
+ * Return the CPU id as a raw string.
+ *
+ * Each architecture should provide a more precise id string that
+ * can be use to match the architecture's "mapfile".
+ */
+char * __weak get_cpuid_str(void)
+{
+ return NULL;
+}
+
+/*
+ * From the pmu_events_map, find the table of PMU events that corresponds
+ * to the current running CPU. Then, add all PMU events from that table
+ * as aliases.
+ */
+static void pmu_add_cpu_aliases(struct list_head *head)
+{
+ int i;
+ struct pmu_events_map *map;
+ struct pmu_event *pe;
+ char *cpuid;
+
+ cpuid = getenv("PERF_CPUID");
+ if (cpuid)
+ cpuid = strdup(cpuid);
+ if (!cpuid)
+ cpuid = get_cpuid_str();
+ if (!cpuid)
+ return;
+
+ pr_debug("Using CPUID %s\n", cpuid);
+
+ i = 0;
+ while (1) {
+ map = &pmu_events_map[i++];
+ if (!map->table)
+ goto out;
+
+ if (!strcmp(map->cpuid, cpuid))
+ break;
+ }
+
+ /*
+ * Found a matching PMU events table. Create aliases
+ */
+ i = 0;
+ while (1) {
+ pe = &map->table[i++];
+ if (!pe->name)
+ break;
+
+ /* need type casts to override 'const' */
+ __perf_pmu__new_alias(head, NULL, (char *)pe->name,
+ (char *)pe->desc, (char *)pe->event,
+ (char *)pe->long_desc, (char *)pe->topic);
+ }
+
+out:
+ free(cpuid);
+}
+
struct perf_event_attr * __weak
perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
{
@@ -497,6 +568,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
if (pmu_aliases(name, &aliases))
return NULL;
+ if (!strcmp(name, "cpu"))
+ pmu_add_cpu_aliases(&aliases);
+
if (pmu_type(name, &type))
return NULL;
@@ -983,21 +1057,63 @@ static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
return buf;
}
-static int cmp_string(const void *a, const void *b)
+struct sevent {
+ char *name;
+ char *desc;
+ char *topic;
+};
+
+static int cmp_sevent(const void *a, const void *b)
{
- const char * const *as = a;
- const char * const *bs = b;
- return strcmp(*as, *bs);
+ const struct sevent *as = a;
+ const struct sevent *bs = b;
+
+ /* Put extra events last */
+ if (!!as->desc != !!bs->desc)
+ return !!as->desc - !!bs->desc;
+ if (as->topic && bs->topic) {
+ int n = strcmp(as->topic, bs->topic);
+
+ if (n)
+ return n;
+ }
+ return strcmp(as->name, bs->name);
}
-void print_pmu_events(const char *event_glob, bool name_only)
+static void wordwrap(char *s, int start, int max, int corr)
+{
+ int column = start;
+ int n;
+
+ while (*s) {
+ int wlen = strcspn(s, " \t");
+
+ if (column + wlen >= max && column > start) {
+ printf("\n%*s", start, "");
+ column = start + corr;
+ }
+ n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+ if (n <= 0)
+ break;
+ s += wlen;
+ column += n;
+ while (isspace(*s))
+ s++;
+ }
+}
+
+void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
+ bool long_desc)
{
struct perf_pmu *pmu;
struct perf_pmu_alias *alias;
char buf[1024];
int printed = 0;
int len, j;
- char **aliases;
+ struct sevent *aliases;
+ int numdesc = 0;
+ int columns = pager_get_columns();
+ char *topic = NULL;
pmu = NULL;
len = 0;
@@ -1007,14 +1123,15 @@ void print_pmu_events(const char *event_glob, bool name_only)
if (pmu->selectable)
len++;
}
- aliases = zalloc(sizeof(char *) * len);
+ aliases = zalloc(sizeof(struct sevent) * len);
if (!aliases)
goto out_enomem;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
list_for_each_entry(alias, &pmu->aliases, list) {
- char *name = format_alias(buf, sizeof(buf), pmu, alias);
+ char *name = alias->desc ? alias->name :
+ format_alias(buf, sizeof(buf), pmu, alias);
bool is_cpu = !strcmp(pmu->name, "cpu");
if (event_glob != NULL &&
@@ -1023,12 +1140,21 @@ void print_pmu_events(const char *event_glob, bool name_only)
event_glob))))
continue;
- if (is_cpu && !name_only)
+ if (is_cpu && !name_only && !alias->desc)
name = format_alias_or(buf, sizeof(buf), pmu, alias);
- aliases[j] = strdup(name);
- if (aliases[j] == NULL)
+ aliases[j].name = name;
+ if (is_cpu && !name_only && !alias->desc)
+ aliases[j].name = format_alias_or(buf,
+ sizeof(buf),
+ pmu, alias);
+ aliases[j].name = strdup(aliases[j].name);
+ if (!aliases[j].name)
goto out_enomem;
+
+ aliases[j].desc = long_desc ? alias->long_desc :
+ alias->desc;
+ aliases[j].topic = alias->topic;
j++;
}
if (pmu->selectable &&
@@ -1036,25 +1162,39 @@ void print_pmu_events(const char *event_glob, bool name_only)
char *s;
if (asprintf(&s, "%s//", pmu->name) < 0)
goto out_enomem;
- aliases[j] = s;
+ aliases[j].name = s;
j++;
}
}
len = j;
- qsort(aliases, len, sizeof(char *), cmp_string);
+ qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
for (j = 0; j < len; j++) {
if (name_only) {
- printf("%s ", aliases[j]);
+ printf("%s ", aliases[j].name);
continue;
}
- printf(" %-50s [Kernel PMU event]\n", aliases[j]);
+ if (aliases[j].desc && !quiet_flag) {
+ if (numdesc++ == 0)
+ printf("\n");
+ if (aliases[j].topic && (!topic ||
+ strcmp(topic, aliases[j].topic))) {
+ printf("%s%s:\n", topic ? "\n" : "",
+ aliases[j].topic);
+ topic = aliases[j].topic;
+ }
+ printf(" %-50s\n", aliases[j].name);
+ printf("%*s", 8, "[");
+ wordwrap(aliases[j].desc, 8, columns, 0);
+ printf("]\n");
+ } else
+ printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
printed++;
}
if (printed && pager_in_use())
printf("\n");
out_free:
for (j = 0; j < len; j++)
- zfree(&aliases[j]);
+ zfree(&aliases[j].name);
zfree(&aliases);
return;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 743422ad900b..25712034c815 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -40,6 +40,9 @@ struct perf_pmu_info {
struct perf_pmu_alias {
char *name;
+ char *desc;
+ char *long_desc;
+ char *topic;
struct list_head terms; /* HEAD struct parse_events_term -> list */
struct list_head list; /* ELEM */
char unit[UNIT_MAX_LEN+1];
@@ -71,7 +74,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
-void print_pmu_events(const char *event_glob, bool name_only);
+void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
+ bool long_desc);
bool pmu_have_event(const char *pname, const char *name);
int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcfbef07b92d..d281ae2b54e8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -213,7 +213,7 @@ static int convert_exec_to_group(const char *exec, char **result)
goto out;
}
- for (ptr2 = ptr1; ptr2 != '\0'; ptr2++) {
+ for (ptr2 = ptr1; *ptr2 != '\0'; ptr2++) {
if (!isalnum(*ptr2) && *ptr2 != '_') {
*ptr2 = '\0';
break;
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index b268a6648a5d..318424ea561d 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -66,9 +66,8 @@ static inline ssize_t strbuf_avail(const struct strbuf *sb) {
int strbuf_grow(struct strbuf *buf, size_t);
static inline int strbuf_setlen(struct strbuf *sb, size_t len) {
- int ret;
if (!sb->alloc) {
- ret = strbuf_grow(sb, 0);
+ int ret = strbuf_grow(sb, 0);
if (ret)
return ret;
}
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8b10a55410a2..f5af87f66663 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -14,13 +14,12 @@
int thread__init_map_groups(struct thread *thread, struct machine *machine)
{
- struct thread *leader;
pid_t pid = thread->pid_;
if (pid == thread->tid || pid == -1) {
thread->mg = map_groups__new(machine);
} else {
- leader = __machine__findnew_thread(machine, pid, pid);
+ struct thread *leader = __machine__findnew_thread(machine, pid, pid);
if (leader) {
thread->mg = map_groups__get(leader->mg);
thread__put(leader);
@@ -130,11 +129,10 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
bool exec)
{
struct comm *new, *curr = thread__comm(thread);
- int err;
/* Override the default :tid entry */
if (!thread->comm_set) {
- err = comm__override(curr, str, timestamp, exec);
+ int err = comm__override(curr, str, timestamp, exec);
if (err)
return err;
} else {
@@ -270,10 +268,9 @@ static int thread__clone_map_groups(struct thread *thread,
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
{
- int err;
-
if (parent->comm_set) {
const char *comm = thread__comm_str(parent);
+ int err;
if (!comm)
return -ENOMEM;
err = thread__set_comm(thread, comm, timestamp);
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 1cc6d64c39b7..db54a33f850f 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -19,6 +19,7 @@ SUB_DIRS = alignment \
dscr \
mm \
pmu \
+ signal \
primitives \
stringloops \
switch_endian \
diff --git a/tools/testing/selftests/powerpc/fpu_asm.h b/tools/testing/selftests/powerpc/fpu_asm.h
new file mode 100644
index 000000000000..6a387d255e27
--- /dev/null
+++ b/tools/testing/selftests/powerpc/fpu_asm.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _SELFTESTS_POWERPC_FPU_ASM_H
+#define _SELFTESTS_POWERPC_FPU_ASM_H
+#include "basic_asm.h"
+
+#define PUSH_FPU(stack_size) \
+ stfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \
+ stfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \
+ stfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \
+ stfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \
+ stfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \
+ stfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \
+ stfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \
+ stfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \
+ stfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \
+ stfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \
+ stfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \
+ stfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \
+ stfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \
+ stfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \
+ stfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \
+ stfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \
+ stfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \
+ stfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1);
+
+#define POP_FPU(stack_size) \
+ lfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \
+ lfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \
+ lfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \
+ lfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \
+ lfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \
+ lfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \
+ lfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \
+ lfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \
+ lfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \
+ lfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \
+ lfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \
+ lfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \
+ lfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \
+ lfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \
+ lfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \
+ lfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \
+ lfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \
+ lfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1);
+
+/*
+ * Careful calling this, it will 'clobber' fpu (by design)
+ * Don't call this from C
+ */
+FUNC_START(load_fpu)
+ lfd f14,0(r3)
+ lfd f15,8(r3)
+ lfd f16,16(r3)
+ lfd f17,24(r3)
+ lfd f18,32(r3)
+ lfd f19,40(r3)
+ lfd f20,48(r3)
+ lfd f21,56(r3)
+ lfd f22,64(r3)
+ lfd f23,72(r3)
+ lfd f24,80(r3)
+ lfd f25,88(r3)
+ lfd f26,96(r3)
+ lfd f27,104(r3)
+ lfd f28,112(r3)
+ lfd f29,120(r3)
+ lfd f30,128(r3)
+ lfd f31,136(r3)
+ blr
+FUNC_END(load_fpu)
+
+#endif /* _SELFTESTS_POWERPC_FPU_ASM_H */
diff --git a/tools/testing/selftests/powerpc/gpr_asm.h b/tools/testing/selftests/powerpc/gpr_asm.h
new file mode 100644
index 000000000000..f6f38852d3a0
--- /dev/null
+++ b/tools/testing/selftests/powerpc/gpr_asm.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _SELFTESTS_POWERPC_GPR_ASM_H
+#define _SELFTESTS_POWERPC_GPR_ASM_H
+
+#include "basic_asm.h"
+
+#define __PUSH_NVREGS(top_pos); \
+ std r31,(top_pos)(%r1); \
+ std r30,(top_pos - 8)(%r1); \
+ std r29,(top_pos - 16)(%r1); \
+ std r28,(top_pos - 24)(%r1); \
+ std r27,(top_pos - 32)(%r1); \
+ std r26,(top_pos - 40)(%r1); \
+ std r25,(top_pos - 48)(%r1); \
+ std r24,(top_pos - 56)(%r1); \
+ std r23,(top_pos - 64)(%r1); \
+ std r22,(top_pos - 72)(%r1); \
+ std r21,(top_pos - 80)(%r1); \
+ std r20,(top_pos - 88)(%r1); \
+ std r19,(top_pos - 96)(%r1); \
+ std r18,(top_pos - 104)(%r1); \
+ std r17,(top_pos - 112)(%r1); \
+ std r16,(top_pos - 120)(%r1); \
+ std r15,(top_pos - 128)(%r1); \
+ std r14,(top_pos - 136)(%r1)
+
+#define __POP_NVREGS(top_pos); \
+ ld r31,(top_pos)(%r1); \
+ ld r30,(top_pos - 8)(%r1); \
+ ld r29,(top_pos - 16)(%r1); \
+ ld r28,(top_pos - 24)(%r1); \
+ ld r27,(top_pos - 32)(%r1); \
+ ld r26,(top_pos - 40)(%r1); \
+ ld r25,(top_pos - 48)(%r1); \
+ ld r24,(top_pos - 56)(%r1); \
+ ld r23,(top_pos - 64)(%r1); \
+ ld r22,(top_pos - 72)(%r1); \
+ ld r21,(top_pos - 80)(%r1); \
+ ld r20,(top_pos - 88)(%r1); \
+ ld r19,(top_pos - 96)(%r1); \
+ ld r18,(top_pos - 104)(%r1); \
+ ld r17,(top_pos - 112)(%r1); \
+ ld r16,(top_pos - 120)(%r1); \
+ ld r15,(top_pos - 128)(%r1); \
+ ld r14,(top_pos - 136)(%r1)
+
+#define PUSH_NVREGS(stack_size) \
+ __PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE)
+
+/* 18 NV FPU REGS */
+#define PUSH_NVREGS_BELOW_FPU(stack_size) \
+ __PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8))
+
+#define POP_NVREGS(stack_size) \
+ __POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE)
+
+/* 18 NV FPU REGS */
+#define POP_NVREGS_BELOW_FPU(stack_size) \
+ __POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8))
+
+/*
+ * Careful calling this, it will 'clobber' NVGPRs (by design)
+ * Don't call this from C
+ */
+FUNC_START(load_gpr)
+ ld r14,0(r3)
+ ld r15,8(r3)
+ ld r16,16(r3)
+ ld r17,24(r3)
+ ld r18,32(r3)
+ ld r19,40(r3)
+ ld r20,48(r3)
+ ld r21,56(r3)
+ ld r22,64(r3)
+ ld r23,72(r3)
+ ld r24,80(r3)
+ ld r25,88(r3)
+ ld r26,96(r3)
+ ld r27,104(r3)
+ ld r28,112(r3)
+ ld r29,120(r3)
+ ld r30,128(r3)
+ ld r31,136(r3)
+ blr
+FUNC_END(load_gpr)
+
+
+#endif /* _SELFTESTS_POWERPC_GPR_ASM_H */
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index 52f9be7f61f0..248a820048df 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -19,9 +19,9 @@
#include "subunit.h"
#include "utils.h"
-#define TIMEOUT 120
#define KILL_TIMEOUT 5
+static uint64_t timeout = 120;
int run_test(int (test_function)(void), char *name)
{
@@ -44,7 +44,7 @@ int run_test(int (test_function)(void), char *name)
setpgid(pid, pid);
/* Wake us up in timeout seconds */
- alarm(TIMEOUT);
+ alarm(timeout);
terminated = false;
wait:
@@ -94,6 +94,11 @@ static struct sigaction alarm_action = {
.sa_handler = alarm_handler,
};
+void test_harness_set_timeout(uint64_t time)
+{
+ timeout = time;
+}
+
int test_harness(int (test_function)(void), char *name)
{
int rc;
diff --git a/tools/testing/selftests/powerpc/math/Makefile b/tools/testing/selftests/powerpc/math/Makefile
index 5b88875d5955..a505b66d408a 100644
--- a/tools/testing/selftests/powerpc/math/Makefile
+++ b/tools/testing/selftests/powerpc/math/Makefile
@@ -1,4 +1,4 @@
-TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal
+TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal vsx_preempt
all: $(TEST_PROGS)
@@ -13,6 +13,9 @@ vmx_syscall: vmx_asm.S
vmx_preempt: vmx_asm.S
vmx_signal: vmx_asm.S
+vsx_preempt: CFLAGS += -mvsx
+vsx_preempt: vsx_asm.S
+
include ../../lib.mk
clean:
diff --git a/tools/testing/selftests/powerpc/math/fpu_asm.S b/tools/testing/selftests/powerpc/math/fpu_asm.S
index f3711d80e709..241f067a510f 100644
--- a/tools/testing/selftests/powerpc/math/fpu_asm.S
+++ b/tools/testing/selftests/powerpc/math/fpu_asm.S
@@ -8,70 +8,7 @@
*/
#include "../basic_asm.h"
-
-#define PUSH_FPU(pos) \
- stfd f14,pos(sp); \
- stfd f15,pos+8(sp); \
- stfd f16,pos+16(sp); \
- stfd f17,pos+24(sp); \
- stfd f18,pos+32(sp); \
- stfd f19,pos+40(sp); \
- stfd f20,pos+48(sp); \
- stfd f21,pos+56(sp); \
- stfd f22,pos+64(sp); \
- stfd f23,pos+72(sp); \
- stfd f24,pos+80(sp); \
- stfd f25,pos+88(sp); \
- stfd f26,pos+96(sp); \
- stfd f27,pos+104(sp); \
- stfd f28,pos+112(sp); \
- stfd f29,pos+120(sp); \
- stfd f30,pos+128(sp); \
- stfd f31,pos+136(sp);
-
-#define POP_FPU(pos) \
- lfd f14,pos(sp); \
- lfd f15,pos+8(sp); \
- lfd f16,pos+16(sp); \
- lfd f17,pos+24(sp); \
- lfd f18,pos+32(sp); \
- lfd f19,pos+40(sp); \
- lfd f20,pos+48(sp); \
- lfd f21,pos+56(sp); \
- lfd f22,pos+64(sp); \
- lfd f23,pos+72(sp); \
- lfd f24,pos+80(sp); \
- lfd f25,pos+88(sp); \
- lfd f26,pos+96(sp); \
- lfd f27,pos+104(sp); \
- lfd f28,pos+112(sp); \
- lfd f29,pos+120(sp); \
- lfd f30,pos+128(sp); \
- lfd f31,pos+136(sp);
-
-# Careful calling this, it will 'clobber' fpu (by design)
-# Don't call this from C
-FUNC_START(load_fpu)
- lfd f14,0(r3)
- lfd f15,8(r3)
- lfd f16,16(r3)
- lfd f17,24(r3)
- lfd f18,32(r3)
- lfd f19,40(r3)
- lfd f20,48(r3)
- lfd f21,56(r3)
- lfd f22,64(r3)
- lfd f23,72(r3)
- lfd f24,80(r3)
- lfd f25,88(r3)
- lfd f26,96(r3)
- lfd f27,104(r3)
- lfd f28,112(r3)
- lfd f29,120(r3)
- lfd f30,128(r3)
- lfd f31,136(r3)
- blr
-FUNC_END(load_fpu)
+#include "../fpu_asm.h"
FUNC_START(check_fpu)
mr r4,r3
@@ -138,9 +75,9 @@ FUNC_START(test_fpu)
# r4 holds pointer to the pid
# f14-f31 are non volatiles
PUSH_BASIC_STACK(256)
+ PUSH_FPU(256)
std r3,STACK_FRAME_PARAM(0)(sp) # Address of darray
std r4,STACK_FRAME_PARAM(1)(sp) # Address of pid
- PUSH_FPU(STACK_FRAME_LOCAL(2,0))
bl load_fpu
nop
@@ -155,7 +92,7 @@ FUNC_START(test_fpu)
bl check_fpu
nop
- POP_FPU(STACK_FRAME_LOCAL(2,0))
+ POP_FPU(256)
POP_BASIC_STACK(256)
blr
FUNC_END(test_fpu)
@@ -166,10 +103,10 @@ FUNC_END(test_fpu)
# registers while running is not zero.
FUNC_START(preempt_fpu)
PUSH_BASIC_STACK(256)
+ PUSH_FPU(256)
std r3,STACK_FRAME_PARAM(0)(sp) # double *darray
std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
std r5,STACK_FRAME_PARAM(2)(sp) # int *running
- PUSH_FPU(STACK_FRAME_LOCAL(3,0))
bl load_fpu
nop
@@ -192,7 +129,7 @@ FUNC_START(preempt_fpu)
cmpwi r5,0
bne 2b
-3: POP_FPU(STACK_FRAME_LOCAL(3,0))
+3: POP_FPU(256)
POP_BASIC_STACK(256)
blr
FUNC_END(preempt_fpu)
diff --git a/tools/testing/selftests/powerpc/math/vmx_asm.S b/tools/testing/selftests/powerpc/math/vmx_asm.S
index 1b8c248b3ac1..fd74da488625 100644
--- a/tools/testing/selftests/powerpc/math/vmx_asm.S
+++ b/tools/testing/selftests/powerpc/math/vmx_asm.S
@@ -8,90 +8,7 @@
*/
#include "../basic_asm.h"
-
-# POS MUST BE 16 ALIGNED!
-#define PUSH_VMX(pos,reg) \
- li reg,pos; \
- stvx v20,reg,sp; \
- addi reg,reg,16; \
- stvx v21,reg,sp; \
- addi reg,reg,16; \
- stvx v22,reg,sp; \
- addi reg,reg,16; \
- stvx v23,reg,sp; \
- addi reg,reg,16; \
- stvx v24,reg,sp; \
- addi reg,reg,16; \
- stvx v25,reg,sp; \
- addi reg,reg,16; \
- stvx v26,reg,sp; \
- addi reg,reg,16; \
- stvx v27,reg,sp; \
- addi reg,reg,16; \
- stvx v28,reg,sp; \
- addi reg,reg,16; \
- stvx v29,reg,sp; \
- addi reg,reg,16; \
- stvx v30,reg,sp; \
- addi reg,reg,16; \
- stvx v31,reg,sp;
-
-# POS MUST BE 16 ALIGNED!
-#define POP_VMX(pos,reg) \
- li reg,pos; \
- lvx v20,reg,sp; \
- addi reg,reg,16; \
- lvx v21,reg,sp; \
- addi reg,reg,16; \
- lvx v22,reg,sp; \
- addi reg,reg,16; \
- lvx v23,reg,sp; \
- addi reg,reg,16; \
- lvx v24,reg,sp; \
- addi reg,reg,16; \
- lvx v25,reg,sp; \
- addi reg,reg,16; \
- lvx v26,reg,sp; \
- addi reg,reg,16; \
- lvx v27,reg,sp; \
- addi reg,reg,16; \
- lvx v28,reg,sp; \
- addi reg,reg,16; \
- lvx v29,reg,sp; \
- addi reg,reg,16; \
- lvx v30,reg,sp; \
- addi reg,reg,16; \
- lvx v31,reg,sp;
-
-# Carefull this will 'clobber' vmx (by design)
-# Don't call this from C
-FUNC_START(load_vmx)
- li r5,0
- lvx v20,r5,r3
- addi r5,r5,16
- lvx v21,r5,r3
- addi r5,r5,16
- lvx v22,r5,r3
- addi r5,r5,16
- lvx v23,r5,r3
- addi r5,r5,16
- lvx v24,r5,r3
- addi r5,r5,16
- lvx v25,r5,r3
- addi r5,r5,16
- lvx v26,r5,r3
- addi r5,r5,16
- lvx v27,r5,r3
- addi r5,r5,16
- lvx v28,r5,r3
- addi r5,r5,16
- lvx v29,r5,r3
- addi r5,r5,16
- lvx v30,r5,r3
- addi r5,r5,16
- lvx v31,r5,r3
- blr
-FUNC_END(load_vmx)
+#include "../vmx_asm.h"
# Should be safe from C, only touches r4, r5 and v0,v1,v2
FUNC_START(check_vmx)
diff --git a/tools/testing/selftests/powerpc/math/vsx_asm.S b/tools/testing/selftests/powerpc/math/vsx_asm.S
new file mode 100644
index 000000000000..a110dd882d5e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/math/vsx_asm.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "../basic_asm.h"
+#include "../vsx_asm.h"
+
+#long check_vsx(vector int *r3);
+#This function wraps storeing VSX regs to the end of an array and a
+#call to a comparison function in C which boils down to a memcmp()
+FUNC_START(check_vsx)
+ PUSH_BASIC_STACK(32)
+ std r3,STACK_FRAME_PARAM(0)(sp)
+ addi r3, r3, 16 * 12 #Second half of array
+ bl store_vsx
+ ld r3,STACK_FRAME_PARAM(0)(sp)
+ bl vsx_memcmp
+ POP_BASIC_STACK(32)
+ blr
+FUNC_END(check_vsx)
+
+# int preempt_vmx(vector int *varray, int *threads_starting,
+# int *running);
+# On starting will (atomically) decrement threads_starting as a signal
+# that the VMX have been loaded with varray. Will proceed to check the
+# validity of the VMX registers while running is not zero.
+FUNC_START(preempt_vsx)
+ PUSH_BASIC_STACK(512)
+ std r3,STACK_FRAME_PARAM(0)(sp) # vector int *varray
+ std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
+ std r5,STACK_FRAME_PARAM(2)(sp) # int *running
+
+ bl load_vsx
+ nop
+
+ sync
+ # Atomic DEC
+ ld r3,STACK_FRAME_PARAM(1)(sp)
+1: lwarx r4,0,r3
+ addi r4,r4,-1
+ stwcx. r4,0,r3
+ bne- 1b
+
+2: ld r3,STACK_FRAME_PARAM(0)(sp)
+ bl check_vsx
+ nop
+ cmpdi r3,0
+ bne 3f
+ ld r4,STACK_FRAME_PARAM(2)(sp)
+ ld r5,0(r4)
+ cmpwi r5,0
+ bne 2b
+
+3: POP_BASIC_STACK(512)
+ blr
+FUNC_END(preempt_vsx)
diff --git a/tools/testing/selftests/powerpc/math/vsx_preempt.c b/tools/testing/selftests/powerpc/math/vsx_preempt.c
new file mode 100644
index 000000000000..6387f03a0a6a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/math/vsx_preempt.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2015, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This test attempts to see if the VSX registers change across preemption.
+ * There is no way to be sure preemption happened so this test just
+ * uses many threads and a long wait. As such, a successful test
+ * doesn't mean much but a failure is bad.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "utils.h"
+
+/* Time to wait for workers to get preempted (seconds) */
+#define PREEMPT_TIME 20
+/*
+ * Factor by which to multiply number of online CPUs for total number of
+ * worker threads
+ */
+#define THREAD_FACTOR 8
+
+/*
+ * Ensure there is twice the number of non-volatile VMX regs!
+ * check_vmx() is going to use the other half as space to put the live
+ * registers before calling vsx_memcmp()
+ */
+__thread vector int varray[24] = {
+ {1, 2, 3, 4 }, {5, 6, 7, 8 }, {9, 10,11,12},
+ {13,14,15,16}, {17,18,19,20}, {21,22,23,24},
+ {25,26,27,28}, {29,30,31,32}, {33,34,35,36},
+ {37,38,39,40}, {41,42,43,44}, {45,46,47,48}
+};
+
+int threads_starting;
+int running;
+
+extern long preempt_vsx(vector int *varray, int *threads_starting, int *running);
+
+long vsx_memcmp(vector int *a) {
+ vector int zero = {0, 0, 0, 0};
+ int i;
+
+ FAIL_IF(a != varray);
+
+ for(i = 0; i < 12; i++) {
+ if (memcmp(&a[i + 12], &zero, sizeof(vector int)) == 0) {
+ fprintf(stderr, "Detected zero from the VSX reg %d\n", i + 12);
+ return 2;
+ }
+ }
+
+ if (memcmp(a, &a[12], 12 * sizeof(vector int))) {
+ long *p = (long *)a;
+ fprintf(stderr, "VSX mismatch\n");
+ for (i = 0; i < 24; i=i+2)
+ fprintf(stderr, "%d: 0x%08lx%08lx | 0x%08lx%08lx\n",
+ i/2 + i%2 + 20, p[i], p[i + 1], p[i + 24], p[i + 25]);
+ return 1;
+ }
+ return 0;
+}
+
+void *preempt_vsx_c(void *p)
+{
+ int i, j;
+ long rc;
+ srand(pthread_self());
+ for (i = 0; i < 12; i++)
+ for (j = 0; j < 4; j++) {
+ varray[i][j] = rand();
+ /* Don't want zero because it hides kernel problems */
+ if (varray[i][j] == 0)
+ j--;
+ }
+ rc = preempt_vsx(varray, &threads_starting, &running);
+ if (rc == 2)
+ fprintf(stderr, "Caught zeros in VSX compares\n");
+ return (void *)rc;
+}
+
+int test_preempt_vsx(void)
+{
+ int i, rc, threads;
+ pthread_t *tids;
+
+ threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
+ tids = malloc(threads * sizeof(pthread_t));
+ FAIL_IF(!tids);
+
+ running = true;
+ threads_starting = threads;
+ for (i = 0; i < threads; i++) {
+ rc = pthread_create(&tids[i], NULL, preempt_vsx_c, NULL);
+ FAIL_IF(rc);
+ }
+
+ setbuf(stdout, NULL);
+ /* Not really nessesary but nice to wait for every thread to start */
+ printf("\tWaiting for %d workers to start...", threads_starting);
+ while(threads_starting)
+ asm volatile("": : :"memory");
+ printf("done\n");
+
+ printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME);
+ sleep(PREEMPT_TIME);
+ printf("done\n");
+
+ printf("\tStopping workers...");
+ /*
+ * Working are checking this value every loop. In preempt_vsx 'cmpwi r5,0; bne 2b'.
+ * r5 will have loaded the value of running.
+ */
+ running = 0;
+ for (i = 0; i < threads; i++) {
+ void *rc_p;
+ pthread_join(tids[i], &rc_p);
+
+ /*
+ * Harness will say the fail was here, look at why preempt_vsx
+ * returned
+ */
+ if ((long) rc_p)
+ printf("oops\n");
+ FAIL_IF((long) rc_p);
+ }
+ printf("done\n");
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ return test_harness(test_preempt_vsx, "vsx_preempt");
+}
diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile
new file mode 100644
index 000000000000..f0eef27458e2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/Makefile
@@ -0,0 +1,13 @@
+TEST_PROGS := signal signal_tm
+
+all: $(TEST_PROGS)
+
+$(TEST_PROGS): ../harness.c ../utils.c signal.S
+
+CFLAGS += -maltivec
+signal_tm: CFLAGS += -mhtm
+
+include ../../lib.mk
+
+clean:
+ rm -f $(TEST_PROGS) *.o
diff --git a/tools/testing/selftests/powerpc/signal/signal.S b/tools/testing/selftests/powerpc/signal/signal.S
new file mode 100644
index 000000000000..7043d521df0a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/signal.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "../basic_asm.h"
+
+/* long signal_self(pid_t pid, int sig); */
+FUNC_START(signal_self)
+ li r0,37 /* sys_kill */
+ /* r3 already has our pid in it */
+ /* r4 already has signal type in it */
+ sc
+ bc 4,3,1f
+ subfze r3,r3
+1: blr
+FUNC_END(signal_self)
+
+/* long tm_signal_self(pid_t pid, int sig, int *ret); */
+FUNC_START(tm_signal_self)
+ PUSH_BASIC_STACK(8)
+ std r5,STACK_FRAME_PARAM(0)(sp) /* ret */
+ tbegin.
+ beq 1f
+ tsuspend.
+ li r0,37 /* sys_kill */
+ /* r3 already has our pid in it */
+ /* r4 already has signal type in it */
+ sc
+ ld r5,STACK_FRAME_PARAM(0)(sp) /* ret */
+ bc 4,3,2f
+ subfze r3,r3
+2: std r3,0(r5)
+ tabort. 0
+ tresume. /* Be nice to some cleanup, jumps back to tbegin then to 1: */
+ /*
+ * Transaction should be proper doomed and we should never get
+ * here
+ */
+ li r3,1
+ POP_BASIC_STACK(8)
+ blr
+1: li r3,0
+ POP_BASIC_STACK(8)
+ blr
+FUNC_END(tm_signal_self)
diff --git a/tools/testing/selftests/powerpc/signal/signal.c b/tools/testing/selftests/powerpc/signal/signal.c
new file mode 100644
index 000000000000..e7dedd28b3c2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/signal.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Sending one self a signal should always get delivered.
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <altivec.h>
+
+#include "utils.h"
+
+#define MAX_ATTEMPT 500000
+#define TIMEOUT 5
+
+extern long signal_self(pid_t pid, int sig);
+
+static sig_atomic_t signaled;
+static sig_atomic_t fail;
+
+static void signal_handler(int sig)
+{
+ if (sig == SIGUSR1)
+ signaled = 1;
+ else
+ fail = 1;
+}
+
+static int test_signal()
+{
+ int i;
+ struct sigaction act;
+ pid_t ppid = getpid();
+ pid_t pid;
+
+ act.sa_handler = signal_handler;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction SIGUSR1");
+ exit(1);
+ }
+ if (sigaction(SIGALRM, &act, NULL) < 0) {
+ perror("sigaction SIGALRM");
+ exit(1);
+ }
+
+ /* Don't do this for MAX_ATTEMPT, its simply too long */
+ for(i = 0; i < 1000; i++) {
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ exit(1);
+ }
+ if (pid == 0) {
+ signal_self(ppid, SIGUSR1);
+ exit(1);
+ } else {
+ alarm(0); /* Disable any pending */
+ alarm(2);
+ while (!signaled && !fail)
+ asm volatile("": : :"memory");
+ if (!signaled) {
+ fprintf(stderr, "Didn't get signal from child\n");
+ FAIL_IF(1); /* For the line number */
+ }
+ /* Otherwise we'll loop too fast and fork() will eventually fail */
+ waitpid(pid, NULL, 0);
+ }
+ }
+
+ for (i = 0; i < MAX_ATTEMPT; i++) {
+ long rc;
+
+ alarm(0); /* Disable any pending */
+ signaled = 0;
+ alarm(TIMEOUT);
+ rc = signal_self(ppid, SIGUSR1);
+ if (rc) {
+ fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
+ i, fail, rc);
+ FAIL_IF(1); /* For the line number */
+ }
+ while (!signaled && !fail)
+ asm volatile("": : :"memory");
+ if (!signaled) {
+ fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
+ i, fail, rc);
+ FAIL_IF(1); /* For the line number */
+ }
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ test_harness_set_timeout(300);
+ return test_harness(test_signal, "signal");
+}
diff --git a/tools/testing/selftests/powerpc/signal/signal_tm.c b/tools/testing/selftests/powerpc/signal/signal_tm.c
new file mode 100644
index 000000000000..2e7451a37cc6
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/signal_tm.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Sending one self a signal should always get delivered.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <altivec.h>
+
+#include "utils.h"
+#include "../tm/tm.h"
+
+#define MAX_ATTEMPT 500000
+#define TIMEOUT 10
+
+extern long tm_signal_self(pid_t pid, int sig, long *ret);
+
+static sig_atomic_t signaled;
+static sig_atomic_t fail;
+
+static void signal_handler(int sig)
+{
+ if (tcheck_active()) {
+ fail = 2;
+ return;
+ }
+
+ if (sig == SIGUSR1)
+ signaled = 1;
+ else
+ fail = 1;
+}
+
+static int test_signal_tm()
+{
+ int i;
+ struct sigaction act;
+
+ act.sa_handler = signal_handler;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction SIGUSR1");
+ exit(1);
+ }
+ if (sigaction(SIGALRM, &act, NULL) < 0) {
+ perror("sigaction SIGALRM");
+ exit(1);
+ }
+
+ SKIP_IF(!have_htm());
+
+ for (i = 0; i < MAX_ATTEMPT; i++) {
+ /*
+ * If anything bad happens in ASM and we fail to set ret
+ * because *handwave* TM this will cause failure
+ */
+ long ret = 0xdead;
+ long rc = 0xbeef;
+
+ alarm(0); /* Disable any pending */
+ signaled = 0;
+ alarm(TIMEOUT);
+ FAIL_IF(tcheck_transactional());
+ rc = tm_signal_self(getpid(), SIGUSR1, &ret);
+ if (ret == 0xdead)
+ /*
+ * This basically means the transaction aborted before we
+ * even got to the suspend... this is crazy but it
+ * happens.
+ * Yes this also means we might never make forward
+ * progress... the alarm() will trip eventually...
+ */
+ continue;
+
+ if (rc || ret) {
+ /* Ret is actually an errno */
+ printf("TEXASR 0x%016lx, TFIAR 0x%016lx\n",
+ __builtin_get_texasr(), __builtin_get_tfiar());
+ fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
+ i, fail, rc, ret);
+ FAIL_IF(ret);
+ }
+ while(!signaled && !fail)
+ asm volatile("": : :"memory");
+ if (!signaled) {
+ fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
+ i, fail, rc, ret);
+ FAIL_IF(fail); /* For the line number */
+ }
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(test_signal_tm, "signal_tm");
+}
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
index 9d301d785d9e..c6c53c82fdd6 100644
--- a/tools/testing/selftests/powerpc/tm/Makefile
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -1,5 +1,8 @@
+SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu \
+ tm-signal-context-chk-vmx tm-signal-context-chk-vsx
+
TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \
- tm-vmxcopy tm-fork tm-tar tm-tmspr tm-exec tm-execed
+ tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS)
all: $(TEST_PROGS)
@@ -11,6 +14,9 @@ tm-syscall: tm-syscall-asm.S
tm-syscall: CFLAGS += -I../../../../../usr/include
tm-tmspr: CFLAGS += -pthread
+$(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S
+$(SIGNAL_CONTEXT_CHK_TESTS): CFLAGS += -mhtm -m64 -mvsx
+
include ../../lib.mk
clean:
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c
new file mode 100644
index 000000000000..c760debbd5ad
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Test the kernel's signal frame code.
+ *
+ * The kernel sets up two sets of ucontexts if the signal was to be
+ * delivered while the thread was in a transaction.
+ * Expected behaviour is that the checkpointed state is in the user
+ * context passed to the signal handler. The speculated state can be
+ * accessed with the uc_link pointer.
+ *
+ * The rationale for this is that if TM unaware code (which linked
+ * against TM libs) installs a signal handler it will not know of the
+ * speculative nature of the 'live' registers and may infer the wrong
+ * thing.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <altivec.h>
+
+#include "utils.h"
+#include "tm.h"
+
+#define MAX_ATTEMPT 500000
+
+#define NV_FPU_REGS 18
+
+long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
+
+/* Be sure there are 2x as many as there are NV FPU regs (2x18) */
+static double fps[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
+};
+
+static sig_atomic_t fail;
+
+static void signal_usr1(int signum, siginfo_t *info, void *uc)
+{
+ int i;
+ ucontext_t *ucp = uc;
+ ucontext_t *tm_ucp = ucp->uc_link;
+
+ for (i = 0; i < NV_FPU_REGS && !fail; i++) {
+ fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]);
+ fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]);
+ if (fail)
+ printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]);
+ }
+}
+
+static int tm_signal_context_chk_fpu()
+{
+ struct sigaction act;
+ int i;
+ long rc;
+ pid_t pid = getpid();
+
+ SKIP_IF(!have_htm());
+
+ act.sa_sigaction = signal_usr1;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction sigusr1");
+ exit(1);
+ }
+
+ i = 0;
+ while (i < MAX_ATTEMPT && !fail) {
+ rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
+ FAIL_IF(rc != pid);
+ i++;
+ }
+
+ return fail;
+}
+
+int main(void)
+{
+ return test_harness(tm_signal_context_chk_fpu, "tm_signal_context_chk_fpu");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c
new file mode 100644
index 000000000000..df91330a08ef
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Test the kernel's signal frame code.
+ *
+ * The kernel sets up two sets of ucontexts if the signal was to be
+ * delivered while the thread was in a transaction.
+ * Expected behaviour is that the checkpointed state is in the user
+ * context passed to the signal handler. The speculated state can be
+ * accessed with the uc_link pointer.
+ *
+ * The rationale for this is that if TM unaware code (which linked
+ * against TM libs) installs a signal handler it will not know of the
+ * speculative nature of the 'live' registers and may infer the wrong
+ * thing.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <altivec.h>
+
+#include "utils.h"
+#include "tm.h"
+
+#define MAX_ATTEMPT 500000
+
+#define NV_GPR_REGS 18
+
+long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
+
+static sig_atomic_t fail;
+
+static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18};
+
+static void signal_usr1(int signum, siginfo_t *info, void *uc)
+{
+ int i;
+ ucontext_t *ucp = uc;
+ ucontext_t *tm_ucp = ucp->uc_link;
+
+ for (i = 0; i < NV_GPR_REGS && !fail; i++) {
+ fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]);
+ fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]);
+ if (fail)
+ printf("Failed on %d GPR %lu or %lu\n", i,
+ ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]);
+ }
+}
+
+static int tm_signal_context_chk_gpr()
+{
+ struct sigaction act;
+ int i;
+ long rc;
+ pid_t pid = getpid();
+
+ SKIP_IF(!have_htm());
+
+ act.sa_sigaction = signal_usr1;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction sigusr1");
+ exit(1);
+ }
+
+ i = 0;
+ while (i < MAX_ATTEMPT && !fail) {
+ rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL);
+ FAIL_IF(rc != pid);
+ i++;
+ }
+
+ return fail;
+}
+
+int main(void)
+{
+ return test_harness(tm_signal_context_chk_gpr, "tm_signal_context_chk_gpr");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c
new file mode 100644
index 000000000000..f0ee55fd5185
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Test the kernel's signal frame code.
+ *
+ * The kernel sets up two sets of ucontexts if the signal was to be
+ * delivered while the thread was in a transaction.
+ * Expected behaviour is that the checkpointed state is in the user
+ * context passed to the signal handler. The speculated state can be
+ * accessed with the uc_link pointer.
+ *
+ * The rationale for this is that if TM unaware code (which linked
+ * against TM libs) installs a signal handler it will not know of the
+ * speculative nature of the 'live' registers and may infer the wrong
+ * thing.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <altivec.h>
+
+#include "utils.h"
+#include "tm.h"
+
+#define MAX_ATTEMPT 500000
+
+#define NV_VMX_REGS 12
+
+long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
+
+static sig_atomic_t fail;
+
+vector int vms[] = {
+ {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
+ {13,14,15,16},{17,18,19,20},{21,22,23,24},
+ {25,26,27,28},{29,30,31,32},{33,34,35,36},
+ {37,38,39,40},{41,42,43,44},{45,46,47,48},
+ {-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12},
+ {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
+ {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
+ {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
+};
+
+static void signal_usr1(int signum, siginfo_t *info, void *uc)
+{
+ int i;
+ ucontext_t *ucp = uc;
+ ucontext_t *tm_ucp = ucp->uc_link;
+
+ for (i = 0; i < NV_VMX_REGS && !fail; i++) {
+ fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20],
+ &vms[i], sizeof(vector int));
+ fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20],
+ &vms[i + NV_VMX_REGS], sizeof (vector int));
+
+ if (fail) {
+ int j;
+
+ fprintf(stderr, "Failed on %d vmx 0x", i);
+ for (j = 0; j < 4; j++)
+ fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
+ fprintf(stderr, " vs 0x");
+ for (j = 0 ; j < 4; j++)
+ fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
+ fprintf(stderr, "\n");
+ }
+ }
+}
+
+static int tm_signal_context_chk()
+{
+ struct sigaction act;
+ int i;
+ long rc;
+ pid_t pid = getpid();
+
+ SKIP_IF(!have_htm());
+
+ act.sa_sigaction = signal_usr1;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction sigusr1");
+ exit(1);
+ }
+
+ i = 0;
+ while (i < MAX_ATTEMPT && !fail) {
+ rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL);
+ FAIL_IF(rc != pid);
+ i++;
+ }
+
+ return fail;
+}
+
+int main(void)
+{
+ return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vmx");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c
new file mode 100644
index 000000000000..b99c3d835957
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2016, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Test the kernel's signal frame code.
+ *
+ * The kernel sets up two sets of ucontexts if the signal was to be
+ * delivered while the thread was in a transaction.
+ * Expected behaviour is that the checkpointed state is in the user
+ * context passed to the signal handler. The speculated state can be
+ * accessed with the uc_link pointer.
+ *
+ * The rationale for this is that if TM unaware code (which linked
+ * against TM libs) installs a signal handler it will not know of the
+ * speculative nature of the 'live' registers and may infer the wrong
+ * thing.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <altivec.h>
+
+#include "utils.h"
+#include "tm.h"
+
+#define MAX_ATTEMPT 500000
+
+#define NV_VSX_REGS 12
+
+long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
+
+static sig_atomic_t fail;
+
+vector int vss[] = {
+ {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
+ {13,14,15,16},{17,18,19,20},{21,22,23,24},
+ {25,26,27,28},{29,30,31,32},{33,34,35,36},
+ {37,38,39,40},{41,42,43,44},{45,46,47,48},
+ {-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12},
+ {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
+ {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
+ {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
+};
+
+static void signal_usr1(int signum, siginfo_t *info, void *uc)
+{
+ int i;
+ uint8_t vsc[sizeof(vector int)];
+ uint8_t vst[sizeof(vector int)];
+ ucontext_t *ucp = uc;
+ ucontext_t *tm_ucp = ucp->uc_link;
+
+ /*
+ * The other half of the VSX regs will be after v_regs.
+ *
+ * In short, vmx_reserve array holds everything. v_regs is a 16
+ * byte aligned pointer at the start of vmx_reserve (vmx_reserve
+ * may or may not be 16 aligned) where the v_regs structure exists.
+ * (half of) The VSX regsters are directly after v_regs so the
+ * easiest way to find them below.
+ */
+ long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1);
+ long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1);
+ for (i = 0; i < NV_VSX_REGS && !fail; i++) {
+ memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8);
+ memcpy(vsc + 8, &vsx_ptr[20 + i], 8);
+ fail = memcmp(vsc, &vss[i], sizeof(vector int));
+ memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8);
+ memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8);
+ fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int));
+
+ if (fail) {
+ int j;
+
+ fprintf(stderr, "Failed on %d vsx 0x", i);
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%02x", vsc[j]);
+ fprintf(stderr, " vs 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%02x", vst[j]);
+ fprintf(stderr, "\n");
+ }
+ }
+}
+
+static int tm_signal_context_chk()
+{
+ struct sigaction act;
+ int i;
+ long rc;
+ pid_t pid = getpid();
+
+ SKIP_IF(!have_htm());
+
+ act.sa_sigaction = signal_usr1;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGUSR1, &act, NULL) < 0) {
+ perror("sigaction sigusr1");
+ exit(1);
+ }
+
+ i = 0;
+ while (i < MAX_ATTEMPT && !fail) {
+ rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss);
+ FAIL_IF(rc != pid);
+ i++;
+ }
+
+ return fail;
+}
+
+int main(void)
+{
+ return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vsx");
+}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal.S b/tools/testing/selftests/powerpc/tm/tm-signal.S
new file mode 100644
index 000000000000..4e13e8b3a96f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal.S
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "../basic_asm.h"
+#include "../gpr_asm.h"
+#include "../fpu_asm.h"
+#include "../vmx_asm.h"
+#include "../vsx_asm.h"
+
+/*
+ * Large caveat here being that the caller cannot expect the
+ * signal to always be sent! The hardware can (AND WILL!) abort
+ * the transaction between the tbegin and the tsuspend (however
+ * unlikely it seems or infrequently it actually happens).
+ * You have been warned.
+ */
+/* long tm_signal_self(pid_t pid, long *gprs, double *fps, vector *vms, vector *vss); */
+FUNC_START(tm_signal_self_context_load)
+ PUSH_BASIC_STACK(512)
+ /*
+ * Don't strictly need to save and restore as it depends on if
+ * we're going to use them, however this reduces messy logic
+ */
+ PUSH_VMX(STACK_FRAME_LOCAL(5,0),r8)
+ PUSH_FPU(512)
+ PUSH_NVREGS_BELOW_FPU(512)
+ std r3, STACK_FRAME_PARAM(0)(sp) /* pid */
+ std r4, STACK_FRAME_PARAM(1)(sp) /* gps */
+ std r5, STACK_FRAME_PARAM(2)(sp) /* fps */
+ std r6, STACK_FRAME_PARAM(3)(sp) /* vms */
+ std r7, STACK_FRAME_PARAM(4)(sp) /* vss */
+
+ ld r3, STACK_FRAME_PARAM(1)(sp)
+ cmpdi r3, 0
+ beq skip_gpr_lc
+ bl load_gpr
+skip_gpr_lc:
+ ld r3, STACK_FRAME_PARAM(2)(sp)
+ cmpdi r3, 0
+ beq skip_fpu_lc
+ bl load_fpu
+skip_fpu_lc:
+ ld r3, STACK_FRAME_PARAM(3)(sp)
+ cmpdi r3, 0
+ beq skip_vmx_lc
+ bl load_vmx
+skip_vmx_lc:
+ ld r3, STACK_FRAME_PARAM(4)(sp)
+ cmpdi r3, 0
+ beq skip_vsx_lc
+ bl load_vsx
+skip_vsx_lc:
+ /*
+ * Set r3 (return value) before tbegin. Use the pid as a known
+ * 'all good' return value, zero is used to indicate a non-doomed
+ * transaction.
+ */
+ ld r3, STACK_FRAME_PARAM(0)(sp)
+ tbegin.
+ beq 1f
+ tsuspend. /* Can't enter a syscall transactionally */
+ ld r3, STACK_FRAME_PARAM(1)(sp)
+ cmpdi r3, 0
+ beq skip_gpr_lt
+ /* Get the second half of the array */
+ addi r3, r3, 8 * 18
+ bl load_gpr
+skip_gpr_lt:
+ ld r3, STACK_FRAME_PARAM(2)(sp)
+ cmpdi r3, 0
+ beq skip_fpu_lt
+ /* Get the second half of the array */
+ addi r3, r3, 8 * 18
+ bl load_fpu
+skip_fpu_lt:
+ ld r3, STACK_FRAME_PARAM(3)(sp)
+ cmpdi r3, 0
+ beq skip_vmx_lt
+ /* Get the second half of the array */
+ addi r3, r3, 16 * 12
+ bl load_vmx
+skip_vmx_lt:
+ ld r3, STACK_FRAME_PARAM(4)(sp)
+ cmpdi r3, 0
+ beq skip_vsx_lt
+ /* Get the second half of the array */
+ addi r3, r3, 16 * 12
+ bl load_vsx
+skip_vsx_lt:
+ li r0, 37 /* sys_kill */
+ ld r3, STACK_FRAME_PARAM(0)(sp) /* pid */
+ li r4, 10 /* SIGUSR1 */
+ sc /* Taking the signal will doom the transaction */
+ tabort. 0
+ tresume. /* Be super sure we abort */
+ /*
+ * This will cause us to resume doomed transaction and cause
+ * hardware to cleanup, we'll end up at 1: anything between
+ * tresume. and 1: shouldn't ever run.
+ */
+ li r3, 0
+ 1:
+ POP_VMX(STACK_FRAME_LOCAL(5,0),r4)
+ POP_FPU(512)
+ POP_NVREGS_BELOW_FPU(512)
+ POP_BASIC_STACK(512)
+ blr
+FUNC_END(tm_signal_self_context_load)
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h
index 60318bad7d7a..2c8da74304e7 100644
--- a/tools/testing/selftests/powerpc/tm/tm.h
+++ b/tools/testing/selftests/powerpc/tm/tm.h
@@ -52,4 +52,31 @@ static inline bool failure_is_nesting(void)
return (__builtin_get_texasru() & 0x400000);
}
+static inline int tcheck(void)
+{
+ long cr;
+ asm volatile ("tcheck 0" : "=r"(cr) : : "cr0");
+ return (cr >> 28) & 4;
+}
+
+static inline bool tcheck_doomed(void)
+{
+ return tcheck() & 8;
+}
+
+static inline bool tcheck_active(void)
+{
+ return tcheck() & 4;
+}
+
+static inline bool tcheck_suspended(void)
+{
+ return tcheck() & 2;
+}
+
+static inline bool tcheck_transactional(void)
+{
+ return tcheck() & 6;
+}
+
#endif /* _SELFTESTS_POWERPC_TM_TM_H */
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index fbd33e52ef8f..53405e8a52ab 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -22,7 +22,7 @@ typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
-
+void test_harness_set_timeout(uint64_t time);
int test_harness(int (test_function)(void), char *name);
extern void *get_auxv_entry(int type);
int pick_online_cpu(void);
@@ -32,10 +32,17 @@ static inline bool have_hwcap(unsigned long ftr)
return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr;
}
+#ifdef AT_HWCAP2
static inline bool have_hwcap2(unsigned long ftr2)
{
return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2;
}
+#else
+static inline bool have_hwcap2(unsigned long ftr2)
+{
+ return false;
+}
+#endif
/* Yes, this is evil */
#define FAIL_IF(x) \
diff --git a/tools/testing/selftests/powerpc/vmx_asm.h b/tools/testing/selftests/powerpc/vmx_asm.h
new file mode 100644
index 000000000000..2eaaeca9cf1d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/vmx_asm.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "basic_asm.h"
+
+/* POS MUST BE 16 ALIGNED! */
+#define PUSH_VMX(pos,reg) \
+ li reg,pos; \
+ stvx v20,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v21,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v22,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v23,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v24,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v25,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v26,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v27,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v28,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v29,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v30,reg,%r1; \
+ addi reg,reg,16; \
+ stvx v31,reg,%r1;
+
+/* POS MUST BE 16 ALIGNED! */
+#define POP_VMX(pos,reg) \
+ li reg,pos; \
+ lvx v20,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v21,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v22,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v23,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v24,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v25,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v26,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v27,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v28,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v29,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v30,reg,%r1; \
+ addi reg,reg,16; \
+ lvx v31,reg,%r1;
+
+/*
+ * Careful this will 'clobber' vmx (by design)
+ * Don't call this from C
+ */
+FUNC_START(load_vmx)
+ li r5,0
+ lvx v20,r5,r3
+ addi r5,r5,16
+ lvx v21,r5,r3
+ addi r5,r5,16
+ lvx v22,r5,r3
+ addi r5,r5,16
+ lvx v23,r5,r3
+ addi r5,r5,16
+ lvx v24,r5,r3
+ addi r5,r5,16
+ lvx v25,r5,r3
+ addi r5,r5,16
+ lvx v26,r5,r3
+ addi r5,r5,16
+ lvx v27,r5,r3
+ addi r5,r5,16
+ lvx v28,r5,r3
+ addi r5,r5,16
+ lvx v29,r5,r3
+ addi r5,r5,16
+ lvx v30,r5,r3
+ addi r5,r5,16
+ lvx v31,r5,r3
+ blr
+FUNC_END(load_vmx)
diff --git a/tools/testing/selftests/powerpc/vsx_asm.h b/tools/testing/selftests/powerpc/vsx_asm.h
new file mode 100644
index 000000000000..d828bfb6ef2d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/vsx_asm.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015, Cyril Bur, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "basic_asm.h"
+
+/*
+ * Careful this will 'clobber' vsx (by design), VSX are always
+ * volatile though so unlike vmx this isn't so much of an issue
+ * Still should avoid calling from C
+ */
+FUNC_START(load_vsx)
+ li r5,0
+ lxvx vs20,r5,r3
+ addi r5,r5,16
+ lxvx vs21,r5,r3
+ addi r5,r5,16
+ lxvx vs22,r5,r3
+ addi r5,r5,16
+ lxvx vs23,r5,r3
+ addi r5,r5,16
+ lxvx vs24,r5,r3
+ addi r5,r5,16
+ lxvx vs25,r5,r3
+ addi r5,r5,16
+ lxvx vs26,r5,r3
+ addi r5,r5,16
+ lxvx vs27,r5,r3
+ addi r5,r5,16
+ lxvx vs28,r5,r3
+ addi r5,r5,16
+ lxvx vs29,r5,r3
+ addi r5,r5,16
+ lxvx vs30,r5,r3
+ addi r5,r5,16
+ lxvx vs31,r5,r3
+ blr
+FUNC_END(load_vsx)
+
+FUNC_START(store_vsx)
+ li r5,0
+ stxvx vs20,r5,r3
+ addi r5,r5,16
+ stxvx vs21,r5,r3
+ addi r5,r5,16
+ stxvx vs22,r5,r3
+ addi r5,r5,16
+ stxvx vs23,r5,r3
+ addi r5,r5,16
+ stxvx vs24,r5,r3
+ addi r5,r5,16
+ stxvx vs25,r5,r3
+ addi r5,r5,16
+ stxvx vs26,r5,r3
+ addi r5,r5,16
+ stxvx vs27,r5,r3
+ addi r5,r5,16
+ stxvx vs28,r5,r3
+ addi r5,r5,16
+ stxvx vs29,r5,r3
+ addi r5,r5,16
+ stxvx vs30,r5,r3
+ addi r5,r5,16
+ stxvx vs31,r5,r3
+ blr
+FUNC_END(store_vsx)
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index a937a9d26b60..142c565bb351 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -7,3 +7,4 @@ mlock2-tests
on-fault-limit
transhuge-stress
userfaultfd
+mlock-intersect-test
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index e4bb1de1d526..bbab7f4664ac 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -10,6 +10,7 @@ BINARIES += on-fault-limit
BINARIES += thuge-gen
BINARIES += transhuge-stress
BINARIES += userfaultfd
+BINARIES += mlock-random-test
all: $(BINARIES)
%: %.c
@@ -17,6 +18,9 @@ all: $(BINARIES)
userfaultfd: userfaultfd.c ../../../../usr/include/linux/kernel.h
$(CC) $(CFLAGS) -O2 -o $@ $< -lpthread
+mlock-random-test: mlock-random-test.c
+ $(CC) $(CFLAGS) -o $@ $< -lcap
+
../../../../usr/include/linux/kernel.h:
make -C ../../../.. headers_install
diff --git a/tools/testing/selftests/vm/mlock-random-test.c b/tools/testing/selftests/vm/mlock-random-test.c
new file mode 100644
index 000000000000..83de4f58d262
--- /dev/null
+++ b/tools/testing/selftests/vm/mlock-random-test.c
@@ -0,0 +1,293 @@
+/*
+ * It tests the mlock/mlock2() when they are invoked
+ * on randomly memory region.
+ */
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/capability.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <time.h>
+#include "mlock2.h"
+
+#define CHUNK_UNIT (128 * 1024)
+#define MLOCK_RLIMIT_SIZE (CHUNK_UNIT * 2)
+#define MLOCK_WITHIN_LIMIT_SIZE CHUNK_UNIT
+#define MLOCK_OUTOF_LIMIT_SIZE (CHUNK_UNIT * 3)
+
+#define TEST_LOOP 100
+#define PAGE_ALIGN(size, ps) (((size) + ((ps) - 1)) & ~((ps) - 1))
+
+int set_cap_limits(rlim_t max)
+{
+ struct rlimit new;
+ cap_t cap = cap_init();
+
+ new.rlim_cur = max;
+ new.rlim_max = max;
+ if (setrlimit(RLIMIT_MEMLOCK, &new)) {
+ perror("setrlimit() returns error\n");
+ return -1;
+ }
+
+ /* drop capabilities including CAP_IPC_LOCK */
+ if (cap_set_proc(cap)) {
+ perror("cap_set_proc() returns error\n");
+ return -2;
+ }
+
+ return 0;
+}
+
+int get_proc_locked_vm_size(void)
+{
+ FILE *f;
+ int ret = -1;
+ char line[1024] = {0};
+ unsigned long lock_size = 0;
+
+ f = fopen("/proc/self/status", "r");
+ if (!f) {
+ perror("fopen");
+ return -1;
+ }
+
+ while (fgets(line, 1024, f)) {
+ if (strstr(line, "VmLck")) {
+ ret = sscanf(line, "VmLck:\t%8lu kB", &lock_size);
+ if (ret <= 0) {
+ printf("sscanf() on VmLck error: %s: %d\n",
+ line, ret);
+ fclose(f);
+ return -1;
+ }
+ fclose(f);
+ return (int)(lock_size << 10);
+ }
+ }
+
+ perror("cann't parse VmLck in /proc/self/status\n");
+ fclose(f);
+ return -1;
+}
+
+/*
+ * Get the MMUPageSize of the memory region including input
+ * address from proc file.
+ *
+ * return value: on error case, 0 will be returned.
+ * Otherwise the page size(in bytes) is returned.
+ */
+int get_proc_page_size(unsigned long addr)
+{
+ FILE *smaps;
+ char *line;
+ unsigned long mmupage_size = 0;
+ size_t size;
+
+ smaps = seek_to_smaps_entry(addr);
+ if (!smaps) {
+ printf("Unable to parse /proc/self/smaps\n");
+ return 0;
+ }
+
+ while (getline(&line, &size, smaps) > 0) {
+ if (!strstr(line, "MMUPageSize")) {
+ free(line);
+ line = NULL;
+ size = 0;
+ continue;
+ }
+
+ /* found the MMUPageSize of this section */
+ if (sscanf(line, "MMUPageSize: %8lu kB",
+ &mmupage_size) < 1) {
+ printf("Unable to parse smaps entry for Size:%s\n",
+ line);
+ break;
+ }
+
+ }
+ free(line);
+ if (smaps)
+ fclose(smaps);
+ return mmupage_size << 10;
+}
+
+/*
+ * Test mlock/mlock2() on provided memory chunk.
+ * It expects the mlock/mlock2() to be successful (within rlimit)
+ *
+ * With allocated memory chunk [p, p + alloc_size), this
+ * test will choose start/len randomly to perform mlock/mlock2
+ * [start, start + len] memory range. The range is within range
+ * of the allocated chunk.
+ *
+ * The memory region size alloc_size is within the rlimit.
+ * So we always expect a success of mlock/mlock2.
+ *
+ * VmLck is assumed to be 0 before this test.
+ *
+ * return value: 0 - success
+ * else: failure
+ */
+int test_mlock_within_limit(char *p, int alloc_size)
+{
+ int i;
+ int ret = 0;
+ int locked_vm_size = 0;
+ struct rlimit cur;
+ int page_size = 0;
+
+ getrlimit(RLIMIT_MEMLOCK, &cur);
+ if (cur.rlim_cur < alloc_size) {
+ printf("alloc_size[%d] < %u rlimit,lead to mlock failure\n",
+ alloc_size, (unsigned int)cur.rlim_cur);
+ return -1;
+ }
+
+ srand(time(NULL));
+ for (i = 0; i < TEST_LOOP; i++) {
+ /*
+ * - choose mlock/mlock2 randomly
+ * - choose lock_size randomly but lock_size < alloc_size
+ * - choose start_offset randomly but p+start_offset+lock_size
+ * < p+alloc_size
+ */
+ int is_mlock = !!(rand() % 2);
+ int lock_size = rand() % alloc_size;
+ int start_offset = rand() % (alloc_size - lock_size);
+
+ if (is_mlock)
+ ret = mlock(p + start_offset, lock_size);
+ else
+ ret = mlock2_(p + start_offset, lock_size,
+ MLOCK_ONFAULT);
+
+ if (ret) {
+ printf("%s() failure at |%p(%d)| mlock:|%p(%d)|\n",
+ is_mlock ? "mlock" : "mlock2",
+ p, alloc_size,
+ p + start_offset, lock_size);
+ return ret;
+ }
+ }
+
+ /*
+ * Check VmLck left by the tests.
+ */
+ locked_vm_size = get_proc_locked_vm_size();
+ page_size = get_proc_page_size((unsigned long)p);
+ if (page_size == 0) {
+ printf("cannot get proc MMUPageSize\n");
+ return -1;
+ }
+
+ if (locked_vm_size > PAGE_ALIGN(alloc_size, page_size) + page_size) {
+ printf("test_mlock_within_limit() left VmLck:%d on %d chunk\n",
+ locked_vm_size, alloc_size);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * We expect the mlock/mlock2() to be fail (outof limitation)
+ *
+ * With allocated memory chunk [p, p + alloc_size), this
+ * test will randomly choose start/len and perform mlock/mlock2
+ * on [start, start+len] range.
+ *
+ * The memory region size alloc_size is above the rlimit.
+ * And the len to be locked is higher than rlimit.
+ * So we always expect a failure of mlock/mlock2.
+ * No locked page number should be increased as a side effect.
+ *
+ * return value: 0 - success
+ * else: failure
+ */
+int test_mlock_outof_limit(char *p, int alloc_size)
+{
+ int i;
+ int ret = 0;
+ int locked_vm_size = 0, old_locked_vm_size = 0;
+ struct rlimit cur;
+
+ getrlimit(RLIMIT_MEMLOCK, &cur);
+ if (cur.rlim_cur >= alloc_size) {
+ printf("alloc_size[%d] >%u rlimit, violates test condition\n",
+ alloc_size, (unsigned int)cur.rlim_cur);
+ return -1;
+ }
+
+ old_locked_vm_size = get_proc_locked_vm_size();
+ srand(time(NULL));
+ for (i = 0; i < TEST_LOOP; i++) {
+ int is_mlock = !!(rand() % 2);
+ int lock_size = (rand() % (alloc_size - cur.rlim_cur))
+ + cur.rlim_cur;
+ int start_offset = rand() % (alloc_size - lock_size);
+
+ if (is_mlock)
+ ret = mlock(p + start_offset, lock_size);
+ else
+ ret = mlock2_(p + start_offset, lock_size,
+ MLOCK_ONFAULT);
+ if (ret == 0) {
+ printf("%s() succeeds? on %p(%d) mlock%p(%d)\n",
+ is_mlock ? "mlock" : "mlock2",
+ p, alloc_size,
+ p + start_offset, lock_size);
+ return -1;
+ }
+ }
+
+ locked_vm_size = get_proc_locked_vm_size();
+ if (locked_vm_size != old_locked_vm_size) {
+ printf("tests leads to new mlocked page: old[%d], new[%d]\n",
+ old_locked_vm_size,
+ locked_vm_size);
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *p = NULL;
+ int ret = 0;
+
+ if (set_cap_limits(MLOCK_RLIMIT_SIZE))
+ return -1;
+
+ p = malloc(MLOCK_WITHIN_LIMIT_SIZE);
+ if (p == NULL) {
+ perror("malloc() failure\n");
+ return -1;
+ }
+ ret = test_mlock_within_limit(p, MLOCK_WITHIN_LIMIT_SIZE);
+ if (ret)
+ return ret;
+ munlock(p, MLOCK_WITHIN_LIMIT_SIZE);
+ free(p);
+
+
+ p = malloc(MLOCK_OUTOF_LIMIT_SIZE);
+ if (p == NULL) {
+ perror("malloc() failure\n");
+ return -1;
+ }
+ ret = test_mlock_outof_limit(p, MLOCK_OUTOF_LIMIT_SIZE);
+ if (ret)
+ return ret;
+ munlock(p, MLOCK_OUTOF_LIMIT_SIZE);
+ free(p);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/vm/mlock2-tests.c b/tools/testing/selftests/vm/mlock2-tests.c
index 02ca5e0177c5..ff0cda2b19c9 100644
--- a/tools/testing/selftests/vm/mlock2-tests.c
+++ b/tools/testing/selftests/vm/mlock2-tests.c
@@ -1,33 +1,12 @@
#define _GNU_SOURCE
#include <sys/mman.h>
#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
-#include <syscall.h>
-#include <errno.h>
#include <stdbool.h>
-
-#ifndef MLOCK_ONFAULT
-#define MLOCK_ONFAULT 1
-#endif
-
-#ifndef MCL_ONFAULT
-#define MCL_ONFAULT (MCL_FUTURE << 1)
-#endif
-
-static int mlock2_(void *start, size_t len, int flags)
-{
-#ifdef __NR_mlock2
- return syscall(__NR_mlock2, start, len, flags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
+#include "mlock2.h"
struct vm_boundaries {
unsigned long start;
@@ -138,46 +117,6 @@ static uint64_t get_kpageflags(unsigned long pfn)
return flags;
}
-static FILE *seek_to_smaps_entry(unsigned long addr)
-{
- FILE *file;
- char *line = NULL;
- size_t size = 0;
- unsigned long start, end;
- char perms[5];
- unsigned long offset;
- char dev[32];
- unsigned long inode;
- char path[BUFSIZ];
-
- file = fopen("/proc/self/smaps", "r");
- if (!file) {
- perror("fopen smaps");
- _exit(1);
- }
-
- while (getline(&line, &size, file) > 0) {
- if (sscanf(line, "%lx-%lx %s %lx %s %lu %s\n",
- &start, &end, perms, &offset, dev, &inode, path) < 6)
- goto next;
-
- if (start <= addr && addr < end)
- goto out;
-
-next:
- free(line);
- line = NULL;
- size = 0;
- }
-
- fclose(file);
- file = NULL;
-
-out:
- free(line);
- return file;
-}
-
#define VMFLAGS "VmFlags:"
static bool is_vmflag_set(unsigned long addr, const char *vmflag)
diff --git a/tools/testing/selftests/vm/mlock2.h b/tools/testing/selftests/vm/mlock2.h
new file mode 100644
index 000000000000..7ee062929d3e
--- /dev/null
+++ b/tools/testing/selftests/vm/mlock2.h
@@ -0,0 +1,62 @@
+#include <syscall.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef MLOCK_ONFAULT
+#define MLOCK_ONFAULT 1
+#endif
+
+#ifndef MCL_ONFAULT
+#define MCL_ONFAULT (MCL_FUTURE << 1)
+#endif
+
+static int mlock2_(void *start, size_t len, int flags)
+{
+#ifdef __NR_mlock2
+ return syscall(__NR_mlock2, start, len, flags);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static FILE *seek_to_smaps_entry(unsigned long addr)
+{
+ FILE *file;
+ char *line = NULL;
+ size_t size = 0;
+ unsigned long start, end;
+ char perms[5];
+ unsigned long offset;
+ char dev[32];
+ unsigned long inode;
+ char path[BUFSIZ];
+
+ file = fopen("/proc/self/smaps", "r");
+ if (!file) {
+ perror("fopen smaps");
+ _exit(1);
+ }
+
+ while (getline(&line, &size, file) > 0) {
+ if (sscanf(line, "%lx-%lx %s %lx %s %lu %s\n",
+ &start, &end, perms, &offset, dev, &inode, path) < 6)
+ goto next;
+
+ if (start <= addr && addr < end)
+ goto out;
+
+next:
+ free(line);
+ line = NULL;
+ size = 0;
+ }
+
+ fclose(file);
+ file = NULL;
+
+out:
+ free(line);
+ return file;
+}
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 4f747ee07f10..a89f80a5b711 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -5,7 +5,8 @@ include ../lib.mk
.PHONY: all all_32 all_64 warn_32bit_failure clean
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \
- check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test
+ check_initial_reg_state sigreturn ldt_gdt iopl \
+ protection_keys
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
vdso_restorer
diff --git a/tools/testing/selftests/x86/pkey-helpers.h b/tools/testing/selftests/x86/pkey-helpers.h
new file mode 100644
index 000000000000..b20293956eec
--- /dev/null
+++ b/tools/testing/selftests/x86/pkey-helpers.h
@@ -0,0 +1,219 @@
+#ifndef _PKEYS_HELPER_H
+#define _PKEYS_HELPER_H
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <sys/mman.h>
+
+#define NR_PKEYS 16
+#define PKRU_BITS_PER_PKEY 2
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL 0
+#endif
+#define DPRINT_IN_SIGNAL_BUF_SIZE 4096
+extern int dprint_in_signal;
+extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
+static inline void sigsafe_printf(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ if (!dprint_in_signal) {
+ vprintf(format, ap);
+ } else {
+ int len = vsnprintf(dprint_in_signal_buffer,
+ DPRINT_IN_SIGNAL_BUF_SIZE,
+ format, ap);
+ /*
+ * len is amount that would have been printed,
+ * but actual write is truncated at BUF_SIZE.
+ */
+ if (len > DPRINT_IN_SIGNAL_BUF_SIZE)
+ len = DPRINT_IN_SIGNAL_BUF_SIZE;
+ write(1, dprint_in_signal_buffer, len);
+ }
+ va_end(ap);
+}
+#define dprintf_level(level, args...) do { \
+ if (level <= DEBUG_LEVEL) \
+ sigsafe_printf(args); \
+ fflush(NULL); \
+} while (0)
+#define dprintf0(args...) dprintf_level(0, args)
+#define dprintf1(args...) dprintf_level(1, args)
+#define dprintf2(args...) dprintf_level(2, args)
+#define dprintf3(args...) dprintf_level(3, args)
+#define dprintf4(args...) dprintf_level(4, args)
+
+extern unsigned int shadow_pkru;
+static inline unsigned int __rdpkru(void)
+{
+ unsigned int eax, edx;
+ unsigned int ecx = 0;
+ unsigned int pkru;
+
+ asm volatile(".byte 0x0f,0x01,0xee\n\t"
+ : "=a" (eax), "=d" (edx)
+ : "c" (ecx));
+ pkru = eax;
+ return pkru;
+}
+
+static inline unsigned int _rdpkru(int line)
+{
+ unsigned int pkru = __rdpkru();
+
+ dprintf4("rdpkru(line=%d) pkru: %x shadow: %x\n",
+ line, pkru, shadow_pkru);
+ assert(pkru == shadow_pkru);
+
+ return pkru;
+}
+
+#define rdpkru() _rdpkru(__LINE__)
+
+static inline void __wrpkru(unsigned int pkru)
+{
+ unsigned int eax = pkru;
+ unsigned int ecx = 0;
+ unsigned int edx = 0;
+
+ dprintf4("%s() changing %08x to %08x\n", __func__, __rdpkru(), pkru);
+ asm volatile(".byte 0x0f,0x01,0xef\n\t"
+ : : "a" (eax), "c" (ecx), "d" (edx));
+ assert(pkru == __rdpkru());
+}
+
+static inline void wrpkru(unsigned int pkru)
+{
+ dprintf4("%s() changing %08x to %08x\n", __func__, __rdpkru(), pkru);
+ /* will do the shadow check for us: */
+ rdpkru();
+ __wrpkru(pkru);
+ shadow_pkru = pkru;
+ dprintf4("%s(%08x) pkru: %08x\n", __func__, pkru, __rdpkru());
+}
+
+/*
+ * These are technically racy. since something could
+ * change PKRU between the read and the write.
+ */
+static inline void __pkey_access_allow(int pkey, int do_allow)
+{
+ unsigned int pkru = rdpkru();
+ int bit = pkey * 2;
+
+ if (do_allow)
+ pkru &= (1<<bit);
+ else
+ pkru |= (1<<bit);
+
+ dprintf4("pkru now: %08x\n", rdpkru());
+ wrpkru(pkru);
+}
+
+static inline void __pkey_write_allow(int pkey, int do_allow_write)
+{
+ long pkru = rdpkru();
+ int bit = pkey * 2 + 1;
+
+ if (do_allow_write)
+ pkru &= (1<<bit);
+ else
+ pkru |= (1<<bit);
+
+ wrpkru(pkru);
+ dprintf4("pkru now: %08x\n", rdpkru());
+}
+
+#define PROT_PKEY0 0x10 /* protection key value (bit 0) */
+#define PROT_PKEY1 0x20 /* protection key value (bit 1) */
+#define PROT_PKEY2 0x40 /* protection key value (bit 2) */
+#define PROT_PKEY3 0x80 /* protection key value (bit 3) */
+
+#define PAGE_SIZE 4096
+#define MB (1<<20)
+
+static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ /* ecx is often an input as well as an output. */
+ asm volatile(
+ "cpuid;"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (*eax), "2" (*ecx));
+}
+
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */
+#define X86_FEATURE_PKU (1<<3) /* Protection Keys for Userspace */
+#define X86_FEATURE_OSPKE (1<<4) /* OS Protection Keys Enable */
+
+static inline int cpu_has_pku(void)
+{
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ eax = 0x7;
+ ecx = 0x0;
+ __cpuid(&eax, &ebx, &ecx, &edx);
+
+ if (!(ecx & X86_FEATURE_PKU)) {
+ dprintf2("cpu does not have PKU\n");
+ return 0;
+ }
+ if (!(ecx & X86_FEATURE_OSPKE)) {
+ dprintf2("cpu does not have OSPKE\n");
+ return 0;
+ }
+ return 1;
+}
+
+#define XSTATE_PKRU_BIT (9)
+#define XSTATE_PKRU 0x200
+
+int pkru_xstate_offset(void)
+{
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ int xstate_offset;
+ int xstate_size;
+ unsigned long XSTATE_CPUID = 0xd;
+ int leaf;
+
+ /* assume that XSTATE_PKRU is set in XCR0 */
+ leaf = XSTATE_PKRU_BIT;
+ {
+ eax = XSTATE_CPUID;
+ ecx = leaf;
+ __cpuid(&eax, &ebx, &ecx, &edx);
+
+ if (leaf == XSTATE_PKRU_BIT) {
+ xstate_offset = ebx;
+ xstate_size = eax;
+ }
+ }
+
+ if (xstate_size == 0) {
+ printf("could not find size/offset of PKRU in xsave state\n");
+ return 0;
+ }
+
+ return xstate_offset;
+}
+
+#endif /* _PKEYS_HELPER_H */
diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c
new file mode 100644
index 000000000000..bdd58c78902e
--- /dev/null
+++ b/tools/testing/selftests/x86/protection_keys.c
@@ -0,0 +1,1410 @@
+/*
+ * Tests x86 Memory Protection Keys (see Documentation/x86/protection-keys.txt)
+ *
+ * There are examples in here of:
+ * * how to set protection keys on memory
+ * * how to set/clear bits in PKRU (the rights register)
+ * * how to handle SEGV_PKRU signals and extract pkey-relevant
+ * information from the siginfo
+ *
+ * Things to add:
+ * make sure KSM and KSM COW breaking works
+ * prefault pages in at malloc, or not
+ * protect MPX bounds tables with protection keys?
+ * make sure VMA splitting/merging is working correctly
+ * OOMs can destroy mm->mmap (see exit_mmap()), so make sure it is immune to pkeys
+ * look for pkey "leaks" where it is still set on a VMA but "freed" back to the kernel
+ * do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks
+ *
+ * Compile like this:
+ * gcc -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
+ * gcc -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
+ */
+#define _GNU_SOURCE
+#include <errno.h>
+#include <linux/futex.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <setjmp.h>
+
+#include "pkey-helpers.h"
+
+int iteration_nr = 1;
+int test_nr;
+
+unsigned int shadow_pkru;
+
+#define HPAGE_SIZE (1UL<<21)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+#define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1))
+#define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
+#define ALIGN_PTR_UP(p, ptr_align_to) ((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
+#define ALIGN_PTR_DOWN(p, ptr_align_to) ((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+#define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
+
+int dprint_in_signal;
+char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
+
+extern void abort_hooks(void);
+#define pkey_assert(condition) do { \
+ if (!(condition)) { \
+ dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
+ __FILE__, __LINE__, \
+ test_nr, iteration_nr); \
+ dprintf0("errno at assert: %d", errno); \
+ abort_hooks(); \
+ assert(condition); \
+ } \
+} while (0)
+#define raw_assert(cond) assert(cond)
+
+void cat_into_file(char *str, char *file)
+{
+ int fd = open(file, O_RDWR);
+ int ret;
+
+ dprintf2("%s(): writing '%s' to '%s'\n", __func__, str, file);
+ /*
+ * these need to be raw because they are called under
+ * pkey_assert()
+ */
+ raw_assert(fd >= 0);
+ ret = write(fd, str, strlen(str));
+ if (ret != strlen(str)) {
+ perror("write to file failed");
+ fprintf(stderr, "filename: '%s' str: '%s'\n", file, str);
+ raw_assert(0);
+ }
+ close(fd);
+}
+
+#if CONTROL_TRACING > 0
+static int warned_tracing;
+int tracing_root_ok(void)
+{
+ if (geteuid() != 0) {
+ if (!warned_tracing)
+ fprintf(stderr, "WARNING: not run as root, "
+ "can not do tracing control\n");
+ warned_tracing = 1;
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+void tracing_on(void)
+{
+#if CONTROL_TRACING > 0
+#define TRACEDIR "/sys/kernel/debug/tracing"
+ char pidstr[32];
+
+ if (!tracing_root_ok())
+ return;
+
+ sprintf(pidstr, "%d", getpid());
+ cat_into_file("0", TRACEDIR "/tracing_on");
+ cat_into_file("\n", TRACEDIR "/trace");
+ if (1) {
+ cat_into_file("function_graph", TRACEDIR "/current_tracer");
+ cat_into_file("1", TRACEDIR "/options/funcgraph-proc");
+ } else {
+ cat_into_file("nop", TRACEDIR "/current_tracer");
+ }
+ cat_into_file(pidstr, TRACEDIR "/set_ftrace_pid");
+ cat_into_file("1", TRACEDIR "/tracing_on");
+ dprintf1("enabled tracing\n");
+#endif
+}
+
+void tracing_off(void)
+{
+#if CONTROL_TRACING > 0
+ if (!tracing_root_ok())
+ return;
+ cat_into_file("0", "/sys/kernel/debug/tracing/tracing_on");
+#endif
+}
+
+void abort_hooks(void)
+{
+ fprintf(stderr, "running %s()...\n", __func__);
+ tracing_off();
+#ifdef SLEEP_ON_ABORT
+ sleep(SLEEP_ON_ABORT);
+#endif
+}
+
+static inline void __page_o_noops(void)
+{
+ /* 8-bytes of instruction * 512 bytes = 1 page */
+ asm(".rept 512 ; nopl 0x7eeeeeee(%eax) ; .endr");
+}
+
+/*
+ * This attempts to have roughly a page of instructions followed by a few
+ * instructions that do a write, and another page of instructions. That
+ * way, we are pretty sure that the write is in the second page of
+ * instructions and has at least a page of padding behind it.
+ *
+ * *That* lets us be sure to madvise() away the write instruction, which
+ * will then fault, which makes sure that the fault code handles
+ * execute-only memory properly.
+ */
+__attribute__((__aligned__(PAGE_SIZE)))
+void lots_o_noops_around_write(int *write_to_me)
+{
+ dprintf3("running %s()\n", __func__);
+ __page_o_noops();
+ /* Assume this happens in the second page of instructions: */
+ *write_to_me = __LINE__;
+ /* pad out by another page: */
+ __page_o_noops();
+ dprintf3("%s() done\n", __func__);
+}
+
+/* Define some kernel-like types */
+#define u8 uint8_t
+#define u16 uint16_t
+#define u32 uint32_t
+#define u64 uint64_t
+
+#ifdef __i386__
+#define SYS_mprotect_key 380
+#define SYS_pkey_alloc 381
+#define SYS_pkey_free 382
+#define REG_IP_IDX REG_EIP
+#define si_pkey_offset 0x18
+#else
+#define SYS_mprotect_key 329
+#define SYS_pkey_alloc 330
+#define SYS_pkey_free 331
+#define REG_IP_IDX REG_RIP
+#define si_pkey_offset 0x20
+#endif
+
+void dump_mem(void *dumpme, int len_bytes)
+{
+ char *c = (void *)dumpme;
+ int i;
+
+ for (i = 0; i < len_bytes; i += sizeof(u64)) {
+ u64 *ptr = (u64 *)(c + i);
+ dprintf1("dump[%03d][@%p]: %016jx\n", i, ptr, *ptr);
+ }
+}
+
+#define __SI_FAULT (3 << 16)
+#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */
+#define SEGV_PKUERR (__SI_FAULT|4)
+
+static char *si_code_str(int si_code)
+{
+ if (si_code & SEGV_MAPERR)
+ return "SEGV_MAPERR";
+ if (si_code & SEGV_ACCERR)
+ return "SEGV_ACCERR";
+ if (si_code & SEGV_BNDERR)
+ return "SEGV_BNDERR";
+ if (si_code & SEGV_PKUERR)
+ return "SEGV_PKUERR";
+ return "UNKNOWN";
+}
+
+int pkru_faults;
+int last_si_pkey = -1;
+void signal_handler(int signum, siginfo_t *si, void *vucontext)
+{
+ ucontext_t *uctxt = vucontext;
+ int trapno;
+ unsigned long ip;
+ char *fpregs;
+ u32 *pkru_ptr;
+ u64 si_pkey;
+ u32 *si_pkey_ptr;
+ int pkru_offset;
+ fpregset_t fpregset;
+
+ dprint_in_signal = 1;
+ dprintf1(">>>>===============SIGSEGV============================\n");
+ dprintf1("%s()::%d, pkru: 0x%x shadow: %x\n", __func__, __LINE__,
+ __rdpkru(), shadow_pkru);
+
+ trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
+ ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
+ fpregset = uctxt->uc_mcontext.fpregs;
+ fpregs = (void *)fpregset;
+
+ dprintf2("%s() trapno: %d ip: 0x%lx info->si_code: %s/%d\n", __func__,
+ trapno, ip, si_code_str(si->si_code), si->si_code);
+#ifdef __i386__
+ /*
+ * 32-bit has some extra padding so that userspace can tell whether
+ * the XSTATE header is present in addition to the "legacy" FPU
+ * state. We just assume that it is here.
+ */
+ fpregs += 0x70;
+#endif
+ pkru_offset = pkru_xstate_offset();
+ pkru_ptr = (void *)(&fpregs[pkru_offset]);
+
+ dprintf1("siginfo: %p\n", si);
+ dprintf1(" fpregs: %p\n", fpregs);
+ /*
+ * If we got a PKRU fault, we *HAVE* to have at least one bit set in
+ * here.
+ */
+ dprintf1("pkru_xstate_offset: %d\n", pkru_xstate_offset());
+ if (DEBUG_LEVEL > 4)
+ dump_mem(pkru_ptr - 128, 256);
+ pkey_assert(*pkru_ptr);
+
+ si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset);
+ dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr);
+ dump_mem(si_pkey_ptr - 8, 24);
+ si_pkey = *si_pkey_ptr;
+ pkey_assert(si_pkey < NR_PKEYS);
+ last_si_pkey = si_pkey;
+
+ if ((si->si_code == SEGV_MAPERR) ||
+ (si->si_code == SEGV_ACCERR) ||
+ (si->si_code == SEGV_BNDERR)) {
+ printf("non-PK si_code, exiting...\n");
+ exit(4);
+ }
+
+ dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr);
+ /* need __rdpkru() version so we do not do shadow_pkru checking */
+ dprintf1("signal pkru from pkru: %08x\n", __rdpkru());
+ dprintf1("si_pkey from siginfo: %jx\n", si_pkey);
+ *(u64 *)pkru_ptr = 0x00000000;
+ dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n");
+ pkru_faults++;
+ dprintf1("<<<<==================================================\n");
+ return;
+ if (trapno == 14) {
+ fprintf(stderr,
+ "ERROR: In signal handler, page fault, trapno = %d, ip = %016lx\n",
+ trapno, ip);
+ fprintf(stderr, "si_addr %p\n", si->si_addr);
+ fprintf(stderr, "REG_ERR: %lx\n",
+ (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]);
+ exit(1);
+ } else {
+ fprintf(stderr, "unexpected trap %d! at 0x%lx\n", trapno, ip);
+ fprintf(stderr, "si_addr %p\n", si->si_addr);
+ fprintf(stderr, "REG_ERR: %lx\n",
+ (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]);
+ exit(2);
+ }
+ dprint_in_signal = 0;
+}
+
+int wait_all_children(void)
+{
+ int status;
+ return waitpid(-1, &status, 0);
+}
+
+void sig_chld(int x)
+{
+ dprint_in_signal = 1;
+ dprintf2("[%d] SIGCHLD: %d\n", getpid(), x);
+ dprint_in_signal = 0;
+}
+
+void setup_sigsegv_handler(void)
+{
+ int r, rs;
+ struct sigaction newact;
+ struct sigaction oldact;
+
+ /* #PF is mapped to sigsegv */
+ int signum = SIGSEGV;
+
+ newact.sa_handler = 0;
+ newact.sa_sigaction = signal_handler;
+
+ /*sigset_t - signals to block while in the handler */
+ /* get the old signal mask. */
+ rs = sigprocmask(SIG_SETMASK, 0, &newact.sa_mask);
+ pkey_assert(rs == 0);
+
+ /* call sa_sigaction, not sa_handler*/
+ newact.sa_flags = SA_SIGINFO;
+
+ newact.sa_restorer = 0; /* void(*)(), obsolete */
+ r = sigaction(signum, &newact, &oldact);
+ r = sigaction(SIGALRM, &newact, &oldact);
+ pkey_assert(r == 0);
+}
+
+void setup_handlers(void)
+{
+ signal(SIGCHLD, &sig_chld);
+ setup_sigsegv_handler();
+}
+
+pid_t fork_lazy_child(void)
+{
+ pid_t forkret;
+
+ forkret = fork();
+ pkey_assert(forkret >= 0);
+ dprintf3("[%d] fork() ret: %d\n", getpid(), forkret);
+
+ if (!forkret) {
+ /* in the child */
+ while (1) {
+ dprintf1("child sleeping...\n");
+ sleep(30);
+ }
+ }
+ return forkret;
+}
+
+void davecmp(void *_a, void *_b, int len)
+{
+ int i;
+ unsigned long *a = _a;
+ unsigned long *b = _b;
+
+ for (i = 0; i < len / sizeof(*a); i++) {
+ if (a[i] == b[i])
+ continue;
+
+ dprintf3("[%3d]: a: %016lx b: %016lx\n", i, a[i], b[i]);
+ }
+}
+
+void dumpit(char *f)
+{
+ int fd = open(f, O_RDONLY);
+ char buf[100];
+ int nr_read;
+
+ dprintf2("maps fd: %d\n", fd);
+ do {
+ nr_read = read(fd, &buf[0], sizeof(buf));
+ write(1, buf, nr_read);
+ } while (nr_read > 0);
+ close(fd);
+}
+
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+
+u32 pkey_get(int pkey, unsigned long flags)
+{
+ u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
+ u32 pkru = __rdpkru();
+ u32 shifted_pkru;
+ u32 masked_pkru;
+
+ dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
+ __func__, pkey, flags, 0, 0);
+ dprintf2("%s() raw pkru: %x\n", __func__, pkru);
+
+ shifted_pkru = (pkru >> (pkey * PKRU_BITS_PER_PKEY));
+ dprintf2("%s() shifted_pkru: %x\n", __func__, shifted_pkru);
+ masked_pkru = shifted_pkru & mask;
+ dprintf2("%s() masked pkru: %x\n", __func__, masked_pkru);
+ /*
+ * shift down the relevant bits to the lowest two, then
+ * mask off all the other high bits.
+ */
+ return masked_pkru;
+}
+
+int pkey_set(int pkey, unsigned long rights, unsigned long flags)
+{
+ u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
+ u32 old_pkru = __rdpkru();
+ u32 new_pkru;
+
+ /* make sure that 'rights' only contains the bits we expect: */
+ assert(!(rights & ~mask));
+
+ /* copy old pkru */
+ new_pkru = old_pkru;
+ /* mask out bits from pkey in old value: */
+ new_pkru &= ~(mask << (pkey * PKRU_BITS_PER_PKEY));
+ /* OR in new bits for pkey: */
+ new_pkru |= (rights << (pkey * PKRU_BITS_PER_PKEY));
+
+ __wrpkru(new_pkru);
+
+ dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x pkru now: %x old_pkru: %x\n",
+ __func__, pkey, rights, flags, 0, __rdpkru(), old_pkru);
+ return 0;
+}
+
+void pkey_disable_set(int pkey, int flags)
+{
+ unsigned long syscall_flags = 0;
+ int ret;
+ int pkey_rights;
+ u32 orig_pkru;
+
+ dprintf1("START->%s(%d, 0x%x)\n", __func__,
+ pkey, flags);
+ pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
+
+ pkey_rights = pkey_get(pkey, syscall_flags);
+
+ dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
+ pkey, pkey, pkey_rights);
+ pkey_assert(pkey_rights >= 0);
+
+ pkey_rights |= flags;
+
+ ret = pkey_set(pkey, pkey_rights, syscall_flags);
+ assert(!ret);
+ /*pkru and flags have the same format */
+ shadow_pkru |= flags << (pkey * 2);
+ dprintf1("%s(%d) shadow: 0x%x\n", __func__, pkey, shadow_pkru);
+
+ pkey_assert(ret >= 0);
+
+ pkey_rights = pkey_get(pkey, syscall_flags);
+ dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
+ pkey, pkey, pkey_rights);
+
+ dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru());
+ if (flags)
+ pkey_assert(rdpkru() > orig_pkru);
+ dprintf1("END<---%s(%d, 0x%x)\n", __func__,
+ pkey, flags);
+}
+
+void pkey_disable_clear(int pkey, int flags)
+{
+ unsigned long syscall_flags = 0;
+ int ret;
+ int pkey_rights = pkey_get(pkey, syscall_flags);
+ u32 orig_pkru = rdpkru();
+
+ pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
+
+ dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
+ pkey, pkey, pkey_rights);
+ pkey_assert(pkey_rights >= 0);
+
+ pkey_rights |= flags;
+
+ ret = pkey_set(pkey, pkey_rights, 0);
+ /* pkru and flags have the same format */
+ shadow_pkru &= ~(flags << (pkey * 2));
+ pkey_assert(ret >= 0);
+
+ pkey_rights = pkey_get(pkey, syscall_flags);
+ dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
+ pkey, pkey, pkey_rights);
+
+ dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru());
+ if (flags)
+ assert(rdpkru() > orig_pkru);
+}
+
+void pkey_write_allow(int pkey)
+{
+ pkey_disable_clear(pkey, PKEY_DISABLE_WRITE);
+}
+void pkey_write_deny(int pkey)
+{
+ pkey_disable_set(pkey, PKEY_DISABLE_WRITE);
+}
+void pkey_access_allow(int pkey)
+{
+ pkey_disable_clear(pkey, PKEY_DISABLE_ACCESS);
+}
+void pkey_access_deny(int pkey)
+{
+ pkey_disable_set(pkey, PKEY_DISABLE_ACCESS);
+}
+
+int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
+ unsigned long pkey)
+{
+ int sret;
+
+ dprintf2("%s(0x%p, %zx, prot=%lx, pkey=%lx)\n", __func__,
+ ptr, size, orig_prot, pkey);
+
+ errno = 0;
+ sret = syscall(SYS_mprotect_key, ptr, size, orig_prot, pkey);
+ if (errno) {
+ dprintf2("SYS_mprotect_key sret: %d\n", sret);
+ dprintf2("SYS_mprotect_key prot: 0x%lx\n", orig_prot);
+ dprintf2("SYS_mprotect_key failed, errno: %d\n", errno);
+ if (DEBUG_LEVEL >= 2)
+ perror("SYS_mprotect_pkey");
+ }
+ return sret;
+}
+
+int sys_pkey_alloc(unsigned long flags, unsigned long init_val)
+{
+ int ret = syscall(SYS_pkey_alloc, flags, init_val);
+ dprintf1("%s(flags=%lx, init_val=%lx) syscall ret: %d errno: %d\n",
+ __func__, flags, init_val, ret, errno);
+ return ret;
+}
+
+int alloc_pkey(void)
+{
+ int ret;
+ unsigned long init_val = 0x0;
+
+ dprintf1("alloc_pkey()::%d, pkru: 0x%x shadow: %x\n",
+ __LINE__, __rdpkru(), shadow_pkru);
+ ret = sys_pkey_alloc(0, init_val);
+ /*
+ * pkey_alloc() sets PKRU, so we need to reflect it in
+ * shadow_pkru:
+ */
+ dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ if (ret) {
+ /* clear both the bits: */
+ shadow_pkru &= ~(0x3 << (ret * 2));
+ dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ /*
+ * move the new state in from init_val
+ * (remember, we cheated and init_val == pkru format)
+ */
+ shadow_pkru |= (init_val << (ret * 2));
+ }
+ dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ dprintf1("alloc_pkey()::%d errno: %d\n", __LINE__, errno);
+ /* for shadow checking: */
+ rdpkru();
+ dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ return ret;
+}
+
+int sys_pkey_free(unsigned long pkey)
+{
+ int ret = syscall(SYS_pkey_free, pkey);
+ dprintf1("%s(pkey=%ld) syscall ret: %d\n", __func__, pkey, ret);
+ return ret;
+}
+
+/*
+ * I had a bug where pkey bits could be set by mprotect() but
+ * not cleared. This ensures we get lots of random bit sets
+ * and clears on the vma and pte pkey bits.
+ */
+int alloc_random_pkey(void)
+{
+ int max_nr_pkey_allocs;
+ int ret;
+ int i;
+ int alloced_pkeys[NR_PKEYS];
+ int nr_alloced = 0;
+ int random_index;
+ memset(alloced_pkeys, 0, sizeof(alloced_pkeys));
+
+ /* allocate every possible key and make a note of which ones we got */
+ max_nr_pkey_allocs = NR_PKEYS;
+ max_nr_pkey_allocs = 1;
+ for (i = 0; i < max_nr_pkey_allocs; i++) {
+ int new_pkey = alloc_pkey();
+ if (new_pkey < 0)
+ break;
+ alloced_pkeys[nr_alloced++] = new_pkey;
+ }
+
+ pkey_assert(nr_alloced > 0);
+ /* select a random one out of the allocated ones */
+ random_index = rand() % nr_alloced;
+ ret = alloced_pkeys[random_index];
+ /* now zero it out so we don't free it next */
+ alloced_pkeys[random_index] = 0;
+
+ /* go through the allocated ones that we did not want and free them */
+ for (i = 0; i < nr_alloced; i++) {
+ int free_ret;
+ if (!alloced_pkeys[i])
+ continue;
+ free_ret = sys_pkey_free(alloced_pkeys[i]);
+ pkey_assert(!free_ret);
+ }
+ dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ return ret;
+}
+
+int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
+ unsigned long pkey)
+{
+ int nr_iterations = random() % 100;
+ int ret;
+
+ while (0) {
+ int rpkey = alloc_random_pkey();
+ ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey);
+ dprintf1("sys_mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
+ ptr, size, orig_prot, pkey, ret);
+ if (nr_iterations-- < 0)
+ break;
+
+ dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ sys_pkey_free(rpkey);
+ dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ }
+ pkey_assert(pkey < NR_PKEYS);
+
+ ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey);
+ dprintf1("mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
+ ptr, size, orig_prot, pkey, ret);
+ pkey_assert(!ret);
+ dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
+ __LINE__, ret, __rdpkru(), shadow_pkru);
+ return ret;
+}
+
+struct pkey_malloc_record {
+ void *ptr;
+ long size;
+};
+struct pkey_malloc_record *pkey_malloc_records;
+long nr_pkey_malloc_records;
+void record_pkey_malloc(void *ptr, long size)
+{
+ long i;
+ struct pkey_malloc_record *rec = NULL;
+
+ for (i = 0; i < nr_pkey_malloc_records; i++) {
+ rec = &pkey_malloc_records[i];
+ /* find a free record */
+ if (rec)
+ break;
+ }
+ if (!rec) {
+ /* every record is full */
+ size_t old_nr_records = nr_pkey_malloc_records;
+ size_t new_nr_records = (nr_pkey_malloc_records * 2 + 1);
+ size_t new_size = new_nr_records * sizeof(struct pkey_malloc_record);
+ dprintf2("new_nr_records: %zd\n", new_nr_records);
+ dprintf2("new_size: %zd\n", new_size);
+ pkey_malloc_records = realloc(pkey_malloc_records, new_size);
+ pkey_assert(pkey_malloc_records != NULL);
+ rec = &pkey_malloc_records[nr_pkey_malloc_records];
+ /*
+ * realloc() does not initialize memory, so zero it from
+ * the first new record all the way to the end.
+ */
+ for (i = 0; i < new_nr_records - old_nr_records; i++)
+ memset(rec + i, 0, sizeof(*rec));
+ }
+ dprintf3("filling malloc record[%d/%p]: {%p, %ld}\n",
+ (int)(rec - pkey_malloc_records), rec, ptr, size);
+ rec->ptr = ptr;
+ rec->size = size;
+ nr_pkey_malloc_records++;
+}
+
+void free_pkey_malloc(void *ptr)
+{
+ long i;
+ int ret;
+ dprintf3("%s(%p)\n", __func__, ptr);
+ for (i = 0; i < nr_pkey_malloc_records; i++) {
+ struct pkey_malloc_record *rec = &pkey_malloc_records[i];
+ dprintf4("looking for ptr %p at record[%ld/%p]: {%p, %ld}\n",
+ ptr, i, rec, rec->ptr, rec->size);
+ if ((ptr < rec->ptr) ||
+ (ptr >= rec->ptr + rec->size))
+ continue;
+
+ dprintf3("found ptr %p at record[%ld/%p]: {%p, %ld}\n",
+ ptr, i, rec, rec->ptr, rec->size);
+ nr_pkey_malloc_records--;
+ ret = munmap(rec->ptr, rec->size);
+ dprintf3("munmap ret: %d\n", ret);
+ pkey_assert(!ret);
+ dprintf3("clearing rec->ptr, rec: %p\n", rec);
+ rec->ptr = NULL;
+ dprintf3("done clearing rec->ptr, rec: %p\n", rec);
+ return;
+ }
+ pkey_assert(false);
+}
+
+
+void *malloc_pkey_with_mprotect(long size, int prot, u16 pkey)
+{
+ void *ptr;
+ int ret;
+
+ rdpkru();
+ dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
+ size, prot, pkey);
+ pkey_assert(pkey < NR_PKEYS);
+ ptr = mmap(NULL, size, prot, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ pkey_assert(ptr != (void *)-1);
+ ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey);
+ pkey_assert(!ret);
+ record_pkey_malloc(ptr, size);
+ rdpkru();
+
+ dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr);
+ return ptr;
+}
+
+void *malloc_pkey_anon_huge(long size, int prot, u16 pkey)
+{
+ int ret;
+ void *ptr;
+
+ dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
+ size, prot, pkey);
+ /*
+ * Guarantee we can fit at least one huge page in the resulting
+ * allocation by allocating space for 2:
+ */
+ size = ALIGN_UP(size, HPAGE_SIZE * 2);
+ ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ pkey_assert(ptr != (void *)-1);
+ record_pkey_malloc(ptr, size);
+ mprotect_pkey(ptr, size, prot, pkey);
+
+ dprintf1("unaligned ptr: %p\n", ptr);
+ ptr = ALIGN_PTR_UP(ptr, HPAGE_SIZE);
+ dprintf1(" aligned ptr: %p\n", ptr);
+ ret = madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE);
+ dprintf1("MADV_HUGEPAGE ret: %d\n", ret);
+ ret = madvise(ptr, HPAGE_SIZE, MADV_WILLNEED);
+ dprintf1("MADV_WILLNEED ret: %d\n", ret);
+ memset(ptr, 0, HPAGE_SIZE);
+
+ dprintf1("mmap()'d thp for pkey %d @ %p\n", pkey, ptr);
+ return ptr;
+}
+
+int hugetlb_setup_ok;
+#define GET_NR_HUGE_PAGES 10
+void setup_hugetlbfs(void)
+{
+ int err;
+ int fd;
+ int validated_nr_pages;
+ int i;
+ char buf[] = "123";
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "WARNING: not run as root, can not do hugetlb test\n");
+ return;
+ }
+
+ cat_into_file(__stringify(GET_NR_HUGE_PAGES), "/proc/sys/vm/nr_hugepages");
+
+ /*
+ * Now go make sure that we got the pages and that they
+ * are 2M pages. Someone might have made 1G the default.
+ */
+ fd = open("/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages", O_RDONLY);
+ if (fd < 0) {
+ perror("opening sysfs 2M hugetlb config");
+ return;
+ }
+
+ /* -1 to guarantee leaving the trailing \0 */
+ err = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if (err <= 0) {
+ perror("reading sysfs 2M hugetlb config");
+ return;
+ }
+
+ if (atoi(buf) != GET_NR_HUGE_PAGES) {
+ fprintf(stderr, "could not confirm 2M pages, got: '%s' expected %d\n",
+ buf, GET_NR_HUGE_PAGES);
+ return;
+ }
+
+ hugetlb_setup_ok = 1;
+}
+
+void *malloc_pkey_hugetlb(long size, int prot, u16 pkey)
+{
+ void *ptr;
+ int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB;
+
+ if (!hugetlb_setup_ok)
+ return PTR_ERR_ENOTSUP;
+
+ dprintf1("doing %s(%ld, %x, %x)\n", __func__, size, prot, pkey);
+ size = ALIGN_UP(size, HPAGE_SIZE * 2);
+ pkey_assert(pkey < NR_PKEYS);
+ ptr = mmap(NULL, size, PROT_NONE, flags, -1, 0);
+ pkey_assert(ptr != (void *)-1);
+ mprotect_pkey(ptr, size, prot, pkey);
+
+ record_pkey_malloc(ptr, size);
+
+ dprintf1("mmap()'d hugetlbfs for pkey %d @ %p\n", pkey, ptr);
+ return ptr;
+}
+
+void *malloc_pkey_mmap_dax(long size, int prot, u16 pkey)
+{
+ void *ptr;
+ int fd;
+
+ dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
+ size, prot, pkey);
+ pkey_assert(pkey < NR_PKEYS);
+ fd = open("/dax/foo", O_RDWR);
+ pkey_assert(fd >= 0);
+
+ ptr = mmap(0, size, prot, MAP_SHARED, fd, 0);
+ pkey_assert(ptr != (void *)-1);
+
+ mprotect_pkey(ptr, size, prot, pkey);
+
+ record_pkey_malloc(ptr, size);
+
+ dprintf1("mmap()'d for pkey %d @ %p\n", pkey, ptr);
+ close(fd);
+ return ptr;
+}
+
+void *(*pkey_malloc[])(long size, int prot, u16 pkey) = {
+
+ malloc_pkey_with_mprotect,
+ malloc_pkey_anon_huge,
+ malloc_pkey_hugetlb
+/* can not do direct with the pkey_mprotect() API:
+ malloc_pkey_mmap_direct,
+ malloc_pkey_mmap_dax,
+*/
+};
+
+void *malloc_pkey(long size, int prot, u16 pkey)
+{
+ void *ret;
+ static int malloc_type;
+ int nr_malloc_types = ARRAY_SIZE(pkey_malloc);
+
+ pkey_assert(pkey < NR_PKEYS);
+
+ while (1) {
+ pkey_assert(malloc_type < nr_malloc_types);
+
+ ret = pkey_malloc[malloc_type](size, prot, pkey);
+ pkey_assert(ret != (void *)-1);
+
+ malloc_type++;
+ if (malloc_type >= nr_malloc_types)
+ malloc_type = (random()%nr_malloc_types);
+
+ /* try again if the malloc_type we tried is unsupported */
+ if (ret == PTR_ERR_ENOTSUP)
+ continue;
+
+ break;
+ }
+
+ dprintf3("%s(%ld, prot=%x, pkey=%x) returning: %p\n", __func__,
+ size, prot, pkey, ret);
+ return ret;
+}
+
+int last_pkru_faults;
+void expected_pk_fault(int pkey)
+{
+ dprintf2("%s(): last_pkru_faults: %d pkru_faults: %d\n",
+ __func__, last_pkru_faults, pkru_faults);
+ dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey);
+ pkey_assert(last_pkru_faults + 1 == pkru_faults);
+ pkey_assert(last_si_pkey == pkey);
+ /*
+ * The signal handler shold have cleared out PKRU to let the
+ * test program continue. We now have to restore it.
+ */
+ if (__rdpkru() != 0)
+ pkey_assert(0);
+
+ __wrpkru(shadow_pkru);
+ dprintf1("%s() set PKRU=%x to restore state after signal nuked it\n",
+ __func__, shadow_pkru);
+ last_pkru_faults = pkru_faults;
+ last_si_pkey = -1;
+}
+
+void do_not_expect_pk_fault(void)
+{
+ pkey_assert(last_pkru_faults == pkru_faults);
+}
+
+int test_fds[10] = { -1 };
+int nr_test_fds;
+void __save_test_fd(int fd)
+{
+ pkey_assert(fd >= 0);
+ pkey_assert(nr_test_fds < ARRAY_SIZE(test_fds));
+ test_fds[nr_test_fds] = fd;
+ nr_test_fds++;
+}
+
+int get_test_read_fd(void)
+{
+ int test_fd = open("/etc/passwd", O_RDONLY);
+ __save_test_fd(test_fd);
+ return test_fd;
+}
+
+void close_test_fds(void)
+{
+ int i;
+
+ for (i = 0; i < nr_test_fds; i++) {
+ if (test_fds[i] < 0)
+ continue;
+ close(test_fds[i]);
+ test_fds[i] = -1;
+ }
+ nr_test_fds = 0;
+}
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+__attribute__((noinline)) int read_ptr(int *ptr)
+{
+ /*
+ * Keep GCC from optimizing this away somehow
+ */
+ barrier();
+ return *ptr;
+}
+
+void test_read_of_write_disabled_region(int *ptr, u16 pkey)
+{
+ int ptr_contents;
+
+ dprintf1("disabling write access to PKEY[1], doing read\n");
+ pkey_write_deny(pkey);
+ ptr_contents = read_ptr(ptr);
+ dprintf1("*ptr: %d\n", ptr_contents);
+ dprintf1("\n");
+}
+void test_read_of_access_disabled_region(int *ptr, u16 pkey)
+{
+ int ptr_contents;
+
+ dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", pkey, ptr);
+ rdpkru();
+ pkey_access_deny(pkey);
+ ptr_contents = read_ptr(ptr);
+ dprintf1("*ptr: %d\n", ptr_contents);
+ expected_pk_fault(pkey);
+}
+void test_write_of_write_disabled_region(int *ptr, u16 pkey)
+{
+ dprintf1("disabling write access to PKEY[%02d], doing write\n", pkey);
+ pkey_write_deny(pkey);
+ *ptr = __LINE__;
+ expected_pk_fault(pkey);
+}
+void test_write_of_access_disabled_region(int *ptr, u16 pkey)
+{
+ dprintf1("disabling access to PKEY[%02d], doing write\n", pkey);
+ pkey_access_deny(pkey);
+ *ptr = __LINE__;
+ expected_pk_fault(pkey);
+}
+void test_kernel_write_of_access_disabled_region(int *ptr, u16 pkey)
+{
+ int ret;
+ int test_fd = get_test_read_fd();
+
+ dprintf1("disabling access to PKEY[%02d], "
+ "having kernel read() to buffer\n", pkey);
+ pkey_access_deny(pkey);
+ ret = read(test_fd, ptr, 1);
+ dprintf1("read ret: %d\n", ret);
+ pkey_assert(ret);
+}
+void test_kernel_write_of_write_disabled_region(int *ptr, u16 pkey)
+{
+ int ret;
+ int test_fd = get_test_read_fd();
+
+ pkey_write_deny(pkey);
+ ret = read(test_fd, ptr, 100);
+ dprintf1("read ret: %d\n", ret);
+ if (ret < 0 && (DEBUG_LEVEL > 0))
+ perror("verbose read result (OK for this to be bad)");
+ pkey_assert(ret);
+}
+
+void test_kernel_gup_of_access_disabled_region(int *ptr, u16 pkey)
+{
+ int pipe_ret, vmsplice_ret;
+ struct iovec iov;
+ int pipe_fds[2];
+
+ pipe_ret = pipe(pipe_fds);
+
+ pkey_assert(pipe_ret == 0);
+ dprintf1("disabling access to PKEY[%02d], "
+ "having kernel vmsplice from buffer\n", pkey);
+ pkey_access_deny(pkey);
+ iov.iov_base = ptr;
+ iov.iov_len = PAGE_SIZE;
+ vmsplice_ret = vmsplice(pipe_fds[1], &iov, 1, SPLICE_F_GIFT);
+ dprintf1("vmsplice() ret: %d\n", vmsplice_ret);
+ pkey_assert(vmsplice_ret == -1);
+
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+}
+
+void test_kernel_gup_write_to_write_disabled_region(int *ptr, u16 pkey)
+{
+ int ignored = 0xdada;
+ int futex_ret;
+ int some_int = __LINE__;
+
+ dprintf1("disabling write to PKEY[%02d], "
+ "doing futex gunk in buffer\n", pkey);
+ *ptr = some_int;
+ pkey_write_deny(pkey);
+ futex_ret = syscall(SYS_futex, ptr, FUTEX_WAIT, some_int-1, NULL,
+ &ignored, ignored);
+ if (DEBUG_LEVEL > 0)
+ perror("futex");
+ dprintf1("futex() ret: %d\n", futex_ret);
+}
+
+/* Assumes that all pkeys other than 'pkey' are unallocated */
+void test_pkey_syscalls_on_non_allocated_pkey(int *ptr, u16 pkey)
+{
+ int err;
+ int i;
+
+ /* Note: 0 is the default pkey, so don't mess with it */
+ for (i = 1; i < NR_PKEYS; i++) {
+ if (pkey == i)
+ continue;
+
+ dprintf1("trying get/set/free to non-allocated pkey: %2d\n", i);
+ err = sys_pkey_free(i);
+ pkey_assert(err);
+
+ /* not enforced when pkey_get() is not a syscall
+ err = pkey_get(i, 0);
+ pkey_assert(err < 0);
+ */
+
+ err = sys_pkey_free(i);
+ pkey_assert(err);
+
+ err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, i);
+ pkey_assert(err);
+ }
+}
+
+/* Assumes that all pkeys other than 'pkey' are unallocated */
+void test_pkey_syscalls_bad_args(int *ptr, u16 pkey)
+{
+ int err;
+ int bad_flag = (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE) + 1;
+ int bad_pkey = NR_PKEYS+99;
+
+ /* not enforced when pkey_get() is not a syscall
+ err = pkey_get(bad_pkey, bad_flag);
+ pkey_assert(err < 0);
+ */
+
+ /* pass a known-invalid pkey in: */
+ err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, bad_pkey);
+ pkey_assert(err);
+}
+
+/* Assumes that all pkeys other than 'pkey' are unallocated */
+void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
+{
+ unsigned long flags;
+ unsigned long init_val;
+ int err;
+ int allocated_pkeys[NR_PKEYS] = {0};
+ int nr_allocated_pkeys = 0;
+ int i;
+
+ for (i = 0; i < NR_PKEYS*2; i++) {
+ int new_pkey;
+ dprintf1("%s() alloc loop: %d\n", __func__, i);
+ new_pkey = alloc_pkey();
+ dprintf4("%s()::%d, err: %d pkru: 0x%x shadow: 0x%x\n", __func__,
+ __LINE__, err, __rdpkru(), shadow_pkru);
+ rdpkru(); /* for shadow checking */
+ dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC);
+ if ((new_pkey == -1) && (errno == ENOSPC)) {
+ dprintf2("%s() failed to allocate pkey after %d tries\n",
+ __func__, nr_allocated_pkeys);
+ break;
+ }
+ pkey_assert(nr_allocated_pkeys < NR_PKEYS);
+ allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
+ }
+
+ dprintf3("%s()::%d\n", __func__, __LINE__);
+
+ /*
+ * ensure it did not reach the end of the loop without
+ * failure:
+ */
+ pkey_assert(i < NR_PKEYS*2);
+
+ /*
+ * There are 16 pkeys supported in hardware. One is taken
+ * up for the default (0) and another can be taken up by
+ * an execute-only mapping. Ensure that we can allocate
+ * at least 14 (16-2).
+ */
+ pkey_assert(i >= NR_PKEYS-2);
+
+ for (i = 0; i < nr_allocated_pkeys; i++) {
+ err = sys_pkey_free(allocated_pkeys[i]);
+ pkey_assert(!err);
+ rdpkru(); /* for shadow checking */
+ }
+}
+
+void test_ptrace_of_child(int *ptr, u16 pkey)
+{
+ __attribute__((__unused__)) int peek_result;
+ pid_t child_pid;
+ void *ignored = 0;
+ long ret;
+ int status;
+ /*
+ * This is the "control" for our little expermient. Make sure
+ * we can always access it when ptracing.
+ */
+ int *plain_ptr_unaligned = malloc(HPAGE_SIZE);
+ int *plain_ptr = ALIGN_PTR_UP(plain_ptr_unaligned, PAGE_SIZE);
+
+ /*
+ * Fork a child which is an exact copy of this process, of course.
+ * That means we can do all of our tests via ptrace() and then plain
+ * memory access and ensure they work differently.
+ */
+ child_pid = fork_lazy_child();
+ dprintf1("[%d] child pid: %d\n", getpid(), child_pid);
+
+ ret = ptrace(PTRACE_ATTACH, child_pid, ignored, ignored);
+ if (ret)
+ perror("attach");
+ dprintf1("[%d] attach ret: %ld %d\n", getpid(), ret, __LINE__);
+ pkey_assert(ret != -1);
+ ret = waitpid(child_pid, &status, WUNTRACED);
+ if ((ret != child_pid) || !(WIFSTOPPED(status))) {
+ fprintf(stderr, "weird waitpid result %ld stat %x\n",
+ ret, status);
+ pkey_assert(0);
+ }
+ dprintf2("waitpid ret: %ld\n", ret);
+ dprintf2("waitpid status: %d\n", status);
+
+ pkey_access_deny(pkey);
+ pkey_write_deny(pkey);
+
+ /* Write access, untested for now:
+ ret = ptrace(PTRACE_POKEDATA, child_pid, peek_at, data);
+ pkey_assert(ret != -1);
+ dprintf1("poke at %p: %ld\n", peek_at, ret);
+ */
+
+ /*
+ * Try to access the pkey-protected "ptr" via ptrace:
+ */
+ ret = ptrace(PTRACE_PEEKDATA, child_pid, ptr, ignored);
+ /* expect it to work, without an error: */
+ pkey_assert(ret != -1);
+ /* Now access from the current task, and expect an exception: */
+ peek_result = read_ptr(ptr);
+ expected_pk_fault(pkey);
+
+ /*
+ * Try to access the NON-pkey-protected "plain_ptr" via ptrace:
+ */
+ ret = ptrace(PTRACE_PEEKDATA, child_pid, plain_ptr, ignored);
+ /* expect it to work, without an error: */
+ pkey_assert(ret != -1);
+ /* Now access from the current task, and expect NO exception: */
+ peek_result = read_ptr(plain_ptr);
+ do_not_expect_pk_fault();
+
+ ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0);
+ pkey_assert(ret != -1);
+
+ ret = kill(child_pid, SIGKILL);
+ pkey_assert(ret != -1);
+
+ wait(&status);
+
+ free(plain_ptr_unaligned);
+}
+
+void test_executing_on_unreadable_memory(int *ptr, u16 pkey)
+{
+ void *p1;
+ int scratch;
+ int ptr_contents;
+ int ret;
+
+ p1 = ALIGN_PTR_UP(&lots_o_noops_around_write, PAGE_SIZE);
+ dprintf3("&lots_o_noops: %p\n", &lots_o_noops_around_write);
+ /* lots_o_noops_around_write should be page-aligned already */
+ assert(p1 == &lots_o_noops_around_write);
+
+ /* Point 'p1' at the *second* page of the function: */
+ p1 += PAGE_SIZE;
+
+ madvise(p1, PAGE_SIZE, MADV_DONTNEED);
+ lots_o_noops_around_write(&scratch);
+ ptr_contents = read_ptr(p1);
+ dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
+
+ ret = mprotect_pkey(p1, PAGE_SIZE, PROT_EXEC, (u64)pkey);
+ pkey_assert(!ret);
+ pkey_access_deny(pkey);
+
+ dprintf2("pkru: %x\n", rdpkru());
+
+ /*
+ * Make sure this is an *instruction* fault
+ */
+ madvise(p1, PAGE_SIZE, MADV_DONTNEED);
+ lots_o_noops_around_write(&scratch);
+ do_not_expect_pk_fault();
+ ptr_contents = read_ptr(p1);
+ dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
+ expected_pk_fault(pkey);
+}
+
+void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
+{
+ int size = PAGE_SIZE;
+ int sret;
+
+ if (cpu_has_pku()) {
+ dprintf1("SKIP: %s: no CPU support\n", __func__);
+ return;
+ }
+
+ sret = syscall(SYS_mprotect_key, ptr, size, PROT_READ, pkey);
+ pkey_assert(sret < 0);
+}
+
+void (*pkey_tests[])(int *ptr, u16 pkey) = {
+ test_read_of_write_disabled_region,
+ test_read_of_access_disabled_region,
+ test_write_of_write_disabled_region,
+ test_write_of_access_disabled_region,
+ test_kernel_write_of_access_disabled_region,
+ test_kernel_write_of_write_disabled_region,
+ test_kernel_gup_of_access_disabled_region,
+ test_kernel_gup_write_to_write_disabled_region,
+ test_executing_on_unreadable_memory,
+ test_ptrace_of_child,
+ test_pkey_syscalls_on_non_allocated_pkey,
+ test_pkey_syscalls_bad_args,
+ test_pkey_alloc_exhaust,
+};
+
+void run_tests_once(void)
+{
+ int *ptr;
+ int prot = PROT_READ|PROT_WRITE;
+
+ for (test_nr = 0; test_nr < ARRAY_SIZE(pkey_tests); test_nr++) {
+ int pkey;
+ int orig_pkru_faults = pkru_faults;
+
+ dprintf1("======================\n");
+ dprintf1("test %d preparing...\n", test_nr);
+
+ tracing_on();
+ pkey = alloc_random_pkey();
+ dprintf1("test %d starting with pkey: %d\n", test_nr, pkey);
+ ptr = malloc_pkey(PAGE_SIZE, prot, pkey);
+ dprintf1("test %d starting...\n", test_nr);
+ pkey_tests[test_nr](ptr, pkey);
+ dprintf1("freeing test memory: %p\n", ptr);
+ free_pkey_malloc(ptr);
+ sys_pkey_free(pkey);
+
+ dprintf1("pkru_faults: %d\n", pkru_faults);
+ dprintf1("orig_pkru_faults: %d\n", orig_pkru_faults);
+
+ tracing_off();
+ close_test_fds();
+
+ printf("test %2d PASSED (itertation %d)\n", test_nr, iteration_nr);
+ dprintf1("======================\n\n");
+ }
+ iteration_nr++;
+}
+
+void pkey_setup_shadow(void)
+{
+ shadow_pkru = __rdpkru();
+}
+
+int main(void)
+{
+ int nr_iterations = 22;
+
+ setup_handlers();
+
+ printf("has pku: %d\n", cpu_has_pku());
+
+ if (!cpu_has_pku()) {
+ int size = PAGE_SIZE;
+ int *ptr;
+
+ printf("running PKEY tests for unsupported CPU/OS\n");
+
+ ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ assert(ptr != (void *)-1);
+ test_mprotect_pkey_on_unsupported_cpu(ptr, 1);
+ exit(0);
+ }
+
+ pkey_setup_shadow();
+ printf("startup pkru: %x\n", rdpkru());
+ setup_hugetlbfs();
+
+ while (nr_iterations-- > 0)
+ run_tests_once();
+
+ printf("done (all tests OK)\n");
+ return 0;
+}